Skip to content

Commit 9bdc919

Browse files
committed
CSHARP-4339: Added database.AsQueryable().
1 parent b836109 commit 9bdc919

21 files changed

+133
-53
lines changed

src/MongoDB.Driver/IMongoDatabaseExtensions.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using MongoDB.Bson;
1919
using MongoDB.Driver.Core.Misc;
2020
using MongoDB.Driver.Core.Operations;
21+
using MongoDB.Driver.Linq;
2122

2223
namespace MongoDB.Driver
2324
{
@@ -56,6 +57,34 @@ public static IAggregateFluent<NoPipelineInput> Aggregate(this IMongoDatabase da
5657
return new DatabaseAggregateFluent<NoPipelineInput>(session, database, emptyPipeline, options ?? new AggregateOptions());
5758
}
5859

60+
/// <summary>
61+
/// Creates a queryable source of documents.
62+
/// </summary>
63+
/// <param name="database">The database.</param>
64+
/// <param name="aggregateOptions">The aggregate options</param>
65+
/// <returns>A queryable source of documents.</returns>
66+
public static IMongoQueryable<NoPipelineInput> AsQueryable(this IMongoDatabase database, AggregateOptions aggregateOptions = null)
67+
{
68+
Ensure.IsNotNull(database, nameof(database));
69+
70+
return AsQueryableHelper(database, session: null, aggregateOptions);
71+
}
72+
73+
/// <summary>
74+
/// Creates a queryable source of documents.
75+
/// </summary>
76+
/// <param name="database">The collection.</param>
77+
/// <param name="session">The session.</param>
78+
/// <param name="aggregateOptions">The aggregate options</param>
79+
/// <returns>A queryable source of documents.</returns>
80+
public static IMongoQueryable<NoPipelineInput> AsQueryable(this IMongoDatabase database, IClientSessionHandle session, AggregateOptions aggregateOptions = null)
81+
{
82+
Ensure.IsNotNull(database, nameof(database));
83+
Ensure.IsNotNull(session, nameof(session));
84+
85+
return AsQueryableHelper(database, session, aggregateOptions);
86+
}
87+
5988
/// <summary>
6089
/// Watches changes on all collection in a database.
6190
/// </summary>
@@ -137,5 +166,13 @@ public static Task<IChangeStreamCursor<ChangeStreamDocument<BsonDocument>>> Watc
137166
var emptyPipeline = new EmptyPipelineDefinition<ChangeStreamDocument<BsonDocument>>();
138167
return database.WatchAsync(session, emptyPipeline, options, cancellationToken);
139168
}
169+
170+
// private static methods
171+
private static IMongoQueryable<NoPipelineInput> AsQueryableHelper(IMongoDatabase database, IClientSessionHandle session, AggregateOptions aggregateOptions)
172+
{
173+
var linqProvider = database.Client.Settings.LinqProvider;
174+
aggregateOptions = aggregateOptions ?? new AggregateOptions();
175+
return linqProvider.GetAdapter().AsQueryable(database, session, aggregateOptions);
176+
}
140177
}
141178
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ internal override IMongoQueryable<TDocument> AsQueryable<TDocument>(
3636
return new MongoQueryableImpl<TDocument, TDocument>(provider);
3737
}
3838

39+
internal override IMongoQueryable<NoPipelineInput> AsQueryable(
40+
IMongoDatabase database,
41+
IClientSessionHandle session,
42+
AggregateOptions options)
43+
{
44+
throw new InvalidOperationException("LINQ2 does not support AsQueryable against a database.");
45+
}
46+
3947
public override string ToString() => "V2";
4048

4149
internal override BsonValue TranslateExpressionToAggregateExpression<TSource, TResult>(

src/MongoDB.Driver/Linq/Linq3Implementation/LinqProviderAdapterV3.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
using System;
17+
using System.Collections.ObjectModel;
1718
using System.Linq;
1819
using System.Linq.Expressions;
1920
using MongoDB.Bson;
@@ -38,6 +39,15 @@ internal override IMongoQueryable<TDocument> AsQueryable<TDocument>(
3839
return new MongoQuery<TDocument, TDocument>(provider);
3940
}
4041

42+
internal override IMongoQueryable<NoPipelineInput> AsQueryable(
43+
IMongoDatabase database,
44+
IClientSessionHandle session,
45+
AggregateOptions options)
46+
{
47+
var provider = new MongoQueryProvider<NoPipelineInput>(database, session, options);
48+
return new MongoQuery<NoPipelineInput, NoPipelineInput>(provider);
49+
}
50+
4151
public override string ToString() => "V3";
4252

4353
internal override BsonValue TranslateExpressionToAggregateExpression<TSource, TResult>(

src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ internal sealed class MongoQueryProvider<TDocument> : MongoQueryProvider
6060
{
6161
// private fields
6262
private readonly IMongoCollection<TDocument> _collection;
63+
private readonly IMongoDatabase _database;
6364
private ExecutableQuery<TDocument> _mostRecentExecutableQuery;
6465

6566
// constructors
@@ -72,10 +73,20 @@ public MongoQueryProvider(
7273
_collection = collection;
7374
}
7475

76+
public MongoQueryProvider(
77+
IMongoDatabase database,
78+
IClientSessionHandle session,
79+
AggregateOptions options)
80+
: base(session, options)
81+
{
82+
_database = database;
83+
}
84+
7585
// public properties
7686
public IMongoCollection<TDocument> Collection => _collection;
7787
public override CollectionNamespace CollectionNamespace => _collection.CollectionNamespace;
7888
public override IBsonSerializer CollectionDocumentSerializer => _collection.DocumentSerializer;
89+
public IMongoDatabase Database => _database;
7990

8091
// public methods
8192
public override IQueryable CreateQuery(Expression expression)

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/AllMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ public static ExecutableQuery<TDocument, bool> Translate<TDocument>(MongoQueryPr
6060
AstProject.Set("_v", BsonNull.Value)));
6161

6262
return ExecutableQuery.Create(
63-
provider.Collection,
64-
provider.Options,
63+
provider,
6564
pipeline,
6665
__finalizer);
6766
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/AnyMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@ public static ExecutableQuery<TDocument, bool> Translate<TDocument>(MongoQueryPr
8686
AstProject.Set("_v", BsonNull.Value)));
8787

8888
return ExecutableQuery.Create(
89-
provider.Collection,
90-
provider.Options,
89+
provider,
9190
pipeline,
9291
__finalizer);
9392
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/AverageMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
156156
AstStage.Project(AstProject.ExcludeId()));
157157

158158
return ExecutableQuery.Create(
159-
provider.Collection,
160-
provider.Options,
159+
provider,
161160
pipeline,
162161
__finalizer);
163162
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ContainsMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ public static ExecutableQuery<TDocument, bool> Translate<TDocument>(MongoQueryPr
7979
AstProject.Set("_v", BsonNull.Value)));
8080

8181
return ExecutableQuery.Create(
82-
provider.Collection,
83-
provider.Options,
82+
provider,
8483
pipeline,
8584
__finalizer);
8685
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/CountMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ public static ExecutableQuery<TDocument, int> Translate<TDocument>(MongoQueryPro
7979
AstStage.Count("_v"));
8080

8181
return ExecutableQuery.Create(
82-
provider.Collection,
83-
provider.Options,
82+
provider,
8483
pipeline,
8584
_finalizer);
8685
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ElementAtMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
4848
AstStage.Limit(1));
4949

5050
return ExecutableQuery.Create(
51-
provider.Collection,
52-
provider.Options,
51+
provider,
5352
pipeline,
5453
__finalizer);
5554
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ExecutableQuery.cs

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,14 @@ public static ExecutableQuery<TDocument, TResult> AsExecutableQuery<TDocument, T
3434
internal static class ExecutableQuery
3535
{
3636
public static ExecutableQuery<TDocument, TOutput, TResult> Create<TDocument, TOutput, TResult>(
37-
IMongoCollection<TDocument> collection,
38-
AggregateOptions options,
37+
MongoQueryProvider<TDocument> provider,
3938
AstPipeline unoptimizedPipeline,
4039
IExecutableQueryFinalizer<TOutput, TResult> finalizer)
4140
{
4241
var pipeline = AstPipelineOptimizer.Optimize(unoptimizedPipeline);
43-
return new ExecutableQuery<TDocument, TOutput, TResult>(collection, options, unoptimizedPipeline, pipeline, finalizer);
42+
return provider.Collection == null ?
43+
new ExecutableQuery<TDocument, TOutput, TResult>(provider.Database, provider.Options, unoptimizedPipeline, pipeline, finalizer) :
44+
new ExecutableQuery<TDocument, TOutput, TResult>(provider.Collection, provider.Options, unoptimizedPipeline, pipeline, finalizer);
4445
}
4546
}
4647

@@ -60,6 +61,7 @@ internal class ExecutableQuery<TDocument, TOutput, TResult> : ExecutableQuery<TD
6061
{
6162
// private fields
6263
private readonly IMongoCollection<TDocument> _collection;
64+
private readonly IMongoDatabase _database;
6365
private readonly IExecutableQueryFinalizer<TOutput, TResult> _finalizer;
6466
private readonly AggregateOptions _options;
6567
private readonly AstPipeline _pipeline;
@@ -72,8 +74,28 @@ public ExecutableQuery(
7274
AstPipeline unoptimizedPipeline,
7375
AstPipeline pipeline,
7476
IExecutableQueryFinalizer<TOutput, TResult> finalizer)
77+
: this(options, unoptimizedPipeline, pipeline, finalizer)
7578
{
7679
_collection = collection;
80+
}
81+
82+
public ExecutableQuery(
83+
IMongoDatabase database,
84+
AggregateOptions options,
85+
AstPipeline unoptimizedPipeline,
86+
AstPipeline pipeline,
87+
IExecutableQueryFinalizer<TOutput, TResult> finalizer)
88+
: this(options, unoptimizedPipeline, pipeline, finalizer)
89+
{
90+
_database = database;
91+
}
92+
93+
private ExecutableQuery(
94+
AggregateOptions options,
95+
AstPipeline unoptimizedPipeline,
96+
AstPipeline pipeline,
97+
IExecutableQueryFinalizer<TOutput, TResult> finalizer)
98+
{
7799
_options = options;
78100
_unoptimizedPipeline = unoptimizedPipeline;
79101
_pipeline = pipeline;
@@ -87,44 +109,46 @@ public ExecutableQuery(
87109
// public methods
88110
public override TResult Execute(IClientSessionHandle session, CancellationToken cancellationToken)
89111
{
90-
var pipelineDefinition = CreatePipelineDefinition();
91-
IAsyncCursor<TOutput> cursor;
92-
if (session == null)
93-
{
94-
cursor = _collection.Aggregate(pipelineDefinition, _options, cancellationToken);
95-
}
96-
else
112+
var cursor = (_collection, session) switch
97113
{
98-
cursor = _collection.Aggregate(session, pipelineDefinition, _options, cancellationToken);
99-
}
114+
(null, null) => _database.Aggregate(CreateDatabasePipelineDefinition(), _options, cancellationToken),
115+
(null, _) => _database.Aggregate(session, CreateDatabasePipelineDefinition(), _options, cancellationToken),
116+
(_, null) => _collection.Aggregate(CreateCollectionPipelineDefinition(), _options, cancellationToken),
117+
(_, _) => _collection.Aggregate(session, CreateCollectionPipelineDefinition(), _options, cancellationToken)
118+
};
119+
100120
return _finalizer.Finalize(cursor, cancellationToken);
101121
}
102122

103123
public override async Task<TResult> ExecuteAsync(IClientSessionHandle session, CancellationToken cancellationToken)
104124
{
105-
var pipelineDefinition = CreatePipelineDefinition();
106-
IAsyncCursor<TOutput> cursor;
107-
if (session == null)
125+
var cursor = (_collection, session) switch
108126
{
109-
cursor = await _collection.AggregateAsync(pipelineDefinition, _options, cancellationToken).ConfigureAwait(false);
110-
}
111-
else
112-
{
113-
cursor = await _collection.AggregateAsync(session, pipelineDefinition, _options, cancellationToken).ConfigureAwait(false);
114-
}
127+
(null, null) => await _database.AggregateAsync(CreateDatabasePipelineDefinition(), _options, cancellationToken).ConfigureAwait(false),
128+
(null, _) => await _database.AggregateAsync(session, CreateDatabasePipelineDefinition(), _options, cancellationToken).ConfigureAwait(false),
129+
(_, null) => await _collection.AggregateAsync(CreateCollectionPipelineDefinition(), _options, cancellationToken).ConfigureAwait(false),
130+
(_, _) => await _collection.AggregateAsync(session, CreateCollectionPipelineDefinition(), _options, cancellationToken).ConfigureAwait(false)
131+
};
132+
115133
return await _finalizer.FinalizeAsync(cursor, cancellationToken).ConfigureAwait(false);
116134
}
117135

118136
public override string ToString()
119137
{
120-
return $"{_collection.CollectionNamespace}.Aggregate({_pipeline})";
138+
return $"{(_collection == null ? _database.DatabaseNamespace : _collection.CollectionNamespace)}.Aggregate({_pipeline})";
121139
}
122140

123141
// private methods
124-
private BsonDocumentStagePipelineDefinition<TDocument, TOutput> CreatePipelineDefinition()
142+
private BsonDocumentStagePipelineDefinition<TDocument, TOutput> CreateCollectionPipelineDefinition()
125143
{
126144
var stages = _pipeline.Stages.Select(s => (BsonDocument)s.Render());
127145
return new BsonDocumentStagePipelineDefinition<TDocument, TOutput>(stages, (IBsonSerializer<TOutput>)_pipeline.OutputSerializer);
128146
}
147+
148+
private BsonDocumentStagePipelineDefinition<NoPipelineInput, TOutput> CreateDatabasePipelineDefinition()
149+
{
150+
var stages = _pipeline.Stages.Select(s => (BsonDocument)s.Render());
151+
return new BsonDocumentStagePipelineDefinition<NoPipelineInput, TOutput>(stages, (IBsonSerializer<TOutput>)_pipeline.OutputSerializer);
152+
}
129153
}
130154
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ExpressionToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ public static ExecutableQuery<TDocument, IAsyncCursor<TOutput>> Translate<TDocum
3434
var pipeline = ExpressionToPipelineTranslator.Translate(context, expression);
3535

3636
return ExecutableQuery.Create(
37-
provider.Collection,
38-
provider.Options,
37+
provider,
3938
pipeline,
4039
IdentityFinalizer<TOutput>.Instance);
4140
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/FirstMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
8484
var finalizer = method.Name == "FirstOrDefault" ? __firstOrDefaultFinalizer : __firstFinalizer;
8585

8686
return ExecutableQuery.Create(
87-
provider.Collection,
88-
provider.Options,
87+
provider,
8988
pipeline,
9089
finalizer);
9190
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/LastMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
8282
var finalizer = method.Name == "LastOrDefault" ? __singleOrDefaultFinalizer : __singleFinalizer;
8383

8484
return ExecutableQuery.Create(
85-
provider.Collection,
86-
provider.Options,
85+
provider,
8786
pipeline,
8887
finalizer);
8988
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/LongCountMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ public static ExecutableQuery<TDocument, long> Translate<TDocument>(MongoQueryPr
7979
AstStage.Count("_v"));
8080

8181
return ExecutableQuery.Create(
82-
provider.Collection,
83-
provider.Options,
82+
provider,
8483
pipeline,
8584
_finalizer);
8685
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/MaxMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
9797
AstStage.ReplaceRoot(AstExpression.GetField(root, "_max")));
9898

9999
return ExecutableQuery.Create(
100-
provider.Collection,
101-
provider.Options,
100+
provider,
102101
pipeline,
103102
__finalizer);
104103
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/MinMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
9797
AstStage.ReplaceRoot(AstExpression.GetField(root, "_min")));
9898

9999
return ExecutableQuery.Create(
100-
provider.Collection,
101-
provider.Options,
100+
provider,
102101
pipeline,
103102
__finalizer);
104103
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/SingleMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
9393
var finalizer = method.IsOneOf(__singleOrDefaultMethods) ? __singleOrDefaultFinalizer : __singleFinalizer;
9494

9595
return ExecutableQuery.Create(
96-
provider.Collection,
97-
provider.Options,
96+
provider,
9897
pipeline,
9998
finalizer);
10099
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/StandardDeviationMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
297297
var finalizer = method.IsOneOf(__standardDeviationNullableMethods) ? __singleOrDefaultFinalizer : __singleFinalizer;
298298

299299
return ExecutableQuery.Create(
300-
provider.Collection,
301-
provider.Options,
300+
provider,
302301
pipeline,
303302
finalizer);
304303
}

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/SumMethodToExecutableQueryTranslator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,7 @@ public static ExecutableQuery<TDocument, TOutput> Translate<TDocument>(MongoQuer
146146
AstStage.Project(AstProject.ExcludeId()));
147147

148148
return ExecutableQuery.Create(
149-
provider.Collection,
150-
provider.Options,
149+
provider,
151150
pipeline,
152151
__finalizer);
153152
}

0 commit comments

Comments
 (0)