Skip to content

Conversation

@rstam
Copy link
Contributor

@rstam rstam commented Oct 7, 2025

No description provided.

@rstam rstam requested a review from a team as a code owner October 7, 2025 19:42
@rstam rstam added the improvement Optimizations or refactoring (no new features or fixes). label Oct 7, 2025
var strATranslation = ExpressionToAggregationExpressionTranslator.Translate(context, strAExpression);
var strBExpression = arguments[1];
var strBTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, strBExpression);
var ast = AstExpression.Cmp(strATranslation.Ast, strBTranslation.Ast);
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 add support for case insensitive/more overloads comparison by translating to $strcasecmp?

Copy link
Contributor

Choose a reason for hiding this comment

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

var strATranslation = ExpressionToAggregationExpressionTranslator.Translate(context, strAExpression);
var strBExpression = arguments[1];
var strBTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, strBExpression);
var ast = AstExpression.Cmp(strATranslation.Ast, strBTranslation.Ast);
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

@adelinowona adelinowona Oct 15, 2025

Choose a reason for hiding this comment

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

Given that this class was extended to support the static string.Compare method, it seems its name is a bit outdated now? I would suggest updating the class name though I don't have a good suggestion maybe StringComparisonExpressionToFilterTranslator?

throw new ExpressionNotSupportedException(expression);
}

private static bool IsStaticCompareMethod(MethodInfo method)
Copy link
Contributor

Choose a reason for hiding this comment

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

The IsStaticCompareMethod doesn't actually check if the method is named "Compare". I doubt this is intentional?

Copy link
Contributor Author

@rstam rstam left a comment

Choose a reason for hiding this comment

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

Did some refactoring and added support for the overload of Compare that has an ignoreCase parameter.


internal static class AstComparisonFilterOperatorExtensions
{
public static AstComparisonFilterOperator GetComparisonOperatorForSwappedLeftAndRight(this AstComparisonFilterOperator @operator)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Put here so that it can be used from more than one place.

return false;
}

public static bool IsInstanceCompareToMethod(this MethodInfo method)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Put here so that it can be used from more than one place.


namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
{
internal static class CompareMethodToAggregationExpressionTranslator
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Compare and CompareTo handling is consolidated into a single class.


namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionTranslators
{
internal static class CompareComparisonExpressionToFilterTranslator
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Compare and CompareTo handling is consolidated into a single class.

{
Expression value1Expression;
Expression value2Expression;
if (method.IsStatic)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The main difference between Compare and CompareTo is whether it's a static method or not.


Expression fieldExpression;
Expression innerValueExpression;
if (compareMethod.IsStatic)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The main difference between Compare and CompareTo is whether it's a static method or not.

}
}

private static AstComparisonFilterOperator GetComparisonOperatorForSwappedLeftAndRight(Expression expression)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to an extension method so it can be used from more than one class.

[InlineData(11, false, "{ $match : { B : { $gte : 'A' } } }", new int[] { 1, 2, 3, 4, 5, 6 })]
[InlineData(12, false, "{ $match : { B : { $lte : 'A' } } }", new int[] { 1, 3 })]
[InlineData(1, true, "{ $match : { $expr : { $eq : [{ $strcasecmp : ['A', '$B'] }, -1] } } }", new int[] { 2, 5 })]
[InlineData(2, true, "{ $match : { $expr : { $eq : [{ $strcasecmp : ['A', '$B'] }, 0] } } }", new int[] { 1, 3, 4, 6 })]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This one might have been possible without using $expr by using regular expressions but I don't think it's worth the effort.

sanych-sun
sanych-sun previously approved these changes Oct 22, 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 comments


namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Jira;

public class CSharp5730Tests : LinqIntegrationTest<CSharp5730Tests.ClassFixture>
Copy link
Member

Choose a reason for hiding this comment

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

Do we have tests for CompareTo and IComparable<T>.CompareTo?


var value1Translation = ExpressionToAggregationExpressionTranslator.Translate(context, value1Expression);
var value2Translation = ExpressionToAggregationExpressionTranslator.Translate(context, value2Expression);

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 the value1 and value2 has string representation?

@adelinowona adelinowona requested a review from Copilot November 10, 2025 16:40
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 adds support for the static String.Compare method in LINQ queries, enabling translation of string comparison operations to MongoDB queries. The implementation extends the existing CompareTo method support to include both static and instance comparison methods, with optional case-insensitive comparison support.

Key Changes:

  • Unified comparison method translation by consolidating String.Compare, CompareTo, and IComparable<T>.CompareTo handling
  • Added support for case-insensitive string comparison using MongoDB's $strcasecmp operator
  • Refactored comparison operator swapping logic into a reusable extension method

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp5730Tests.cs Comprehensive test suite covering all comparison scenarios with static Compare, instance CompareTo, and IComparable methods, testing both case-sensitive and case-insensitive comparisons
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ComparisonExpressionToFilterTranslator.cs Refactored to use the new unified CompareComparisonExpressionToFilterTranslator and extracted operator swapping logic
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/CompareToComparisonExpressionToFilterTranslator.cs Removed file - functionality consolidated into CompareComparisonExpressionToFilterTranslator
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/CompareComparisonExpressionToFilterTranslator.cs New unified translator handling static Compare, instance CompareTo, and IComparable methods, including ignoreCase parameter support
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CompareToMethodToAggregationExpressionTranslator.cs Removed file - functionality consolidated into CompareMethodToAggregationExpressionTranslator
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CompareMethodToAggregationExpressionTranslator.cs New unified translator for aggregation expressions supporting both static and instance comparison methods, with conditional $strcasecmp usage
src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs Updated routing to use new CompareMethodToAggregationExpressionTranslator for both Compare and CompareTo methods
src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/StringMethod.cs Added static field definitions for String.Compare methods (with and without ignoreCase parameter)
src/MongoDB.Driver/Linq/Linq3Implementation/Misc/MethodInfoExtensions.cs Added extension methods to identify static Compare and instance CompareTo methods via reflection
src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstComparisonFilterOperator.cs Added GetComparisonOperatorForSwappedLeftAndRight extension method to centralize operator reversal logic

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

var ignoreCase = ignoreCaseExpression.GetConstantValue<bool>(containingExpression: compareMethodCallExpression);
if (ignoreCase)
{
throw new ExpressionNotSupportedException(compareMethodCallExpression, because: "ignoreCase must be false");
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 error message 'ignoreCase must be false' is misleading in a filter context. The code should not throw an exception when ignoreCase is true; instead it should allow ignoreCase but not generate a simplified field comparison. The current implementation incorrectly restricts functionality that should work (though it may require $expr). Consider either supporting ignoreCase:true with $expr or clarifying the error message.

Suggested change
throw new ExpressionNotSupportedException(compareMethodCallExpression, because: "ignoreCase must be false");
throw new ExpressionNotSupportedException(compareMethodCallExpression, because: "Case-insensitive comparisons (ignoreCase: true) are not supported in this filter context.");

Copilot uses AI. Check for mistakes.
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Optimizations or refactoring (no new features or fixes).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants