From 57a7d59e959baf4a00cc169c725224d880355b28 Mon Sep 17 00:00:00 2001 From: rstam Date: Sat, 25 Jan 2025 13:14:07 -0800 Subject: [PATCH 1/2] CSHARP-5473: Provide API to turn LINQ expression into MQL. --- .../Linq/IMongoQueryProvider.cs | 9 +++ .../Linq3Implementation/MongoQueryProvider.cs | 10 ++++ .../Jira/CSharp5473Tests.cs | 56 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs diff --git a/src/MongoDB.Driver/Linq/IMongoQueryProvider.cs b/src/MongoDB.Driver/Linq/IMongoQueryProvider.cs index 6f26855d2be..478e89a695b 100644 --- a/src/MongoDB.Driver/Linq/IMongoQueryProvider.cs +++ b/src/MongoDB.Driver/Linq/IMongoQueryProvider.cs @@ -40,6 +40,15 @@ public interface IMongoQueryProvider : IQueryProvider /// The cancellation token. /// The value that results from executing the specified query. Task ExecuteAsync(Expression expression, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Translates an IQueryable to MQL. + /// + /// The IQueryable. + /// The output serializer. + /// The type of the result. + /// An array of MQL pipeline stages represented as BsonDocuments. + BsonDocument[] Translate(IQueryable queryable, out IBsonSerializer outputSerializer); } /// diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs index 2717a7e71d7..770e9d614e7 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs @@ -55,6 +55,7 @@ protected MongoQueryProvider( public abstract TResult Execute(Expression expression); public abstract Task ExecuteAsync(Expression expression, CancellationToken cancellationToken); public abstract ExpressionTranslationOptions GetTranslationOptions(); + public abstract BsonDocument[] Translate(IQueryable queryable, out IBsonSerializer outputSerializer); } internal sealed class MongoQueryProvider : MongoQueryProvider @@ -152,5 +153,14 @@ public override ExpressionTranslationOptions GetTranslationOptions() var database = _database ?? _collection?.Database; return translationOptions.AddMissingOptionsFrom(database?.Client.Settings.TranslationOptions); } + + public override BsonDocument[] Translate(IQueryable queryable, out IBsonSerializer outputSerializer) + { + var translationOptions = GetTranslationOptions(); + var executableQuery = ExpressionToExecutableQueryTranslator.Translate(provider: this, queryable.Expression, translationOptions); + var stages = executableQuery.Pipeline.Ast.Stages; + outputSerializer = (IBsonSerializer)executableQuery.Pipeline.OutputSerializer; + return stages.Select(s => s.Render().AsBsonDocument).ToArray(); + } } } diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs new file mode 100644 index 00000000000..c71fb45d87c --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs @@ -0,0 +1,56 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Linq; +using FluentAssertions; +using MongoDB.Driver.Linq; +using Xunit; + +namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira +{ + public class CSharp5473Tests : Linq3IntegrationTest + { + [Fact] + public void Select_decimal_divide_should_work() + { + var collection = GetCollection(); + + var queryable = collection.AsQueryable() + .Select(x => x.X + 1); + + var provider = (IMongoQueryProvider)queryable.Provider; + var stages = provider.Translate(queryable, out var outputSerializer); + AssertStages(stages, "{ $project : { _v : { $add : ['$X', 1] }, _id : 0 } }"); + + var result = queryable.First(); + result.Should().Be(2); + } + + private IMongoCollection GetCollection() + { + var collection = GetCollection("test"); + CreateCollection( + collection, + new C { Id = 1, X = 1 }); + return collection; + } + + private class C + { + public int Id { get; set; } + public int X { get; set; } + } + } +} From 55407f772182b24c02cdc33a4ec27f1b4b627be9 Mon Sep 17 00:00:00 2001 From: rstam Date: Wed, 29 Jan 2025 14:55:05 -0800 Subject: [PATCH 2/2] CSHARP-5473: Requested changes. --- .../Linq/Linq3Implementation/Jira/CSharp5473Tests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs index c71fb45d87c..384f3443af6 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs @@ -23,7 +23,7 @@ namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira public class CSharp5473Tests : Linq3IntegrationTest { [Fact] - public void Select_decimal_divide_should_work() + public void Translate_should_work() { var collection = GetCollection(); @@ -34,7 +34,8 @@ public void Select_decimal_divide_should_work() var stages = provider.Translate(queryable, out var outputSerializer); AssertStages(stages, "{ $project : { _v : { $add : ['$X', 1] }, _id : 0 } }"); - var result = queryable.First(); + var pipeline = new BsonDocumentStagePipelineDefinition(stages, outputSerializer); + var result = collection.Aggregate(pipeline).Single(); result.Should().Be(2); }