diff --git a/docs/user/ppl/cmd/sort.rst b/docs/user/ppl/cmd/sort.rst index 2305d29673e..c9750bab079 100644 --- a/docs/user/ppl/cmd/sort.rst +++ b/docs/user/ppl/cmd/sort.rst @@ -16,13 +16,13 @@ Description Syntax ============ -sort [count] <[+|-] sort-field>... [desc|d] +sort [count] <[+|-] sort-field>... [asc|a|desc|d] -* count: optional. The number of results to return. **Default:** returns all results. Specifying a count of 0 or less than 0 also returns all results. +* count (Since 3.3): optional. The number of results to return. **Default:** returns all results. Specifying a count of 0 or less than 0 also returns all results. * [+|-]: optional. The plus [+] stands for ascending order and NULL/MISSING first and a minus [-] stands for descending order and NULL/MISSING last. **Default:** ascending order and NULL/MISSING first. * sort-field: mandatory. The field used to sort. Can use ``auto(field)``, ``str(field)``, ``ip(field)``, or ``num(field)`` to specify how to interpret field values. -* [desc|d]: optional. Reverses the sort results. If multiple fields are specified, reverses order of the first field then for all duplicate values of the first field, reverses the order of the values of the second field and so on. +* [asc|a|desc|d] (Since 3.3): optional. asc/a keeps the sort order as specified. desc/d reverses the sort results. If multiple fields are specified with desc/d, reverses order of the first field then for all duplicate values of the first field, reverses the order of the values of the second field and so on. **Default:** asc. Example 1: Sort by one field diff --git a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLSortIT.java b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLSortIT.java index 559bcaf8eab..1b090580d94 100644 --- a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLSortIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLSortIT.java @@ -234,4 +234,100 @@ public void testSortDate() throws IOException { rows("Virginia", "2018-08-19 00:00:00"), rows("Dale", "2018-11-13 23:33:20")); } + + @Test + public void testSortWithAscKeyword() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | sort account_number asc | fields account_number, firstname", + TEST_INDEX_BANK)); + verifySchema(result, schema("account_number", "bigint"), schema("firstname", "string")); + verifyDataRowsInOrder( + result, + rows(1, "Amber JOHnny"), + rows(6, "Hattie"), + rows(13, "Nanette"), + rows(18, "Dale"), + rows(20, "Elinor"), + rows(25, "Virginia"), + rows(32, "Dillard")); + } + + @Test + public void testSortWithAKeyword() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | sort account_number a | fields account_number, firstname", + TEST_INDEX_BANK)); + verifySchema(result, schema("account_number", "bigint"), schema("firstname", "string")); + verifyDataRowsInOrder( + result, + rows(1, "Amber JOHnny"), + rows(6, "Hattie"), + rows(13, "Nanette"), + rows(18, "Dale"), + rows(20, "Elinor"), + rows(25, "Virginia"), + rows(32, "Dillard")); + } + + @Test + public void testSortWithDescKeyword() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | sort account_number desc | fields account_number, firstname", + TEST_INDEX_BANK)); + verifySchema(result, schema("account_number", "bigint"), schema("firstname", "string")); + verifyDataRowsInOrder( + result, + rows(32, "Dillard"), + rows(25, "Virginia"), + rows(20, "Elinor"), + rows(18, "Dale"), + rows(13, "Nanette"), + rows(6, "Hattie"), + rows(1, "Amber JOHnny")); + } + + @Test + public void testSortWithCount() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | sort 3 account_number | fields account_number, firstname", + TEST_INDEX_BANK)); + verifySchema(result, schema("account_number", "bigint"), schema("firstname", "string")); + verifyDataRowsInOrder(result, rows(1, "Amber JOHnny"), rows(6, "Hattie"), rows(13, "Nanette")); + } + + @Test + public void testSortWithStrCast() throws IOException { + + JSONObject result = + executeQuery( + String.format( + "source=%s | sort STR(account_number) | fields account_number", TEST_INDEX_BANK)); + verifyDataRowsInOrder( + result, rows(1), rows(13), rows(18), rows(20), rows(25), rows(32), rows(6)); + } + + @Test + public void testSortWithAutoCast() throws IOException { + JSONObject result = + executeQuery( + String.format("source=%s | sort AUTO(age) | fields firstname, age", TEST_INDEX_BANK)); + verifySchema(result, schema("firstname", "string"), schema("age", "int")); + verifyDataRowsInOrder( + result, + rows("Nanette", 28), + rows("Amber JOHnny", 32), + rows("Dale", 33), + rows("Dillard", 34), + rows("Hattie", 36), + rows("Elinor", 36), + rows("Virginia", 39)); + } } diff --git a/integ-test/src/test/java/org/opensearch/sql/ppl/SortCommandIT.java b/integ-test/src/test/java/org/opensearch/sql/ppl/SortCommandIT.java index 682a0ab5c5c..be2cae9c843 100644 --- a/integ-test/src/test/java/org/opensearch/sql/ppl/SortCommandIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/ppl/SortCommandIT.java @@ -217,4 +217,40 @@ public void testSortWithNumCast() throws IOException { verifyOrder( result, rows("1234"), rows("3985"), rows("4085"), rows("4321"), rows("6245"), rows("9876")); } + + @Test + public void testSortWithAsc() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | sort account_number asc | fields account_number", TEST_INDEX_BANK)); + verifyOrder(result, rows(1), rows(6), rows(13), rows(18), rows(20), rows(25), rows(32)); + } + + @Test + public void testSortWithA() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | sort account_number a | fields account_number", TEST_INDEX_BANK)); + verifyOrder(result, rows(1), rows(6), rows(13), rows(18), rows(20), rows(25), rows(32)); + } + + @Test + public void testSortWithAscMultipleFields() throws IOException { + JSONObject result = + executeQuery( + String.format( + "source=%s | sort age, account_number asc | fields age, account_number", + TEST_INDEX_BANK)); + verifyOrder( + result, + rows(28, 13), + rows(32, 1), + rows(33, 18), + rows(34, 32), + rows(36, 6), + rows(36, 20), + rows(39, 25)); + } } diff --git a/ppl/src/main/antlr/OpenSearchPPLLexer.g4 b/ppl/src/main/antlr/OpenSearchPPLLexer.g4 index f0d8529767a..81b553bb445 100644 --- a/ppl/src/main/antlr/OpenSearchPPLLexer.g4 +++ b/ppl/src/main/antlr/OpenSearchPPLLexer.g4 @@ -70,6 +70,8 @@ AS: 'AS'; BY: 'BY'; SOURCE: 'SOURCE'; INDEX: 'INDEX'; +A: 'A'; +ASC: 'ASC'; D: 'D'; DESC: 'DESC'; DATASOURCES: 'DATASOURCES'; diff --git a/ppl/src/main/antlr/OpenSearchPPLParser.g4 b/ppl/src/main/antlr/OpenSearchPPLParser.g4 index f7aa477ddea..9c7845f8d55 100644 --- a/ppl/src/main/antlr/OpenSearchPPLParser.g4 +++ b/ppl/src/main/antlr/OpenSearchPPLParser.g4 @@ -158,7 +158,7 @@ dedupCommand ; sortCommand - : SORT (count = integerLiteral)? sortbyClause (DESC | D)? + : SORT (count = integerLiteral)? sortbyClause (ASC | A | DESC | D)? ; reverseCommand @@ -1201,6 +1201,8 @@ keywordsCanBeId | EXISTS | SOURCE | INDEX + | A + | ASC | DESC | DATASOURCES | FROM diff --git a/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstBuilderTest.java b/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstBuilderTest.java index aef2cb99dd2..207cc1e9959 100644 --- a/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstBuilderTest.java +++ b/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstBuilderTest.java @@ -503,6 +503,42 @@ public void testSortCommandWithMultipleFieldsAndDesc() { exprList(argument("asc", booleanLiteral(true)), argument("type", nullLiteral()))))); } + @Test + public void testSortCommandWithAsc() { + assertEqual( + "source=t | sort f1 asc", + sort( + relation("t"), + field( + "f1", + exprList(argument("asc", booleanLiteral(true)), argument("type", nullLiteral()))))); + } + + @Test + public void testSortCommandWithA() { + assertEqual( + "source=t | sort f1 a", + sort( + relation("t"), + field( + "f1", + exprList(argument("asc", booleanLiteral(true)), argument("type", nullLiteral()))))); + } + + @Test + public void testSortCommandWithMultipleFieldsAndAsc() { + assertEqual( + "source=t | sort f1, f2 asc", + sort( + relation("t"), + field( + "f1", + exprList(argument("asc", booleanLiteral(true)), argument("type", nullLiteral()))), + field( + "f2", + exprList(argument("asc", booleanLiteral(true)), argument("type", nullLiteral()))))); + } + @Test public void testEvalCommand() { assertEqual(