@@ -890,38 +890,67 @@ else instance
890890-- Query builder
891891-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
892892
893−newtype Q :: Symbol -> Row Type -> Row Type -> Row Type -> Type
894−newtype Q name cols result params = Q { sql :: String, values :: Array PG.PGValue }
893+newtype Q :: Symbol -> Row Type -> Row Type -> Row Type -> Row Type -> Type
894+newtype Q name cols result params stage = Q { sql :: String, values :: Array PG.PGValue }
895895
896−from :: forall name cols. Proxy (Table name cols) -> Q name cols () ()
896+class HasClause :: Symbol -> Row Type -> Constraint
897+class HasClause label row
898+
899+instance Row.Cons label Unit rest row => HasClause label row
900+
901+from :: forall name cols. Proxy (Table name cols) -> Q name cols () () ()
897902from _ = Q { sql: "", values: [] }
898903
899904selectAll
900− :: forall name cols result r p
905+ :: forall name cols result r p stage stage'
901906 . IsSymbol name
902907 => StripColumns cols result
903− => Q name cols r p
904− -> Q name cols result p
908+ => Row.Lacks "select" stage
909+ => Row.Lacks "insert" stage
910+ => Row.Lacks "set" stage
911+ => Row.Lacks "delete" stage
912+ => Row.Lacks "where" stage
913+ => Row.Lacks "orderBy" stage
914+ => Row.Lacks "limit" stage
915+ => Row.Lacks "offset" stage
916+ => Row.Cons "select" Unit stage stage'
917+ => Q name cols r p stage
918+ -> Q name cols result p stage'
905919selectAll _ = Q { sql: "SELECT * FROM " <> reflectSymbol (Proxy :: Proxy name), values: [] }
906920
907921select
908− :: forall @sel name cols result r p
922+ :: forall @sel name cols result r p stage stage'
909923 . IsSymbol name
910924 => IsSymbol sel
911925 => ParseSelect sel cols result
912− => Q name cols r p
913− -> Q name cols result p
926+ => Row.Lacks "select" stage
927+ => Row.Lacks "insert" stage
928+ => Row.Lacks "set" stage
929+ => Row.Lacks "delete" stage
930+ => Row.Lacks "where" stage
931+ => Row.Lacks "orderBy" stage
932+ => Row.Lacks "limit" stage
933+ => Row.Lacks "offset" stage
934+ => Row.Cons "select" Unit stage stage'
935+ => Q name cols r p stage
936+ -> Q name cols result p stage'
914937select _ = Q { sql: "SELECT " <> reflectSymbol (Proxy :: Proxy sel) <> " FROM " <> reflectSymbol (Proxy :: Proxy name), values: [] }
915938
916939where_
917− :: forall @whr name cols result params p
940+ :: forall @whr name cols result params p stage stage'
918941 . IsSymbol whr
919942 => ParseWhere whr cols params
920− => Q name cols result p
921− -> Q name cols result params
943+ => Row.Lacks "where" stage
944+ => Row.Lacks "insert" stage
945+ => Row.Lacks "orderBy" stage
946+ => Row.Lacks "limit" stage
947+ => Row.Lacks "offset" stage
948+ => Row.Cons "where" Unit stage stage'
949+ => Q name cols result p stage
950+ -> Q name cols result params stage'
922951where_ (Q q) = Q (q { sql = q.sql <> " WHERE " <> reflectSymbol (Proxy :: Proxy whr) })
923952
924−toSQL :: forall name cols result params. Q name cols result params -> String
953+toSQL :: forall name cols result params stage. Q name cols result params stage -> String
925954toSQL (Q q) = q.sql
926955
927956-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -994,16 +1023,21 @@ instance
9941023-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
9951024
9961025insert
997− :: forall name cols colsRL insertableRL insertRow
1026+ :: forall name cols colsRL insertableRL insertRow stage stage'
9981027 . RowToList cols colsRL
9991028 => InsertableColumnsRL colsRL insertableRL
10001029 => ListToRow insertableRL insertRow
10011030 => IsSymbol name
10021031 => InsertColumnsRL colsRL
10031032 => RecordValuesRL insertableRL insertRow
1033+ => Row.Lacks "select" stage
1034+ => Row.Lacks "insert" stage
1035+ => Row.Lacks "set" stage
1036+ => Row.Lacks "delete" stage
1037+ => Row.Cons "insert" Unit stage stage'
10041038 => { | insertRow }
1005− -> Q name cols () ()
1006− -> Q name cols () ()
1039+ -> Q name cols () () stage
1040+ -> Q name cols () () stage'
10071041insert rec _ = Q { sql, values }
10081042 where
10091043 tableName = reflectSymbol (Proxy :: Proxy name)
@@ -1023,11 +1057,14 @@ insert rec _ = Q { sql, values }
10231057-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10241058
10251059returning
1026− :: forall @sel name cols result p
1060+ :: forall @sel name cols result p stage stage'
10271061 . IsSymbol sel
10281062 => ParseSelect sel cols result
1029− => Q name cols () p
1030− -> Q name cols result p
1063+ => Row.Lacks "returning" stage
1064+ => Row.Lacks "select" stage
1065+ => Row.Cons "returning" Unit stage stage'
1066+ => Q name cols () p stage
1067+ -> Q name cols result p stage'
10311068returning (Q q) = Q (q { sql = q.sql <> " RETURNING " <> reflectSymbol (Proxy :: Proxy sel) })
10321069
10331070-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -1057,15 +1094,20 @@ instance (IsSymbol name, SetClauseRL tail) => SetClauseRL (RL.Cons name typ tail
10571094 <> setClauseRL (Proxy :: Proxy tail) (idx + 1)
10581095
10591096set
1060− :: forall name cols setRow setRL
1097+ :: forall name cols setRow setRL stage stage'
10611098 . RowToList setRow setRL
10621099 => IsSymbol name
10631100 => ValidateSetColumnsRL setRL cols
10641101 => SetClauseRL setRL
10651102 => RecordValuesRL setRL setRow
1103+ => Row.Lacks "select" stage
1104+ => Row.Lacks "insert" stage
1105+ => Row.Lacks "set" stage
1106+ => Row.Lacks "delete" stage
1107+ => Row.Cons "set" Unit stage stage'
10661108 => { | setRow }
1067− -> Q name cols () ()
1068− -> Q name cols () ()
1109+ -> Q name cols () () stage
1110+ -> Q name cols () () stage'
10691111set rec _ = Q { sql, values }
10701112 where
10711113 tableName = reflectSymbol (Proxy :: Proxy name)
@@ -1078,10 +1120,15 @@ set rec _ = Q { sql, values }
10781120-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10791121
10801122delete
1081− :: forall name cols r p
1123+ :: forall name cols r p stage stage'
10821124 . IsSymbol name
1083− => Q name cols r p
1084− -> Q name cols () ()
1125+ => Row.Lacks "select" stage
1126+ => Row.Lacks "insert" stage
1127+ => Row.Lacks "set" stage
1128+ => Row.Lacks "delete" stage
1129+ => Row.Cons "delete" Unit stage stage'
1130+ => Q name cols r p stage
1131+ -> Q name cols () () stage'
10851132delete _ = Q { sql: "DELETE FROM " <> reflectSymbol (Proxy :: Proxy name), values: [] }
10861133
10871134-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -1089,25 +1136,36 @@ delete _ = Q { sql: "DELETE FROM " <> reflectSymbol (Proxy :: Proxy name), value
10891136-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10901137
10911138orderBy
1092− :: forall @cols name tableCols result params
1139+ :: forall @cols name tableCols result params stage stage'
10931140 . IsSymbol cols
10941141 => ValidateOrderBy cols tableCols
1095− => Q name tableCols result params
1096− -> Q name tableCols result params
1142+ => HasClause "select" stage
1143+ => Row.Lacks "orderBy" stage
1144+ => Row.Lacks "limit" stage
1145+ => Row.Lacks "offset" stage
1146+ => Row.Cons "orderBy" Unit stage stage'
1147+ => Q name tableCols result params stage
1148+ -> Q name tableCols result params stage'
10971149orderBy (Q q) = Q (q { sql = q.sql <> " ORDER BY " <> reflectSymbol (Proxy :: Proxy cols) })
10981150
10991151limit
1100− :: forall name cols result params
1101− . Int
1102− -> Q name cols result params
1103− -> Q name cols result params
1152+ :: forall name cols result params stage stage'
1153+ . HasClause "select" stage
1154+ => Row.Lacks "limit" stage
1155+ => Row.Cons "limit" Unit stage stage'
1156+ => Int
1157+ -> Q name cols result params stage
1158+ -> Q name cols result params stage'
11041159limit n (Q q) = Q (q { sql = q.sql <> " LIMIT " <> show n })
11051160
11061161offset
1107− :: forall name cols result params
1108− . Int
1109− -> Q name cols result params
1110− -> Q name cols result params
1162+ :: forall name cols result params stage stage'
1163+ . HasClause "select" stage
1164+ => Row.Lacks "offset" stage
1165+ => Row.Cons "offset" Unit stage stage'
1166+ => Int
1167+ -> Q name cols result params stage
1168+ -> Q name cols result params stage'
11111169offset n (Q q) = Q (q { sql = q.sql <> " OFFSET " <> show n })
11121170
11131171-- Validate ORDER BY columns: "name, age DESC" → validate name, age exist
@@ -1333,13 +1391,16 @@ else instance
13331391 MatchSymbol actual expected
13341392
13351393onConflict
1336− :: forall @target @action name cols result params
1394+ :: forall @target @action name cols result params stage stage'
13371395 . IsSymbol target
13381396 => IsSymbol action
13391397 => ValidateColumns target cols
13401398 => ParseConflictAction action cols
1341− => Q name cols result params
1342− -> Q name cols result params
1399+ => HasClause "insert" stage
1400+ => Row.Lacks "conflict" stage
1401+ => Row.Cons "conflict" Unit stage stage'
1402+ => Q name cols result params stage
1403+ -> Q name cols result params stage'
13431404onConflict (Q q) = Q
13441405 ( q
13451406 { sql = q.sql
@@ -1351,11 +1412,14 @@ onConflict (Q q) = Q
13511412 )
13521413
13531414onConflictDoNothing
1354− :: forall @target name cols result params
1415+ :: forall @target name cols result params stage stage'
13551416 . IsSymbol target
13561417 => ValidateColumns target cols
1357− => Q name cols result params
1358− -> Q name cols result params
1418+ => HasClause "insert" stage
1419+ => Row.Lacks "conflict" stage
1420+ => Row.Cons "conflict" Unit stage stage'
1421+ => Q name cols result params stage
1422+ -> Q name cols result params stage'
13591423onConflictDoNothing (Q q) = Q
13601424 ( q
13611425 { sql = q.sql
@@ -1409,13 +1473,13 @@ replaceNamedParams offset entries sql = do
14091473 { sql: sql', values: map (\e -> unsafeCoerce e.value) indexed }
14101474
14111475runQuery
1412− :: forall name cols result params paramsRL
1476+ :: forall name cols result params paramsRL stage
14131477 . RowToList params paramsRL
14141478 => ParamsToArray paramsRL params
14151479 => ReadForeign { | result }
14161480 => PG.Connection
14171481 -> { | params }
1418− -> Q name cols result params
1482+ -> Q name cols result params stage
14191483 -> Aff (Array { | result })
14201484runQuery conn params (Q q) = do
14211485 let entries = paramsToArray (Proxy :: Proxy paramsRL) params
@@ -1425,13 +1489,13 @@ runQuery conn params (Q q) = do
14251489 pure (unsafeDecodeRows result.rows)
14261490
14271491runQueryOne
1428− :: forall name cols result params paramsRL
1492+ :: forall name cols result params paramsRL stage
14291493 . RowToList params paramsRL
14301494 => ParamsToArray paramsRL params
14311495 => ReadForeign { | result }
14321496 => PG.Connection
14331497 -> { | params }
1434− -> Q name cols result params
1498+ -> Q name cols result params stage
14351499 -> Aff (Maybe { | result })
14361500runQueryOne conn params (Q q) = do
14371501 let entries = paramsToArray (Proxy :: Proxy paramsRL) params
@@ -1441,12 +1505,12 @@ runQueryOne conn params (Q q) = do
14411505 pure (result <#> unsafeDecodeRow)
14421506
14431507runExecute
1444− :: forall name cols params paramsRL
1508+ :: forall name cols params paramsRL stage
14451509 . RowToList params paramsRL
14461510 => ParamsToArray paramsRL params
14471511 => PG.Connection
14481512 -> { | params }
1449− -> Q name cols () params
1513+ -> Q name cols () params stage
14501514 -> Aff Int
14511515runExecute conn params (Q q) = do
14521516 let entries = paramsToArray (Proxy :: Proxy paramsRL) params