-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CSHARP-5473: Provide API to turn LINQ expression into MQL #1601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| public class CSharp5473Tests : Linq3IntegrationTest | ||
| { | ||
| [Fact] | ||
| public void Select_decimal_divide_should_work() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor : Test method name seems to be wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
| var stages = provider.Translate(queryable, out var outputSerializer); | ||
| AssertStages(stages, "{ $project : { _v : { $add : ['$X', 1] }, _id : 0 } }"); | ||
|
|
||
| var result = queryable.First(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we try to execute translated MQL in some way instead to make sure the translation was done properly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but not necessarily to verify that the translation was done correctly.
I'm more interested in showing HOW you could execute the result of Translate.
sanych-sun
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM + minor question.
| return translationOptions.AddMissingOptionsFrom(database?.Client.Settings.TranslationOptions); | ||
| } | ||
|
|
||
| public override BsonDocument[] Translate<TResult>(IQueryable<TResult> queryable, out IBsonSerializer<TResult> outputSerializer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check if provided queryable is MongoDB queryable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe receiving an expression is sufficient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be sufficient.
I chose IQueryable to emphasize that it's the Expression associated with an IQueryable that is being translated, not any old expression.
But the .NET method takes an Expression, so we could also here.
@damieng what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The translate method seems to only care about the expression of the queryable so I think we should just take Expression here as well. We can add a note in the comments of methods to emphasize the expression should be associated with an IQueryable and maybe throw an exception if we catch such as a case?
|
I think if we want to ship this for now we should use the Alternatively I could use reflection to do the same sort of thing on the already-released version and make sure it meets our use cases on the EF provider before shipping. |
You are the one that asked for this. If you are not sure it does what you need then we shouldn't ship it yet. |
BorisDog
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
| /// <param name="outputSerializer">The output serializer.</param> | ||
| /// <typeparam name="TResult">The type of the result.</typeparam> | ||
| /// <returns>An array of MQL pipeline stages represented as BsonDocuments.</returns> | ||
| BsonDocument[] Translate<TResult>(Expression expression, out IBsonSerializer<TResult> outputSerializer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think receiving expression is more consistent with ExecuteAsync.
Analyzer will not use this functionality at all.
BorisDog
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is still needed for EF, LGTM.
…instead of an IQueryable.
|
Rebase on main. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a public API to translate LINQ expressions into MongoDB Query Language (MQL) pipeline stages. The implementation adds a Translate method to the IMongoQueryProvider interface that converts a LINQ expression into an array of BsonDocument stages along with the appropriate output serializer.
Key Changes:
- Added
Translate<TResult>method toIMongoQueryProviderinterface and its implementations - Implemented translation logic in
MongoQueryProvider<TDocument>that leverages existing internal translation infrastructure - Added comprehensive test coverage demonstrating the translation of a simple projection expression
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/MongoDB.Driver/Linq/IMongoQueryProvider.cs | Adds public API method signature with XML documentation for translating expressions to MQL |
| src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs | Implements the translation method in both abstract base class and concrete provider, using existing translation infrastructure |
| tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5473Tests.cs | Adds test validating the new translation API with a projection example |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var executableQuery = ExpressionToExecutableQueryTranslator.Translate<TDocument, TResult>(provider: this, expression, translationOptions); | ||
| var stages = executableQuery.Pipeline.Ast.Stages; | ||
| outputSerializer = (IBsonSerializer<TResult>)executableQuery.Pipeline.OutputSerializer; | ||
| return stages.Select(s => s.Render().AsBsonDocument).ToArray(); |
Copilot
AI
Nov 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Select().ToArray() pattern creates an intermediate enumerable before materializing the array. Consider using a for loop or Array.ConvertAll for better performance, especially if the stages collection could be large.
| return stages.Select(s => s.Render().AsBsonDocument).ToArray(); | |
| var result = new BsonDocument[stages.Count]; | |
| for (int i = 0; i < stages.Count; i++) | |
| { | |
| result[i] = stages[i].Render().AsBsonDocument; | |
| } | |
| return result; |
The BIG question for this PR is whether we want to do this at all, and if so what the public API should be.