Skip to content

Commit

Permalink
implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
leminh98 committed Jan 27, 2025
1 parent a6982be commit 9fb9c12
Show file tree
Hide file tree
Showing 11 changed files with 402 additions and 18 deletions.
35 changes: 22 additions & 13 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.

3 changes: 3 additions & 0 deletions Microsoft.Azure.Cosmos/src/ClientResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,7 @@
<data name="FeedToken_InvalidFeedTokenForContainer" xml:space="preserve">
<value>The continuation was generated for container {0} but current container is {1}.</value>
</data>
<data name="LINQExtensionFunctionNotImplemented" xml:space="preserve">
<value>Extension function can be used in Linq expressions only and are evaluated in Azure CosmosDB server.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ public static SqlScalarExpression VisitBuiltinFunctionCall(MethodCallExpression
if (methodCallExpression.Method.DeclaringType.GeUnderlyingSystemType() == typeof(CosmosLinqExtensions))
{
// CosmosLinq Extensions can be RegexMatch, DocumentId or Type check functions (IsString, IsBool, etc.)
if (methodCallExpression.Method.Name == nameof(CosmosLinqExtensions.RegexMatch))
if ((methodCallExpression.Method.Name == nameof(CosmosLinqExtensions.RegexMatch)) ||
(methodCallExpression.Method.Name == nameof(CosmosLinqExtensions.FullTextContains)) ||
(methodCallExpression.Method.Name == nameof(CosmosLinqExtensions.FullTextContainsAll)) ||
(methodCallExpression.Method.Name == nameof(CosmosLinqExtensions.FullTextContainsAny)))
{
return StringBuiltinFunctions.Visit(methodCallExpression, context);
}
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,91 @@ protected override SqlScalarExpression VisitImplicit(MethodCallExpression method
return null;
}
}

private class FullTextContainsVisit : SqlBuiltinFunctionVisitor
{
public FullTextContainsVisit()
: base("FullTextContains",
true,
new List<Type[]>()
{
new Type[]{typeof(object), typeof(string)}
})
{
}
}

private class FullTextContainsAllVisit : SqlBuiltinFunctionVisitor
{
public FullTextContainsAllVisit()
: base("FullTextContainsAll",
true,
new List<Type[]>()
{
new Type[]{typeof(object), typeof(string[])}
})
{
}

protected override SqlScalarExpression VisitImplicit(MethodCallExpression methodCallExpression, TranslationContext context)
{
Console.WriteLine(methodCallExpression.Arguments[1].Type);
if (methodCallExpression.Arguments.Count == 2
&& methodCallExpression.Arguments[1] is ConstantExpression stringListArgumentExpression
&& ExpressionToSql.VisitConstant(stringListArgumentExpression, context) is SqlArrayCreateScalarExpression arrayScalarExpressions)
{
List<SqlScalarExpression> arguments = new List<SqlScalarExpression>();

arguments.Add(ExpressionToSql.VisitNonSubqueryScalarExpression(methodCallExpression.Arguments[0], context));
arguments.AddRange(arrayScalarExpressions.Items);

return SqlFunctionCallScalarExpression.CreateBuiltin(SqlFunctionCallScalarExpression.Names.FullTextContainsAll, arguments.ToImmutableArray());
}

return null;
}

protected override SqlScalarExpression VisitExplicit(MethodCallExpression methodCallExpression, TranslationContext context)
{
return null;
}
}

private class FullTextContainsAnyVisit : SqlBuiltinFunctionVisitor
{
public FullTextContainsAnyVisit()
: base("FullTextContainsAny",
true,
new List<Type[]>()
{
new Type[]{typeof(object), typeof(string[])}
})
{
}

protected override SqlScalarExpression VisitImplicit(MethodCallExpression methodCallExpression, TranslationContext context)
{
Console.WriteLine(methodCallExpression.Arguments[1].Type);
if (methodCallExpression.Arguments.Count == 2
&& methodCallExpression.Arguments[1] is ConstantExpression stringListArgumentExpression
&& ExpressionToSql.VisitConstant(stringListArgumentExpression, context) is SqlArrayCreateScalarExpression arrayScalarExpressions)
{
List<SqlScalarExpression> arguments = new List<SqlScalarExpression>();

arguments.Add(ExpressionToSql.VisitNonSubqueryScalarExpression(methodCallExpression.Arguments[0], context));
arguments.AddRange(arrayScalarExpressions.Items);

return SqlFunctionCallScalarExpression.CreateBuiltin(SqlFunctionCallScalarExpression.Names.FullTextContainsAny, arguments.ToImmutableArray());
}

return null;
}

protected override SqlScalarExpression VisitExplicit(MethodCallExpression methodCallExpression, TranslationContext context)
{
return null;
}
}

static StringBuiltinFunctions()
{
Expand Down Expand Up @@ -528,6 +613,18 @@ static StringBuiltinFunctions()
{
"Equals",
new StringEqualsVisitor()
},
{
nameof(CosmosLinqExtensions.FullTextContains),
new FullTextContainsVisit()
},
{
nameof(CosmosLinqExtensions.FullTextContainsAll),
new FullTextContainsAllVisit()
},
{
nameof(CosmosLinqExtensions.FullTextContainsAny),
new FullTextContainsAnyVisit()
}
};
}
Expand Down
71 changes: 67 additions & 4 deletions Microsoft.Azure.Cosmos/src/Linq/CosmosLinqExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public static bool IsString(this object obj)
/// </example>
public static bool RegexMatch(this object obj, string regularExpression)
{
throw new NotImplementedException(ClientResources.TypeCheckExtensionFunctionsNotImplemented);
throw new NotImplementedException(ClientResources.LINQExtensionFunctionNotImplemented);
}

/// <summary>
Expand All @@ -234,9 +234,72 @@ public static bool RegexMatch(this object obj, string regularExpression)
/// </example>
public static bool RegexMatch(this object obj, string regularExpression, string searchModifier)
{
throw new NotImplementedException(ClientResources.TypeCheckExtensionFunctionsNotImplemented);
}

throw new NotImplementedException(ClientResources.LINQExtensionFunctionNotImplemented);
}

/// <summary>
/// Returns a boolean indicating whether the keyword string expression is contained in a specified property path.
/// For more information, see https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/query/fulltextcontains.
/// 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="search">The string to find.</param>
/// <returns>Returns true if a given string is contained in the specified property of a document.</returns>
/// <example>
/// <code>
/// <![CDATA[
/// var matched = documents.Where(document => document.Name.FullTextContains(<keyword>));
/// ]]>
/// </code>
/// </example>
public static bool FullTextContains(this object obj, string search)
{
throw new NotImplementedException(ClientResources.LINQExtensionFunctionNotImplemented);
}

/// <summary>
/// Returns a boolean indicating whether all of the provided string expressions are contained in a specified property path.
/// For more information, see https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/query/fulltextcontainsall.
/// 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="searches">The strings to find.</param>
/// <returns>Returns true if all of the given strings are contained in the specified property of a document.</returns>
/// <example>
/// <code>
/// <![CDATA[
/// var matched = documents.Where(document => document.Name.FullTextContainsAll(<keyword1>, <keyword2>, <keyword3>, ...));
/// ]]>
/// </code>
/// </example>
public static bool FullTextContainsAll(this object obj, params string[] searches)
{
throw new NotImplementedException(ClientResources.LINQExtensionFunctionNotImplemented);
}

/// <summary>
/// Returns a boolean indicating whether any of the provided string expressions are contained in a specified property path.
/// For more information, see https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/query/fulltextcontainsany.
/// 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="searches">The strings to find.</param>
/// <returns>Returns true if any of the given strings are contained in the specified property of a document.</returns>
/// <example>
/// <code>
/// <![CDATA[
/// var matched = documents.Where(document => document.Name.FullTextContainsAny(<keyword1>, <keyword2>, <keyword3>, ...));
/// ]]>
/// </code>
/// </example>
public static bool FullTextContainsAny(this object obj, params string[] searches)
{
throw new NotImplementedException(ClientResources.LINQExtensionFunctionNotImplemented);
}

/// <summary>
/// This method generate query definition from LINQ query.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ sealed class SqlFunctionCallScalarExpression : SqlScalarExpression
{ Names.Endswith, Identifiers.Endswith },
{ Names.Exp, Identifiers.Exp },
{ Names.Floor, Identifiers.Floor },
{ Names.FullTextContains, Identifiers.FullTextContains },
{ Names.FullTextContainsAll, Identifiers.FullTextContainsAll },
{ Names.FullTextContainsAny, Identifiers.FullTextContainsAny },
{ Names.GetCurrentDateTime, Identifiers.GetCurrentDateTime },
{ Names.GetCurrentTicks, Identifiers.GetCurrentTicks },
{ Names.GetCurrentTimestamp, Identifiers.GetCurrentTimestamp },
Expand Down Expand Up @@ -294,6 +297,9 @@ public static class Names
public const string Endswith = "ENDSWITH";
public const string Exp = "EXP";
public const string Floor = "FLOOR";
public const string FullTextContains = "FullTextContains";
public const string FullTextContainsAll = "FullTextContainsAll";
public const string FullTextContainsAny = "FullTextContainsAny";
public const string GetCurrentDateTime = "GetCurrentDateTime";
public const string GetCurrentTicks = "GetCurrentTicks";
public const string GetCurrentTimestamp = "GetCurrentTimestamp";
Expand Down Expand Up @@ -437,6 +443,9 @@ public static class Identifiers
public static readonly SqlIdentifier Endswith = SqlIdentifier.Create(Names.Endswith);
public static readonly SqlIdentifier Exp = SqlIdentifier.Create(Names.Exp);
public static readonly SqlIdentifier Floor = SqlIdentifier.Create(Names.Floor);
public static readonly SqlIdentifier FullTextContains = SqlIdentifier.Create(Names.FullTextContains);
public static readonly SqlIdentifier FullTextContainsAll = SqlIdentifier.Create(Names.FullTextContainsAll);
public static readonly SqlIdentifier FullTextContainsAny = SqlIdentifier.Create(Names.FullTextContainsAny);
public static readonly SqlIdentifier GetCurrentDateTime = SqlIdentifier.Create(Names.GetCurrentDateTime);
public static readonly SqlIdentifier GetCurrentTicks = SqlIdentifier.Create(Names.GetCurrentTicks);
public static readonly SqlIdentifier GetCurrentTimestamp = SqlIdentifier.Create(Names.GetCurrentTimestamp);
Expand Down
Loading

0 comments on commit 9fb9c12

Please sign in to comment.