Query: Adds support for multi-value Group By query for LINQ (#4481)
* init * Added tests * Preliminary code * baseline * add ordering ignore to test cases * upate baseline * address code review 1 * Changed the way comparison between Anonymoustype object worked. Also added handling of multivalue case to call directly to leaf layer visitors, instead of going through the top level scalar expression visitor to avoid changing binding and context scope * addressed code review * address code review * addressed missing field --------- Co-authored-by: Minh Le (from Dev Box) <leminh@microsoft.com>
This commit is contained in:
Родитель
7867f549e8
Коммит
5bba9a05b0
|
@ -884,6 +884,29 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
result[i] = prop;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static SqlSelectItem[] CreateSelectItems(ReadOnlyCollection<Expression> arguments, ReadOnlyCollection<MemberInfo> members, TranslationContext context)
|
||||
{
|
||||
if (arguments.Count != members.Count)
|
||||
{
|
||||
throw new InvalidOperationException("Expected same number of arguments as members");
|
||||
}
|
||||
|
||||
SqlSelectItem[] result = new SqlSelectItem[arguments.Count];
|
||||
for (int i = 0; i < arguments.Count; i++)
|
||||
{
|
||||
Expression arg = arguments[i];
|
||||
MemberInfo member = members[i];
|
||||
SqlScalarExpression selectExpression = ExpressionToSql.VisitScalarExpression(arg, context);
|
||||
|
||||
string memberName = member.GetMemberName(context);
|
||||
SqlIdentifier alias = SqlIdentifier.Create(memberName);
|
||||
SqlSelectItem prop = SqlSelectItem.Create(selectExpression, alias);
|
||||
result[i] = prop;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1314,6 +1337,80 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
context.PopMethod();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visit a method call, construct the corresponding query and return the select clause for the aggregate function.
|
||||
/// At ExpressionToSql point only LINQ method calls are allowed.
|
||||
/// These methods are static extension methods of IQueryable or IEnumerable.
|
||||
/// </summary>
|
||||
/// <param name="inputExpression">Method to translate.</param>
|
||||
/// <param name="context">Query translation context.</param>
|
||||
private static SqlSelectClause VisitGroupByAggregateMethodCall(MethodCallExpression inputExpression, TranslationContext context)
|
||||
{
|
||||
context.PushMethod(inputExpression);
|
||||
|
||||
Type declaringType = inputExpression.Method.DeclaringType;
|
||||
if ((declaringType != typeof(Queryable) && declaringType != typeof(Enumerable))
|
||||
|| !inputExpression.Method.IsStatic)
|
||||
{
|
||||
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.OnlyLINQMethodsAreSupported, inputExpression.Method.Name));
|
||||
}
|
||||
|
||||
if (inputExpression.Object != null)
|
||||
{
|
||||
throw new DocumentQueryException(ClientResources.ExpectedMethodCallsMethods);
|
||||
}
|
||||
|
||||
Expression inputCollection = inputExpression.Arguments[0]; // all these methods are static extension methods, so argument[0] is the collection
|
||||
|
||||
Collection collection = ExpressionToSql.Translate(inputCollection, context);
|
||||
context.PushCollection(collection);
|
||||
|
||||
bool shouldBeOnNewQuery = context.CurrentQuery.ShouldBeOnNewQuery(inputExpression.Method.Name, inputExpression.Arguments.Count);
|
||||
context.PushSubqueryBinding(shouldBeOnNewQuery);
|
||||
|
||||
if (context.LastExpressionIsGroupBy)
|
||||
{
|
||||
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, "Group By cannot be followed by other methods"));
|
||||
}
|
||||
|
||||
SqlSelectClause select;
|
||||
switch (inputExpression.Method.Name)
|
||||
{
|
||||
case LinqMethods.Average:
|
||||
{
|
||||
select = ExpressionToSql.VisitAggregateFunction(inputExpression.Arguments, context, SqlFunctionCallScalarExpression.Names.Avg);
|
||||
break;
|
||||
}
|
||||
case LinqMethods.Count:
|
||||
{
|
||||
select = ExpressionToSql.VisitCount(inputExpression.Arguments, context);
|
||||
break;
|
||||
}
|
||||
case LinqMethods.Max:
|
||||
{
|
||||
select = ExpressionToSql.VisitAggregateFunction(inputExpression.Arguments, context, SqlFunctionCallScalarExpression.Names.Max);
|
||||
break;
|
||||
}
|
||||
case LinqMethods.Min:
|
||||
{
|
||||
select = ExpressionToSql.VisitAggregateFunction(inputExpression.Arguments, context, SqlFunctionCallScalarExpression.Names.Min);
|
||||
break;
|
||||
}
|
||||
case LinqMethods.Sum:
|
||||
{
|
||||
select = ExpressionToSql.VisitAggregateFunction(inputExpression.Arguments, context, SqlFunctionCallScalarExpression.Names.Sum);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.MethodNotSupported, inputExpression.Method.Name));
|
||||
}
|
||||
|
||||
context.PopSubqueryBinding();
|
||||
context.PopCollection();
|
||||
context.PopMethod();
|
||||
return select;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if an expression should be translated to a subquery.
|
||||
|
@ -1735,48 +1832,93 @@ namespace Microsoft.Azure.Cosmos.Linq
|
|||
switch (valueSelectorExpression.NodeType)
|
||||
{
|
||||
case ExpressionType.Constant:
|
||||
{
|
||||
ConstantExpression constantExpression = (ConstantExpression)valueSelectorExpression;
|
||||
SqlScalarExpression selectExpression = ExpressionToSql.VisitConstant(constantExpression, context);
|
||||
|
||||
SqlSelectSpec sqlSpec = SqlSelectValueSpec.Create(selectExpression);
|
||||
SqlSelectClause select = SqlSelectClause.Create(sqlSpec, null);
|
||||
context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
|
||||
break;
|
||||
}
|
||||
case ExpressionType.Parameter:
|
||||
{
|
||||
ParameterExpression parameterValueExpression = (ParameterExpression)valueSelectorExpression;
|
||||
SqlScalarExpression selectExpression = ExpressionToSql.VisitParameter(parameterValueExpression, context);
|
||||
|
||||
SqlSelectSpec sqlSpec = SqlSelectValueSpec.Create(selectExpression);
|
||||
SqlSelectClause select = SqlSelectClause.Create(sqlSpec, null);
|
||||
context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
|
||||
break;
|
||||
}
|
||||
case ExpressionType.Call:
|
||||
{
|
||||
// Single Value Selector
|
||||
MethodCallExpression methodCallExpression = (MethodCallExpression)valueSelectorExpression;
|
||||
switch (methodCallExpression.Method.Name)
|
||||
{
|
||||
case LinqMethods.Max:
|
||||
case LinqMethods.Min:
|
||||
case LinqMethods.Average:
|
||||
case LinqMethods.Count:
|
||||
case LinqMethods.Sum:
|
||||
ExpressionToSql.VisitMethodCall(methodCallExpression, context);
|
||||
break;
|
||||
default:
|
||||
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.MethodNotSupported, methodCallExpression.Method.Name));
|
||||
}
|
||||
ConstantExpression constantExpression = (ConstantExpression)valueSelectorExpression;
|
||||
SqlScalarExpression selectExpression = ExpressionToSql.VisitConstant(constantExpression, context);
|
||||
|
||||
break;
|
||||
}
|
||||
case ExpressionType.New:
|
||||
// TODO: Multi Value Selector
|
||||
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.ExpressionTypeIsNotSupported, ExpressionType.New));
|
||||
SqlSelectSpec sqlSpec = SqlSelectValueSpec.Create(selectExpression);
|
||||
SqlSelectClause select = SqlSelectClause.Create(sqlSpec, null);
|
||||
context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
|
||||
break;
|
||||
}
|
||||
case ExpressionType.Parameter:
|
||||
{
|
||||
ParameterExpression parameterValueExpression = (ParameterExpression)valueSelectorExpression;
|
||||
SqlScalarExpression selectExpression = ExpressionToSql.VisitParameter(parameterValueExpression, context);
|
||||
|
||||
SqlSelectSpec sqlSpec = SqlSelectValueSpec.Create(selectExpression);
|
||||
SqlSelectClause select = SqlSelectClause.Create(sqlSpec, null);
|
||||
context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
|
||||
break;
|
||||
}
|
||||
case ExpressionType.Call:
|
||||
{
|
||||
// Single Value Selector
|
||||
MethodCallExpression methodCallExpression = (MethodCallExpression)valueSelectorExpression;
|
||||
SqlSelectClause select = ExpressionToSql.VisitGroupByAggregateMethodCall(methodCallExpression, context);
|
||||
context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
|
||||
break;
|
||||
}
|
||||
case ExpressionType.New:
|
||||
{
|
||||
// Add select item clause at the end of this method
|
||||
NewExpression newExpression = (NewExpression)valueSelectorExpression;
|
||||
|
||||
if (newExpression.Members == null)
|
||||
{
|
||||
throw new DocumentQueryException(ClientResources.ConstructorInvocationNotSupported);
|
||||
}
|
||||
|
||||
// Get the list of items and the bindings
|
||||
ReadOnlyCollection<Expression> newExpressionArguments = newExpression.Arguments;
|
||||
ReadOnlyCollection<MemberInfo> newExpressionMembers = newExpression.Members;
|
||||
|
||||
SqlSelectItem[] selectItems = new SqlSelectItem[newExpressionArguments.Count];
|
||||
for (int i = 0; i < newExpressionArguments.Count; i++)
|
||||
{
|
||||
MemberInfo member = newExpressionMembers[i];
|
||||
string memberName = member.GetMemberName(context);
|
||||
SqlIdentifier alias = SqlIdentifier.Create(memberName);
|
||||
|
||||
Expression arg = newExpressionArguments[i];
|
||||
switch (arg.NodeType)
|
||||
{
|
||||
case ExpressionType.Constant:
|
||||
{
|
||||
SqlScalarExpression selectExpression = ExpressionToSql.VisitConstant((ConstantExpression)arg, context);
|
||||
|
||||
SqlSelectItem prop = SqlSelectItem.Create(selectExpression, alias);
|
||||
selectItems[i] = prop;
|
||||
break;
|
||||
}
|
||||
case ExpressionType.Parameter:
|
||||
{
|
||||
SqlScalarExpression selectExpression = ExpressionToSql.VisitParameter((ParameterExpression)arg, context);
|
||||
|
||||
SqlSelectItem prop = SqlSelectItem.Create(selectExpression, alias);
|
||||
selectItems[i] = prop;
|
||||
break;
|
||||
}
|
||||
case ExpressionType.Call:
|
||||
{
|
||||
SqlSelectClause selectClause = ExpressionToSql.VisitGroupByAggregateMethodCall((MethodCallExpression)arg, context);
|
||||
SqlScalarExpression selectExpression = ((SqlSelectValueSpec)selectClause.SelectSpec).Expression;
|
||||
|
||||
SqlSelectItem prop = SqlSelectItem.Create(selectExpression, alias);
|
||||
selectItems[i] = prop;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.ExpressionTypeIsNotSupported, arg.NodeType));
|
||||
}
|
||||
}
|
||||
|
||||
SqlSelectListSpec sqlSpec = SqlSelectListSpec.Create(selectItems);
|
||||
SqlSelectClause select = SqlSelectClause.Create(sqlSpec, null);
|
||||
context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.ExpressionTypeIsNotSupported, valueSelectorExpression.NodeType));
|
||||
}
|
||||
|
|
|
@ -17,8 +17,10 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.GroupBy(k => k.Id, (key, values) => new AnonymousType(Key = key, key = key))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT root["id"] AS Key, root["id"] AS key
|
||||
FROM root
|
||||
GROUP BY root["id"] ]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -27,8 +29,10 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.GroupBy(k => k.Id, (key, values) => new AnonymousType(KeyAlias = key, values = 123))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT root["id"] AS KeyAlias, 123 AS values
|
||||
FROM root
|
||||
GROUP BY root["id"] ]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -37,8 +41,10 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.GroupBy(k => k.Id, (key, values) => new AnonymousType(Min = values.Min(value => value.Int), Max = values.Max(value => value.Int), Avg = values.Average(value => value.Int), Count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT MIN(root["Int"]) AS Min, MAX(root["Int"]) AS Max, AVG(root["Int"]) AS Avg, COUNT(1) AS Count
|
||||
FROM root
|
||||
GROUP BY root["id"] ]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -47,8 +53,10 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.GroupBy(k => k.FamilyId, (key, values) => new AnonymousType(familyId = key, familyIdCount = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT root["FamilyId"] AS familyId, COUNT(1) AS familyIdCount
|
||||
FROM root
|
||||
GROUP BY root["FamilyId"] ]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -57,8 +65,10 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.GroupBy(k => k.Id, (key, values) => new AnonymousType(Min = values.Min(), Max = values.Max()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT MIN(root) AS Min, MAX(root) AS Max
|
||||
FROM root
|
||||
GROUP BY root["id"] ]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -68,7 +78,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Method 'Select' is not supported.]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -77,8 +87,13 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.Select(x => x.Id).GroupBy(k => k, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT r0 AS keyAlias, COUNT(1) AS count
|
||||
FROM (
|
||||
SELECT VALUE root["id"]
|
||||
FROM root) AS r0
|
||||
GROUP BY r0
|
||||
]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -87,8 +102,13 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.Select(x => new AnonymousType(Id1 = x.Id, family1 = x.FamilyId, childrenN1 = x.Children)).GroupBy(k => k.Id1, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT r0["Id1"] AS keyAlias, COUNT(1) AS count
|
||||
FROM (
|
||||
SELECT VALUE {"Id1": root["id"], "family1": root["FamilyId"], "childrenN1": root["Children"]}
|
||||
FROM root) AS r0
|
||||
GROUP BY r0["Id1"]
|
||||
]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -97,8 +117,11 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.SelectMany(x => x.Children).GroupBy(k => k, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT x0 AS keyAlias, COUNT(1) AS count
|
||||
FROM root
|
||||
JOIN x0 IN root["Children"]
|
||||
GROUP BY x0 ]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -107,8 +130,15 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.Skip(10).GroupBy(k => k.Id, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT r0["id"] AS keyAlias, COUNT(1) AS count
|
||||
FROM (
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
OFFSET 10 LIMIT 2147483647) AS r0
|
||||
GROUP BY r0["id"]
|
||||
]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","location":{"start":81,"end":107},"code":"SC2204","message":"'OFFSET LIMIT' clause is not supported in subqueries."}]},0x800A0B00]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -117,8 +147,14 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.Take(10).GroupBy(k => k.Id, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT r0["id"] AS keyAlias, COUNT(1) AS count
|
||||
FROM (
|
||||
SELECT TOP 10 VALUE root
|
||||
FROM root) AS r0
|
||||
GROUP BY r0["id"]
|
||||
]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","location":{"start":60,"end":66},"code":"SC2203","message":"'TOP' is not supported in subqueries."}]},0x800A0B00]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -127,8 +163,15 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.Skip(10).Take(10).GroupBy(k => k.Id, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT r0["id"] AS keyAlias, COUNT(1) AS count
|
||||
FROM (
|
||||
SELECT VALUE root
|
||||
FROM root
|
||||
OFFSET 10 LIMIT 10) AS r0
|
||||
GROUP BY r0["id"]
|
||||
]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","location":{"start":81,"end":99},"code":"SC2204","message":"'OFFSET LIMIT' clause is not supported in subqueries."}]},0x800A0B00]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -137,8 +180,11 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.Where(x => (x.Id != "a")).GroupBy(k => k.Id, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT root["id"] AS keyAlias, COUNT(1) AS count
|
||||
FROM root
|
||||
WHERE (root["id"] != "a")
|
||||
GROUP BY root["id"] ]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -147,8 +193,12 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.OrderBy(x => x.Int).GroupBy(k => k.Id, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT root["id"] AS keyAlias, COUNT(1) AS count
|
||||
FROM root
|
||||
GROUP BY root["id"]
|
||||
ORDER BY root["Int"] ASC]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Status Code: BadRequest,{"errors":[{"severity":"Error","location":{"start":89,"end":100},"code":"SC2103","message":"Property reference 'root[\"Int\"]' is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause."}]},0x800A0B00]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -157,8 +207,11 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.OrderByDescending(x => x.Id).GroupBy(k => k.Id, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT root["id"] AS keyAlias, COUNT(1) AS count
|
||||
FROM root
|
||||
GROUP BY root["id"]
|
||||
ORDER BY root["id"] DESC]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -167,8 +220,12 @@ GROUP BY root ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.Where(x => (x.Id != "a")).OrderBy(x => x.Id).GroupBy(k => k.Id, (key, values) => new AnonymousType(keyAlias = key, count = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT root["id"] AS keyAlias, COUNT(1) AS count
|
||||
FROM root
|
||||
WHERE (root["id"] != "a")
|
||||
GROUP BY root["id"]
|
||||
ORDER BY root["id"] ASC]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -178,7 +235,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -188,7 +245,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -198,7 +255,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -208,7 +265,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -218,7 +275,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -228,7 +285,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -238,7 +295,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -248,7 +305,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -258,7 +315,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -268,7 +325,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
@ -278,7 +335,7 @@ GROUP BY root ]]></SqlQuery>
|
|||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<ErrorMessage><![CDATA[Group By cannot be followed by other methods]]></ErrorMessage>
|
||||
</Output>
|
||||
</Result>
|
||||
</Results>
|
|
@ -167,8 +167,10 @@ GROUP BY root["Int"] ]]></SqlQuery>
|
|||
<Expression><![CDATA[query.GroupBy(k => k.FamilyId, (key, values) => new AnonymousType(familyId = key, familyIdCount = values.Count()))]]></Expression>
|
||||
</Input>
|
||||
<Output>
|
||||
<SqlQuery><![CDATA[]]></SqlQuery>
|
||||
<ErrorMessage><![CDATA[Expression with NodeType 'New' is not supported.]]></ErrorMessage>
|
||||
<SqlQuery><![CDATA[
|
||||
SELECT root["FamilyId"] AS familyId, COUNT(1) AS familyIdCount
|
||||
FROM root
|
||||
GROUP BY root["FamilyId"] ]]></SqlQuery>
|
||||
</Output>
|
||||
</Result>
|
||||
<Result>
|
||||
|
|
|
@ -747,7 +747,8 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
|
||||
// Currently unsupported case
|
||||
inputs.Add(new LinqTestInput("GroupBy Single Value With Min", b => getQuery(b).GroupBy(k => k.FamilyId /*keySelector*/,
|
||||
(key, values) => new { familyId = key, familyIdCount = values.Count() } /*multi-value select */)));
|
||||
(key, values) => new { familyId = key, familyIdCount = values.Count() } /*multi-value select */),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
// Other methods followed by GroupBy
|
||||
|
||||
|
@ -851,48 +852,49 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
{
|
||||
List<LinqTestInput> inputs = new List<LinqTestInput>();
|
||||
inputs.Add(new LinqTestInput("GroupBy Multi Value Select Constant", b => getQuery(b).GroupBy(k => k /*keySelector*/,
|
||||
(key, values) =>
|
||||
(key, values) =>
|
||||
new {
|
||||
stringField = "abv",
|
||||
numField = 123
|
||||
})));
|
||||
numField = 123}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy Multi Value Select Key", b => getQuery(b).GroupBy(k => k.Id /*keySelector*/,
|
||||
(key, values) => new {
|
||||
Key = key,
|
||||
key
|
||||
})));
|
||||
key}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy Multi Value Select Key and Constant", b => getQuery(b).GroupBy(k => k.Id /*keySelector*/,
|
||||
(key, values) => new {
|
||||
KeyAlias = key,
|
||||
values = 123 /* intentionally have the same spelling as the IGrouping values */
|
||||
})));
|
||||
values = 123 /* intentionally have the same spelling as the IGrouping values */}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy Multi Value With Aggregate", b => getQuery(b).GroupBy(k => k.Id /*keySelector*/,
|
||||
(key, values) => new {
|
||||
Min = values.Min(value => value.Int),
|
||||
Max = values.Max(value => value.Int),
|
||||
Avg = values.Average(value => value.Int),
|
||||
Count = values.Count()
|
||||
})));
|
||||
Count = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy Multi Value With Property Ref and Aggregate", b => getQuery(b).GroupBy(k => k.FamilyId /*keySelector*/,
|
||||
(key, values) => new {
|
||||
familyId = key,
|
||||
familyIdCount = values.Count()
|
||||
})));
|
||||
familyIdCount = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
// Negative cases
|
||||
|
||||
// The translation is correct (SELECT VALUE MIN(root) FROM root GROUP BY root["Number"]
|
||||
// but the behavior between LINQ and SQL is different
|
||||
// In Linq, it requires the object to have comparer traits, where as in CosmosDB, we will return null
|
||||
// In Linq, the queries will return an object on root, where as in CosmosDB, we will return null
|
||||
inputs.Add(new LinqTestInput("GroupBy Multi Value With Aggregate On Root", b => getQuery(b).GroupBy(k => k.Id /*keySelector*/,
|
||||
(key, values) => new {
|
||||
Min = values.Min(),
|
||||
Max = values.Max()
|
||||
})));
|
||||
Max = values.Max()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true,
|
||||
skipVerification: true));
|
||||
|
||||
// Non-aggregate method calls
|
||||
inputs.Add(new LinqTestInput("GroupBy Multi Value With Non-Aggregate", b => getQuery(b).GroupBy(k => k.Id /*keySelector*/,
|
||||
|
@ -906,50 +908,50 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
.Select(x => x.Id)
|
||||
.GroupBy(k => k /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()
|
||||
})));
|
||||
count = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("Select + GroupBy 2", b => getQuery(b)
|
||||
.Select(x => new { Id1 = x.Id, family1 = x.FamilyId, childrenN1 = x.Children })
|
||||
.GroupBy(k => k.Id1 /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()
|
||||
})));
|
||||
count = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("SelectMany + GroupBy", b => getQuery(b)
|
||||
.SelectMany(x => x.Children)
|
||||
.GroupBy(k => k /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()
|
||||
})));
|
||||
count = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("Skip + GroupBy", b => getQuery(b)
|
||||
.Skip(10)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()
|
||||
})));
|
||||
count = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("Take + GroupBy", b => getQuery(b)
|
||||
.Take(10)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()
|
||||
})));
|
||||
count = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("Skip + Take + GroupBy", b => getQuery(b)
|
||||
.Skip(10).Take(10)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()
|
||||
})));
|
||||
count = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("Filter + GroupBy", b => getQuery(b)
|
||||
.Where(x => x.Id != "a")
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()
|
||||
})));
|
||||
count = values.Count()}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
// should this become a subquery with order by then group by?
|
||||
inputs.Add(new LinqTestInput("OrderBy + GroupBy", b => getQuery(b)
|
||||
|
@ -979,7 +981,8 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()})
|
||||
.Select(x => x)));
|
||||
.Select(x => x),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy + Select 2", b => getQuery(b)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
|
@ -992,25 +995,29 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()})
|
||||
.Skip(10)));
|
||||
.Skip(10),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy + Take", b => getQuery(b)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()})
|
||||
.Take(10)));
|
||||
.Take(10),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy + Skip + Take", b => getQuery(b)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()})
|
||||
.Skip(10).Take(10)));
|
||||
.Skip(10).Take(10),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy + Filter", b => getQuery(b)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()})
|
||||
.Where(x => x.keyAlias == "a")));
|
||||
.Where(x => x.keyAlias == "a"),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy + OrderBy", b => getQuery(b)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
|
@ -1028,13 +1035,15 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()})
|
||||
.Where(x => x.keyAlias == "a").Skip(10).Take(10)));
|
||||
.Where(x => x.keyAlias == "a").Skip(10).Take(10),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy + GroupBy", b => getQuery(b)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
count = values.Count()})
|
||||
.GroupBy(k => k.count /*keySelector*/, (key, values) => key /*return the group by key */)));
|
||||
.GroupBy(k => k.count /*keySelector*/, (key, values) => key /*return the group by key */),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
inputs.Add(new LinqTestInput("GroupBy + GroupBy2", b => getQuery(b)
|
||||
.GroupBy(k => k.Id /*keySelector*/, (key, values) => new {
|
||||
|
@ -1044,7 +1053,8 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests.LinqProviderTests
|
|||
.GroupBy(k => k.count /*keySelector*/, (key, values) => new {
|
||||
keyAlias = key,
|
||||
stringField = "abc"
|
||||
})));
|
||||
}),
|
||||
ignoreOrderingForAnonymousTypeObject: true));
|
||||
|
||||
this.ExecuteTestSuite(inputs);
|
||||
}
|
||||
|
|
|
@ -35,9 +35,38 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests
|
|||
/// <param name="queryResults"></param>
|
||||
/// <param name="dataResults"></param>
|
||||
/// <returns></returns>
|
||||
private static bool CompareListOfAnonymousType(List<object> queryResults, List<dynamic> dataResults)
|
||||
{
|
||||
return queryResults.SequenceEqual(dataResults);
|
||||
private static bool CompareListOfAnonymousType(List<object> queryResults, List<dynamic> dataResults, bool ignoreOrder)
|
||||
{
|
||||
if (!ignoreOrder)
|
||||
{
|
||||
return queryResults.SequenceEqual(dataResults);
|
||||
}
|
||||
|
||||
if (queryResults.Count != dataResults.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool resultMatched = true;
|
||||
foreach (object obj in queryResults)
|
||||
{
|
||||
if (!dataResults.Any(a => a.Equals(obj)))
|
||||
{
|
||||
resultMatched = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (dynamic obj in dataResults)
|
||||
{
|
||||
if (!queryResults.Any(a => a.Equals(obj)))
|
||||
{
|
||||
resultMatched = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return resultMatched;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -186,7 +215,7 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests
|
|||
/// </summary>
|
||||
/// <param name="queryResultsList"></param>
|
||||
/// <param name="dataResultsList"></param>
|
||||
private static void ValidateResults(List<object> queryResultsList, List<dynamic> dataResultsList)
|
||||
private static void ValidateResults(List<object> queryResultsList, List<dynamic> dataResultsList, bool ignoreOrder)
|
||||
{
|
||||
bool resultMatched = true;
|
||||
string actualStr = null;
|
||||
|
@ -204,7 +233,7 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests
|
|||
}
|
||||
else if (LinqTestsCommon.IsAnonymousType(firstElem.GetType()))
|
||||
{
|
||||
resultMatched &= CompareListOfAnonymousType(queryResultsList, dataResultsList);
|
||||
resultMatched &= CompareListOfAnonymousType(queryResultsList, dataResultsList, ignoreOrder);
|
||||
}
|
||||
else if (LinqTestsCommon.IsNumber(firstElem))
|
||||
{
|
||||
|
@ -548,7 +577,7 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests
|
|||
// we skip unordered query because the LINQ results vs actual query results are non-deterministic
|
||||
if (!input.skipVerification)
|
||||
{
|
||||
LinqTestsCommon.ValidateResults(queryResults, dataResults);
|
||||
LinqTestsCommon.ValidateResults(queryResults, dataResults, input.ignoreOrder);
|
||||
}
|
||||
|
||||
string serializedResults = serializeResultsInBaseline ?
|
||||
|
@ -646,17 +675,22 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests
|
|||
// - unordered query since the results are not deterministics for LinQ results and actual query results
|
||||
// - scenarios not supported in LINQ, e.g. sequence doesn't contain element.
|
||||
internal bool skipVerification;
|
||||
|
||||
// Ignore Ordering for AnonymousType object
|
||||
internal readonly bool ignoreOrder;
|
||||
|
||||
internal LinqTestInput(
|
||||
string description,
|
||||
Expression<Func<bool, IQueryable>> expr,
|
||||
bool skipVerification = false,
|
||||
bool skipVerification = false,
|
||||
bool ignoreOrderingForAnonymousTypeObject = false,
|
||||
string expressionStr = null,
|
||||
string inputData = null)
|
||||
: base(description)
|
||||
{
|
||||
this.Expression = expr ?? throw new ArgumentNullException($"{nameof(expr)} must not be null.");
|
||||
this.skipVerification = skipVerification;
|
||||
this.skipVerification = skipVerification;
|
||||
this.ignoreOrder = ignoreOrderingForAnonymousTypeObject;
|
||||
this.expressionStr = expressionStr;
|
||||
this.inputData = inputData;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче