Skip to content

Commit 32835bf

Browse files
committed
CSHARP-4339: Add support for $documents in LINQ.
1 parent 9bdc919 commit 32835bf

File tree

22 files changed

+394
-30
lines changed

22 files changed

+394
-30
lines changed

src/MongoDB.Driver/IMongoDatabaseExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
using System.Threading.Tasks;
1818
using MongoDB.Bson;
1919
using MongoDB.Driver.Core.Misc;
20-
using MongoDB.Driver.Core.Operations;
2120
using MongoDB.Driver.Linq;
2221

2322
namespace MongoDB.Driver

src/MongoDB.Driver/Linq/IMongoQueryProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ internal interface IMongoQueryProvider : IQueryProvider
3232
CollectionNamespace CollectionNamespace { get; }
3333

3434
/// <summary>
35-
/// Gets the collection document serializer.
35+
/// Gets the pipeline input serializer (the DocumentSerializer for collection queries and NoPipelineInputSerializer for database queries).
3636
/// </summary>
37-
IBsonSerializer CollectionDocumentSerializer { get; }
37+
IBsonSerializer PipelineInputSerializer { get; }
3838

3939
/// <summary>
4040
/// Gets the execution model.

src/MongoDB.Driver/Linq/Linq2Implementation/MongoQueryProviderImpl.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using System.Threading.Tasks;
2222
using MongoDB.Bson.Serialization;
2323
using MongoDB.Driver.Core.Misc;
24-
using MongoDB.Driver.Linq;
2524
using MongoDB.Driver.Linq.Linq2Implementation.Processors;
2625
using MongoDB.Driver.Linq.Linq2Implementation.Processors.Pipeline;
2726
using MongoDB.Driver.Linq.Linq2Implementation.Translators;
@@ -44,7 +43,7 @@ public MongoQueryProviderImpl(IMongoCollection<TDocument> collection, IClientSes
4443

4544
public CollectionNamespace CollectionNamespace => _collection.CollectionNamespace;
4645

47-
public IBsonSerializer CollectionDocumentSerializer => _collection.DocumentSerializer;
46+
public IBsonSerializer PipelineInputSerializer => _collection.DocumentSerializer;
4847

4948
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
5049
{

src/MongoDB.Driver/Linq/Linq2Implementation/Processors/Pipeline/PipelineBinder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ protected override Expression BindNonMethodCall(Expression node)
8080
var queryable = (IMongoQueryable)((ConstantExpression)node).Value;
8181
var provider = (IMongoQueryProvider)queryable.Provider;
8282
return new PipelineExpression(
83-
new CollectionExpression(provider.CollectionNamespace, provider.CollectionDocumentSerializer),
84-
new DocumentExpression(provider.CollectionDocumentSerializer));
83+
new CollectionExpression(provider.CollectionNamespace, provider.PipelineInputSerializer),
84+
new DocumentExpression(provider.PipelineInputSerializer));
8585
}
8686

8787
var message = string.Format("The expression tree is not supported: {0}",

src/MongoDB.Driver/Linq/Linq2Implementation/Processors/SerializationBinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ protected override Expression VisitConstant(ConstantExpression node)
9696
var provider = (IMongoQueryProvider)queryable.Provider;
9797
return new CollectionExpression(
9898
provider.CollectionNamespace,
99-
provider.CollectionDocumentSerializer);
99+
provider.PipelineInputSerializer);
100100
}
101101

102102
return base.VisitConstant(node);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ internal enum AstNodeType
5353
DateTruncExpression,
5454
DensifyStage,
5555
DerivativeOrIntegralWindowExpression,
56+
DocumentsStage,
5657
ElemMatchFilterOperation,
5758
ExistsFilterOperation,
5859
ExponentialMovingAverageWindowExpression,
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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 MongoDB.Bson;
17+
using MongoDB.Driver.Core.Misc;
18+
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
19+
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Visitors;
20+
21+
namespace MongoDB.Driver.Linq.Linq3Implementation.Ast.Stages
22+
{
23+
internal sealed class AstDocumentsStage : AstStage
24+
{
25+
private readonly AstExpression _documents;
26+
27+
public AstDocumentsStage(AstExpression documents)
28+
{
29+
_documents = Ensure.IsNotNull(documents, nameof(documents));
30+
}
31+
32+
public new AstExpression Documents => _documents;
33+
public override AstNodeType NodeType => AstNodeType.DocumentsStage;
34+
35+
public override AstNode Accept(AstNodeVisitor visitor)
36+
{
37+
return visitor.VisitDocumentsStage(this);
38+
}
39+
40+
public override BsonValue Render()
41+
{
42+
return new BsonDocument("$documents", _documents.Render());
43+
}
44+
45+
public AstDocumentsStage Update(AstExpression documents)
46+
{
47+
if (documents == _documents)
48+
{
49+
return this;
50+
}
51+
52+
return new AstDocumentsStage(documents);
53+
}
54+
}
55+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ public static AstStage Densify(
7777
return new AstDensifyStage(fieldPath, range, partitionByFieldPaths);
7878
}
7979

80+
public static AstStage Documents(
81+
AstExpression documents)
82+
{
83+
return new AstDocumentsStage(documents);
84+
}
85+
8086
public static AstStage Facet(IEnumerable<AstFacetStageFacet> facets)
8187
{
8288
return new AstFacetStage(facets);

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Visitors/AstNodeVisitor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@ public virtual AstNode VisitDerivativeOrIntegralWindowExpression(AstDerivativeOr
299299
return node.Update(node.Operator, VisitAndConvert(node.Arg), node.Unit, node.Window);
300300
}
301301

302+
public virtual AstNode VisitDocumentsStage(AstDocumentsStage node)
303+
{
304+
return node.Update(VisitAndConvert(node.Documents));
305+
}
306+
302307
public virtual AstNode VisitElemMatchFilterOperation(AstElemMatchFilterOperation node)
303308
{
304309
return node.Update(VisitAndConvert(node.Filter));

src/MongoDB.Driver/Linq/Linq3Implementation/ExtensionMethods/ExpressionExtensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
* limitations under the License.
1414
*/
1515

16-
using System.Linq;
1716
using System.Linq.Expressions;
1817
using MongoDB.Bson.Serialization;
1918

@@ -24,14 +23,15 @@ internal static class ExpressionExtensions
2423
public static (string CollectionName, IBsonSerializer DocumentSerializer) GetCollectionInfo(this Expression innerExpression, Expression containerExpression)
2524
{
2625
if (innerExpression is ConstantExpression constantExpression &&
27-
constantExpression.Value is IQueryable queryable &&
28-
queryable.Provider is MongoQueryProvider queryProvider)
26+
constantExpression.Value is IMongoQueryable mongoQueryable &&
27+
mongoQueryable.Provider is IMongoQueryProvider mongoQueryProvider &&
28+
mongoQueryProvider.CollectionNamespace != null)
2929
{
30-
return (queryProvider.CollectionNamespace.CollectionName, queryProvider.CollectionDocumentSerializer);
30+
return (mongoQueryProvider.CollectionNamespace.CollectionName, mongoQueryProvider.PipelineInputSerializer);
3131
}
3232

33-
var message = $"Expression inner must be a MongoDB queryable representing a collection: {innerExpression} in {containerExpression}.";
34-
throw new ExpressionNotSupportedException(message);
33+
var message = $"inner expression is not an IMongoQueryable representing a collection";
34+
throw new ExpressionNotSupportedException(innerExpression, containerExpression, because: message);
3535
}
3636

3737
public static TValue GetConstantValue<TValue>(this Expression expression, Expression containingExpression)

0 commit comments

Comments
 (0)