Query: Adds LINQ RegexMatch Extension method (#4078)
* Add support for translation to REgexmatch * Add test and fix some indexing issues * remove visit explicit, add some comment. Update public contract and added the baseline for the test * add the missing baseline * added test * address code review * update csproj --------- Co-authored-by: Minh Le <leminh@microsoft.com>
This commit is contained in:
Родитель
101b9b1ad5
Коммит
11fa17b6e9
|
@ -5,6 +5,7 @@
|
|||
namespace Microsoft.Azure.Cosmos.Linq
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.Azure.Cosmos;
|
||||
|
@ -49,6 +50,12 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
|
||||
if (methodCallExpression.Method.DeclaringType.GeUnderlyingSystemType() == typeof(CosmosLinqExtensions))
|
||||
{
|
||||
// CosmosLinq Extensions are either RegexMatch or Type check functions (IsString, IsBool, etc.)
|
||||
if (methodCallExpression.Method.Name == nameof(CosmosLinqExtensions.RegexMatch))
|
||||
{
|
||||
return StringBuiltinFunctions.Visit(methodCallExpression, context);
|
||||
}
|
||||
|
||||
return TypeCheckFunctions.Visit(methodCallExpression, context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -327,6 +327,43 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
}
|
||||
}
|
||||
|
||||
private class RegexMatchVisitor : SqlBuiltinFunctionVisitor
|
||||
{
|
||||
public RegexMatchVisitor()
|
||||
: base(SqlFunctionCallScalarExpression.Names.RegexMatch,
|
||||
isStatic: true,
|
||||
new List<Type[]>()
|
||||
{
|
||||
new Type[]{ typeof(object), typeof(string)}, // search string, regex pattern
|
||||
new Type[]{ typeof(object), typeof(string), typeof(string)} // search string, regex pattern, search modifier
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
protected override SqlScalarExpression VisitImplicit(MethodCallExpression methodCallExpression, TranslationContext context)
|
||||
{
|
||||
int argumentCount = methodCallExpression.Arguments.Count;
|
||||
if (argumentCount == 0 || argumentCount > 3 || (methodCallExpression.Arguments[1].NodeType != ExpressionType.Constant))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<SqlScalarExpression> arguments = new List<SqlScalarExpression>
|
||||
{
|
||||
// Argument 0 and the Method object is the same, since Regex is an extension method
|
||||
ExpressionToSql.VisitNonSubqueryScalarExpression(methodCallExpression.Arguments[0], context),
|
||||
ExpressionToSql.VisitNonSubqueryScalarExpression(methodCallExpression.Arguments[1], context)
|
||||
};
|
||||
|
||||
if (argumentCount > 2 && (methodCallExpression.Arguments[2].NodeType == ExpressionType.Constant))
|
||||
{
|
||||
arguments.Add(ExpressionToSql.VisitNonSubqueryScalarExpression(methodCallExpression.Arguments[2], context));
|
||||
}
|
||||
|
||||
return SqlFunctionCallScalarExpression.CreateBuiltin(SqlFunctionCallScalarExpression.Names.RegexMatch, arguments.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private class StringVisitToString : SqlBuiltinFunctionVisitor
|
||||
{
|
||||
public StringVisitToString()
|
||||
|
@ -432,6 +469,10 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
"TrimStart",
|
||||
new StringVisitTrimStart()
|
||||
},
|
||||
{
|
||||
nameof(CosmosLinqExtensions.RegexMatch),
|
||||
new RegexMatchVisitor()
|
||||
},
|
||||
{
|
||||
"Replace",
|
||||
new SqlBuiltinFunctionVisitor(SqlFunctionCallScalarExpression.Names.Replace,
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Cosmos.Diagnostics;
|
||||
|
@ -175,6 +176,49 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
throw new NotImplementedException(ClientResources.TypeCheckExtensionFunctionsNotImplemented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Boolean value indicating if the specified expression matches the supplied regex pattern.
|
||||
/// For more information, see https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/query/regexmatch.
|
||||
/// This method is to be used in LINQ expressions only and will be evaluated on server.
|
||||
/// There's no implementation provided in the client library.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="regularExpression">A string expression with a regular expression defined to use when searching.</param>
|
||||
/// <returns>Returns true if the string matches the regex expressions; otherwise, false.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// var matched = documents.Where(document => document.Name.RegexMatch(<regex>));
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static bool RegexMatch(this object obj, string regularExpression)
|
||||
{
|
||||
throw new NotImplementedException(ClientResources.TypeCheckExtensionFunctionsNotImplemented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Boolean value indicating if the specified expression matches the supplied regex pattern.
|
||||
/// For more information, see https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/query/regexmatch.
|
||||
/// This method is to be used in LINQ expressions only and will be evaluated on server.
|
||||
/// There's no implementation provided in the client library.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="regularExpression">A string expression with a regular expression defined to use when searching.</param>
|
||||
/// <param name="searchModifier">An optional string expression with the selected modifiers to use with the regular expression.</param>
|
||||
/// <returns>Returns true if the string matches the regex expressions; otherwise, false.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// var matched = documents.Where(document => document.Name.RegexMatch(<regex>, <search_modifier>));
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static bool RegexMatch(this object obj, string regularExpression, string searchModifier)
|
||||
{
|
||||
throw new NotImplementedException(ClientResources.TypeCheckExtensionFunctionsNotImplemented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method generate query definition from LINQ query.
|
||||
/// </summary>
|
||||
|
|
|
@ -112,6 +112,7 @@ namespace Microsoft.Azure.Cosmos.SqlObjects
|
|||
{ Names.Power, Identifiers.Power },
|
||||
{ Names.Radians, Identifiers.Radians },
|
||||
{ Names.Rand, Identifiers.Rand },
|
||||
{ Names.RegexMatch, Identifiers.RegexMatch },
|
||||
{ Names.Replace, Identifiers.Replace },
|
||||
{ Names.Replicate, Identifiers.Replicate },
|
||||
{ Names.Reverse, Identifiers.Reverse },
|
||||
|
@ -332,6 +333,7 @@ namespace Microsoft.Azure.Cosmos.SqlObjects
|
|||
public const string Power = "POWER";
|
||||
public const string Radians = "RADIANS";
|
||||
public const string Rand = "RAND";
|
||||
public const string RegexMatch = "RegexMatch";
|
||||
public const string Replace = "REPLACE";
|
||||
public const string Replicate = "REPLICATE";
|
||||
public const string Reverse = "REVERSE";
|
||||
|
@ -474,6 +476,7 @@ namespace Microsoft.Azure.Cosmos.SqlObjects
|
|||
public static readonly SqlIdentifier Power = SqlIdentifier.Create(Names.Power);
|
||||
public static readonly SqlIdentifier Radians = SqlIdentifier.Create(Names.Radians);
|
||||
public static readonly SqlIdentifier Rand = SqlIdentifier.Create(Names.Rand);
|
||||
public static readonly SqlIdentifier RegexMatch = SqlIdentifier.Create(Names.RegexMatch);
|
||||
public static readonly SqlIdentifier Replace = SqlIdentifier.Create(Names.Replace);
|
||||
public static readonly SqlIdentifier Replicate = SqlIdentifier.Create(Names.Replicate);
|
||||
public static readonly SqlIdentifier Reverse = SqlIdentifier.Create(Names.Reverse);
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
<Results>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with 1 argument]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch("abcd"))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(root["StringField"], "abcd")]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with 2 argument]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch("abcd", "i"))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(root["StringField"], "abcd", "i")]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with 1st argument member expression]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch(doc.StringField2))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(root["StringField"], root["StringField2"])]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with ToString]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch(doc.IntField.ToString()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(root["StringField"], ToString(root["IntField"]))]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with StringUpper]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch(doc.StringField2.ToUpper()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(root["StringField"], UPPER(root["StringField2"]))]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with StringLower]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch(doc.StringField2.ToLower()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(root["StringField"], LOWER(root["StringField2"]))]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with StringConcat]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch(Concat(doc.StringField, "str")))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(root["StringField"], CONCAT(root["StringField"], "str"))]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with string composition]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.IntField.ToString().RegexMatch(doc.StringField))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(ToString(root["IntField"]), root["StringField"])]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with string composition 2]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.IntField.ToString().RegexMatch(doc.StringField, doc.StringField2.ToString()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(ToString(root["IntField"]), root["StringField"], root["StringField2"])]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with conditional]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => (doc.StringField.RegexMatch("abc") AndAlso doc.StringField2.RegexMatch("def")))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE (RegexMatch(root["StringField"], "abc") AND RegexMatch(root["StringField2"], "def"))]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with conditional 2]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => (doc.StringField.RegexMatch("abc") OrElse doc.StringField2.RegexMatch("def")))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE (RegexMatch(root["StringField"], "abc") OR RegexMatch(root["StringField2"], "def"))]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with conditional 3]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch("abc")).Where(doc => doc.StringField2.RegexMatch("abc"))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE (RegexMatch(root["StringField"], "abc") AND RegexMatch(root["StringField2"], "abc"))]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with conditional 4]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch("abc")).Where(doc => Not(doc.StringField2.RegexMatch("abc")))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE (RegexMatch(root["StringField"], "abc") AND (NOT RegexMatch(root["StringField2"], "abc")))]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[RegexMatch with 2nd argument invalid string options]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => doc.StringField.RegexMatch("abcd", "this should error out on the back end"))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE RegexMatch(root["StringField"], "abcd", "this should error out on the back end")]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
</Results>
|
|
@ -5,11 +5,9 @@
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, doc.StringField2) == 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] = root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] = root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -18,11 +16,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, doc.StringField2) > 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] > root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] > root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -31,11 +27,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, doc.StringField2) >= 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] >= root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] >= root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -44,11 +38,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, doc.StringField2) < 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] < root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] < root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -57,11 +49,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, doc.StringField2) <= 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] <= root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] <= root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -70,11 +60,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, "str") == 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] = "str")
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] = "str")
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -83,11 +71,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, "str") > 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] > "str")
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] > "str")
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -96,11 +82,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, "str") >= 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] >= "str")
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] >= "str")
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -109,11 +93,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, "str") < 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] < "str")
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] < "str")
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -122,11 +104,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (Compare(doc.StringField, "str") <= 0))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] <= "str")
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] <= "str")
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -135,11 +115,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (0 == Compare(doc.StringField, doc.StringField2)))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] = root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] = root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -148,11 +126,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (0 < Compare(doc.StringField, doc.StringField2)))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] > root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] > root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -161,11 +137,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (0 <= Compare(doc.StringField, doc.StringField2)))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] >= root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] >= root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -174,11 +148,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (0 > Compare(doc.StringField, doc.StringField2)))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] < root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] < root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -187,11 +159,9 @@ FROM root]]>
|
|||
<Expression><![CDATA[query.Select(doc => (0 >= Compare(doc.StringField, doc.StringField2)))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery>
|
||||
<![CDATA[
|
||||
SELECT VALUE (root["StringField"] <= root["StringField2"])
|
||||
FROM root]]>
|
||||
</SqlQuery>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE (root["StringField"] <= root["StringField2"])
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
|
|
@ -291,6 +291,38 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
this.ExecuteTestSuite(inputs);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestRegexMatchFunction()
|
||||
{
|
||||
// Similar to the type checking function, RegexMatch are not supported client side.
|
||||
// Therefore this method is verified with baseline only.
|
||||
List<DataObject> data = new List<DataObject>();
|
||||
IOrderedQueryable<DataObject> query = testContainer.GetItemLinqQueryable<DataObject>(allowSynchronousQueryExecution: true);
|
||||
Func<bool, IQueryable<DataObject>> getQuery = useQuery => useQuery ? query : data.AsQueryable();
|
||||
|
||||
List<LinqTestInput> inputs = new List<LinqTestInput>
|
||||
{
|
||||
new LinqTestInput("RegexMatch with 1 argument", b => getQuery(b).Where(doc => doc.StringField.RegexMatch("abcd"))),
|
||||
new LinqTestInput("RegexMatch with 2 argument", b => getQuery(b).Where(doc => doc.StringField.RegexMatch("abcd", "i"))),
|
||||
new LinqTestInput("RegexMatch with 1st argument member expression", b => getQuery(b).Where(doc => doc.StringField.RegexMatch(doc.StringField2))),
|
||||
new LinqTestInput("RegexMatch with ToString", b => getQuery(b).Where(doc => doc.StringField.RegexMatch(doc.IntField.ToString()))),
|
||||
new LinqTestInput("RegexMatch with StringUpper", b => getQuery(b).Where(doc => doc.StringField.RegexMatch(doc.StringField2.ToUpper()))),
|
||||
new LinqTestInput("RegexMatch with StringLower", b => getQuery(b).Where(doc => doc.StringField.RegexMatch(doc.StringField2.ToLower()))),
|
||||
new LinqTestInput("RegexMatch with StringConcat", b => getQuery(b).Where(doc => doc.StringField.RegexMatch(string.Concat(doc.StringField, "str")))),
|
||||
|
||||
new LinqTestInput("RegexMatch with string composition", b => getQuery(b).Where(doc => doc.IntField.ToString().RegexMatch(doc.StringField))),
|
||||
new LinqTestInput("RegexMatch with string composition 2", b => getQuery(b).Where(doc => doc.IntField.ToString().RegexMatch(doc.StringField, doc.StringField2.ToString()))),
|
||||
|
||||
new LinqTestInput("RegexMatch with conditional", b => getQuery(b).Where(doc => doc.StringField.RegexMatch("abc") && doc.StringField2.RegexMatch("def"))),
|
||||
new LinqTestInput("RegexMatch with conditional 2", b => getQuery(b).Where(doc => doc.StringField.RegexMatch("abc") || doc.StringField2.RegexMatch("def"))),
|
||||
new LinqTestInput("RegexMatch with conditional 3", b => getQuery(b).Where(doc => doc.StringField.RegexMatch("abc")).Where(doc => doc.StringField2.RegexMatch("abc"))),
|
||||
new LinqTestInput("RegexMatch with conditional 4", b => getQuery(b).Where(doc => doc.StringField.RegexMatch("abc")).Where(doc => !doc.StringField2.RegexMatch("abc"))),
|
||||
|
||||
new LinqTestInput("RegexMatch with 2nd argument invalid string options", b => getQuery(b).Where(doc => doc.StringField.RegexMatch("abcd", "this should error out on the back end"))),
|
||||
};
|
||||
this.ExecuteTestSuite(inputs);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMemberInitializer()
|
||||
{
|
||||
|
|
|
@ -202,6 +202,9 @@
|
|||
<Content Include="BaselineTest\TestBaseline\LinqTranslationBaselineTests.TestMemberAccessWithNullableTypes.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="BaselineTest\TestBaseline\LinqTranslationBaselineTests.TestRegexMatchFunction.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="BaselineTest\TestBaseline\LinqTranslationBaselineTests.TestSelectTop.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
@ -5367,6 +5367,20 @@
|
|||
],
|
||||
"MethodInfo": "Boolean IsString(System.Object);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
|
||||
},
|
||||
"Boolean RegexMatch(System.Object, System.String, System.String)[System.Runtime.CompilerServices.ExtensionAttribute()]": {
|
||||
"Type": "Method",
|
||||
"Attributes": [
|
||||
"ExtensionAttribute"
|
||||
],
|
||||
"MethodInfo": "Boolean RegexMatch(System.Object, System.String, System.String);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
|
||||
},
|
||||
"Boolean RegexMatch(System.Object, System.String)[System.Runtime.CompilerServices.ExtensionAttribute()]": {
|
||||
"Type": "Method",
|
||||
"Attributes": [
|
||||
"ExtensionAttribute"
|
||||
],
|
||||
"MethodInfo": "Boolean RegexMatch(System.Object, System.String);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
|
||||
},
|
||||
"Microsoft.Azure.Cosmos.FeedIterator ToStreamIterator[T](System.Linq.IQueryable`1[T])[System.Runtime.CompilerServices.ExtensionAttribute()]": {
|
||||
"Type": "Method",
|
||||
"Attributes": [
|
||||
|
|
Загрузка…
Ссылка в новой задаче