Skip to content

Conversation

@rstam
Copy link
Contributor

@rstam rstam commented Jan 25, 2025

The BIG question for this PR is whether we want to do this at all, and if so what the public API should be.

@rstam rstam requested a review from a team as a code owner January 25, 2025 21:15
public class CSharp5473Tests : Linq3IntegrationTest
{
[Fact]
public void Select_decimal_divide_should_work()
Copy link
Member

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.

Copy link
Contributor Author

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();
Copy link
Member

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?

Copy link
Contributor Author

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.

@rstam rstam requested a review from sanych-sun January 29, 2025 22:55
sanych-sun
sanych-sun previously approved these changes Feb 3, 2025
Copy link
Member

@sanych-sun sanych-sun left a 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)
Copy link
Member

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?

Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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?

@damieng
Copy link
Member

damieng commented Feb 3, 2025

I think if we want to ship this for now we should use the [Experimental] attribute.

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.

@rstam
Copy link
Contributor Author

rstam commented Feb 3, 2025

I think if we want to ship this for now we should use the [Experimental] attribute.

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.

Copy link
Contributor

@BorisDog BorisDog left a 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);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adelin commented:

The translate method seems to only care about the expression of the queryable so I think we should just take Expression here as well.

The latest commit implements his suggestion.

@BorisDog and @damieng will this work for you two in the Analyzer and the EF Core Provider?

Copy link
Contributor

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.

@rstam rstam requested review from BorisDog and sanych-sun April 3, 2025 17:51
Copy link
Contributor

@BorisDog BorisDog left a 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.

@sanych-sun sanych-sun added the feature Adds new user-facing functionality. label Apr 10, 2025
@rstam rstam marked this pull request as draft April 11, 2025 21:20
@rstam
Copy link
Contributor Author

rstam commented Nov 10, 2025

Rebase on main.

@rstam rstam changed the title CSHARP-5473: Provide API to turn LINQ expression into MQL. CSHARP-5473: Provide API to turn LINQ expression into MQL Nov 10, 2025
@adelinowona adelinowona requested a review from Copilot November 10, 2025 17:03
Copy link
Contributor

Copilot AI left a 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 to IMongoQueryProvider interface 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();
Copy link

Copilot AI Nov 10, 2025

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.

Suggested change
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;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Adds new user-facing functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants