From 810c42bc63a76e9e81b53f6cb97853815e80be4e Mon Sep 17 00:00:00 2001 From: Minh Le Date: Fri, 14 Apr 2023 11:15:50 -0700 Subject: [PATCH 1/3] add trim support --- .../StringBuiltinFunctions.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/Microsoft.Azure.Cosmos/src/Linq/BuiltinFunctions/StringBuiltinFunctions.cs b/Microsoft.Azure.Cosmos/src/Linq/BuiltinFunctions/StringBuiltinFunctions.cs index 781eb8d20a..b04bd58c3c 100644 --- a/Microsoft.Azure.Cosmos/src/Linq/BuiltinFunctions/StringBuiltinFunctions.cs +++ b/Microsoft.Azure.Cosmos/src/Linq/BuiltinFunctions/StringBuiltinFunctions.cs @@ -348,6 +348,45 @@ protected override SqlScalarExpression VisitImplicit(MethodCallExpression method } } + private class StringVisitTrim : SqlBuiltinFunctionVisitor + { + public StringVisitTrim() + : base("TRIM", + false, + null) + { + } + + protected override SqlScalarExpression VisitImplicit(MethodCallExpression methodCallExpression, TranslationContext context) + { + bool validInNet = false; + bool validInNetCore = false; + + if (methodCallExpression.Arguments.Count == 1 && + methodCallExpression.Arguments[0].NodeType == ExpressionType.Constant && + methodCallExpression.Arguments[0].Type == typeof(char[])) + { + char[] argumentsExpressions = (char[])((ConstantExpression)methodCallExpression.Arguments[0]).Value; + if (argumentsExpressions.Length == 0) + { + validInNet = true; + } + } + else if (methodCallExpression.Arguments.Count == 0) + { + validInNetCore = true; + } + + if (validInNet || validInNetCore) + { + SqlScalarExpression str = ExpressionToSql.VisitScalarExpression(methodCallExpression.Object, context); + return SqlFunctionCallScalarExpression.CreateBuiltin(SqlFunctionCallScalarExpression.Names.Trim, str); + } + + return null; + } + } + static StringBuiltinFunctions() { StringBuiltinFunctionDefinitions = new Dictionary @@ -415,6 +454,10 @@ static StringBuiltinFunctions() "TrimEnd", new StringVisitTrimEnd() }, + { + "Trim", + new StringVisitTrim() + }, { "StartsWith", new SqlStringWithComparisonVisitor(SqlFunctionCallScalarExpression.Names.Startswith) From 4e283e55d1ed5ba6ce158aed584ac61e19272190 Mon Sep 17 00:00:00 2001 From: Minh Le Date: Mon, 1 May 2023 09:56:51 -0700 Subject: [PATCH 2/3] Added some test coverage --- ...ationBaselineTests.TestStringFunctions.xml | 68 +++++++++++++++---- .../LinqTranslationBaselineTests.cs | 13 ++-- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestStringFunctions.xml b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestStringFunctions.xml index a9fc581461..398c849c25 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestStringFunctions.xml +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestStringFunctions.xml @@ -368,45 +368,56 @@ FROM root]]> - - doc.StringField.ToLower())]]> + + doc.StringField.Replace(c, a))]]> - - doc.StringField.TrimStart())]]> + + doc.StringField.Replace("str", "str2"))]]> - - doc.StringField.Replace(c, a))]]> + + doc.StringField.ToLower())]]> - - doc.StringField.Replace("str", "str2"))]]> + + doc.StringField.Trim())]]> + + + + + + " abc ".Trim())]]> + + + @@ -418,6 +429,39 @@ FROM root]]> + + + + + + " abc ".TrimEnd())]]> + + + + + + + + + doc.StringField.TrimStart())]]> + + + + + + + + + " abc ".TrimStart())]]> + + + diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationBaselineTests.cs index 14aadd354f..4e367d387b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationBaselineTests.cs @@ -744,15 +744,20 @@ public void TestStringFunctions() new LinqTestInput("IndexOf string w/ startIndex", b => getQuery(b).Select(doc => doc.StringField.IndexOf("str", 0))), // Count new LinqTestInput("Count", b => getQuery(b).Select(doc => doc.StringField.Count())), - // ToLower - new LinqTestInput("ToLower", b => getQuery(b).Select(doc => doc.StringField.ToLower())), - // TrimStart - new LinqTestInput("TrimStart", b => getQuery(b).Select(doc => doc.StringField.TrimStart())), // Replace new LinqTestInput("Replace char", b => getQuery(b).Select(doc => doc.StringField.Replace('c', 'a'))), new LinqTestInput("Replace string", b => getQuery(b).Select(doc => doc.StringField.Replace("str", "str2"))), + // ToLower + new LinqTestInput("ToLower", b => getQuery(b).Select(doc => doc.StringField.ToLower())), + // Trim + new LinqTestInput("Trim", b => getQuery(b).Select(doc => doc.StringField.Trim())), + new LinqTestInput("Trim with Literal", b => getQuery(b).Select(doc => " abc ".Trim())), // TrimEnd new LinqTestInput("TrimEnd", b => getQuery(b).Select(doc => doc.StringField.TrimEnd())), + new LinqTestInput("TrimEnd with Literal", b => getQuery(b).Select(doc => " abc ".TrimEnd())), + // TrimStart + new LinqTestInput("TrimStart", b => getQuery(b).Select(doc => doc.StringField.TrimStart())), + new LinqTestInput("TrimStart with Literal", b => getQuery(b).Select(doc => " abc ".TrimStart())), //StartsWith new LinqTestInput("StartsWith", b => getQuery(b).Select(doc => doc.StringField.StartsWith("str"))), new LinqTestInput("String constant StartsWith", b => getQuery(b).Select(doc => "str".StartsWith(doc.StringField))), From 98b5af5bcfeedf2b470f46e0da7e8cd85c2d020e Mon Sep 17 00:00:00 2001 From: Minh Le Date: Mon, 1 May 2023 12:29:30 -0700 Subject: [PATCH 3/3] address reviews --- ...ationBaselineTests.TestStringFunctions.xml | 66 +++++++++++++++++++ .../LinqTranslationBaselineTests.cs | 6 ++ 2 files changed, 72 insertions(+) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestStringFunctions.xml b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestStringFunctions.xml index 398c849c25..4ccc9d34ca 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestStringFunctions.xml +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/BaselineTest/TestBaseline/LinqTranslationBaselineTests.TestStringFunctions.xml @@ -418,6 +418,28 @@ FROM root]]> + + + + + + doc.StringField.Trim(new [] {}))]]> + + + + + + + + + " abc ".Trim(new [] {}))]]> + + + @@ -440,6 +462,28 @@ FROM root]]> + + + + + + doc.StringField.TrimEnd(new [] {}))]]> + + + + + + + + + " abc ".TrimEnd(new [] {}))]]> + + + @@ -462,6 +506,28 @@ FROM root]]> + + + + + + doc.StringField.TrimStart(new [] {}))]]> + + + + + + + + + " abc ".TrimStart(new [] {}))]]> + + + diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationBaselineTests.cs index 4e367d387b..76bd0ffc81 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/LinqTranslationBaselineTests.cs @@ -752,12 +752,18 @@ public void TestStringFunctions() // Trim new LinqTestInput("Trim", b => getQuery(b).Select(doc => doc.StringField.Trim())), new LinqTestInput("Trim with Literal", b => getQuery(b).Select(doc => " abc ".Trim())), + new LinqTestInput("Trim with EmptyCharArray", b => getQuery(b).Select(doc => doc.StringField.Trim(new char[]{ }))), + new LinqTestInput("Trim with Literal and EmptyCharArray", b => getQuery(b).Select(doc => " abc ".Trim(new char[]{ }))), // TrimEnd new LinqTestInput("TrimEnd", b => getQuery(b).Select(doc => doc.StringField.TrimEnd())), new LinqTestInput("TrimEnd with Literal", b => getQuery(b).Select(doc => " abc ".TrimEnd())), + new LinqTestInput("TrimEnd with EmptyCharArray", b => getQuery(b).Select(doc => doc.StringField.TrimEnd(new char[]{ }))), + new LinqTestInput("TrimEnd with Literal and EmptyCharArray", b => getQuery(b).Select(doc => " abc ".TrimEnd(new char[]{ }))), // TrimStart new LinqTestInput("TrimStart", b => getQuery(b).Select(doc => doc.StringField.TrimStart())), new LinqTestInput("TrimStart with Literal", b => getQuery(b).Select(doc => " abc ".TrimStart())), + new LinqTestInput("TrimStart with EmptyCharArray", b => getQuery(b).Select(doc => doc.StringField.TrimStart(new char[]{ }))), + new LinqTestInput("TrimStart with Literal and EmptyCharArray", b => getQuery(b).Select(doc => " abc ".TrimStart(new char[]{ }))), //StartsWith new LinqTestInput("StartsWith", b => getQuery(b).Select(doc => doc.StringField.StartsWith("str"))), new LinqTestInput("String constant StartsWith", b => getQuery(b).Select(doc => "str".StartsWith(doc.StringField))),