diff --git a/langlib/lang.query/build.gradle b/langlib/lang.query/build.gradle index adddb2be59c2..083f217848c6 100644 --- a/langlib/lang.query/build.gradle +++ b/langlib/lang.query/build.gradle @@ -33,6 +33,7 @@ dependencies { distributionBala project(path: ':ballerina-lang:table', configuration: 'distributionBala') distributionBala project(path: ':ballerina-lang:stream', configuration: 'distributionBala') distributionBala project(path: ':ballerina-lang:error', configuration: 'distributionBala') + distributionBala project(path: ':ballerina-lang:function', configuration: 'distributionBala') distributionBala project(path: ':ballerina-lang:jballerina.java', configuration: 'distributionBala') distributionBala project(path: ':ballerina-lang:object', configuration: 'distributionBala') diff --git a/langlib/lang.query/src/main/ballerina/types.bal b/langlib/lang.query/src/main/ballerina/types.bal index 71b3fc8fb376..980f0f8efd10 100644 --- a/langlib/lang.query/src/main/ballerina/types.bal +++ b/langlib/lang.query/src/main/ballerina/types.bal @@ -22,6 +22,7 @@ import ballerina/lang.'xml as lang_xml; import ballerina/lang.'stream as lang_stream; import ballerina/lang.'table as lang_table; import ballerina/lang.'object as lang_object; +import ballerina/lang.'function; # A type parameter that is a subtype of `any|error`. # Has the special semantic that when used in a declaration @@ -1053,39 +1054,14 @@ class _OrderTreeNode { return orderedFrames; } - # sorting is not supported for any[], therefore have to resolve runtime type and sort it. + # sorting is not supported for any[], thus use the `function:call` method call the sort operation. # + return - ordered array. function getSortedArray(any[] arr) returns any[] { - if (arr.length() > 0) { - int i = 0; - while (i < arr.length()) { - if (arr[i] is ()) { - i += 1; - continue; - } else if (arr[i] is boolean) { - boolean?[] res = []; - self.copyArray(arr, res); - return res.sort(self.nodesDirection, (v) => v); - } else if (arr[i] is int) { - int?[] res = []; - self.copyArray(arr, res); - return res.sort(self.nodesDirection, (v) => v); - } else if (arr[i] is float) { - float?[] res = []; - self.copyArray(arr, res); - return res.sort(self.nodesDirection, (v) => v); - } else if (arr[i] is decimal) { - decimal?[] res = []; - self.copyArray(arr, res); - return res.sort(self.nodesDirection, (v) => v); - } else if (arr[i] is string) { - string?[] res = []; - self.copyArray(arr, res); - return res.sort(self.nodesDirection, (v) => v); - } - } + any|error res = function:call(lang_array:sort, arr, self.nodesDirection); + if res is any[] { + return res; } - return arr; + panic error(string `Error while sorting the arr: ${arr.toBalString()}`); } # copy every element of source array into empty target array. diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/query/OrderByClauseTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/query/OrderByClauseTest.java index 59b4789c5199..448332adbbf7 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/query/OrderByClauseTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/query/OrderByClauseTest.java @@ -233,7 +233,6 @@ public void testQueryExprWithOrderByClauseReturnXML() { @Test(description = "Test negative scenarios for query expr with order by clause") public void testNegativeScenarios() { - Assert.assertEquals(negativeResult.getErrorCount(), 3); int index = 0; validateError(negativeResult, index++, "order by not supported for complex type fields, " + @@ -241,9 +240,21 @@ public void testNegativeScenarios() { 35, 18); validateError(negativeResult, index++, "undefined symbol 'address'", 35, 18); - validateError(negativeResult, index, "order by not supported for complex type fields, " + - "order key should belong to a basic type", + validateError(negativeResult, index++, + "order by not supported for complex type fields, order key should belong to a basic type", 47, 18); + validateError(negativeResult, index++, + "order by not supported for complex type fields, order key should belong to a basic type", + 55, 18); + validateError(negativeResult, index++, + "order by not supported for complex type fields, order key should belong to a basic type", + 61, 18); + Assert.assertEquals(negativeResult.getErrorCount(), index); + } + + @Test + public void testQueryExprWithOrderByClauseWithArrayKey() { + BRunUtil.invoke(result, "testQueryExprWithOrderByClauseWithArrayKey"); } @AfterClass diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/query/order-by-clause-negative.bal b/tests/jballerina-unit-test/src/test/resources/test-src/query/order-by-clause-negative.bal index a0aaab3baa7d..eeddb57c8ea4 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/query/order-by-clause-negative.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/query/order-by-clause-negative.bal @@ -47,3 +47,17 @@ function testOrderByClauseWithComplexTypeFieldInOrderBy() { order by customer.address select customer; } + +function testOrderByClauseWithArrayTypeFieldInOrderBy() { + record {|(int|boolean)[] t; string s;|}[] data1 = []; + + _ = from var rec in data1 + order by rec.t descending + select rec.s; + + record {|int k; [decimal|float, int] arr;|}[] data2 = []; + + _ = from var rec in data2 + order by rec.arr + select rec.k; +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/query/order-by-clause.bal b/tests/jballerina-unit-test/src/test/resources/test-src/query/order-by-clause.bal index 7913b3e5e775..f1edb6added6 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/query/order-by-clause.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/query/order-by-clause.bal @@ -502,3 +502,117 @@ function incrementCount(int i) returns int { int count = i + 2; return count; } + +enum Color { + RED, + GREEN, + BLUE +} + +function testQueryExprWithOrderByClauseWithArrayKey() { + record {|int[] t; string s;|}[] data1 = [ + {s: "s5", t: [5, 2]}, + {s: "s1", t: [1, 1, 3, 4]}, + {s: "s0", t: [0]}, + {s: "s4", t: [4]} + ]; + + string[] q1 = from var rec in data1 + order by rec.t descending + select rec.s; + assertEquality(["s5", "s4", "s1", "s0"], q1); + + record {|int k; [decimal, int] arr;|}[] data2 = [ + {k: 1, arr: [3.2, 1]}, + {k: 2, arr: [212.21, 3]}, + {k: 3, arr: [0.2, 4]}, + {k: 4, arr: [-1.2, 10]} + ]; + + int[] q2 = from var rec in data2 + order by rec.arr descending + select rec.k; + assertEquality([2, 1, 3, 4], q2); + + record {|int k; [boolean, string, int] arr;|}[] data3 = [ + {k: 1, arr: [true, "abcd", 1]}, + {k: 2, arr: [false, "efgh", 9]}, + {k: 3, arr: [false, "abcd", 10]}, + {k: 4, arr: [true, "ijkl", -5]} + ]; + + int[] q3 = from var rec in data3 + order by rec.arr + select rec.k; + assertEquality([3, 2, 1, 4], q3); + + record {|int k; [float...] arr;|}[] data4 = [ + {k: 1, arr: [1.2, 3.1, 5.6, 9.2]}, + {k: 2, arr: []}, + {k: 3, arr: [-0.7, 0.8, 1.45]}, + {k: 4, arr: [1, 2]} + ]; + + int[] q4 = from var rec in data4 + order by rec.arr + select rec.k; + assertEquality([2, 3, 4, 1], q4); + + record {|int k; [float...] arr1; [string, string...] arr2;|}[] data5 = [ + {k: 1, arr1: [1.2, 3.1, 5.6, 9.2], arr2: ["s1", "s2"]}, + {k: 2, arr1: [], arr2: ["s10", "s9"]}, + {k: 3, arr1: [], arr2: ["s1", "s2"]}, + {k: 4, arr1: [], arr2: ["s1", "s2"]}, + {k: 5, arr1: [1, 2], arr2: ["s24", "s2"]} + ]; + + int[] q5 = from var rec in data5 + order by rec.arr1 descending, rec.arr2 ascending + select rec.k; + assertEquality([1, 5, 3, 4, 2], q5); + + record {|int k; float?[]? arr1;|}[] data6 = [ + {k: 1, arr1: [1.2, 3.1, 5.6, 9.2]}, + {k: 2, arr1: [1.2, 3.1, 5.6, ()]}, + {k: 3, arr1: [(), (), ()]}, + {k: 4, arr1: ()}, + {k: 5, arr1: [1, 2]} + ]; + + int[] q6 = from var rec in data6 + order by rec.arr1 descending + select rec.k; + assertEquality([1, 2, 5, 3, 4], q6); + + record {|int k; [int?, string?, decimal?...] arr1;|}[] data7 = [ + {k: 1, arr1: [1, "a", 9.2]}, + {k: 2, arr1: [1, (), ()]}, + {k: 3, arr1: [(), (), 4.2]}, + {k: 4, arr1: [2, "b"]}, + {k: 5, arr1: [2, (), 2.3]} + ]; + + int[] q7 = from var rec in data7 + order by rec.arr1 descending + select rec.k; + assertEquality([4, 5, 1, 2, 3], q7); + + record {|int k; Color[] arr1;|}[] data8 = [ + {k: 1, arr1: [RED]}, + {k: 2, arr1: [RED, GREEN]}, + {k: 3, arr1: [GREEN, BLUE, RED]}, + {k: 4, arr1: [BLUE, RED]}, + {k: 5, arr1: [BLUE, BLUE]} + ]; + + int[] q8 = from var rec in data8 + order by rec.arr1 descending + select rec.k; + assertEquality([2, 1, 3, 4, 5], q8); +} + +function assertEquality(anydata expected, anydata actual) { + if expected != actual { + panic error(string `Expected ${expected.toBalString()}, found ${actual.toBalString()}`); + } +}