Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjusting First and Last order_by to use Sort_Column_Selector #3517

Merged
merged 16 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
- [Implemented `Table.order_by` for the in-memory table.][3515]
- [Renamed `File_Format.Text` to `Plain_Text`, updated `File_Format.Delimited`
API and added builders for customizing less common settings.][3516]
- [Allow control of sort direction in `First` and `Last` aggregations.][3517]

[debug-shortcuts]:
https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug
Expand Down Expand Up @@ -215,6 +216,7 @@
[3514]: https://github.com/enso-org/enso/pull/3514
[3515]: https://github.com/enso-org/enso/pull/3515
[3516]: https://github.com/enso-org/enso/pull/3516
[3517]: https://github.com/enso-org/enso/pull/3517

#### Enso Compiler

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ type Sort_Direction
Sort_Direction.Descending
type Descending

## Convert into the sign of the direction
to_sign : Integer
to_sign = case this of
Ascending -> 1
Descending -> -1
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,12 @@ first_last_aggregators =
make_first_aggregator reverse ignore_null args =
if args.length < 2 then Error.throw (Illegal_State_Error "Insufficient number of arguments for the operation.") else
result_expr = args.head
order_exprs = args.tail
order_bys = args.tail

filter_clause = if ignore_null.not then Sql.code "" else
Sql.code " FILTER (WHERE " ++ result_expr.paren ++ Sql.code " IS NOT NULL)"
modified_order_exprs =
order_exprs.map expr-> expr ++ Sql.code " ASC NULLS FIRST"
order_clause =
Sql.code " ORDER BY " ++ Sql.join "," modified_order_exprs
Sql.code " ORDER BY " ++ Sql.join "," order_bys
index_expr = case reverse of
True -> if ignore_null.not then Sql.code "COUNT(*)" else
Sql.code "COUNT(" ++ result_expr ++ Sql.code ")"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from Standard.Base import all
from Standard.Base.Data.Text.Text_Ordering as Text_Ordering_Module import Text_Ordering

from Standard.Table.Data.Aggregate_Column import all
import Standard.Database.Data.Internal.IR
Expand All @@ -14,15 +15,15 @@ from Standard.Database.Error as Database_Errors import Unsupported_Database_Oper
make_aggregate_column : Table -> Aggregate_Column -> Text -> IR.Internal_Column
make_aggregate_column table aggregate new_name =
sql_type = table.connection.dialect.resolve_target_sql_type aggregate
expression = here.make_expression aggregate
expression = here.make_expression aggregate table.connection.dialect
IR.Internal_Column new_name sql_type expression

## PRIVATE
Creates an Internal Representation of the expression that computes a
requested statistic.
make_expression : Aggregate_Column -> IR.Expression
make_expression aggregate =
is_non_empty_vector v = if v.is_nothing then False else v.not_empty
make_expression : Aggregate_Column -> Dialect -> IR.Expression
make_expression aggregate dialect =
is_non_empty_selector v = if v.is_nothing then False else v.columns.not_empty
case aggregate of
Group_By c _ -> c.expression
Count _ -> IR.Operation "COUNT_ROWS" []
Expand All @@ -36,20 +37,20 @@ make_expression aggregate =
Count_Empty c _ -> IR.Operation "COUNT_EMPTY" [c.expression]
Percentile p c _ -> IR.Operation "PERCENTILE" [IR.Constant Sql_Type.double p, c.expression]
Mode c _ -> IR.Operation "MODE" [c.expression]
First c _ ignore_nothing order_by -> case is_non_empty_vector order_by of
First c _ ignore_nothing order_by -> case is_non_empty_selector order_by of
False -> Error.throw (Unsupported_Database_Operation_Error "`First` aggregation requires at least one `order_by` column.")
True ->
order_exprs = order_by.map .expression
order_bys = order_by.columns.map c-> dialect.prepare_order_descriptor c.column.as_internal c.direction Text_Ordering
case ignore_nothing of
False -> IR.Operation "FIRST" [c.expression]+order_exprs
True -> IR.Operation "FIRST_NOT_NULL" [c.expression]+order_exprs
Last c _ ignore_nothing order_by -> case is_non_empty_vector order_by of
False -> IR.Operation "FIRST" [c.expression]+order_bys
True -> IR.Operation "FIRST_NOT_NULL" [c.expression]+order_bys
Last c _ ignore_nothing order_by -> case is_non_empty_selector order_by of
False -> Error.throw (Unsupported_Database_Operation_Error "`Last` aggregation requires at least one `order_by` column.")
True ->
order_exprs = order_by.map .expression
order_bys = order_by.columns.map c-> dialect.prepare_order_descriptor c.column.as_internal c.direction Text_Ordering
case ignore_nothing of
False -> IR.Operation "LAST" [c.expression]+order_exprs
True -> IR.Operation "LAST_NOT_NULL" [c.expression]+order_exprs
False -> IR.Operation "LAST" [c.expression]+order_bys
True -> IR.Operation "LAST_NOT_NULL" [c.expression]+order_bys
Maximum c _ -> IR.Operation "MAX" [c.expression]
Minimum c _ -> IR.Operation "MIN" [c.expression]
Shortest c _ -> IR.Operation "SHORTEST" [c.expression]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ generate_expression dialect expr = case expr of
op = dialect.operation_map.get_or_else kind (Error.throw <| Unsupported_Database_Operation_Error kind)
parsed_args = arguments.map (here.generate_expression dialect)
op parsed_args
IR.Order_Descriptor _ _ _ _ -> here.generate_order dialect expr

## PRIVATE

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type Expression
- kind: the name of the operation, these can be both functions or infix
operators, the actual implementation is determined by a specific
dialect.
- expression: a list of expressions which are arguments to the operation;
- expressions: a list of expressions which are arguments to the operation
different operations support different amounts of arguments.
type Operation (kind : Text) (expressions : Vector Expression)

Expand Down Expand Up @@ -277,7 +277,6 @@ type Join_Kind
in the query can be used to filter the results.
type Join_Cross


## PRIVATE
type Order_Descriptor (expression : Expression) (direction : Sort_Direction) (nulls_order : Nothing | Nulls_Order = Nothing) (collation : Nothing | Text = Nothing)

Expand Down
25 changes: 14 additions & 11 deletions distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Standard.Table.Data.Column as Materialized_Column
import Standard.Table.Data.Table as Materialized_Table
import Standard.Table.Internal.Java_Exports
import Standard.Table.Internal.Table_Helpers
import Standard.Table.Internal.Problem_Builder

import Standard.Table.Data.Aggregate_Column
import Standard.Table.Internal.Aggregate_Column_Helper
Expand Down Expand Up @@ -480,17 +481,19 @@ type Table
table.order_by (Sort_Column_Selector.By_Index [Sort_Column.Index 1, Sort_Column.Index -7 Sort_Direction.Descending])
order_by : Sort_Column_Selector -> Text_Ordering -> Problem_Behavior -> Table
order_by (columns = (Sort_Column_Selector.By_Name [(Sort_Column.Name (this.columns.at 0 . name))])) text_ordering=Text_Ordering on_problems=Report_Warning = Panic.handle_wrapped_dataflow_error <|
columns_for_ordering = Table_Helpers.prepare_order_by this.internal_columns columns on_problems
new_order_descriptors = columns_for_ordering.map selected_column->
internal_column = selected_column.column
associated_selector = selected_column.associated_selector
## TODO [RW] this is only needed because `Vector.map` does not
propagate dataflow errors correctly. See:
https://www.pivotaltracker.com/story/show/181057718
Panic.throw_wrapped_if_error <|
this.connection.dialect.prepare_order_descriptor internal_column associated_selector.direction text_ordering
new_ctx = this.context.add_orders new_order_descriptors
this.updated_context new_ctx
problem_builder = Problem_Builder.new
columns_for_ordering = Table_Helpers.prepare_order_by this.columns columns problem_builder
problem_builder.attach_problems_before on_problems <|
new_order_descriptors = columns_for_ordering.map selected_column->
internal_column = selected_column.column
associated_selector = selected_column.associated_selector
## TODO [RW] this is only needed because `Vector.map` does not
propagate dataflow errors correctly. See:
https://www.pivotaltracker.com/story/show/181057718
Panic.throw_wrapped_if_error <|
this.connection.dialect.prepare_order_descriptor internal_column associated_selector.direction text_ordering
new_ctx = this.context.add_orders new_order_descriptors
this.updated_context new_ctx

## UNSTABLE

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from Standard.Base import all

from Standard.Table.Data.Column as Column_Module import Column
import Standard.Table.Data.Column_Selector
import Standard.Table.Data.Sort_Column_Selector

## Defines an Aggregate Column
type Aggregate_Column
Expand Down Expand Up @@ -140,7 +142,7 @@ type Aggregate_Column
not missing value returned.
- order_by: required for database tables. Specifies how to order the
results within the group.
type First (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=True) (order_by:Column_Selector|Nothing=Nothing)
type First (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=True) (order_by:Sort_Column_Selector|Nothing=Nothing)

## Creates a new column with the last value in each group. If no rows,
evaluates to `Nothing`.
Expand All @@ -153,7 +155,7 @@ type Aggregate_Column
not missing value returned.
- order_by: required for database tables. Specifies how to order the
results within the group.
type Last (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=True) (order_by:Column_Selector|Nothing=Nothing)
type Last (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=True) (order_by:Sort_Column_Selector|Nothing=Nothing)

## Creates a new column with the maximum value in each group. If no rows,
evaluates to `Nothing`.
Expand Down
19 changes: 9 additions & 10 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 @@ -11,6 +11,7 @@ import Standard.Table.Internal.Table_Helpers
import Standard.Table.Internal.Aggregate_Column_Helper
import Standard.Table.Internal.Parse_Values_Helper
import Standard.Table.Internal.Delimited_Reader
import Standard.Table.Internal.Problem_Builder

from Standard.Table.Data.Order_Rule as Order_Rule_Module import Order_Rule
from Standard.Table.Data.Column_Selector as Column_Selector_Module import Column_Selector, By_Index
Expand Down Expand Up @@ -572,16 +573,14 @@ type Table
table.order_by (Sort_Column_Selector.By_Index [Sort_Column.Index 1, Sort_Column.Index -7 Sort_Direction.Descending])
order_by : Sort_Column_Selector -> Text_Ordering -> Problem_Behavior -> Table
order_by (columns = (Sort_Column_Selector.By_Name [(Sort_Column.Name (this.columns.at 0 . name))])) text_ordering=Text_Ordering on_problems=Report_Warning =
columns_for_ordering = Table_Helpers.prepare_order_by this.columns columns on_problems
selected_columns = columns_for_ordering.map c->c.column.java_column
ordering = columns_for_ordering.map c->
case c.associated_selector.direction of
Sort_Direction.Ascending -> 1
Sort_Direction.Descending -> -1
comparator = Comparator.for_text_ordering text_ordering
Table <|
this.java_table.orderBy selected_columns.to_array ordering.to_array comparator

problem_builder = Problem_Builder.new
columns_for_ordering = Table_Helpers.prepare_order_by this.columns columns problem_builder
problem_builder.attach_problems_before on_problems <|
selected_columns = columns_for_ordering.map c->c.column.java_column
ordering = columns_for_ordering.map c->c.associated_selector.direction.to_sign
comparator = Comparator.for_text_ordering text_ordering
java_table = this.java_table.orderBy selected_columns.to_array ordering.to_array comparator
Table java_table

## Parses columns within a Table to a specific value type.
By default, it looks at all `Text` columns and attempts to deduce the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import Standard.Table.Internal.Problem_Builder
import Standard.Table.Internal.Unique_Name_Strategy
import Standard.Table.Internal.Table_Helpers

import Standard.Table.Data.Sort_Column_Selector
import Standard.Table.Data.Sort_Column

import Standard.Base.Data.Ordering.Comparator

from Standard.Table.Error as Error_Module import Missing_Input_Columns, Column_Indexes_Out_Of_Range, No_Output_Columns, Duplicate_Output_Column_Names, Invalid_Output_Column_Names, Invalid_Aggregation, Floating_Point_Grouping, Unquoted_Delimiter, Additional_Warnings
Expand Down Expand Up @@ -103,6 +106,9 @@ default_aggregate_column_name aggregate_column =
indices or column references potentially from a different table) are
replaced with column references from the provided table.

Sort_Column_Selectors are resolved to Sort_Column_Select.By_Column with the
matched columns coming from the provided table.

This preprocess step is required by some helper function, to avoid having
to pass the table reference and resolve the column descriptors all the
time.
Expand All @@ -123,9 +129,13 @@ resolve_aggregate table problem_builder aggregate_column =
resolved = Table_Helpers.select_columns_helper table_columns selector reorder=True problem_builder
if resolved.is_empty then Error.throw Internal_Missing_Column_Error else resolved

resolve_selector_or_nothing selector = case selector of
resolve_order_by selector = case selector of
Nothing -> Nothing
_ -> resolve_selector_to_vector selector
_ ->
columns_for_ordering = Table_Helpers.prepare_order_by table_columns selector problem_builder
sort_columns = columns_for_ordering.map c->
Sort_Column.Column c.column c.associated_selector.direction
Sort_Column_Selector.By_Column sort_columns
jdunkerley marked this conversation as resolved.
Show resolved Hide resolved

result = case aggregate_column of
Group_By c new_name -> Group_By (resolve c) new_name
Expand All @@ -149,8 +159,8 @@ resolve_aggregate table problem_builder aggregate_column =
Mode c new_name -> Mode (resolve c) new_name
Standard_Deviation c new_name population -> Standard_Deviation (resolve c) new_name population
Concatenate c new_name separator prefix suffix quote_char -> Concatenate (resolve c) new_name separator prefix suffix quote_char
First c new_name ignore_nothing order_by -> First (resolve c) new_name ignore_nothing (resolve_selector_or_nothing order_by)
Last c new_name ignore_nothing order_by -> Last (resolve c) new_name ignore_nothing (resolve_selector_or_nothing order_by)
First c new_name ignore_nothing order_by -> First (resolve c) new_name ignore_nothing (resolve_order_by order_by)
Last c new_name ignore_nothing order_by -> Last (resolve c) new_name ignore_nothing (resolve_order_by order_by)
Maximum c new_name -> Maximum (resolve c) new_name
Minimum c new_name -> Minimum (resolve c) new_name
Shortest c new_name -> Shortest (resolve c) new_name
Expand Down Expand Up @@ -188,12 +198,14 @@ java_aggregator name column =
Mode c _ -> ModeAggregator.new name c.java_column
First c _ ignore_nothing ordering ->
if ordering.is_nothing then FirstAggregator.new name c.java_column ignore_nothing else
ordering_array = ordering.map .java_column
FirstAggregator.new name c.java_column ignore_nothing ordering_array.to_array Comparator.new
order_columns = ordering.columns.map c->c.column.java_column
order_directions = ordering.columns.map c->c.direction.to_sign
FirstAggregator.new name c.java_column ignore_nothing order_columns.to_array order_direction.to_array Comparator.new
Last c _ ignore_nothing ordering ->
if ordering.is_nothing then LastAggregator.new name c.java_column ignore_nothing else
ordering_array = ordering.map .java_column
LastAggregator.new name c.java_column ignore_nothing ordering_array.to_array Comparator.new
order_columns = ordering.columns.map c->c.column.java_column
order_direction = ordering.columns.map c->c.direction.to_sign
LastAggregator.new name c.java_column ignore_nothing order_columns.to_array order_direction.to_array Comparator.new
Maximum c _ -> MinOrMaxAggregator.new name c.java_column 1 Comparator.new
Minimum c _ -> MinOrMaxAggregator.new name c.java_column -1 Comparator.new
Shortest c _ -> ShortestOrLongestAggregator.new name c.java_column -1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,9 +361,8 @@ validate_unique vector problem_callback on=(x->x) =
type Column_Transform_Element column associated_selector

## PRIVATE
prepare_order_by : Vector -> Problem_Behavior -> Vector Column_Transform_Element
prepare_order_by internal_columns column_selectors on_problems =
problem_builder = Problem_Builder.new
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 ->
here.select_columns_by_name internal_columns name_selectors matcher problem_builder name_extractor=(_.name)
Expand All @@ -373,7 +372,7 @@ prepare_order_by internal_columns column_selectors on_problems =
here.select_columns_by_column_reference internal_columns column_selectors problem_builder column_extractor=(_.column)
if selected_elements.is_empty then
problem_builder.report_other_warning No_Input_Columns_Selected
problem_builder.attach_problems_after on_problems selected_elements
selected_elements

## PRIVATE
A helper function which can be used by methods that transform a subset of
Expand Down
Loading