Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c983055
string.Compare supported with LINQ to SQL
ernesto1596 Jan 27, 2023
9b944ac
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Feb 8, 2023
2d3d232
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jun 13, 2023
8412d2a
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jun 14, 2023
e25b814
Update tests
ernesto1596 Jun 14, 2023
3ae9b0e
Update test name
ernesto1596 Jun 14, 2023
8236ec2
Update tests
ernesto1596 Jun 14, 2023
1fd3fba
Add test
ernesto1596 Jun 14, 2023
8db7c5c
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jun 14, 2023
2ec00e5
Create helper ReverseExpressionTypeForStrings
ernesto1596 Jun 14, 2023
fd56903
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jun 15, 2023
890ac4e
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jun 21, 2023
26988c7
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jun 23, 2023
eca95b6
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jul 6, 2023
c0d5805
Merge branch 'master' into ernestoc/stringCompareTo
adityasa Jul 7, 2023
60f933d
Merge branch 'master' into ernestoc/stringCompareTo
adityasa Jul 8, 2023
36a8f3d
PR feedback
ernesto1596 Jul 10, 2023
e155b8f
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jul 10, 2023
ddd2498
Merge branch 'master' into ernestoc/stringCompareTo
ernesto1596 Jul 10, 2023
4b25820
Update tests
ernesto1596 Jul 10, 2023
b3e3620
Update base line
ernesto1596 Jul 10, 2023
6ef4f90
Merge branch 'master' into ernestoc/stringCompareTo
ealsur Jul 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Microsoft.Azure.Cosmos/src/ClientResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Microsoft.Azure.Cosmos/src/ClientResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,17 @@
<value>Failed to deserialize response returned by server.</value>
</data>
<data name="StringCompareToInvalidConstant" xml:space="preserve">
<value>The right hand side of string.CompareTo() comparison must be constant '0'</value>
<value>The right-hand side of String.CompareTo() comparison must be constant '0'.</value>
</data>
<data name="StringCompareInvalidConstant" xml:space="preserve">
<value>The right-hand side of String.Compare() comparison must be constant '0'.</value>
</data>
<data name="StringCompareToInvalidOperator" xml:space="preserve">
<value>Invalid operator for string.CompareTo(). Vaid operators are ('==', '&lt;', '&lt;=', '&gt;' or '&gt;=')</value>
</data>
<data name="StringCompareInvalidOperator" xml:space="preserve">
<value>Invalid operator for string.Compare(). Vaid operators are ('==', '&lt;', '&lt;=', '&gt;' or '&gt;=')</value>
</data>
<data name="TokenRefreshInProgress" xml:space="preserve">
<value>Token refresh in progress.</value>
</data>
Expand Down
87 changes: 75 additions & 12 deletions Microsoft.Azure.Cosmos/src/Linq/ExpressionToSQL.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,11 @@ private static SqlScalarExpression VisitBinary(BinaryExpression inputExpression,
{
return ExpressionToSql.VisitStringCompareTo(methodCallExpression, constantExpression, inputExpression.NodeType, reverseNodeType, context);
}

if (TryMatchStringCompare(methodCallExpression, constantExpression, inputExpression.NodeType))
{
return ExpressionToSql.VisitStringCompare(methodCallExpression, constantExpression, inputExpression.NodeType, reverseNodeType, context);
}
}

SqlScalarExpression left = ExpressionToSql.VisitScalarExpression(inputExpression.Left, context);
Expand Down Expand Up @@ -615,32 +620,90 @@ private static SqlScalarExpression VisitStringCompareTo(
{
if (reverseNodeType)
{
compareOperator = ReverseExpressionTypeForStrings(compareOperator, ClientResources.StringCompareToInvalidOperator);
}

SqlBinaryScalarOperatorKind op = GetBinaryOperatorKind(compareOperator, null);

SqlScalarExpression leftExpression = ExpressionToSql.VisitNonSubqueryScalarExpression(left.Object, context);
SqlScalarExpression rightExpression = ExpressionToSql.VisitNonSubqueryScalarExpression(left.Arguments[0], context);

return SqlBinaryScalarExpression.Create(op, leftExpression, rightExpression);
}

private static ExpressionType ReverseExpressionTypeForStrings(ExpressionType compareOperator, string errorMessage)
{
switch (compareOperator)
{
case ExpressionType.Equal:
// do nothing
break;
case ExpressionType.GreaterThan:
compareOperator = ExpressionType.LessThan;
break;
case ExpressionType.GreaterThanOrEqual:
compareOperator = ExpressionType.LessThanOrEqual;
break;
case ExpressionType.LessThan:
compareOperator = ExpressionType.GreaterThan;
break;
case ExpressionType.LessThanOrEqual:
compareOperator = ExpressionType.GreaterThanOrEqual;
break;
default:
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, errorMessage));
}

return compareOperator;
}

private static bool TryMatchStringCompare(MethodCallExpression left, ConstantExpression right, ExpressionType compareOperator)
{
if (left.Method.Equals(typeof(string).GetMethod("Compare", new Type[] { typeof(string), typeof(string) })) && left.Arguments.Count == 2)
{
// operator can only be =, >, >=, <, <=
switch (compareOperator)
{
case ExpressionType.Equal:
// do nothing
break;
case ExpressionType.GreaterThan:
compareOperator = ExpressionType.LessThan;
break;
case ExpressionType.GreaterThanOrEqual:
compareOperator = ExpressionType.LessThanOrEqual;
break;
case ExpressionType.LessThan:
compareOperator = ExpressionType.GreaterThan;
break;
case ExpressionType.LessThanOrEqual:
compareOperator = ExpressionType.GreaterThanOrEqual;
break;
default:
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.StringCompareToInvalidOperator));
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.StringCompareInvalidOperator));
}

// the constant value should be zero, otherwise we can't determine how to translate the expression
// it could be either integer or nullable integer
if (!(right.Type == typeof(int) && (int)right.Value == 0) &&
!(right.Type == typeof(int?) && ((int?)right.Value).HasValue && ((int?)right.Value).Value == 0))
{
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.StringCompareInvalidConstant));
}

return true;
}

return false;
}

private static SqlScalarExpression VisitStringCompare(
MethodCallExpression left,
ConstantExpression right,
ExpressionType compareOperator,
bool reverseNodeType,
TranslationContext context)
{
if (reverseNodeType)
{
compareOperator = ReverseExpressionTypeForStrings(compareOperator, ClientResources.StringCompareInvalidOperator);
}

SqlBinaryScalarOperatorKind op = GetBinaryOperatorKind(compareOperator, null);

SqlScalarExpression leftExpression = ExpressionToSql.VisitNonSubqueryScalarExpression(left.Object, context);
SqlScalarExpression rightExpression = ExpressionToSql.VisitNonSubqueryScalarExpression(left.Arguments[0], context);
SqlScalarExpression leftExpression = ExpressionToSql.VisitNonSubqueryScalarExpression(left.Arguments[0], context);
SqlScalarExpression rightExpression = ExpressionToSql.VisitNonSubqueryScalarExpression(left.Arguments[1], context);

return SqlBinaryScalarExpression.Create(op, leftExpression, rightExpression);
}
Expand Down
Loading