Skip to content

Commit 97d6724

Browse files
committed
array_agg
1 parent fd88c90 commit 97d6724

File tree

7 files changed

+70
-10
lines changed

7 files changed

+70
-10
lines changed

docs/edsl.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ Droplet offers a few functions built-in:
165165

166166
* `string_agg`
167167

168+
* `array_agg`
169+
168170
* `coalesce`
169171

170172
* `random`
@@ -178,9 +180,9 @@ function :: forall input output. String -> FunctionSignature input output
178180
-- represents a function that takes no arguments
179181
function' :: forall output. String -> FunctionSignature' output
180182

181-
-- example of defining array_agg for integer inputs
182-
int_array_agg :: FunctionSignature Int (Maybe (Array Int))
183-
int_array_agg = function "array_agg"
183+
-- example of defining func from integer to nullable integer
184+
func :: FunctionSignature Int (Maybe Int)
185+
func = function "func"
184186
```
185187

186188
Be aware that functions must be aliased

src/Droplet/Language.purs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import Droplet.Language.Internal.Function
5555
( count
5656
, coalesce
5757
, string_agg
58+
, array_agg
5859
, function
5960
, function'
6061
, Aggregate

src/Droplet/Language/Internal/Function.purs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ module Droplet.Language.Internal.Function
77
, function'
88
, string_agg
99
, class ToStringAgg
10+
, class ToArrayAgg
1011
, class ToCoalesce
1112
, PgFunction(..)
13+
, array_agg
1214
, class MatchArgument
1315
, function
1416
, class MatchArgumentList
@@ -22,7 +24,7 @@ import Prelude
2224
import Data.BigInt (BigInt)
2325
import Data.Maybe (Maybe)
2426
import Data.Tuple.Nested (type (/\))
25-
import Droplet.Language.Internal.Definition (class AppendPath, class ToValue, class UnwrapDefinition, class UnwrapNullable, Default, E, Path, Star)
27+
import Droplet.Language.Internal.Definition (class AppendPath, class ToValue, class UnwrapDefinition, class UnwrapNullable, E, Path, Star)
2628
import Prim.Row (class Cons)
2729
import Type.Equality (class TypeEquals)
2830
import Type.Proxy (Proxy)
@@ -32,6 +34,7 @@ import Type.Proxy (Proxy)
3234
data Aggregate input rest (fieldsRow Type) (outputType)
3335
= Count input
3436
| StringAgg input rest
37+
| ArrayAgg input
3538

3639
-- | Declares a functions
3740
data PgFunction (inputType) args (fieldsRow Type) (outputType) = PgFunction String args
@@ -61,6 +64,12 @@ instance TextColumn String
6164

6265
instance TextColumn (Maybe String)
6366

67+
class ToArrayAgg (fType) (fieldsRow Type) (tType) | f fields t
68+
69+
instance (Cons name t e fields, UnwrapDefinition t u) ToArrayAgg (Proxy name) fields u
70+
71+
instance (Cons name t e fields, UnwrapDefinition t u) ToArrayAgg (Path alias name) fields u
72+
6473
-- | Function arguments must match input type
6574
class MatchArgumentList (inputType) (argsType) (fieldsRow Type)
6675

@@ -103,6 +112,10 @@ count = Count
103112
string_agg f rest fields. ToStringAgg f rest fields f rest Aggregate f rest fields (Maybe String)
104113
string_agg f rest = StringAgg f rest
105114

115+
--Maybe t because null
116+
array_agg f t fields. ToArrayAgg f fields t f Aggregate f E fields (Maybe (Array t))
117+
array_agg f = ArrayAgg f
118+
106119
random FunctionSignature' Number
107120
random = function' "random"
108121

src/Droplet/Language/Internal/Syntax.purs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ import Data.Reflectable as DR
152152
import Data.Tuple.Nested (type (/\))
153153
import Droplet.Language.Internal.Condition (class ToCondition, class ValidComparision, Exists(..), Op(..), OuterScope)
154154
import Droplet.Language.Internal.Definition (class AppendPath, class ToType, class ToValue, class UnwrapDefinition, class UnwrapNullable, C, Column, Composite, Constraint, Default, Dot, E(..), Empty, ForeignKey, Identity, Joined, Path, PrimaryKey, Star, Table(..), Unique)
155-
import Droplet.Language.Internal.Function (class ToStringAgg, Aggregate, PgFunction)
155+
import Droplet.Language.Internal.Function (class ToArrayAgg, class ToStringAgg, Aggregate, PgFunction)
156156
import Prim.Boolean (False, True)
157157
import Prim.Row (class Cons, class Nub, class Union)
158158
import Prim.RowList (class RowToList, Cons, Nil, RowList)
@@ -695,7 +695,7 @@ data OrderBy f rest = OrderBy f rest
695695

696696
data Sort (fType) = Asc | Desc
697697

698-
-- | ORDER BY must be last statement
698+
-- | ORDER BY
699699
class ToOrderBy (fType) (qType)
700700

701701
instance (SortColumnsSource s projection f columns available, SortColumns st available) ToOrderBy st (Select s projection (From f columns E))
@@ -724,6 +724,25 @@ instance ToOrderBy (Proxy name) String
724724

725725
instance ToOrderBy (Path alias name) String
726726

727+
instance ToOrderBy (Proxy name) (Proxy otherName)
728+
729+
instance ToOrderBy (Path alias name) (Path otherAlias otherName)
730+
731+
--must be typed here
732+
instance
733+
( Cons name t e fields
734+
, Cons otherName v r fields
735+
, UnwrapDefinition v w
736+
)
737+
ToArrayAgg (OrderBy (Proxy name) (Proxy otherName)) fields w
738+
739+
instance
740+
( Cons name t e fields
741+
, Cons otherName v r fields
742+
, UnwrapDefinition v w
743+
)
744+
ToArrayAgg (OrderBy (Path alias name) (Path otherAlias otherName)) fields w
745+
727746
--this error might not be clear for the user
728747
-- | Columns available for sorting this query
729748
-- |

src/Droplet/Language/Internal/Token.purs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ dotSymbol = "."
164164
string_aggFunctionName String
165165
string_aggFunctionName = "string_agg"
166166

167+
array_aggFunctionName String
168+
array_aggFunctionName = "array_agg"
169+
167170
simpleQuoteSymbol String
168171
simpleQuoteSymbol = "'"
169172

src/Droplet/Language/Internal/Translate.purs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ import Droplet.Language.Internal.Condition (BinaryOperator(..), Exists, In, IsNu
8181
import Droplet.Language.Internal.Definition (class AppendPath, class IsNullable, class ToParameters, class ToType, class ToValue, class UnwrapDefinition, class UnwrapNullable, C, Column, Composite, Constraint, Default, E(..), ForeignKey, Identity, Path, PrimaryKey, Star, Table, Unique)
8282
import Droplet.Language.Internal.Definition as DLID
8383
import Droplet.Language.Internal.Function (Aggregate(..), PgFunction(..))
84-
import Droplet.Language.Internal.Syntax (class ConstraintsToRowList, class OnlyAggregations, class JoinedToMaybe, class QueryOptionallyAliased, class ToProjection, class ToSingleColumn, class UniqueColumnNames, Add, Alter(..), As(..), Create, DefaultValues(..), Delete(..), Distinct(..), Drop, From(..), GroupBy(..), Inclusion(..), Inner, Insert(..), Into(..), Join(..), Limit(..), Offset(..), On(..), OrderBy(..), Outer, Plan, Prepare(..), Returning(..), Select(..), Set(..), Side, Sort(..), T(..), Union(..), Update(..), Values(..), Where(..))
85-
import Droplet.Language.Internal.Token (addKeyword, allKeyword, alterKeyword, andKeyword, asKeyword, ascKeyword, atSymbol, byKeyword, closeBracket, comma, constraintKeyword, countFunctionName, createKeyword, lesserEqualsThanSymbol, greaterEqualsThanSymbol, defaultKeyword, deleteKeyword, descKeyword, distinctKeyword, dotSymbol, dropKeyword, equalsSymbol, existsKeyword, foreignKeyKeyword, fromKeyword, greaterThanSymbol, groupByKeyword, identityKeyword, inKeyword, innerKeyword, insertKeyword, isNullKeyword, isNotNullKeyword, joinKeyword, leftKeyword, lesserThanSymbol, limitKeyword, notEqualsSymbol, notKeyword, notNullKeyword, offsetKeyword, onKeyword, openBracket, orKeyword, orderKeyword, parameterSymbol, primaryKeyKeyword, quoteSymbol, referencesKeyword, returningKeyword, selectKeyword, setKeyword, space, starSymbol, string_aggFunctionName, tableKeyword, unionKeyword, uniqueKeyword, updateKeyword, valuesKeyword, whereKeyword)
84+
import Droplet.Language.Internal.Syntax (class ConstraintsToRowList, class JoinedToMaybe, class OnlyAggregations, class QueryOptionallyAliased, class ToProjection, class ToSingleColumn, class UniqueColumnNames, Add, Alter(..), As(..), Create, DefaultValues(..), Delete(..), Distinct(..), Drop, From(..), GroupBy(..), Inclusion(..), Inner, Insert(..), Into(..), Join(..), Limit(..), Offset(..), On(..), OrderBy(..), Outer, Plan, Prepare(..), Returning(..), Select(..), Set(..), Side, Sort(..), T(..), Union(..), Update(..), Values(..), Where(..))
85+
import Droplet.Language.Internal.Token (addKeyword, allKeyword, alterKeyword, andKeyword, array_aggFunctionName, asKeyword, ascKeyword, atSymbol, byKeyword, closeBracket, comma, constraintKeyword, countFunctionName, createKeyword, defaultKeyword, deleteKeyword, descKeyword, distinctKeyword, dotSymbol, dropKeyword, equalsSymbol, existsKeyword, foreignKeyKeyword, fromKeyword, greaterEqualsThanSymbol, greaterThanSymbol, groupByKeyword, identityKeyword, inKeyword, innerKeyword, insertKeyword, isNotNullKeyword, isNullKeyword, joinKeyword, leftKeyword, lesserEqualsThanSymbol, lesserThanSymbol, limitKeyword, notEqualsSymbol, notKeyword, notNullKeyword, offsetKeyword, onKeyword, openBracket, orKeyword, orderKeyword, parameterSymbol, primaryKeyKeyword, quoteSymbol, referencesKeyword, returningKeyword, selectKeyword, setKeyword, space, starSymbol, string_aggFunctionName, tableKeyword, unionKeyword, uniqueKeyword, updateKeyword, valuesKeyword, whereKeyword)
8686
import Foreign (Foreign)
8787
import Prelude (class Show, Unit, bind, discard, map, otherwise, pure, show, ($), (<$>), (<<<), (<>), (==), (||))
8888
import Prim.Boolean (False, True)
@@ -779,6 +779,10 @@ instance (Reflectable alias String, Reflectable name String) ⇒ NameList (Path
779779
instance NameList Star where
780780
nameList _ = starSymbol
781781

782+
--e.g. array_agg (field order by field)
783+
instance (NameList f, NameList g) NameList (OrderBy f g) where
784+
nameList (OrderBy f g) = nameList g <> orderKeyword <> byKeyword <> nameList f
785+
782786
instance (NameList f, NameList rest) NameList (Tuple f rest) where
783787
nameList (Tuple f rest) = nameList f <> comma <> nameList rest
784788

@@ -1132,6 +1136,7 @@ printAggregation = case _ of
11321136
StringAgg f rest → do
11331137
nrest ← argumentList rest
11341138
pure $ string_aggFunctionName <> openBracket <> nameList f <> comma <> nrest <> closeBracket
1139+
ArrayAgg f → pure $ array_aggFunctionName <> openBracket <> nameList f <> closeBracket
11351140

11361141
printFunction inp fields args out. ArgumentList args PgFunction inp args fields out State QueryState String
11371142
printFunction (PgFunction name args) = do

test/Function.purs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@ import Prelude
55
import Data.BigInt as DB
66
import Data.Maybe (Maybe(..))
77
import Data.Tuple.Nested ((/\))
8-
import Droplet.Language (as, coalesce, count, from, orderBy, random, select, star, string_agg, (...))
8+
import Droplet.Language
99
import Droplet.Language.Internal.Translate as DLIQ
1010
import Test.Model as TM
1111
import Test.Types
1212

1313
import Test.Spec (Spec)
1414
import Test.Spec as TS
1515

16-
1716
tests Spec Unit
1817
tests = TS.describe "functions" do
1918
TS.describe "user defined functions" do
@@ -81,3 +80,21 @@ tests = TS.describe "functions" do
8180
let q = select (string_agg (u ... name) (", " # orderBy (u ... id)) # as u) # from (users # as u)
8281
TM.parameterized """SELECT string_agg("u"."name", $1 ORDER BY "u"."id") AS "u" FROM "users" AS "u"""" $ DLIQ.buildQuery q
8382
TM.result q [ { u: Just "josh, mary" } ]
83+
TS.describe "int_agg" do
84+
TS.it "field" do
85+
let q = select (array_agg name # as u) # from users
86+
TM.notParameterized """SELECT array_agg("name") AS "u" FROM "users"""" $ DLIQ.buildQuery q
87+
TM.result q [ { u: Just [ "josh", "mary" ] } ]
88+
TS.it "path" do
89+
let q = select (array_agg (u ... id) # as u) # from (users # as u)
90+
TM.notParameterized """SELECT array_agg("u"."id") AS "u" FROM "users" AS "u"""" $ DLIQ.buildQuery q
91+
TM.result q [ { u: Just [1, 2] } ]
92+
TS.describe "order by" do
93+
TS.it "field" do
94+
let q = select (array_agg (id # orderBy id) # as u) # from users
95+
TM.notParameterized """SELECT array_agg("id" ORDER BY "id") AS "u" FROM "users"""" $ DLIQ.buildQuery q
96+
TM.result q [ { u: Just [1, 2]} ]
97+
TS.it "path" do
98+
let q = select (array_agg (u ... name # orderBy (u ... id)) # as u) # from (users # as u)
99+
TM.notParameterized """SELECT array_agg("u"."name" ORDER BY "u"."id") AS "u" FROM "users" AS "u"""" $ DLIQ.buildQuery q
100+
TM.result q [ { u: Just ["josh", "mary"] } ]

0 commit comments

Comments
 (0)