Skip to content

Commit 2aaa2c2

Browse files
committed
Flatten nested queries generated by OData $skip and $select combinations.
1 parent e7126dc commit 2aaa2c2

File tree

8 files changed

+167
-6
lines changed

8 files changed

+167
-6
lines changed

Ciao.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="4.0" DefaultTargets="Bootstrap" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<PropertyGroup Label="Version">
4-
<VersionPrefix>3.3.3</VersionPrefix>
4+
<VersionPrefix>3.3.4</VersionPrefix>
55
<VersionSuffix></VersionSuffix>
66
</PropertyGroup>
77

source/Lucene.Net.Linq.Tests/Integration/SelectTests.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using System.Linq;
1+
using System.Linq;
32
using Lucene.Net.Analysis;
43
using Lucene.Net.Linq.Analysis;
54
using Lucene.Net.Linq.Mapping;
@@ -517,4 +516,4 @@ public void Where_AnyField_StartsWith()
517516

518517
}
519518

520-
}
519+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System.Linq;
2+
using NUnit.Framework;
3+
4+
namespace Lucene.Net.Linq.Tests.Integration
5+
{
6+
[TestFixture]
7+
public class SubQueryTests : IntegrationTestBase
8+
{
9+
[SetUp]
10+
public void SetUp()
11+
{
12+
AddDocument(new SampleDocument { Id = "a", Scalar = 5});
13+
AddDocument(new SampleDocument { Id = "b", Scalar = 1});
14+
AddDocument(new SampleDocument { Id = "c", Scalar = 3});
15+
}
16+
17+
[Test]
18+
public void SubquerySkip()
19+
{
20+
var docs = provider.AsQueryable<SampleDocument>();
21+
22+
var results = (from outer in
23+
(from d in docs
24+
orderby d.Id
25+
select d).Skip(2)
26+
select new { outer.Id })
27+
.ToList();
28+
29+
Assert.That(results.Select(d => d.Id).ToArray(), Is.EqualTo(new[] { "c" }));
30+
}
31+
32+
[Test]
33+
public void MainSkipSubquerySkip()
34+
{
35+
var docs = provider.AsQueryable<SampleDocument>();
36+
37+
var results = (from outer in
38+
(from d in docs
39+
orderby d.Id descending
40+
select d).Skip(1)
41+
select new { outer.Id })
42+
.Skip(1)
43+
.ToList();
44+
45+
Assert.That(results.Select(d => d.Id).ToArray(), Is.EqualTo(new[] { "a" }));
46+
}
47+
48+
[Test]
49+
public void MainOrderBy()
50+
{
51+
var docs = provider.AsQueryable<SampleDocument>();
52+
53+
var results = (from outer in
54+
(from d in docs select d)
55+
orderby outer.Id descending
56+
select new { outer.Id })
57+
.ToList();
58+
59+
Assert.That(results.Select(d => d.Id).ToArray(), Is.EqualTo(new[] { "c", "b", "a" }));
60+
}
61+
62+
[Test]
63+
public void SubQueryOrderWinsOnConflictingOrder()
64+
{
65+
var docs = provider.AsQueryable<SampleDocument>();
66+
67+
var results = (from outer in
68+
(from d in docs
69+
orderby d.Scalar
70+
select d).Skip(1)
71+
orderby outer.Id
72+
select new { outer.Id })
73+
.Skip(1)
74+
.ToList();
75+
76+
Assert.That(results.Select(d => d.Id).ToArray(), Is.EqualTo(new[] { "a" }));
77+
}
78+
79+
[Test]
80+
public void AllowsConflictingOrderOnNoSkipTake()
81+
{
82+
var docs = provider.AsQueryable<SampleDocument>();
83+
84+
var results = (from outer in
85+
(from d in docs
86+
orderby d.Scalar
87+
select d)
88+
orderby outer.Id
89+
select new { outer.Id })
90+
.ToList();
91+
92+
Assert.That(results.Select(d => d.Id).ToArray(), Is.EqualTo(new[] { "b", "c", "a" }));
93+
}
94+
95+
[Test]
96+
public void AllowsSameOrderOnSubSkipTake()
97+
{
98+
var docs = provider.AsQueryable<SampleDocument>();
99+
100+
var results = (from outer in
101+
(from d in docs
102+
orderby d.Scalar
103+
orderby d.Id
104+
select d).Skip(1)
105+
orderby outer.Scalar
106+
orderby outer.Id
107+
select new { outer.Id })
108+
.ToList();
109+
110+
Assert.That(results.Select(d => d.Id).ToArray(), Is.EqualTo(new[] { "c", "a" }));
111+
}
112+
113+
}
114+
}

source/Lucene.Net.Linq.Tests/Lucene.Net.Linq.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
<Compile Include="Integration\RangeTests.cs" />
124124
<Compile Include="Integration\ReleaseTests.cs" />
125125
<Compile Include="Integration\StatisticTests.cs" />
126+
<Compile Include="Integration\SubQueryTests.cs" />
126127
<Compile Include="LuceneQueryExecutorTests.cs" />
127128
<Compile Include="Mapping\FieldMappingInfoBuilderSortFieldTests.cs" />
128129
<Compile Include="Mapping\ReflectionDocumentBoostMapperTests.cs" />

source/Lucene.Net.Linq/Lucene.Net.Linq.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
<Compile Include="Search\Function\DelegatingCustomScoreQuery.cs" />
141141
<Compile Include="Transformation\TreeVisitors\AllowSpecialCharactersMethodExpressionTreeVisitor.cs" />
142142
<Compile Include="Transformation\TreeVisitors\BooleanBinaryToQueryPredicateExpressionTreeVisitor.cs" />
143+
<Compile Include="Transformation\TreeVisitors\AggressiveSubQueryFromClauseFlattener.cs" />
143144
<Compile Include="Transformation\TreeVisitors\FuzzyMethodCallTreeVisitor.cs" />
144145
<Compile Include="Transformation\TreeVisitors\BoostMethodCallTreeVisitor.cs" />
145146
<Compile Include="Transformation\TreeVisitors\ExternallyProvidedQueryExpressionTreeVisitor.cs" />

source/Lucene.Net.Linq/Transformation/QueryModelTransformer.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,14 @@ public static void TransformQueryModel(QueryModel queryModel)
6464
var instance = new QueryModelTransformer();
6565

6666
queryModel.Accept(instance);
67+
}
6768

69+
public override void VisitMainFromClause(MainFromClause fromClause, QueryModel queryModel)
70+
{
71+
Log.Trace(m => m("Original QueryModel: {0}", queryModel));
72+
new AggressiveSubQueryFromClauseFlattener().VisitMainFromClause(fromClause, queryModel);
73+
Log.Trace(m => m("Transformed QueryModel after AggressiveSubQueryFromClauseFlattener: {0}", queryModel));
74+
base.VisitMainFromClause(fromClause, queryModel);
6875
}
6976

7077
public override void VisitWhereClause(WhereClause whereClause, QueryModel queryModel, int index)
@@ -118,4 +125,4 @@ private void ExpandCompositeOrderings(OrderByClause orderByClause)
118125
}
119126
}
120127
}
121-
}
128+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Linq;
3+
using Remotion.Linq;
4+
using Remotion.Linq.Clauses;
5+
using Remotion.Linq.Clauses.Expressions;
6+
using Remotion.Linq.Clauses.ResultOperators;
7+
using Remotion.Linq.Transformations;
8+
9+
namespace Lucene.Net.Linq.Transformation.TreeVisitors
10+
{
11+
internal class AggressiveSubQueryFromClauseFlattener : SubQueryFromClauseFlattener
12+
{
13+
protected override void CheckFlattenable(QueryModel subQueryModel)
14+
{
15+
var first = subQueryModel.ResultOperators.FirstOrDefault();
16+
if (first != null)
17+
{
18+
throw new NotSupportedException(first.GetType() + " is not supported in sub-queries. Sub-queries may only use SequenceTypePreservingResultOperatorBase subclasses.");
19+
}
20+
}
21+
22+
protected override void FlattenSubQuery(SubQueryExpression subQueryExpression, FromClauseBase fromClause, QueryModel queryModel,
23+
int destinationIndex)
24+
{
25+
var subQueryModel = subQueryExpression.QueryModel;
26+
MoveResultOperatorsToParent(queryModel, subQueryModel);
27+
base.FlattenSubQuery(subQueryExpression, fromClause, queryModel, destinationIndex);
28+
}
29+
30+
protected virtual void MoveResultOperatorsToParent(QueryModel queryModel, QueryModel subQueryModel)
31+
{
32+
foreach (var resultOperator in subQueryModel.ResultOperators.OfType<SequenceTypePreservingResultOperatorBase>().Reverse().ToList())
33+
{
34+
queryModel.ResultOperators.Insert(0, resultOperator);
35+
subQueryModel.ResultOperators.Remove(resultOperator);
36+
}
37+
}
38+
}
39+
}

source/Lucene.Net.Linq/Transformation/TreeVisitors/AllowSpecialCharactersMethodExpressionTreeVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,4 @@ private Expression VisitQueryPredicateExpression(LuceneQueryPredicateExpression
5757
return result;
5858
}
5959
}
60-
}
60+
}

0 commit comments

Comments
 (0)