diff --git a/src/Core/Models/GraphQLFilterParsers.cs b/src/Core/Models/GraphQLFilterParsers.cs
index e3346930cd..0476f236f1 100644
--- a/src/Core/Models/GraphQLFilterParsers.cs
+++ b/src/Core/Models/GraphQLFilterParsers.cs
@@ -747,7 +747,7 @@ public static Predicate Parse(
else
{
op = PredicateOperation.LIKE;
- value = $"%{EscapeLikeString((string)value)}%";
+ value = SqlLikePattern.Create(LikeMatch.Contains, (string)value);
lengthOverride = true;
}
@@ -760,19 +760,19 @@ public static Predicate Parse(
else
{
op = PredicateOperation.NOT_LIKE;
- value = $"%{EscapeLikeString((string)value)}%";
+ value = SqlLikePattern.Create(LikeMatch.Contains, (string)value);
lengthOverride = true;
}
break;
case "startsWith":
op = PredicateOperation.LIKE;
- value = $"{EscapeLikeString((string)value)}%";
+ value = SqlLikePattern.Create(LikeMatch.StartsWith, (string)value);
lengthOverride = true;
break;
case "endsWith":
op = PredicateOperation.LIKE;
- value = $"%{EscapeLikeString((string)value)}";
+ value = SqlLikePattern.Create(LikeMatch.EndsWith, (string)value);
lengthOverride = true;
break;
case "isNull":
@@ -871,14 +871,4 @@ private static PredicateOperand GenerateRightOperand(
return new PredicateOperand(processLiteral ? $"{processLiterals(value, column.ColumnName, lengthOverride)}" : value.ToString());
}
-
- private static string EscapeLikeString(string input)
- {
- input = input.Replace(@"\", @"\\");
- input = input.Replace(@"%", @"\%");
- input = input.Replace(@"[", @"\[");
- input = input.Replace(@"]", @"\]");
- input = input.Replace(@"_", @"\_");
- return input;
- }
}
diff --git a/src/Core/Parsers/ODataASTCosmosVisitor.cs b/src/Core/Parsers/ODataASTCosmosVisitor.cs
index 1912972766..72d20d1b97 100644
--- a/src/Core/Parsers/ODataASTCosmosVisitor.cs
+++ b/src/Core/Parsers/ODataASTCosmosVisitor.cs
@@ -45,6 +45,8 @@ public override string Visit(SingleValuePropertyAccessNode nodeIn)
/// String concatenation of (left op right).
public override string Visit(BinaryOperatorNode nodeIn)
{
+ ODataStringFunctionHelper.ThrowIfFunctionIsCompared(nodeIn);
+
string left = nodeIn.Left.Accept(this);
string right = nodeIn.Right.Accept(this);
@@ -113,6 +115,28 @@ public override string Visit(ConvertNode nodeIn)
return nodeIn.Source.Accept(this);
}
+ ///
+ /// Represents visiting a SingleValueFunctionCallNode for the string functions
+ /// contains, startswith and endswith, which map to the Cosmos DB functions of the same name.
+ ///
+ /// The node visited.
+ /// String representing the function call.
+ public override string Visit(SingleValueFunctionCallNode nodeIn)
+ {
+ (LikeMatch match, SingleValuePropertyAccessNode field, string value) = ODataStringFunctionHelper.GetFieldAndValue(nodeIn);
+ string cosmosFunction = match switch
+ {
+ LikeMatch.Contains => "CONTAINS",
+ LikeMatch.StartsWith => "STARTSWITH",
+ LikeMatch.EndsWith => "ENDSWITH",
+ _ => throw new NotSupportedException($"The function '{nodeIn.Name}' is not supported.")
+ };
+ string column = field.Accept(this);
+ string param = _queryStructure.MakeDbConnectionParam(value);
+
+ return $"{cosmosFunction}({column}, {param})";
+ }
+
///
/// Represents visiting a ConstantNode, which is what
/// holds a value in the AST.
diff --git a/src/Core/Parsers/ODataASTFieldVisitor.cs b/src/Core/Parsers/ODataASTFieldVisitor.cs
index 05b9501868..87916d341c 100644
--- a/src/Core/Parsers/ODataASTFieldVisitor.cs
+++ b/src/Core/Parsers/ODataASTFieldVisitor.cs
@@ -77,5 +77,20 @@ public class ODataASTFieldVisitor : QueryNodeVisitor