Skip to content

Commit

Permalink
Fix sub-query handling
Browse files Browse the repository at this point in the history
  • Loading branch information
axelheer committed Feb 19, 2019
1 parent 445f1a9 commit 892d89e
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 14 deletions.
2 changes: 1 addition & 1 deletion PackageData.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ To support different LINQ implementations, the following flavours are available.
<PackageIconUrl>https://www.heer.eu/media/axel.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/axelheer/nein-linq</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReleaseNotes>.</PackageReleaseNotes>
<PackageReleaseNotes>Added sub-query optimizations for certain query providers. Again.</PackageReleaseNotes>
<PackageTags>LINQ;EF;IX</PackageTags>
</PropertyGroup>

Expand Down
23 changes: 16 additions & 7 deletions src/NeinLinq.Interactive/RewriteAsyncQueryCleaner.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

Expand All @@ -13,17 +14,25 @@ protected override Expression VisitMember(MemberExpression node)
if (node == null)
throw new ArgumentNullException(nameof(node));

if (node.Expression is ConstantExpression expression)
if (typeof(IAsyncQueryable).IsAssignableFrom(node.Type))
{
var value = GetValue(expression, node.Member);
var expression = Visit(node.Expression);

while (value is RewriteAsyncQueryable query)
if (expression is ConstantExpression target)
{
value = rewriteQuery.MakeGenericMethod(query.ElementType)
.Invoke(query.Provider, new object[] { query.Expression });
var value = GetValue(target, node.Member);

while (value is RewriteAsyncQueryable rewrite)
{
value = rewriteQuery.MakeGenericMethod(rewrite.ElementType)
.Invoke(rewrite.Provider, new object[] { rewrite.Expression });
}

if (value is IAsyncQueryable query)
{
return query.Expression;
}
}

return Expression.Constant(value, node.Type);
}

return base.VisitMember(node);
Expand Down
21 changes: 15 additions & 6 deletions src/NeinLinq.Queryable/RewriteQueryCleaner.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

Expand All @@ -11,16 +12,24 @@ protected override Expression VisitMember(MemberExpression node)
if (node == null)
throw new ArgumentNullException(nameof(node));

if (node.Expression is ConstantExpression expression)
if (typeof(IQueryable).IsAssignableFrom(node.Type))
{
var value = GetValue(expression, node.Member);
var expression = Visit(node.Expression);

while (value is RewriteQueryable query)
if (expression is ConstantExpression target)
{
value = query.Provider.RewriteQuery(query.Expression);
}
var value = GetValue(target, node.Member);

while (value is RewriteQueryable rewrite)
{
value = rewrite.Provider.RewriteQuery(rewrite.Expression);
}

return Expression.Constant(value, node.Type);
if (value is IQueryable query)
{
return query.Expression;
}
}
}

return base.VisitMember(node);
Expand Down
18 changes: 18 additions & 0 deletions test/NeinLinq.Tests/DbAsyncQuery/RealTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,24 @@ where dummies.Any(d => d.Id < dummy.Id)
Assert.Equal(2, result.Count);
}

[WindowsFact]
public async Task SubQueryShouldSucceedWithProjection()
{
var innerRewriter = new Rewriter();
var dummies = db.Dummies.DbRewrite(innerRewriter).Select(d => new { d.Id });

var outerRewriter = new Rewriter();
var query = from dummy in db.Dummies.DbRewrite(outerRewriter)
where dummies.Any(d => d.Id < dummy.Id)
select dummy;

var result = await query.ToListAsync();

Assert.True(outerRewriter.VisitCalled);
Assert.True(innerRewriter.VisitCalled);
Assert.Equal(2, result.Count);
}

[WindowsFact]
public async Task SubQueryShouldSucceedWithInclude()
{
Expand Down
18 changes: 18 additions & 0 deletions test/NeinLinq.Tests/EntityAsyncQuery/RealTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,24 @@ where dummies.Any(d => d.Id < dummy.Id)
Assert.Equal(2, result.Count);
}

[Fact]
public async Task SubQueryShouldSucceedWithProjection()
{
var innerRewriter = new Rewriter();
var dummies = db.Dummies.EntityRewrite(innerRewriter).Select(d => new { d.Id });

var outerRewriter = new Rewriter();
var query = from dummy in db.Dummies.EntityRewrite(outerRewriter)
where dummies.Any(d => d.Id < dummy.Id)
select dummy;

var result = await query.ToListAsync();

Assert.True(outerRewriter.VisitCalled);
Assert.True(innerRewriter.VisitCalled);
Assert.Equal(2, result.Count);
}

[Fact]
public async Task SubQueryShouldSucceedWithInclude()
{
Expand Down
22 changes: 22 additions & 0 deletions test/NeinLinq.Tests/NullsafeQuery/QueryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,5 +217,27 @@ orderby a.SomeNumeric

var result = query.ToList();
}

[Fact]
public void ShouldHandleMember()
{
var danger = default(string);

var query = from a in data.ToNullsafe()
orderby a.SomeNumeric
select new DummyView
{
Numeric = danger.Length
};

var result = query.ToList();

Assert.Collection(result,
r => Assert.Equal(0, r.Numeric),
r => Assert.Equal(0, r.Numeric),
r => Assert.Equal(0, r.Numeric),
r => Assert.Equal(0, r.Numeric),
r => Assert.Equal(0, r.Numeric));
}
}
}

0 comments on commit 892d89e

Please sign in to comment.