diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f1318173b..9285d3fb58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -176,6 +176,7 @@ `Text.drop`.][3617] - [Updated `Vector.take` and `Vector.drop` and removed their obsolete counterparts.][3629] +- [Short-hand syntax for `order_by` added.][3643] [debug-shortcuts]: https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug @@ -276,6 +277,7 @@ [3601]: https://github.com/enso-org/enso/pull/3601 [3617]: https://github.com/enso-org/enso/pull/3617 [3629]: https://github.com/enso-org/enso/pull/3629 +[3643]: https://github.com/enso-org/enso/pull/3643 [3648]: https://github.com/enso-org/enso/pull/3648 #### Enso Compiler diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso index 4096b1849d..ab50d7b093 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso @@ -472,21 +472,10 @@ type Table Missing (`Nothing`) values are sorted as less than any other object. - > Example - Order the table by the column "alpha" in ascending order. - - table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "alpha"]) - - > Example - Order the table by the second column in ascending order. In case of any - ties, break them based on the 7th column from the end of the table in - descending order. - - table.order_by (Sort_Column_Selector.By_Index [Sort_Column.Index 1, Sort_Column.Index -7 Sort_Direction.Descending]) > Example Sorting `table` in ascending order by the value in column `'Quantity'`. - table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'Quantity']) + table.order_by (Sort_Column_Selector.By_Name ['Quantity']) > Example Sorting `table` in descending order by the value in column `'Quantity'`. @@ -497,7 +486,7 @@ type Table Sorting `table` in ascending order by the value in column `'Quantity'`, using the value in column `'Rating'` for breaking ties. - table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'Quantity', Sort_Column.Name 'Rating']) + table.order_by (Sort_Column_Selector.By_Name ['Quantity', 'Rating']) > Example Sorting `table` in ascending order by the value in column `'Quantity'`, @@ -505,6 +494,12 @@ type Table ties. table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'Quantity', Sort_Column.Name 'Rating' Sort_Direction.Descending]) + > Example + Order the table by the second column in ascending order. In case of any + ties, break them based on the 7th column from the end of the table in + descending order. + + table.order_by (Sort_Column_Selector.By_Index [1, Sort_Column.Index -7 Sort_Direction.Descending]) order_by : Sort_Column_Selector -> Text_Ordering -> Problem_Behavior -> Table order_by self (columns = (Sort_Column_Selector.By_Name [(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering on_problems=Report_Warning = Panic.handle_wrapped_dataflow_error <| problem_builder = Problem_Builder.new diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Sort_Column_Selector.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Sort_Column_Selector.enso index 37ac646764..eb7da65280 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Sort_Column_Selector.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Sort_Column_Selector.enso @@ -3,6 +3,6 @@ from Standard.Base import all import Standard.Table.Data.Sort_Column type Sort_Column_Selector - type By_Name (columns : Vector Sort_Column.Name) (matcher:Matcher=Text_Matcher) - type By_Index (columns : Vector Sort_Column.Index) - type By_Column (columns : Vector Sort_Column.Column) + type By_Name (columns : Vector (Sort_Column.Name | Text)) (matcher:Matcher=Text_Matcher) + type By_Index (columns : Vector (Sort_Column.Index | Integer)) + type By_Column (columns : Vector (Sort_Column.Column | Column)) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso index 52e9581793..6444c90482 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso @@ -560,23 +560,42 @@ type Table `Incomparable_Values_Error`. > Example - Order the table by the column "alpha" in ascending order. + Sorting `table` in ascending order by the value in column `'Quantity'`. - table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "alpha"]) + table.order_by (Sort_Column_Selector.By_Name ['Quantity']) + + > Example + Sorting `table` in descending order by the value in column `'Quantity'`. + + table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'Quantity' Sort_Direction.Descending]) + + > Example + Sorting `table` in ascending order by the value in column `'Quantity'`, + using the value in column `'Rating'` for breaking ties. + + table.order_by (Sort_Column_Selector.By_Name ['Quantity', 'Rating']) + + > Example + Sorting `table` in ascending order by the value in column `'Quantity'`, + using the value in column `'Rating'` in descending order for breaking + ties. + + table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'Quantity', Sort_Column.Name 'Rating' Sort_Direction.Descending]) > Example Order the table by the second column in ascending order. In case of any ties, break them based on the 7th column from the end of the table in descending order. - table.order_by (Sort_Column_Selector.By_Index [Sort_Column.Index 1, Sort_Column.Index -7 Sort_Direction.Descending]) + table.order_by (Sort_Column_Selector.By_Index [1, Sort_Column.Index -7 Sort_Direction.Descending]) + > Example Sorting the shop inventory based on the per-item price in ascending order. import Standard.Examples - example_sort = Examples.inventory_table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "price"]) + example_sort = Examples.inventory_table.order_by (Sort_Column_Selector.By_Name ["price"]) > Example Sort the shop inventory based on the per-item price in descending order @@ -606,7 +625,7 @@ type Table example_sort = table = Examples.inventory_table - table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "total_stock", Sort_Column.Name "sold_stock" Sort_Direction.Descending]) + table.order_by (Sort_Column_Selector.By_Name ["total_stock", Sort_Column.Name "sold_stock" Sort_Direction.Descending]) order_by : Sort_Column_Selector -> Text_Ordering -> Problem_Behavior -> Table order_by self (columns = (Sort_Column_Selector.By_Name [(Sort_Column.Name (self.columns.at 0 . name))])) text_ordering=Text_Ordering on_problems=Report_Warning = diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso index b5378128ea..3da774e549 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso @@ -365,11 +365,23 @@ prepare_order_by : Vector -> Problem_Builder -> Vector Column_Transform_Element prepare_order_by internal_columns column_selectors problem_builder = selected_elements = case column_selectors of Sort_Column_Selector.By_Name name_selectors matcher -> - select_columns_by_name internal_columns name_selectors matcher problem_builder name_extractor=(_.name) + unified_name_selectors = name_selectors.map selector-> case selector of + Text -> Sort_Column.Name selector + Sort_Column.Name _ _ -> selector + select_columns_by_name internal_columns unified_name_selectors matcher problem_builder name_extractor=(_.name) Sort_Column_Selector.By_Index index_selectors -> - select_columns_by_index internal_columns index_selectors problem_builder index_extractor=(_.index) + unified_index_selectors = index_selectors.map selector-> case selector of + Integer -> Sort_Column.Index selector + Sort_Column.Index _ _ -> selector + select_columns_by_index internal_columns unified_index_selectors problem_builder index_extractor=(_.index) Sort_Column_Selector.By_Column column_selectors -> - select_columns_by_column_reference internal_columns column_selectors problem_builder column_extractor=(_.column) + unified_column_selectors = column_selectors.map selector-> case selector of + Sort_Column.Column _ _ -> selector + ## We cannot match by type here, as there is no common `Column` + type - the type is different for In-Memory and Database + tables, and we do not have interfaces yet. + column_reference -> Sort_Column.Column column_reference + select_columns_by_column_reference internal_columns unified_column_selectors problem_builder column_extractor=(_.column) if selected_elements.is_empty then problem_builder.report_other_warning No_Input_Columns_Selected selected_elements diff --git a/test/Table_Tests/src/Common_Table_Spec.enso b/test/Table_Tests/src/Common_Table_Spec.enso index 4c602ff119..89cd1d8f8a 100644 --- a/test/Table_Tests/src/Common_Table_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Spec.enso @@ -544,11 +544,11 @@ spec prefix table_builder test_selection pending=Nothing = table_builder [col1, col2, col3, col4, col5, col6, col7, col8, col9, col10] Test.specify "should work as shown in the doc examples" <| - t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "alpha"]) + t1 = table.order_by (Sort_Column_Selector.By_Name ["alpha"]) t1.at "alpha" . to_vector . should_equal [0, 1, 2, 3] t1.at "gamma" . to_vector . should_equal [4, 3, 2, 1] - t2 = table.order_by (Sort_Column_Selector.By_Index [Sort_Column.Index 1, Sort_Column.Index -8 Sort_Direction.Descending]) + t2 = table.order_by (Sort_Column_Selector.By_Index [1, Sort_Column.Index -8 Sort_Direction.Descending]) t2.at "beta" . to_vector . should_equal ["a", "a", "b", "b"] t2.at "gamma" . to_vector . should_equal [3, 1, 4, 2] t2.at "alpha" . to_vector . should_equal [1, 3, 0, 2] @@ -560,7 +560,7 @@ spec prefix table_builder test_selection pending=Nothing = t1.at "gamma" . to_vector . should_equal [2, 4, 3, 1] Test.specify "should correctly handle problems: out of bounds indices" <| - selector = Sort_Column_Selector.By_Index [Sort_Column.Index 0, Sort_Column.Index 100, Sort_Column.Index -200, Sort_Column.Index 300] + selector = Sort_Column_Selector.By_Index [0, 100, Sort_Column.Index -200, Sort_Column.Index 300] action = table.order_by selector on_problems=_ tester table = table.at "alpha" . to_vector . should_equal [0, 1, 2, 3] @@ -569,7 +569,7 @@ spec prefix table_builder test_selection pending=Nothing = Problems.test_problem_handling action problems tester Test.specify "should correctly handle problems: duplicate indices" <| - selector = Sort_Column_Selector.By_Index [Sort_Column.Index 0, Sort_Column.Index 0, Sort_Column.Index 0 Sort_Direction.Descending] + selector = Sort_Column_Selector.By_Index [0, Sort_Column.Index 0, Sort_Column.Index 0 Sort_Direction.Descending] action = table.order_by selector on_problems=_ tester table = table.at "alpha" . to_vector . should_equal [0, 1, 2, 3] @@ -578,7 +578,7 @@ spec prefix table_builder test_selection pending=Nothing = Problems.test_problem_handling action problems tester Test.specify "should correctly handle problems: aliased indices" <| - selector = Sort_Column_Selector.By_Index [Sort_Column.Index 1, Sort_Column.Index -9 Sort_Direction.Descending, Sort_Column.Index -8 Sort_Direction.Descending, Sort_Column.Index 2 Sort_Direction.Ascending] + selector = Sort_Column_Selector.By_Index [1, Sort_Column.Index -9 Sort_Direction.Descending, Sort_Column.Index -8 Sort_Direction.Descending, Sort_Column.Index 2 Sort_Direction.Ascending] action = table.order_by selector on_problems=_ tester table = table.at "beta" . to_vector . should_equal ["a", "a", "b", "b"] @@ -588,7 +588,7 @@ spec prefix table_builder test_selection pending=Nothing = Problems.test_problem_handling action problems tester Test.specify "should correctly handle problems: duplicate names" <| - selector = Sort_Column_Selector.By_Name [Sort_Column.Name "alpha", Sort_Column.Name "alpha" Sort_Direction.Descending] + selector = Sort_Column_Selector.By_Name ["alpha", Sort_Column.Name "alpha" Sort_Direction.Descending] action = table.order_by selector on_problems=_ tester table = table.at "alpha" . to_vector . should_equal [0, 1, 2, 3] @@ -607,7 +607,7 @@ spec prefix table_builder test_selection pending=Nothing = Test.specify "should correctly handle problems: unmatched names" <| weird_name = '.*?-!@#!"' - selector = Sort_Column_Selector.By_Name [Sort_Column.Name "alpha", Sort_Column.Name "hmm", Sort_Column.Name weird_name] + selector = Sort_Column_Selector.By_Name [Sort_Column.Name "alpha", "hmm", Sort_Column.Name weird_name] action = table.order_by selector on_problems=_ tester table = table.at "alpha" . to_vector . should_equal [0, 1, 2, 3] @@ -621,7 +621,7 @@ spec prefix table_builder test_selection pending=Nothing = weird_column = table_2.at "weird_column" bar = table.at "beta" - selector = Sort_Column_Selector.By_Column [Sort_Column.Column bar, Sort_Column.Column weird_column, Sort_Column.Column foo] + selector = Sort_Column_Selector.By_Column [bar, weird_column, Sort_Column.Column foo] problem = table.order_by selector on_problems=Problem_Behavior.Report_Error . catch problem.should_be_a Missing_Input_Columns problem.criteria.map (selector-> selector.column.name) . should_equal ["weird_column"] @@ -653,12 +653,12 @@ spec prefix table_builder test_selection pending=Nothing = t3.at "beta" . to_vector . should_equal ["a", "a", "b", "b"] t3.at "alpha" . to_vector . should_equal [1, 3, 0, 2] - t4 = t2.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "beta"]) + t4 = t2.order_by (Sort_Column_Selector.By_Name ["beta"]) t4.at "beta" . to_vector . should_equal ["a", "a", "b", "b"] t4.at "alpha" . to_vector . should_equal [3, 1, 2, 0] Test.specify "should give priority to the first selected column and use the next ones for breaking ties" <| - t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "beta", Sort_Column.Name "alpha" Sort_Direction.Ascending]) + t1 = table.order_by (Sort_Column_Selector.By_Name ["beta", Sort_Column.Name "alpha" Sort_Direction.Ascending]) t1.at "beta" . to_vector . should_equal ["a", "a", "b", "b"] t1.at "alpha" . to_vector . should_equal [1, 3, 0, 2] t1.at "gamma" . to_vector . should_equal [3, 1, 4, 2] @@ -673,23 +673,23 @@ spec prefix table_builder test_selection pending=Nothing = t3.at "beta" . to_vector . should_equal ["b", "a", "b", "a"] t3.at "gamma" . to_vector . should_equal [4, 3, 2, 1] - t4 = table.order_by (Sort_Column_Selector.By_Index [Sort_Column.Index 1, Sort_Column.Index 0 Sort_Direction.Ascending]) + t4 = table.order_by (Sort_Column_Selector.By_Index [1, Sort_Column.Index 0 Sort_Direction.Ascending]) t4.at "beta" . to_vector . should_equal ["a", "a", "b", "b"] t4.at "alpha" . to_vector . should_equal [1, 3, 0, 2] t4.at "gamma" . to_vector . should_equal [3, 1, 4, 2] - t5 = table.order_by (Sort_Column_Selector.By_Column [Sort_Column.Column (table.at "beta"), Sort_Column.Column (table.at "alpha") Sort_Direction.Ascending]) + t5 = table.order_by (Sort_Column_Selector.By_Column [table.at "beta", Sort_Column.Column (table.at "alpha") Sort_Direction.Ascending]) t5.at "beta" . to_vector . should_equal ["a", "a", "b", "b"] t5.at "alpha" . to_vector . should_equal [1, 3, 0, 2] t5.at "gamma" . to_vector . should_equal [3, 1, 4, 2] Test.specify "should deal with real numbers" <| - t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "tau"]) + t1 = table.order_by (Sort_Column_Selector.By_Name ["tau"]) t1.at "tau" . to_vector . should_equal [-0.1, 0.5, 1.6, 32.0] t1.at "alpha" . to_vector . should_equal [1, 2, 0, 3] Test.specify "should deal with nulls" <| - t1 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "xi"]) + t1 = table.order_by (Sort_Column_Selector.By_Name ["xi"]) t1.at "xi" . to_vector . should_equal [Nothing, 0.5, 1.0, 1.5] t1.at "alpha" . to_vector . should_equal [1, 0, 3, 2] @@ -714,7 +714,7 @@ spec prefix table_builder test_selection pending=Nothing = t1.at "delta" . to_vector . should_equal ["a1", "a2", "a03", "a10"] t1.at "alpha" . to_vector . should_equal [2, 1, 0, 3] - t2 = table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "delta"]) text_ordering=(Text_Ordering sort_digits_as_numbers=False) + t2 = table.order_by (Sort_Column_Selector.By_Name ["delta"]) text_ordering=(Text_Ordering sort_digits_as_numbers=False) t2.at "delta" . to_vector . should_equal ["a03", "a1", "a10", "a2"] t2.at "alpha" . to_vector . should_equal [0, 2, 3, 1] diff --git a/test/Table_Tests/src/Table_Spec.enso b/test/Table_Tests/src/Table_Spec.enso index e42f8ea47b..e9ddacbd8e 100644 --- a/test/Table_Tests/src/Table_Spec.enso +++ b/test/Table_Tests/src/Table_Spec.enso @@ -335,32 +335,32 @@ spec = df = (enso_project.data / "clothes.csv").read Test.specify "should allow sorting by a single column name" <| - r_1 = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "Quantity"]) + r_1 = df.order_by (Sort_Column_Selector.By_Name ["Quantity"]) r_1.at 'Id' . to_vector . should_equal [2,4,1,3,5,6] r_3 = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "Rating" Sort_Direction.Descending]) r_3.at 'Id' . to_vector . should_equal [3,1,4,5,2,6] Test.specify 'should allow sorting by multiple column names' <| - r_1 = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'Quantity', Sort_Column.Name 'Rating']) + r_1 = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'Quantity', 'Rating']) r_1.at 'Id' . to_vector . should_equal [2,4,1,3,6,5] r_2 = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'Rating' Sort_Direction.Descending, Sort_Column.Name 'Quantity' Sort_Direction.Descending]) r_2.at 'Id' . to_vector . should_equal [3,1,4,5,6,2] Test.specify 'should allow sorting with specific by-column rules' <| - r_1 = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "Quantity", Sort_Column.Name "Price" Sort_Direction.Descending]) + r_1 = df.order_by (Sort_Column_Selector.By_Name ["Quantity", Sort_Column.Name "Price" Sort_Direction.Descending]) r_1.at 'Id' . to_vector . should_equal [4,2,3,1,6,5] Test.specify 'should respect defined comparison operations for custom types' <| c_1 = ['id', [1, 2, 3, 4, 5, 6]] c_2 = ['val', [My 1 2, My 3 4, My 2 1, My 5 2, My 7 0, My 4 -1]] df = Table.new [c_1, c_2] - r = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'val']) + r = df.order_by (Sort_Column_Selector.By_Name ['val']) r.at 'id' . to_vector . should_equal [1,3,6,2,4,5] Test.specify 'should return warnings and errors when passed a non-existent column' <| - action = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'foobar']) on_problems=_ + action = df.order_by (Sort_Column_Selector.By_Name ['foobar']) on_problems=_ tester table = table.at 'Id' . to_vector . should_equal [1,2,3,4,5,6] problems = [Missing_Input_Columns [Sort_Column.Name 'foobar'], No_Input_Columns_Selected] @@ -375,7 +375,7 @@ spec = objs = [Cons 1 2, Cons 2 3, Cons 6 7, Cons 8 9, Cons 10 30] df = Table.new [['ord', ord], ['ints', ints], ['reals', reals], ['bools', bools], ['texts', texts], ['objs', objs]] - r = df.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name 'ord']) + r = df.order_by (Sort_Column_Selector.By_Name ['ord']) r.at 'ints' . to_vector . should_equal [1, 5, 3, 2, 4] df.at 'ints' . to_vector . should_equal ints