Skip to content

Commit

Permalink
Implement shorthand notation for order_by and adapt tests to verify it
Browse files Browse the repository at this point in the history
  • Loading branch information
radeusgd committed Aug 12, 2022
1 parent 3a6c558 commit 1a1dd3d
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -475,18 +475,18 @@ type Table
> Example
Order the table by the column "alpha" in ascending order.

table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "alpha"])
table.order_by (Sort_Column_Selector.By_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])
table.order_by (Sort_Column_Selector.By_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'`.
Expand All @@ -497,7 +497,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'`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
8 changes: 4 additions & 4 deletions distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso
Original file line number Diff line number Diff line change
Expand Up @@ -562,21 +562,21 @@ type Table
> Example
Order the table by the column "alpha" in ascending order.

table.order_by (Sort_Column_Selector.By_Name [Sort_Column.Name "alpha"])
table.order_by (Sort_Column_Selector.By_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])
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
Expand Down Expand Up @@ -606,7 +606,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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 15 additions & 15 deletions test/Table_Tests/src/Common_Table_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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"]
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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"]
Expand Down Expand Up @@ -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]
Expand All @@ -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]

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

Expand Down
12 changes: 6 additions & 6 deletions test/Table_Tests/src/Table_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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
Expand Down

0 comments on commit 1a1dd3d

Please sign in to comment.