Short hand version for order_by (#3643)

Implements https://www.pivotaltracker.com/story/show/182868310
This commit is contained in:
Radosław Waśko 2022-08-16 17:41:37 +02:00 committed by GitHub
parent 146297a0a0
commit fbf6c800f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 45 deletions

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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 =

View File

@ -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

View File

@ -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]

View File

@ -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