Skip to content

Commit 2313984

Browse files
committed
CSHARP-5241: Refactor Join implementation.
1 parent 8da459d commit 2313984

File tree

16 files changed

+456
-137
lines changed

16 files changed

+456
-137
lines changed

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/AstNodeType.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ internal enum AstNodeType
8686
ListLocalSessionsStage,
8787
ListSessionsStage,
8888
LookupStage,
89-
LookupStageEqualityMatch,
90-
LookupStageUncorrelatedMatch,
89+
LookupWithMatchingFieldsAndPipelineStage,
90+
LookupWithPipelineStage,
9191
LTrimExpression,
9292
MapExpression,
9393
MatchesEverythingFilter,

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstExpression.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ private static IEnumerable<AstExpression> FlattenNaryArgs(IEnumerable<AstExpress
961961

962962
public virtual string ConvertToFieldPath()
963963
{
964-
throw new InvalidOperationException();
964+
throw new InvalidOperationException($"{this} cannot be converted to a field path.");
965965
}
966966
}
967967
}

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Stages/AstLookupStage.cs

Lines changed: 17 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -16,108 +16,32 @@
1616
using MongoDB.Bson;
1717
using MongoDB.Driver.Core.Misc;
1818
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Visitors;
19-
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
20-
using System.Collections.Generic;
21-
using System.Linq;
2219

2320
namespace MongoDB.Driver.Linq.Linq3Implementation.Ast.Stages
2421
{
25-
internal abstract class AstLookupStageMatch : AstNode
26-
{
27-
public override BsonValue Render()
28-
{
29-
return new BsonDocument(RenderAsElements());
30-
}
31-
32-
public abstract IEnumerable<BsonElement> RenderAsElements();
33-
}
34-
35-
internal sealed class AstLookupStageEqualityMatch : AstLookupStageMatch
36-
{
37-
private readonly string _foreignField;
38-
private readonly string _localField;
39-
40-
public AstLookupStageEqualityMatch(string localField, string foreignField)
41-
{
42-
_localField = Ensure.IsNotNull(localField, nameof(localField));
43-
_foreignField = Ensure.IsNotNull(foreignField, nameof(foreignField));
44-
}
45-
46-
public string ForeignField => _foreignField;
47-
public string LocalField => _localField;
48-
public override AstNodeType NodeType => AstNodeType.LookupStageEqualityMatch;
49-
50-
public override AstNode Accept(AstNodeVisitor visitor)
51-
{
52-
return visitor.VisitLookupStageEqualityMatch(this);
53-
}
54-
55-
public override IEnumerable<BsonElement> RenderAsElements()
56-
{
57-
return new BsonDocument
58-
{
59-
{ "localField", _localField },
60-
{ "foreignField", _foreignField }
61-
};
62-
}
63-
}
64-
65-
internal sealed class AstLookupStageUncorrelatedMatch : AstLookupStageMatch
66-
{
67-
private readonly IReadOnlyList<AstComputedField> _let;
68-
private readonly AstPipeline _pipeline;
69-
70-
public AstLookupStageUncorrelatedMatch(AstPipeline pipeline, IEnumerable<AstComputedField> let)
71-
{
72-
_pipeline = Ensure.IsNotNull(pipeline, nameof(pipeline));
73-
_let = let?.AsReadOnlyList();
74-
}
75-
76-
public IReadOnlyList<AstComputedField> Let => _let;
77-
public override AstNodeType NodeType => AstNodeType.LookupStageUncorrelatedMatch;
78-
public AstPipeline Pipeline => _pipeline;
79-
80-
public override AstNode Accept(AstNodeVisitor visitor)
81-
{
82-
return visitor.VisitLookupStageUncorrelatedMatch(this);
83-
}
84-
85-
public override IEnumerable<BsonElement> RenderAsElements()
86-
{
87-
return new BsonDocument
88-
{
89-
{ "let", () => new BsonDocument(_let.Select(l => l.RenderAsElement())), _let != null },
90-
{ "pipeline", _pipeline.Render() }
91-
};
92-
}
93-
94-
public AstLookupStageUncorrelatedMatch Update(AstPipeline pipeline, IEnumerable<AstComputedField> let)
95-
{
96-
if (pipeline == _pipeline && let == _let)
97-
{
98-
return this;
99-
}
100-
101-
return new AstLookupStageUncorrelatedMatch(pipeline, let);
102-
}
103-
}
104-
10522
internal sealed class AstLookupStage : AstStage
10623
{
10724
private readonly string _as;
25+
private readonly string _foreignField;
10826
private readonly string _from;
109-
private readonly AstLookupStageMatch _match;
27+
private readonly string _localField;
11028

111-
public AstLookupStage(string from, AstLookupStageMatch match, string @as)
29+
public AstLookupStage(
30+
string from,
31+
string localField,
32+
string foreignField,
33+
string @as)
11234
{
11335
_from = Ensure.IsNotNull(from, nameof(from));
114-
_match = Ensure.IsNotNull(match, nameof(match));
36+
_localField = Ensure.IsNotNull(localField, nameof(localField));
37+
_foreignField = Ensure.IsNotNull(foreignField, nameof(foreignField));
11538
_as = Ensure.IsNotNull(@as, nameof(@as));
11639
}
11740

11841
public string As => _as;
42+
public string ForeignField => _foreignField;
11943
public string From => _from;
120-
public new AstLookupStageMatch Match => _match;
44+
public string LocalField => _localField;
12145
public override AstNodeType NodeType => AstNodeType.LookupStage;
12246

12347
public override AstNode Accept(AstNodeVisitor visitor)
@@ -130,21 +54,14 @@ public override BsonValue Render()
13054
return new BsonDocument
13155
{
13256
{ "$lookup", new BsonDocument()
133-
.Add("from", _from)
134-
.AddRange(_match.RenderAsElements())
135-
.Add("as", _as)
57+
{
58+
{ "from", _from },
59+
{ "localField", _localField },
60+
{ "foreignField", _foreignField },
61+
{ "as", _as }
62+
}
13663
}
13764
};
13865
}
139-
140-
public AstLookupStage Update(AstLookupStageMatch match)
141-
{
142-
if (match == _match)
143-
{
144-
return this;
145-
}
146-
147-
return new AstLookupStage(_from, match, _as);
148-
}
14966
}
15067
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System.Collections.Generic;
17+
using System.Linq;
18+
using MongoDB.Bson;
19+
using MongoDB.Driver.Core.Misc;
20+
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Visitors;
21+
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
22+
23+
namespace MongoDB.Driver.Linq.Linq3Implementation.Ast.Stages
24+
{
25+
internal sealed class AstLookupWithMatchingFieldsAndPipelineStage : AstStage
26+
{
27+
private readonly string _as;
28+
private readonly string _foreignField;
29+
private readonly string _from;
30+
private readonly IReadOnlyList<AstComputedField> _let;
31+
private readonly string _localField;
32+
private readonly AstPipeline _pipeline;
33+
34+
public AstLookupWithMatchingFieldsAndPipelineStage(
35+
string from,
36+
string localField,
37+
string foreignField,
38+
IEnumerable<AstComputedField> let,
39+
AstPipeline pipeline,
40+
string @as)
41+
{
42+
_from = Ensure.IsNotNull(from, nameof(from));
43+
_localField = Ensure.IsNotNull(localField, nameof(localField));
44+
_foreignField = Ensure.IsNotNull(foreignField, nameof(foreignField));
45+
_let = let?.AsReadOnlyList(); // can be null for an uncorrelated subquery
46+
_pipeline = Ensure.IsNotNull(pipeline, nameof(pipeline));
47+
_as = Ensure.IsNotNull(@as, nameof(@as));
48+
}
49+
50+
public string As => _as;
51+
public string ForeignField => _foreignField;
52+
public string From => _from;
53+
public IReadOnlyList<AstComputedField> Let => _let;
54+
public string LocalField => _localField;
55+
public override AstNodeType NodeType => AstNodeType.LookupWithMatchingFieldsAndPipelineStage;
56+
public AstPipeline Pipeline => _pipeline;
57+
58+
public override AstNode Accept(AstNodeVisitor visitor)
59+
{
60+
return visitor.VisitLookupWithMatchingFieldsAndPipelineStage(this);
61+
}
62+
63+
public override BsonValue Render()
64+
{
65+
return new BsonDocument
66+
{
67+
{ "$lookup", new BsonDocument()
68+
{
69+
{ "from", _from },
70+
{ "localField", _localField },
71+
{ "foreignField", _foreignField },
72+
{ "let", () => new BsonDocument(_let.Select(l => l.RenderAsElement())), _let?.Count > 0 },
73+
{ "pipeline", _pipeline.Render() },
74+
{ "as", _as }
75+
}
76+
}
77+
};
78+
}
79+
80+
public AstLookupWithMatchingFieldsAndPipelineStage Update(IReadOnlyList<AstComputedField> let, AstPipeline pipeline)
81+
{
82+
if (let == _let && pipeline == _pipeline)
83+
{
84+
return this;
85+
}
86+
87+
return new AstLookupWithMatchingFieldsAndPipelineStage(_from, _localField, _foreignField, let, pipeline, _as);
88+
}
89+
}
90+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System.Collections.Generic;
17+
using System.Linq;
18+
using MongoDB.Bson;
19+
using MongoDB.Driver.Core.Misc;
20+
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Visitors;
21+
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
22+
23+
namespace MongoDB.Driver.Linq.Linq3Implementation.Ast.Stages
24+
{
25+
internal sealed class AstLookupWithPipelineStage : AstStage
26+
{
27+
private readonly string _as;
28+
private readonly string _from;
29+
private readonly IReadOnlyList<AstComputedField> _let;
30+
private readonly AstPipeline _pipeline;
31+
32+
public AstLookupWithPipelineStage(
33+
string from,
34+
IEnumerable<AstComputedField> let,
35+
AstPipeline pipeline,
36+
string @as)
37+
{
38+
_from = Ensure.IsNotNull(from, nameof(from));
39+
_let = let?.AsReadOnlyList(); // can be null for an uncorrelated subquery
40+
_pipeline = Ensure.IsNotNull(pipeline, nameof(pipeline));
41+
_as = Ensure.IsNotNull(@as, nameof(@as));
42+
}
43+
44+
public string As => _as;
45+
public string From => _from;
46+
public IReadOnlyList<AstComputedField> Let => _let;
47+
public override AstNodeType NodeType => AstNodeType.LookupWithPipelineStage;
48+
public AstPipeline Pipeline => _pipeline;
49+
50+
public override AstNode Accept(AstNodeVisitor visitor)
51+
{
52+
return visitor.VisitLookupWithPipelineStage(this);
53+
}
54+
55+
public override BsonValue Render()
56+
{
57+
return new BsonDocument
58+
{
59+
{ "$lookup", new BsonDocument()
60+
{
61+
{ "from", _from },
62+
{ "let", () => new BsonDocument(_let.Select(l => l.RenderAsElement())), _let?.Count > 0 },
63+
{ "pipeline", _pipeline.Render() },
64+
{ "as", _as }
65+
}
66+
}
67+
};
68+
}
69+
70+
public AstLookupWithPipelineStage Update(IReadOnlyList<AstComputedField> let, AstPipeline pipeline)
71+
{
72+
if (let == _let && pipeline == _pipeline)
73+
{
74+
return this;
75+
}
76+
77+
return new AstLookupWithPipelineStage(_from, let, pipeline, _as);
78+
}
79+
}
80+
}

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Stages/AstStage.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,33 @@ public static AstStage ListSessions(BsonDocument options)
150150
return new AstListSessionsStage(options);
151151
}
152152

153-
public static AstStage Lookup(string from, AstLookupStageMatch match, string @as)
153+
public static AstStage Lookup(
154+
string from,
155+
string localField,
156+
string foreignField,
157+
string @as)
158+
{
159+
return new AstLookupStage(from, localField, foreignField, @as);
160+
}
161+
162+
public static AstStage Lookup(
163+
string from,
164+
IEnumerable<AstComputedField> let,
165+
AstPipeline pipeline,
166+
string @as)
167+
{
168+
return new AstLookupWithPipelineStage(from, let, pipeline, @as);
169+
}
170+
171+
public static AstStage Lookup(
172+
string from,
173+
string localField,
174+
string foreignField,
175+
IEnumerable<AstComputedField> let,
176+
AstPipeline pipeline,
177+
string @as)
154178
{
155-
return new AstLookupStage(from, match, @as);
179+
return new AstLookupWithMatchingFieldsAndPipelineStage(from, localField, foreignField, let, pipeline, @as);
156180
}
157181

158182
public static AstStage Match(AstFilter filter)

0 commit comments

Comments
 (0)