Query: Adds DOCUMENTID extension method for LINQ (#4489)
* Add extension method for doucmentid * test coverage * additional test * update contract * update dotnet api * address code review * update csproj file * update missing baseline --------- Co-authored-by: Minh Le (from Dev Box) <leminh@microsoft.com>
This commit is contained in:
Родитель
5a28704392
Коммит
18a677ace9
|
@ -50,11 +50,16 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
|
||||
if (methodCallExpression.Method.DeclaringType.GeUnderlyingSystemType() == typeof(CosmosLinqExtensions))
|
||||
{
|
||||
// CosmosLinq Extensions are either RegexMatch or Type check functions (IsString, IsBool, etc.)
|
||||
// CosmosLinq Extensions can be RegexMatch, DocumentId or Type check functions (IsString, IsBool, etc.)
|
||||
if (methodCallExpression.Method.Name == nameof(CosmosLinqExtensions.RegexMatch))
|
||||
{
|
||||
return StringBuiltinFunctions.Visit(methodCallExpression, context);
|
||||
}
|
||||
}
|
||||
|
||||
if (methodCallExpression.Method.Name == nameof(CosmosLinqExtensions.DocumentId))
|
||||
{
|
||||
return OtherBuiltinSystemFunctions.Visit(methodCallExpression, context);
|
||||
}
|
||||
|
||||
return TypeCheckFunctions.Visit(methodCallExpression, context);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Linq
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.Azure.Cosmos.SqlObjects;
|
||||
|
||||
internal static class OtherBuiltinSystemFunctions
|
||||
{
|
||||
private static Dictionary<string, BuiltinFunctionVisitor> FunctionsDefinitions { get; set; }
|
||||
|
||||
static OtherBuiltinSystemFunctions()
|
||||
{
|
||||
FunctionsDefinitions = new Dictionary<string, BuiltinFunctionVisitor>
|
||||
{
|
||||
[nameof(CosmosLinqExtensions.DocumentId)] = new SqlBuiltinFunctionVisitor(
|
||||
sqlName: "DOCUMENTID",
|
||||
isStatic: true,
|
||||
argumentLists: new List<Type[]>()
|
||||
{
|
||||
new Type[]{typeof(object)},
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
public static SqlScalarExpression Visit(MethodCallExpression methodCallExpression, TranslationContext context)
|
||||
{
|
||||
return FunctionsDefinitions.TryGetValue(methodCallExpression.Method.Name, out BuiltinFunctionVisitor visitor)
|
||||
? visitor.Visit(methodCallExpression, context)
|
||||
: throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.MethodNotSupported, methodCallExpression.Method.Name));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,7 +19,26 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
/// This class provides extension methods for cosmos LINQ code.
|
||||
/// </summary>
|
||||
public static class CosmosLinqExtensions
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the integer identifier corresponding to a specific item within a physical partition.
|
||||
/// 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">The root object</param>
|
||||
/// <returns>Returns the integer identifier corresponding to a specific item within a physical partition.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// var documentIdQuery = documents.Where(root => root.DocumentId());
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static int DocumentId(this object obj)
|
||||
{
|
||||
throw new NotImplementedException(ClientResources.TypeCheckExtensionFunctionsNotImplemented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Boolean value indicating if the type of the specified expression is an array.
|
||||
/// This method is to be used in LINQ expressions only and will be evaluated on server.
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<Results>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[In Select clause]]></Description>
|
||||
<Expression><![CDATA[query.Select(doc => doc.DocumentId())]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE DOCUMENTID(root)
|
||||
FROM root]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[In Filter clause]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => (doc.DocumentId() > 123))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE (DOCUMENTID(root) > 123)]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[With non root term]]></Description>
|
||||
<Expression><![CDATA[query.Where(doc => (Convert(doc.BooleanField, Object).DocumentId() > 123))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
WHERE (DOCUMENTID(root["BooleanField"]) > 123)]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[With JOIN]]></Description>
|
||||
<Expression><![CDATA[query.SelectMany(doc => doc.EnumerableField.Where(number => (doc.DocumentId() > 0)).Select(number => number))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE number0
|
||||
FROM root
|
||||
JOIN number0 IN root["EnumerableField"]
|
||||
WHERE (DOCUMENTID(root) > 0)]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
<Input>
|
||||
<Description><![CDATA[In Order by clause]]></Description>
|
||||
<Expression><![CDATA[query.OrderBy(doc => doc.DocumentId())]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
ORDER BY DOCUMENTID(root) ASC]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","code":2206,"message":"Unsupported ORDER BY clause. ORDER BY item expression could not be mapped to a document path."}]},0x800A0B00]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
</Results>
|
|
@ -290,6 +290,28 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
};
|
||||
this.ExecuteTestSuite(inputs);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestDocumentIdBuiltinFunction()
|
||||
{
|
||||
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("In Select clause", b => getQuery(b).Select(doc => doc.DocumentId())),
|
||||
new LinqTestInput("In Filter clause", b => getQuery(b).Where(doc => doc.DocumentId() > 123)),
|
||||
new LinqTestInput("With non root term", b => getQuery(b).Where(doc => doc.BooleanField.DocumentId() > 123)),
|
||||
new LinqTestInput("With JOIN", b => getQuery(b).SelectMany(doc => doc.EnumerableField
|
||||
.Where(number => doc.DocumentId() > 0)
|
||||
.Select(number => number))),
|
||||
// Negative case
|
||||
new LinqTestInput("In Order by clause", b => getQuery(b).OrderBy(doc => doc.DocumentId())),
|
||||
};
|
||||
|
||||
this.ExecuteTestSuite(inputs);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestRegexMatchFunction()
|
||||
|
|
|
@ -229,6 +229,9 @@
|
|||
<Content Include="BaselineTest\TestBaseline\LinqTranslationBaselineTests.TestDateTimeJsonConverterTimezones.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="BaselineTest\TestBaseline\LinqTranslationBaselineTests.TestDocumentIdBuiltinFunction.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="BaselineTest\TestBaseline\LinqTranslationBaselineTests.TestMemberAccessWithNullableTypes.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
@ -5650,6 +5650,13 @@
|
|||
],
|
||||
"MethodInfo": "Boolean RegexMatch(System.Object, System.String);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
|
||||
},
|
||||
"Int32 DocumentId(System.Object)[System.Runtime.CompilerServices.ExtensionAttribute()]": {
|
||||
"Type": "Method",
|
||||
"Attributes": [
|
||||
"ExtensionAttribute"
|
||||
],
|
||||
"MethodInfo": "Int32 DocumentId(System.Object);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": [
|
||||
|
|
Загрузка…
Ссылка в новой задаче