Skip to content

Commit b6b0add

Browse files
authored
Add Custom SQL to In Database aggregation (#14472)
- Allows user to choose Custom SQL in an aggregate. https://github.com/user-attachments/assets/badee3cf-c35c-430d-9c25-3d26d15c316c
1 parent f5df5a2 commit b6b0add

File tree

15 files changed

+400
-379
lines changed

15 files changed

+400
-379
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
- [Add Text_Column.index_of][14428]
9494
- [Trigonometry and other maths function on Column.][14433]
9595
- [Support for reading JSON lines files.][14439]
96+
- [Add Custom SQL to in database aggreates.][14472]
9697

9798
[13769]: https://github.com/enso-org/enso/pull/13769
9899
[14026]: https://github.com/enso-org/enso/pull/14026
@@ -123,6 +124,7 @@
123124
[14428]: https://github.com/enso-org/enso/pull/14428
124125
[14433]: https://github.com/enso-org/enso/pull/14433
125126
[14439]: https://github.com/enso-org/enso/pull/14439
127+
[14472]: https://github.com/enso-org/enso/pull/14472
126128

127129
#### Enso Language & Runtime
128130

distribution/lib/Standard/Database/0.0.0-dev/docs/api/Errors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Enso Signatures 1.0
22
## module Standard.Database.Errors
3-
- type Aggregagtion_Requires_Order
3+
- type Aggregation_Requires_Order
44
- Error op_name:Standard.Base.Data.Text.Text
55
- to_display_text self -> Standard.Base.Data.Text.Text
66
- to_text self -> Standard.Base.Data.Text.Text

distribution/lib/Standard/Database/0.0.0-dev/src/Errors.enso

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ type Different_Connections
6868
to_display_text self -> Text =
6969
self.to_text
7070

71-
type Aggregagtion_Requires_Order
71+
type Aggregation_Requires_Order
7272
## ---
7373
private: true
7474
---

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Aggregate_Helper.enso

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Standard.Table.Internal.Aggregate_Column_Helper
77
import Standard.Table.Internal.Aggregate_Column_Helper.Internal_Order_By_Column_Reference
88
import Standard.Table.Internal.Problem_Builder.Problem_Builder
99
from Standard.Table import Aggregate_Column, Table
10-
from Standard.Table.Aggregate_Column.Aggregate_Column import all
1110
from Standard.Table.Errors import No_Output_Columns
1211

1312
import project.DB_Table.DB_Table
@@ -18,7 +17,7 @@ import project.Internal.IR.Internal_Column.Internal_Column
1817
import project.Internal.IR.SQL_IR_Expression.SQL_IR_Expression
1918
import project.Internal.IR.SQL_IR_Source.SQL_IR_Source
2019
import project.Internal.SQL_Type_Reference.SQL_Type_Reference
21-
from project.Errors import Aggregagtion_Requires_Order
20+
from project.Errors import Aggregation_Requires_Order
2221

2322
## ---
2423
private: true
@@ -42,6 +41,12 @@ make_aggregate_column table aggregate as dialect infer_return_type problem_build
4241
sql_type_ref = infer_return_type op_kind columns expression
4342
Internal_Column.Value as sql_type_ref expression
4443

44+
custom_sql function columns =
45+
expression = dialect.cast_aggregate_columns "CUSTOM_SQL" columns
46+
with_function = SQL_IR_Expression.Operation "CUSTOM_SQL" [SQL_IR_Expression.Literal function]+expression.expressions expression.metadata
47+
sql_type_ref = infer_return_type "CUSTOM_SQL" columns with_function
48+
Internal_Column.Value as sql_type_ref with_function
49+
4550
aggregate_with_order_by op_kind column order_by =
4651
order_bys = order_by.map sc->
4752
effective_ordering = if sc.column.value_type.is_text then Text_Ordering.Default else Nothing
@@ -108,6 +113,7 @@ make_aggregate_column table aggregate as dialect infer_return_type problem_build
108113
Aggregate_Column.Sum c _ -> simple_aggregate "SUM" [c]
109114
Aggregate_Column.Average c _ -> simple_aggregate "AVG" [c]
110115
Aggregate_Column.Median c _ -> simple_aggregate "MEDIAN" [c]
116+
Aggregate_Column.SQL fn columns _ -> custom_sql fn columns
111117

112118
## ---
113119
private: true
@@ -266,27 +272,27 @@ map_column_inputs f:Function aggregate_column:Aggregate_Column -> Aggregate_Colu
266272
Internal_Order_By_Column_Reference.Value c direction -> Internal_Order_By_Column_Reference.Value (f c) direction
267273

268274
case aggregate_column of
269-
Group_By c as -> Group_By (f c) as
270-
Count as -> Count as
271-
Count_Distinct c as ignore_nothing ->
272-
Count_Distinct ((c:Vector).map f) as ignore_nothing
273-
Count_Not_Nothing c as -> Count_Not_Nothing (f c) as
274-
Count_Nothing c as -> Count_Nothing (f c) as
275-
Count_Not_Empty c as -> Count_Not_Empty (f c) as
276-
Count_Empty c as -> Count_Empty (f c) as
277-
Sum c as -> Sum (f c) as
278-
Average c as -> Average (f c) as
279-
Median c as -> Median (f c) as
280-
Percentile p c as -> Percentile p (f c) as
281-
Mode c as -> Mode (f c) as
282-
Standard_Deviation c as population -> Standard_Deviation (f c) as population
283-
Concatenate c as separator prefix suffix quote_char -> Concatenate (f c) as separator prefix suffix quote_char
284-
First c as ignore_nothing order_by -> First (f c) as ignore_nothing (update_order_by order_by)
285-
Last c as ignore_nothing order_by -> Last (f c) as ignore_nothing (update_order_by order_by)
286-
Maximum c as -> Maximum (f c) as
287-
Minimum c as -> Minimum (f c) as
288-
Shortest c as -> Shortest (f c) as
289-
Longest c as -> Longest (f c) as
275+
Aggregate_Column.Group_By c as -> Aggregate_Column.Group_By (f c) as
276+
Aggregate_Column.Count as -> Aggregate_Column.Count as
277+
Aggregate_Column.Count_Distinct c as ignore_nothing ->
278+
Aggregate_Column.Count_Distinct ((c:Vector).map f) as ignore_nothing
279+
Aggregate_Column.Count_Not_Nothing c as -> Aggregate_Column.Count_Not_Nothing (f c) as
280+
Aggregate_Column.Count_Nothing c as -> Aggregate_Column.Count_Nothing (f c) as
281+
Aggregate_Column.Count_Not_Empty c as -> Aggregate_Column.Count_Not_Empty (f c) as
282+
Aggregate_Column.Count_Empty c as -> Aggregate_Column.Count_Empty (f c) as
283+
Aggregate_Column.Sum c as -> Aggregate_Column.Sum (f c) as
284+
Aggregate_Column.Average c as -> Aggregate_Column.Average (f c) as
285+
Aggregate_Column.Median c as -> Aggregate_Column.Median (f c) as
286+
Aggregate_Column.Percentile p c as -> Aggregate_Column.Percentile p (f c) as
287+
Aggregate_Column.Mode c as -> Aggregate_Column.Mode (f c) as
288+
Aggregate_Column.Standard_Deviation c as population -> Aggregate_Column.Standard_Deviation (f c) as population
289+
Aggregate_Column.Concatenate c as separator prefix suffix quote_char -> Aggregate_Column.Concatenate (f c) as separator prefix suffix quote_char
290+
Aggregate_Column.First c as ignore_nothing order_by -> Aggregate_Column.First (f c) as ignore_nothing (update_order_by order_by)
291+
Aggregate_Column.Last c as ignore_nothing order_by -> Aggregate_Column.Last (f c) as ignore_nothing (update_order_by order_by)
292+
Aggregate_Column.Maximum c as -> Aggregate_Column.Maximum (f c) as
293+
Aggregate_Column.Minimum c as -> Aggregate_Column.Minimum (f c) as
294+
Aggregate_Column.Shortest c as -> Aggregate_Column.Shortest (f c) as
295+
Aggregate_Column.Longest c as -> Aggregate_Column.Longest (f c) as
290296

291297
## ---
292298
private: true
@@ -296,4 +302,4 @@ is_non_empty_selector v = v.is_nothing.not && v.not_empty
296302
## ---
297303
private: true
298304
---
299-
throw_ordering_required op_name = Error.throw (Aggregagtion_Requires_Order.Error op_name)
305+
throw_ordering_required op_name = Error.throw (Aggregation_Requires_Order.Error op_name)

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import Standard.Base.Errors.Unimplemented.Unimplemented
88
import Standard.Table.In_Memory_Column.In_Memory_Column
99
import Standard.Table.Internal.Problem_Builder.Problem_Builder
1010
from Standard.Table import Aggregate_Column, Column, Table, Value_Type
11-
from Standard.Table.Aggregate_Column.Aggregate_Column import all
1211
from Standard.Table.Errors import Inexact_Type_Coercion
1312

1413
import project.DB_Column.DB_Column

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Standard.Base.Runtime.Ref.Ref
77

88
import Standard.Table.Internal.Problem_Builder.Problem_Builder
99
from Standard.Table import Aggregate_Column, Table, Value_Type
10-
from Standard.Table.Aggregate_Column.Aggregate_Column import all
1110

1211
import project.DB_Column.DB_Column
1312
import project.DB_Table.DB_Table
@@ -275,34 +274,34 @@ type SQLite_Dialect
275274
---
276275
check_aggregate_support : Aggregate_Column -> Boolean ! Unsupported_Database_Operation
277276
check_aggregate_support self aggregate = case aggregate of
278-
Group_By _ _ -> True
279-
Count _ -> True
280-
Count_Distinct columns _ _ ->
277+
Aggregate_Column.Group_By _ _ -> True
278+
Aggregate_Column.Count _ -> True
279+
Aggregate_Column.Count_Distinct columns _ _ ->
281280
if columns.length == 1 then True else
282281
unsupported "Count_Distinct on multiple columns"
283-
Count_Not_Nothing _ _ -> True
284-
Count_Nothing _ _ -> True
285-
Count_Not_Empty _ _ -> True
286-
Count_Empty _ _ -> True
287-
Percentile _ _ _ -> unsupported "Percentile"
288-
Mode _ _ -> unsupported "Mode"
289-
First _ _ ignore_nothing order_by ->
282+
Aggregate_Column.Count_Not_Nothing _ _ -> True
283+
Aggregate_Column.Count_Nothing _ _ -> True
284+
Aggregate_Column.Count_Not_Empty _ _ -> True
285+
Aggregate_Column.Count_Empty _ _ -> True
286+
Aggregate_Column.Percentile _ _ _ -> unsupported "Percentile"
287+
Aggregate_Column.Mode _ _ -> unsupported "Mode"
288+
Aggregate_Column.First _ _ ignore_nothing order_by ->
290289
if ignore_nothing then unsupported "First with ignore_nothing=True" else
291290
if Aggregate_Helper.is_non_empty_selector order_by . not then Aggregate_Helper.throw_ordering_required "First" else
292291
True
293-
Last _ _ ignore_nothing order_by ->
292+
Aggregate_Column.Last _ _ ignore_nothing order_by ->
294293
if ignore_nothing then unsupported "Last with ignore_nothing=True" else
295294
if Aggregate_Helper.is_non_empty_selector order_by . not then Aggregate_Helper.throw_ordering_required "Last" else
296295
True
297-
Maximum _ _ -> True
298-
Minimum _ _ -> True
299-
Shortest _ _ -> unsupported "Shortest"
300-
Longest _ _ -> unsupported "Longest"
301-
Standard_Deviation _ _ _ -> True
302-
Concatenate _ _ _ _ _ _ -> True
303-
Sum _ _ -> True
304-
Average _ _ -> True
305-
Median _ _ -> unsupported "Median"
296+
Aggregate_Column.Maximum _ _ -> True
297+
Aggregate_Column.Minimum _ _ -> True
298+
Aggregate_Column.Shortest _ _ -> unsupported "Shortest"
299+
Aggregate_Column.Longest _ _ -> unsupported "Longest"
300+
Aggregate_Column.Standard_Deviation _ _ _ -> True
301+
Aggregate_Column.Concatenate _ _ _ _ _ _ -> True
302+
Aggregate_Column.Sum _ _ -> True
303+
Aggregate_Column.Average _ _ -> True
304+
Aggregate_Column.Median _ _ -> unsupported "Median"
306305

307306
## ---
308307
private: true

distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Standard.Base.Errors.Unimplemented.Unimplemented
77

88
import Standard.Table.Internal.Problem_Builder.Problem_Builder
99
from Standard.Table import Aggregate_Column, Column, Table, Value_Type
10-
from Standard.Table.Aggregate_Column.Aggregate_Column import all
1110
from Standard.Table.Errors import Inexact_Type_Coercion
1211

1312
import Standard.Database.Connection.Connection.Connection
@@ -273,28 +272,28 @@ type SQLServer_Dialect
273272
unsupported name =
274273
Error.throw (Unsupported_Database_Operation.Error name)
275274
case aggregate of
276-
Group_By _ _ -> True
277-
Count _ -> True
278-
Count_Distinct columns _ _ ->
275+
Aggregate_Column.Group_By _ _ -> True
276+
Aggregate_Column.Count _ -> True
277+
Aggregate_Column.Count_Distinct columns _ _ ->
279278
if columns.length == 1 then True else
280279
unsupported "Count_Distinct on multiple columns"
281-
Count_Not_Nothing _ _ -> True
282-
Count_Nothing _ _ -> True
283-
Count_Not_Empty _ _ -> True
284-
Count_Empty _ _ -> True
285-
Percentile _ _ _ -> unsupported "Percentile"
286-
Mode _ _ -> unsupported "Mode"
287-
First _ _ _ _ -> unsupported "First"
288-
Last _ _ _ _ -> unsupported "Last"
289-
Maximum _ _ -> True
290-
Minimum _ _ -> True
291-
Shortest _ _ -> unsupported "Shortest"
292-
Longest _ _ -> unsupported "Longest"
293-
Standard_Deviation _ _ _ -> True
294-
Concatenate _ _ _ _ _ _ -> True
295-
Sum _ _ -> True
296-
Average _ _ -> True
297-
Median _ _ -> unsupported "Median"
280+
Aggregate_Column.Count_Not_Nothing _ _ -> True
281+
Aggregate_Column.Count_Nothing _ _ -> True
282+
Aggregate_Column.Count_Not_Empty _ _ -> True
283+
Aggregate_Column.Count_Empty _ _ -> True
284+
Aggregate_Column.Percentile _ _ _ -> unsupported "Percentile"
285+
Aggregate_Column.Mode _ _ -> unsupported "Mode"
286+
Aggregate_Column.First _ _ _ _ -> unsupported "First"
287+
Aggregate_Column.Last _ _ _ _ -> unsupported "Last"
288+
Aggregate_Column.Maximum _ _ -> True
289+
Aggregate_Column.Minimum _ _ -> True
290+
Aggregate_Column.Shortest _ _ -> unsupported "Shortest"
291+
Aggregate_Column.Longest _ _ -> unsupported "Longest"
292+
Aggregate_Column.Standard_Deviation _ _ _ -> True
293+
Aggregate_Column.Concatenate _ _ _ _ _ _ -> True
294+
Aggregate_Column.Sum _ _ -> True
295+
Aggregate_Column.Average _ _ -> True
296+
Aggregate_Column.Median _ _ -> unsupported "Median"
298297

299298
## ---
300299
private: true

distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import Standard.Base.Runtime.Ref.Ref
88

99
import Standard.Table.Internal.Problem_Builder.Problem_Builder
1010
from Standard.Table import Aggregate_Column, Column, Table, Value_Type
11-
from Standard.Table.Aggregate_Column.Aggregate_Column import all
1211
from Standard.Table.Errors import Inexact_Type_Coercion
1312

1413
import Standard.Database.DB_Column.DB_Column

distribution/lib/Standard/Table/0.0.0-dev/docs/api/Aggregate_Column.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- Minimum column:(Standard.Base.Data.Text.Text|Standard.Base.Data.Numbers.Integer|Standard.Base.Any.Any)= as:Standard.Base.Data.Text.Text=
1919
- Mode column:(Standard.Base.Data.Text.Text|Standard.Base.Data.Numbers.Integer|Standard.Base.Any.Any)= as:Standard.Base.Data.Text.Text=
2020
- Percentile percentile:Standard.Base.Data.Numbers.Number= column:(Standard.Base.Data.Text.Text|Standard.Base.Data.Numbers.Integer|Standard.Base.Any.Any)= as:Standard.Base.Data.Text.Text=
21+
- SQL function:Standard.Base.Data.Text.Text= arguments:(Standard.Base.Data.Vector.Vector Standard.Base.Any.Any)= as:Standard.Base.Data.Text.Text=
2122
- Shortest column:(Standard.Base.Data.Text.Text|Standard.Base.Data.Numbers.Integer|Standard.Base.Any.Any)= as:Standard.Base.Data.Text.Text=
2223
- Standard_Deviation column:(Standard.Base.Data.Text.Text|Standard.Base.Data.Numbers.Integer|Standard.Base.Any.Any)= as:Standard.Base.Data.Text.Text= population:Standard.Base.Data.Boolean.Boolean=
2324
- Sum column:(Standard.Base.Data.Text.Text|Standard.Base.Data.Numbers.Integer|Standard.Base.Any.Any)= as:Standard.Base.Data.Text.Text=

distribution/lib/Standard/Table/0.0.0-dev/src/Aggregate_Column.enso

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,11 @@ type Aggregate_Column
198198
group longest value.
199199
- `as`: name of new column.
200200
Longest (column:Text|Integer|Any=0) (as:Text="") # Any needed because of 6866
201+
202+
## Custom SQL aggregate function for database backends.
203+
204+
## Arguments
205+
- `function`: the SQL function to use for aggregation.
206+
- `arguments`: arguments to the SQL function.
207+
- `as`: name of new column.
208+
SQL (function:Text=(Missing_Argument.throw "function")) (arguments:(Vector (Text | Sort_Column))=[]) (as:Text="")

0 commit comments

Comments
 (0)