Skip to content

Commit b1ab5b4

Browse files
Ticket #4 : Allow filtering
1 parent 5ab2c54 commit b1ab5b4

9 files changed

Lines changed: 1700 additions & 4 deletions

samples/EFCore.Cassandra.Samples/Program.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,16 @@ static void Main(string[] args)
2828
Console.WriteLine($"Number of applicants '{dbContext.Applicants.LongCount()}'");
2929

3030
Console.WriteLine("Get applicants by partition key");
31-
var filteredApplicants = dbContext.Applicants.Where(_ => _.Id == ApplicantPartitionId).ToList();
31+
var filteredApplicants = dbContext.Applicants.Where(_ => _.Id == ApplicantPartitionId, false).ToList();
3232
Console.WriteLine($"Number of applicants '{filteredApplicants.Count}'");
3333

34+
Console.WriteLine("Get applicants (ALLOW FILTERING)");
35+
var allowedFilteredApplicants = dbContext.Applicants.Where(_ => _.LastName == "lastname", true).ToList();
36+
Console.WriteLine($"Number of applicants {allowedFilteredApplicants.Count}");
37+
3438
Console.WriteLine("Order applicants by 'order'");
35-
var orderedApplicants = dbContext.Applicants.Where(_ => _.Id == ApplicantPartitionId).OrderBy(_ => _.Order).ToList();
39+
var orderedApplicants = dbContext.Applicants.Where(_ => _.Id == ApplicantPartitionId)
40+
.OrderBy(_ => _.Order).ToList();
3641
Console.WriteLine($"Number of applicants {orderedApplicants.Count}");
3742

3843
Console.WriteLine("Update the applicant");

src/EFCore.Cassandra/CassandraServiceCollectionExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.EntityFrameworkCore.Cassandra.Infrastructure.Internal;
66
using Microsoft.EntityFrameworkCore.Cassandra.Migrations;
77
using Microsoft.EntityFrameworkCore.Cassandra.Migrations.Internal;
8+
using Microsoft.EntityFrameworkCore.Cassandra.Query.Internal;
89
using Microsoft.EntityFrameworkCore.Cassandra.Query.Sql.Internal;
910
using Microsoft.EntityFrameworkCore.Cassandra.Storage;
1011
using Microsoft.EntityFrameworkCore.Cassandra.Storage.Internal;
@@ -43,6 +44,7 @@ public static IServiceCollection AddEntityFrameworkCassandra(this IServiceCollec
4344
.TryAdd<IRelationalSqlTranslatingExpressionVisitorFactory, CassandraSqlTranslatingExpressionVisitorFactory>()
4445
.TryAdd<IQuerySqlGeneratorFactory, CassandraSqlGeneratorFactory>()
4546
.TryAdd<IUpdateSqlGenerator, CassandraUpdateSqlGenerator>()
47+
.TryAdd<IQueryableMethodTranslatingExpressionVisitorFactory, CassandraQueryableMethodTranslatingExpressionVisitorFactory>()
4648
.TryAddProviderSpecificServices(b => b.TryAddScoped<ICassandraRelationalConnection, CassandraRelationalConnection>())
4749
.TryAddProviderSpecificServices(b => b.TryAddTransient<ICassandraHistoryRepository, CassandraHistoryRepository>());
4850

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Linq.Expressions;
5+
using System.Reflection;
6+
using System.Text;
7+
8+
namespace System.Linq
9+
{
10+
public static class CassandraQueryable
11+
{
12+
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, bool allowFiltering = false)
13+
{
14+
if (source == null)
15+
{
16+
throw new ArgumentNullException(nameof(source));
17+
}
18+
if (predicate == null)
19+
{
20+
throw new ArgumentNullException(nameof(predicate));
21+
}
22+
23+
if (allowFiltering)
24+
{
25+
return source.Provider.CreateQuery<TSource>(
26+
Expression.Call(
27+
null,
28+
Casandra_Where_TSource_2(typeof(TSource)),
29+
source.Expression, Expression.Quote(predicate), Expression.Constant(allowFiltering)
30+
));
31+
32+
}
33+
34+
return source.Provider.CreateQuery<TSource>(
35+
Expression.Call(
36+
null,
37+
Where_TSource_2(typeof(TSource)),
38+
source.Expression, Expression.Quote(predicate)
39+
));
40+
}
41+
42+
private static MethodInfo? s_Cassandra_Where_TSource_2;
43+
private static MethodInfo? s_Where_TSource_2;
44+
45+
private static MethodInfo Casandra_Where_TSource_2(Type TSource) =>
46+
(s_Cassandra_Where_TSource_2 ??
47+
(s_Cassandra_Where_TSource_2 = new Func<IQueryable<object>, Expression<Func<object, bool>>, bool, IQueryable<object>>(CassandraQueryable.Where).GetMethodInfo().GetGenericMethodDefinition()))
48+
.MakeGenericMethod(TSource);
49+
50+
private static MethodInfo Where_TSource_2(Type TSource) =>
51+
(s_Where_TSource_2 ??
52+
(s_Where_TSource_2 = new Func<IQueryable<object>, Expression<Func<object, bool>>, IQueryable<object>>(Queryable.Where).GetMethodInfo().GetGenericMethodDefinition()))
53+
.MakeGenericMethod(TSource);
54+
}
55+
}

src/EFCore.Cassandra/Query/CassandraQuerySqlGenerator.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) SimpleIdServer. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
using Microsoft.EntityFrameworkCore.Cassandra.Query.Internal;
34
using Microsoft.EntityFrameworkCore.Diagnostics;
45
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
56
using Microsoft.EntityFrameworkCore.Storage;
@@ -64,6 +65,11 @@ private bool IsNonComposedSetOperation(SelectExpression selectExpression)
6465
column.Name, setOperation.Source1.Projection[index].Alias, StringComparison.OrdinalIgnoreCase))
6566
.All(e => e);
6667

68+
public override Expression Visit(Expression node)
69+
{
70+
return base.Visit(node);
71+
}
72+
6773
protected override Expression VisitSelect(SelectExpression selectExpression)
6874
{
6975
if (IsNonComposedSetOperation(selectExpression))
@@ -109,8 +115,16 @@ protected override Expression VisitSelect(SelectExpression selectExpression)
109115
if (selectExpression.Predicate != null)
110116
{
111117
Sql.AppendLine().Append("WHERE ");
112-
113-
Visit(selectExpression.Predicate);
118+
var cassandraBinaryExpression = selectExpression.Predicate as CassandraAllowFilteringBinaryExpression;
119+
if (cassandraBinaryExpression != null)
120+
{
121+
Visit(cassandraBinaryExpression.BinaryExpression);
122+
Sql.AppendLine(" ALLOW FILTERING");
123+
}
124+
else
125+
{
126+
Visit(selectExpression.Predicate);
127+
}
114128
}
115129

116130
if (selectExpression.GroupBy.Count > 0)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) SimpleIdServer. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
using Microsoft.EntityFrameworkCore.Query;
5+
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
6+
using Microsoft.EntityFrameworkCore.Storage;
7+
using System;
8+
using System.Linq.Expressions;
9+
10+
namespace Microsoft.EntityFrameworkCore.Cassandra.Query.Internal
11+
{
12+
public class CassandraAllowFilteringBinaryExpression : SqlExpression
13+
{
14+
public CassandraAllowFilteringBinaryExpression(
15+
RelationalTypeMapping typeMapping,
16+
Type type,
17+
SqlExpression binaryExpression)
18+
: base(type, typeMapping)
19+
{
20+
BinaryExpression = binaryExpression;
21+
}
22+
23+
public SqlExpression BinaryExpression { get; set; }
24+
25+
public override void Print(ExpressionPrinter expressionPrinter)
26+
{
27+
28+
}
29+
30+
protected override Expression VisitChildren(ExpressionVisitor visitor)
31+
{
32+
return this;
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)