Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Internal] Query: Adds Support for ORDER BY RANK in SQL DOM #5052

Merged
Merged
Prev Previous commit
Next Next commit
update dom
Minh Le committed Mar 7, 2025
commit 5d9e380a314a5bbbf59f48d07b529ce3332ad6be
55 changes: 47 additions & 8 deletions Microsoft.Azure.Cosmos/src/Query/Core/Parser/CstToAstVisitor.cs
Original file line number Diff line number Diff line change
@@ -355,15 +355,29 @@ public override SqlObject VisitGroup_by_clause([NotNull] sqlParser.Group_by_clau
public override SqlObject VisitOrder_by_clause([NotNull] sqlParser.Order_by_clauseContext context)
{
Contract.Requires(context != null);

List<SqlOrderByItem> orderByItems = new List<SqlOrderByItem>();
foreach (sqlParser.Order_by_itemContext orderByItemContext in context.order_by_items().order_by_item())
{
SqlOrderByItem orderByItem = (SqlOrderByItem)this.VisitOrder_by_item(orderByItemContext);
orderByItems.Add(orderByItem);

if (context.K_RANK != null)
{
List<SqlScoreExpressionOrderByItem> orderByItems = new List<SqlScoreExpressionOrderByItem>();
foreach (sqlParser.Score_expression_order_by_itemContext orderByItemContext in context.score_expression_order_by_items().score_expression_order_by_item())
{
SqlScoreExpressionOrderByItem orderByItem = (SqlScoreExpressionOrderByItem)this.VisitScore_expression_order_by_item(orderByItemContext);
orderByItems.Add(orderByItem);
}

return SqlOrderByClause.Create(orderByItems.ToImmutableArray());
}
else
{
List<SqlOrderByItem> orderByItems = new List<SqlOrderByItem>();
foreach (sqlParser.Order_by_itemContext orderByItemContext in context.order_by_items().order_by_item())
{
SqlOrderByItem orderByItem = (SqlOrderByItem)this.VisitOrder_by_item(orderByItemContext);
orderByItems.Add(orderByItem);
}

return SqlOrderByClause.Create(orderByItems.ToImmutableArray());
}

return SqlOrderByClause.Create(orderByItems.ToImmutableArray());
}

public override SqlObject VisitOrder_by_item([NotNull] sqlParser.Order_by_itemContext context)
@@ -389,6 +403,31 @@ public override SqlObject VisitOrder_by_item([NotNull] sqlParser.Order_by_itemCo
}

return SqlOrderByItem.Create(expression, isDescending);
}

public override SqlObject VisitScore_expression_order_by_item([NotNull] sqlParser.Score_expression_order_by_itemContext context)
{
Contract.Requires(context != null);

SqlFunctionCallScalarExpression expression = (SqlFunctionCallScalarExpression)this.Visit(context.function_call_scalar_expression());
bool isDescending = false;
if (context.sort_order() != null)
{
if (context.sort_order().K_ASC() != null)
{
isDescending = false;
}
else if (context.sort_order().K_DESC() != null)
{
isDescending = true;
}
else
{
throw new ArgumentOutOfRangeException($"Unknown sort order : {context.sort_order()}.");
}
}

return SqlScoreExpressionOrderByItem.Create(expression, isDescending);
}

#endregion
32 changes: 29 additions & 3 deletions Microsoft.Azure.Cosmos/src/SqlObjects/SqlOrderbyClause.cs
Original file line number Diff line number Diff line change
@@ -22,21 +22,47 @@ private SqlOrderByClause(ImmutableArray<SqlOrderByItem> orderByItems)
{
if (sqlOrderbyItem == null)
{
throw new ArgumentException($"{nameof(sqlOrderbyItem)} must have have null items.");
throw new ArgumentException($"{nameof(sqlOrderbyItem)} must not have null items.");
}
}

this.OrderByItems = orderByItems;
this.OrderByItems = orderByItems;
this.Rank = false;
}

private SqlOrderByClause(ImmutableArray<SqlScoreExpressionOrderByItem> scoreExpressionOrderByItems)
{
foreach (SqlScoreExpressionOrderByItem sqlOrderbyItem in scoreExpressionOrderByItems)
{
if (sqlOrderbyItem == null)
{
throw new ArgumentException($"{nameof(sqlOrderbyItem)} must not have null items.");
}
}

this.Rank = true;
}

public ImmutableArray<SqlOrderByItem> OrderByItems { get; }
public ImmutableArray<SqlOrderByItem> OrderByItems { get; }
public ImmutableArray<SqlScoreExpressionOrderByItem> ScoreExpressionOrderByItems { get; }
public bool Rank { get; }

public static SqlOrderByClause Create(params SqlOrderByItem[] orderByItems)
{
return new SqlOrderByClause(orderByItems.ToImmutableArray());
}

public static SqlOrderByClause Create(ImmutableArray<SqlOrderByItem> orderByItems)
{
return new SqlOrderByClause(orderByItems);
}

public static SqlOrderByClause Create(params SqlScoreExpressionOrderByItem[] orderByItems)
{
return new SqlOrderByClause(orderByItems.ToImmutableArray());
}

public static SqlOrderByClause Create(ImmutableArray<SqlScoreExpressionOrderByItem> orderByItems)
{
return new SqlOrderByClause(orderByItems);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos.SqlObjects
{
using System;
using Microsoft.Azure.Cosmos.SqlObjects.Visitors;

#if INTERNAL
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
#pragma warning disable SA1600 // Elements should be documented
public
#else
internal
#endif
sealed class SqlScoreExpressionOrderByItem : SqlObject
{
private SqlScoreExpressionOrderByItem(
SqlFunctionCallScalarExpression expression,
bool isDescending)
{
this.Expression = expression ?? throw new ArgumentNullException(nameof(expression));
this.IsDescending = isDescending;
}

public SqlFunctionCallScalarExpression Expression { get; }

public bool IsDescending { get; }

public static SqlScoreExpressionOrderByItem Create(
SqlFunctionCallScalarExpression expression,
bool isDescending)
{
return new SqlScoreExpressionOrderByItem(expression, isDescending);
}

public override void Accept(SqlObjectVisitor visitor)
{
visitor.Visit(this);
}

public override TResult Accept<TResult>(SqlObjectVisitor<TResult> visitor)
{
return visitor.Visit(this);
}

public override TResult Accept<T, TResult>(SqlObjectVisitor<T, TResult> visitor, T input)
{
return visitor.Visit(this, input);
}
}
}
Original file line number Diff line number Diff line change
@@ -612,10 +612,25 @@ public override bool Visit(SqlOrderByClause first, SqlObject secondAsObject)
{
return false;
}

if (!SequenceEquals(first.OrderByItems, second.OrderByItems))
{
return false;

if (first.Rank != second.Rank)
{
return false;
}

if (first.Rank)
{
if (!SequenceEquals(first.ScoreExpressionOrderByItems, second.ScoreExpressionOrderByItems))
{
return false;
}
}
else
{
if (!SequenceEquals(first.OrderByItems, second.OrderByItems))
{
return false;
}
}

return true;
@@ -755,6 +770,26 @@ public override bool Visit(SqlQuery first, SqlObject secondAsObject)

return true;
}

public override bool Visit(SqlScoreExpressionOrderByItem first, SqlObject secondAsObject)
{
if (!(secondAsObject is SqlScoreExpressionOrderByItem second))
{
return false;
}

if (first.IsDescending != second.IsDescending)
{
return false;
}

if (!Equals(first.Expression, second.Expression))
{
return false;
}

return true;
}

public override bool Visit(SqlSelectClause first, SqlObject secondAsObject)
{
Original file line number Diff line number Diff line change
@@ -57,7 +57,10 @@ internal sealed class SqlObjectHasher : SqlObjectVisitor<int>
private const int SqlProgramHashCode = -492711050;
private const int SqlPropertyNameHashCode = 1262661966;
private const int SqlPropertyRefScalarExpressionHashCode = -1586896865;
private const int SqlQueryHashCode = 1968642960;
private const int SqlQueryHashCode = 1968642960;
private const int SqlScoreExpressionOrderbyItemHashCode = 46457293;
private const int SqlScoreExpressionOrderbyItemAscendingHashCode = -5155123;
private const int SqlScoreExpressionOrderbyItemDescendingHashCode = 10615937;
private const int SqlSelectClauseHashCode = 19731870;
private const int SqlSelectClauseDistinctHashCode = 1467616881;
private const int SqlSelectItemHashCode = -611151157;
@@ -419,11 +422,21 @@ public override int Visit(SqlOffsetSpec sqlObject)

public override int Visit(SqlOrderByClause sqlOrderByClause)
{
int hashCode = SqlOrderbyClauseHashCode;
for (int i = 0; i < sqlOrderByClause.OrderByItems.Length; i++)
{
hashCode = CombineHashes(hashCode, sqlOrderByClause.OrderByItems[i].Accept(this));
}
int hashCode = SqlOrderbyClauseHashCode;
if (sqlOrderByClause.Rank)
{
for (int i = 0; i < sqlOrderByClause.ScoreExpressionOrderByItems.Length; i++)
{
hashCode = CombineHashes(hashCode, sqlOrderByClause.ScoreExpressionOrderByItems[i].Accept(this));
}
}
else
{
for (int i = 0; i < sqlOrderByClause.OrderByItems.Length; i++)
{
hashCode = CombineHashes(hashCode, sqlOrderByClause.OrderByItems[i].Accept(this));
}
}

return hashCode;
}
@@ -515,7 +528,23 @@ public override int Visit(SqlQuery sqlQuery)
}

return hashCode;
}
}

public override int Visit(SqlScoreExpressionOrderByItem sqlOrderByItem)
{
int hashCode = SqlScoreExpressionOrderbyItemHashCode;
hashCode = CombineHashes(hashCode, sqlOrderByItem.Expression.Accept(this));
if (sqlOrderByItem.IsDescending)
{
hashCode = CombineHashes(hashCode, SqlScoreExpressionOrderbyItemDescendingHashCode);
}
else
{
hashCode = CombineHashes(hashCode, SqlScoreExpressionOrderbyItemAscendingHashCode);
}

return hashCode;
}

public override int Visit(SqlSelectClause sqlSelectClause)
{
Original file line number Diff line number Diff line change
@@ -276,14 +276,27 @@ public override SqlObject Visit(SqlOffsetSpec sqlObject)
}

public override SqlObject Visit(SqlOrderByClause sqlOrderByClause)
{
SqlOrderByItem[] items = new SqlOrderByItem[sqlOrderByClause.OrderByItems.Length];
for (int i = 0; i < sqlOrderByClause.OrderByItems.Length; i++)
{
items[i] = sqlOrderByClause.OrderByItems[i].Accept(this) as SqlOrderByItem;
{
if (sqlOrderByClause.Rank)
{
SqlScoreExpressionOrderByItem[] items = new SqlScoreExpressionOrderByItem[sqlOrderByClause.ScoreExpressionOrderByItems.Length];
for (int i = 0; i < sqlOrderByClause.ScoreExpressionOrderByItems.Length; i++)
{
items[i] = sqlOrderByClause.ScoreExpressionOrderByItems[i].Accept(this) as SqlScoreExpressionOrderByItem;
}

return SqlOrderByClause.Create(items);
}
else
{
SqlOrderByItem[] items = new SqlOrderByItem[sqlOrderByClause.OrderByItems.Length];
for (int i = 0; i < sqlOrderByClause.OrderByItems.Length; i++)
{
items[i] = sqlOrderByClause.OrderByItems[i].Accept(this) as SqlOrderByItem;
}

return SqlOrderByClause.Create(items);
}

return SqlOrderByClause.Create(items);
}

public override SqlObject Visit(SqlOrderByItem sqlOrderByItem)
@@ -337,6 +350,13 @@ public override SqlObject Visit(SqlQuery sqlQuery)
sqlQuery.GroupByClause?.Accept(this) as SqlGroupByClause,
sqlQuery.OrderByClause?.Accept(this) as SqlOrderByClause,
sqlQuery.OffsetLimitClause?.Accept(this) as SqlOffsetLimitClause);
}

public override SqlObject Visit(SqlScoreExpressionOrderByItem sqlScoreOrderByItem)
{
return SqlScoreExpressionOrderByItem.Create(
sqlScoreOrderByItem.Expression.Accept(this) as SqlFunctionCallScalarExpression,
sqlScoreOrderByItem.IsDescending);
}

public override SqlObject Visit(SqlSelectClause sqlSelectClause)
@@ -423,8 +443,8 @@ public override SqlObject Visit(SqlUndefinedLiteral sqlUndefinedLiteral)
public override SqlObject Visit(SqlWhereClause sqlWhereClause)
{
return SqlWhereClause.Create(sqlWhereClause.FilterExpression.Accept(this) as SqlScalarExpression);
}

}
private Number64 GetObfuscatedNumber(Number64 value)
{
Number64 obfuscatedNumber;
Original file line number Diff line number Diff line change
@@ -421,13 +421,19 @@ public override void Visit(SqlOffsetSpec sqlObject)

public override void Visit(SqlOrderByClause sqlOrderByClause)
{
this.writer.Write("ORDER BY ");
sqlOrderByClause.OrderByItems[0].Accept(this);
this.writer.Write("ORDER BY ");
if (sqlOrderByClause.Rank)
{
this.writer.Write("RANK ");
}

dynamic items = sqlOrderByClause.Rank ? sqlOrderByClause.ScoreExpressionOrderByItems : sqlOrderByClause.OrderByItems;
items[0].Accept(this);

for (int i = 1; i < sqlOrderByClause.OrderByItems.Length; i++)
for (int i = 1; i < items.Length; i++)
{
this.writer.Write(", ");
sqlOrderByClause.OrderByItems[i].Accept(this);
items[i].Accept(this);
}
}

@@ -512,6 +518,19 @@ public override void Visit(SqlQuery sqlQuery)
sqlQuery.OffsetLimitClause.Accept(this);
}
}

public override void Visit(SqlScoreExpressionOrderByItem sqlScoreExpressionOrderByItem)
{
sqlScoreExpressionOrderByItem.Expression.Accept(this);
if (sqlScoreExpressionOrderByItem.IsDescending)
{
this.writer.Write(" DESC");
}
else
{
this.writer.Write(" ASC");
}
}

public override void Visit(SqlSelectClause sqlSelectClause)
{
Original file line number Diff line number Diff line change
@@ -52,7 +52,8 @@ abstract class SqlObjectVisitor
public abstract void Visit(SqlProgram sqlObject);
public abstract void Visit(SqlPropertyName sqlObject);
public abstract void Visit(SqlPropertyRefScalarExpression sqlObject);
public abstract void Visit(SqlQuery sqlObject);
public abstract void Visit(SqlQuery sqlObject);
public abstract void Visit(SqlScoreExpressionOrderByItem sqlObject);
public abstract void Visit(SqlSelectClause sqlObject);
public abstract void Visit(SqlSelectItem sqlObject);
public abstract void Visit(SqlSelectListSpec sqlObject);
Original file line number Diff line number Diff line change
@@ -52,7 +52,8 @@ abstract class SqlObjectVisitor<TArg, TOutput>
public abstract TOutput Visit(SqlProgram sqlObject, TArg input);
public abstract TOutput Visit(SqlPropertyName sqlObject, TArg input);
public abstract TOutput Visit(SqlPropertyRefScalarExpression sqlObject, TArg input);
public abstract TOutput Visit(SqlQuery sqlObject, TArg input);
public abstract TOutput Visit(SqlQuery sqlObject, TArg input);
public abstract TOutput Visit(SqlScoreExpressionOrderByItem sqlObject, TArg input);
public abstract TOutput Visit(SqlSelectClause sqlObject, TArg input);
public abstract TOutput Visit(SqlSelectItem sqlObject, TArg input);
public abstract TOutput Visit(SqlSelectListSpec sqlObject, TArg input);
Original file line number Diff line number Diff line change
@@ -52,7 +52,8 @@ abstract class SqlObjectVisitor<TResult>
public abstract TResult Visit(SqlProgram sqlObject);
public abstract TResult Visit(SqlPropertyName sqlObject);
public abstract TResult Visit(SqlPropertyRefScalarExpression sqlObject);
public abstract TResult Visit(SqlQuery sqlObject);
public abstract TResult Visit(SqlQuery sqlObject);
public abstract TResult Visit(SqlScoreExpressionOrderByItem sqlObject);
public abstract TResult Visit(SqlSelectClause sqlObject);
public abstract TResult Visit(SqlSelectItem sqlObject);
public abstract TResult Visit(SqlSelectListSpec sqlObject);