@@ -14,6 +14,7 @@
15module Squeel.PostgreSQL.Statement where
15module Squeel.PostgreSQL.Statement where
17+import Control.Category
17import Data.Boolean
18import Data.Boolean
18import Data.ByteString (ByteString)
19import Data.ByteString (ByteString)
19import Data.Maybe
20import Data.Maybe
@@ -24,15 +25,16 @@ import Data.Vinyl.Functor
24import GHC.Exts
25import GHC.Exts
25import GHC.OverloadedLabels
26import GHC.OverloadedLabels
26import GHC.TypeLits
27import GHC.TypeLits
28+import Prelude hiding (id,(.))
28import qualified Data.ByteString as ByteString
30import qualified Data.ByteString as ByteString
30import Squeel.PostgreSQL.Schema
32import Squeel.PostgreSQL.Schema
32newtype Expression
34newtype Expression
33− (params :: [NullityType])
35+ (params :: [ColumnType])
34− (tables :: [(Symbol,[(Symbol,NullityType)])])
36+ (tables :: [(Symbol,[(Symbol,ColumnType)])])
35− (ty :: NullityType)
37+ (ty :: ColumnType)
36 = UnsafeExpression { renderExpression :: ByteString }
38 = UnsafeExpression { renderExpression :: ByteString }
38class KnownNat n => HasParameter (n :: Nat) params ty | n params -> ty where
40class KnownNat n => HasParameter (n :: Nat) params ty | n params -> ty where
@@ -58,7 +60,7 @@ class KnownSymbol column => HasColumn column columns ty
58 getColumn :: Proxy# column -> Expression params '[table ::: columns] ty
60 getColumn :: Proxy# column -> Expression params '[table ::: columns] ty
59 getColumn column = UnsafeExpression $ fromString $ symbolVal' column
61 getColumn column = UnsafeExpression $ fromString $ symbolVal' column
60instance {-# OVERLAPPING #-} KnownSymbol column
62instance {-# OVERLAPPING #-} KnownSymbol column
61− => HasColumn column ((column ::: ty) ': tys) ty
63+ => HasColumn column ((column ::: optionality ty) ': tys) ('Required ty)
62instance {-# OVERLAPPABLE #-} (KnownSymbol column, HasColumn column table ty)
64instance {-# OVERLAPPABLE #-} (KnownSymbol column, HasColumn column table ty)
63 => HasColumn column (ty' ': table) ty
65 => HasColumn column (ty' ': table) ty
@@ -96,7 +98,7 @@ unsafeFunction
96unsafeFunction fn x = UnsafeExpression $ mconcat
98unsafeFunction fn x = UnsafeExpression $ mconcat
97 [fn, "(", renderExpression x, ")"]
99 [fn, "(", renderExpression x, ")"]
99−instance PGNum ty => Num (Expression params tables (nullity ty)) where
101+instance PGNum ty => Num (Expression params tables ('Required (nullity ty))) where
100 (+) = unsafeBinaryOp "+"
102 (+) = unsafeBinaryOp "+"
101 (-) = unsafeBinaryOp "-"
103 (-) = unsafeBinaryOp "-"
102 (*) = unsafeBinaryOp "*"
104 (*) = unsafeBinaryOp "*"
@@ -104,7 +106,7 @@ instance PGNum ty => Num (Expression params tables (nullity ty)) where
104 signum = unsafeFunction "sign"
106 signum = unsafeFunction "sign"
105 fromInteger = UnsafeExpression . fromString . show
107 fromInteger = UnsafeExpression . fromString . show
107−instance IsString (Expression params tables (nullity 'PGText)) where
109+instance IsString (Expression params tables ('Required (nullity 'PGText))) where
108 fromString str = UnsafeExpression $
110 fromString str = UnsafeExpression $
109 "E\'" <> fromString (escape =<< str) <> "\'"
111 "E\'" <> fromString (escape =<< str) <> "\'"
@@ -119,7 +121,7 @@ instance IsString (Expression params tables (nullity 'PGText)) where
119 '\\' -> "\\\\"
121 '\\' -> "\\\\"
122−instance Boolean (Expression params tables ('NotNull 'PGBool)) where
124+instance Boolean (Expression params tables ('Required ('NotNull 'PGBool))) where
123 true = UnsafeExpression "TRUE"
125 true = UnsafeExpression "TRUE"
124 false = UnsafeExpression "FALSE"
126 false = UnsafeExpression "FALSE"
125 notB = unsafeUnaryOp "NOT"
127 notB = unsafeUnaryOp "NOT"
@@ -127,21 +129,21 @@ instance Boolean (Expression params tables ('NotNull 'PGBool)) where
127 (||*) = unsafeBinaryOp "OR"
129 (||*) = unsafeBinaryOp "OR"
129type instance BooleanOf (Expression params tables ty) =
131type instance BooleanOf (Expression params tables ty) =
130− Expression params tables ('NotNull 'PGBool)
132+ Expression params tables ('Required ('NotNull 'PGBool))
133− :: [Expression params tables ('Null x)]
135+ :: [Expression params tables ('Required ('Null x))]
134− -> Expression params tables ('NotNull x)
136+ -> Expression params tables ('Required ('NotNull x))
135− -> Expression params tables ('NotNull x)
137+ -> Expression params tables ('Required ('NotNull x))
136−coalesce nulls notNull = UnsafeExpression $ mconcat
138+coalesce nulls isn'tNull = UnsafeExpression $ mconcat
137 [ "COALESCE("
139 [ "COALESCE("
138 , ByteString.intercalate ", " $ map renderExpression nulls
140 , ByteString.intercalate ", " $ map renderExpression nulls
139− , ", ", renderExpression notNull
141+ , ", ", renderExpression isn'tNull
143caseWhenThenElse
145caseWhenThenElse
144− :: [(Expression params tables ('NotNull 'PGBool), Expression params tables ty)]
146+ :: [(Expression params tables ('Required ('NotNull 'PGBool)), Expression params tables ty)]
145 -> Expression params tables ty
147 -> Expression params tables ty
146 -> Expression params tables ty
148 -> Expression params tables ty
147caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
149caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
@@ -171,9 +173,9 @@ instance OrdB (Expression params tables ty) where
171 (<=*) = unsafeBinaryOp "<="
173 (<=*) = unsafeBinaryOp "<="
173newtype TableExpression
175newtype TableExpression
174− (params :: [NullityType])
176+ (params :: [ColumnType])
175− (schema :: [(Symbol,[(Symbol,NullityType)])])
177+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
176− (columns :: [(Symbol,NullityType)])
178+ (columns :: [(Symbol,ColumnType)])
177 = UnsafeTableExpression { renderTableExpression :: ByteString }
179 = UnsafeTableExpression { renderTableExpression :: ByteString }
179data JoinExpression params schema tables where
181data JoinExpression params schema tables where
@@ -189,25 +191,25 @@ data JoinExpression params schema tables where
189 -> JoinExpression params schema (table ': tables)
191 -> JoinExpression params schema (table ': tables)
191 :: Aliased (TableExpression params schema) table
193 :: Aliased (TableExpression params schema) table
192− -> Expression params (table ': tables) ('NotNull 'PGBool)
194+ -> Expression params (table ': tables) ('Required ('NotNull 'PGBool))
193 -> JoinExpression params schema tables
195 -> JoinExpression params schema tables
194 -> JoinExpression params schema (table ': tables)
196 -> JoinExpression params schema (table ': tables)
195− LeftOuter
197+ -- LeftOuter
196− :: Aliased (TableExpression params schema) right
198+ -- :: Aliased (TableExpression params schema) right
197− -> Expression params '[left,right] ('NotNull 'PGBool)
199+ -- -> Expression params '[left,right] ('Required ('NotNull 'PGBool))
198− -> JoinExpression params schema (tables)
200+ -- -> JoinExpression params schema (tables)
199− -> JoinExpression params schema (NullifyTable right ': left ': tables)
201+ -- -> JoinExpression params schema (NullifyTable right ': left ': tables)
200− RightOuter
202+ -- RightOuter
201− :: Aliased (TableExpression params schema) right
203+ -- :: Aliased (TableExpression params schema) right
202− -> Expression params '[left,right] ('NotNull 'PGBool)
204+ -- -> Expression params '[left,right] ('Required ('NotNull 'PGBool))
203− -> JoinExpression params schema (left : tables)
205+ -- -> JoinExpression params schema (left : tables)
204− -> JoinExpression params schema (right ': NullifyTable left ': tables)
206+ -- -> JoinExpression params schema (right ': NullifyTable left ': tables)
205− FullOuter
207+ -- FullOuter
206− :: Aliased (TableExpression params schema) right
208+ -- :: Aliased (TableExpression params schema) right
207− -> Expression params '[left,right] ('NotNull 'PGBool)
209+ -- -> Expression params '[left,right] ('Required ('NotNull 'PGBool))
208− -> JoinExpression params schema (left : tables)
210+ -- -> JoinExpression params schema (left : tables)
209− -> JoinExpression params schema
211+ -- -> JoinExpression params schema
210− (NullifyTable right ': NullifyTable left ': tables)
212+ -- (NullifyTable right ': NullifyTable left ': tables)
212renderJoinExpression :: JoinExpression params schema tables -> ByteString
214renderJoinExpression :: JoinExpression params schema tables -> ByteString
213renderJoinExpression = \case
215renderJoinExpression = \case
@@ -225,27 +227,27 @@ renderJoinExpression = \case
226 , renderExpression on
228 , renderExpression on
228− LeftOuter table on tables -> mconcat
230+ -- LeftOuter table on tables -> mconcat
229− [ renderJoinExpression tables
231+ -- [ renderJoinExpression tables
230− , " LEFT OUTER JOIN "
232+ -- , " LEFT OUTER JOIN "
231− , renderAliased renderTableExpression table
233+ -- , renderAliased renderTableExpression table
232− , " ON "
234+ -- , " ON "
233− , renderExpression on
235+ -- , renderExpression on
235− RightOuter table on tables -> mconcat
237+ -- RightOuter table on tables -> mconcat
236− [ renderJoinExpression tables
238+ -- [ renderJoinExpression tables
237− , " RIGHT OUTER JOIN "
239+ -- , " RIGHT OUTER JOIN "
238− , renderAliased renderTableExpression table
240+ -- , renderAliased renderTableExpression table
239− , " ON "
241+ -- , " ON "
240− , renderExpression on
242+ -- , renderExpression on
242− FullOuter table on tables -> mconcat
244+ -- FullOuter table on tables -> mconcat
243− [ renderJoinExpression tables
245+ -- [ renderJoinExpression tables
244− , " FULL OUTER JOIN "
246+ -- , " FULL OUTER JOIN "
245− , renderAliased renderTableExpression table
247+ -- , renderAliased renderTableExpression table
246− , " ON "
248+ -- , " ON "
247− , renderExpression on
249+ -- , renderExpression on
250class KnownSymbol table => HasTable table tables columns
252class KnownSymbol table => HasTable table tables columns
251 | table tables -> columns where
253 | table tables -> columns where
@@ -266,9 +268,9 @@ instance HasTable table schema columns
266 fromLabel p = Table $ fromLabel p
268 fromLabel p = Table $ fromLabel p
268data Clauses params tables = Clauses
270data Clauses params tables = Clauses
269− { whereClause :: Maybe (Expression params tables ('NotNull 'PGBool))
271+ { whereClause :: Maybe (Expression params tables ('Required ('NotNull 'PGBool)))
270− , limitClause :: Maybe (Expression params '[] ('NotNull 'PGInt8))
272+ , limitClause :: Maybe (Expression params '[] ('Required ('NotNull 'PGInt8)))
271− , offsetClause :: Maybe (Expression params '[] ('NotNull 'PGInt8))
273+ , offsetClause :: Maybe (Expression params '[] ('Required ('NotNull 'PGInt8)))
274instance Monoid (Clauses params tables) where
276instance Monoid (Clauses params tables) where
@@ -292,9 +294,9 @@ instance Monoid (Clauses params tables) where
294data FromExpression
296data FromExpression
295− (params :: [NullityType])
297+ (params :: [ColumnType])
296− (schema :: [(Symbol,[(Symbol,NullityType)])])
298+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
297− (tables :: [(Symbol,[(Symbol,NullityType)])])
299+ (tables :: [(Symbol,[(Symbol,ColumnType)])])
298 = FromExpression
300 = FromExpression
299 { joinExpression :: JoinExpression params schema tables
301 { joinExpression :: JoinExpression params schema tables
300 , clauses :: Clauses params tables
302 , clauses :: Clauses params tables
@@ -318,30 +320,30 @@ instance (HasTable table schema columns, table ~ table')
318 fromLabel p = FromExpression (fromLabel p) mempty
320 fromLabel p = FromExpression (fromLabel p) mempty
321− :: Expression params tables ('NotNull 'PGBool)
323+ :: Expression params tables ('Required ('NotNull 'PGBool))
322 -> FromExpression params schema tables
324 -> FromExpression params schema tables
323 -> FromExpression params schema tables
325 -> FromExpression params schema tables
324where_ wh (FromExpression tabs clauses1) = FromExpression tabs
326where_ wh (FromExpression tabs clauses1) = FromExpression tabs
325 (clauses1 <> Clauses (Just wh) Nothing Nothing)
327 (clauses1 <> Clauses (Just wh) Nothing Nothing)
328− :: Expression params '[] ('NotNull 'PGInt8)
330+ :: Expression params '[] ('Required ('NotNull 'PGInt8))
329 -> FromExpression params schema tables
331 -> FromExpression params schema tables
330 -> FromExpression params schema tables
332 -> FromExpression params schema tables
331limit lim (FromExpression tabs clauses1) = FromExpression tabs
333limit lim (FromExpression tabs clauses1) = FromExpression tabs
332 (clauses1 <> Clauses Nothing (Just lim) Nothing)
334 (clauses1 <> Clauses Nothing (Just lim) Nothing)
335− :: Expression params '[] ('NotNull 'PGInt8)
337+ :: Expression params '[] ('Required ('NotNull 'PGInt8))
336 -> FromExpression params schema tables
338 -> FromExpression params schema tables
337 -> FromExpression params schema tables
339 -> FromExpression params schema tables
338offset off (FromExpression tabs clauses1) = FromExpression tabs
340offset off (FromExpression tabs clauses1) = FromExpression tabs
339 (clauses1 <> Clauses Nothing Nothing (Just off))
341 (clauses1 <> Clauses Nothing Nothing (Just off))
341newtype Selection
343newtype Selection
342− (params :: [NullityType])
344+ (params :: [ColumnType])
343− (schema :: [(Symbol,[(Symbol,NullityType)])])
345+ (schema :: [(Symbol,[(Symbol,ColumnType)])])
344− (columns :: [(Symbol,NullityType)])
346+ (columns :: [(Symbol,ColumnType)])
345 = UnsafeSelection { renderSelection :: ByteString }
347 = UnsafeSelection { renderSelection :: ByteString }
@@ -371,24 +373,22 @@ list `from` tabs = UnsafeSelection $
371 . rmap (Const . renderAliased renderExpression)
373 . rmap (Const . renderAliased renderExpression)
373newtype Statement
375newtype Statement
374− (params :: [NullityType])
376+ (params :: [ColumnType])
375− (columns :: [(Symbol,NullityType)])
377+ (columns :: [(Symbol,ColumnType)])
376− (schema0 :: [(Symbol,[(Symbol,NullityType)])])
378+ (schema0 :: [(Symbol,[(Symbol,ColumnType)])])
377− (schema1 :: [(Symbol,[(Symbol,NullityType)])])
379+ (schema1 :: [(Symbol,[(Symbol,ColumnType)])])
378 = UnsafeStatement { renderStatement :: ByteString }
380 = UnsafeStatement { renderStatement :: ByteString }
380−(&>>)
382+instance Category (Statement '[] '[]) where
381− :: Statement '[] '[] schema0 schema1
383+ id = UnsafeStatement ""
382− -> Statement '[] '[] schema1 schema2
383− -> Statement '[] '[] schema0 schema2
384−statement1 &>> statement2 = UnsafeStatement $
384+ statement2 . statement1 = UnsafeStatement $
385− renderStatement statement1 <> " " <> renderStatement statement2
385+ renderStatement statement1 <> " " <> renderStatement statement2
387newtype PreparedStatement
387newtype PreparedStatement
388− (params :: [NullityType])
388+ (params :: [ColumnType])
389− (columns :: [(Symbol,NullityType)])
389+ (columns :: [(Symbol,ColumnType)])
390− (schema0 :: [(Symbol,[(Symbol,NullityType)])])
390+ (schema0 :: [(Symbol,[(Symbol,ColumnType)])])
391− (schema1 :: [(Symbol,[(Symbol,NullityType)])])
391+ (schema1 :: [(Symbol,[(Symbol,ColumnType)])])
392 = UnsafePreparedStatement { renderPreparedStatement :: ByteString }
392 = UnsafePreparedStatement { renderPreparedStatement :: ByteString }
@@ -423,19 +423,6 @@ insertInto (Alias table) expressions = UnsafeStatement $ "INSERT INTO "
423 (\ (expression `As` _) -> Const (renderExpression expression))
423 (\ (expression `As` _) -> Const (renderExpression expression))
424 expressions
424 expressions
427− :: (KnownSymbol table, KnownColumns columns)
430− -> Statement '[] '[] schema ((table ::: columns) ': schema)
431−createTable (Alias table) columns = UnsafeStatement $ mconcat
433− , fromString $ symbolVal' table
435− , renderColumns columns
439class KnownSymbol table => DropTable table schema0 schema1
426class KnownSymbol table => DropTable table schema0 schema1
440 | table schema0 -> schema1 where
427 | table schema0 -> schema1 where
441 dropTable :: Alias table -> Statement '[] '[] schema0 schema1
428 dropTable :: Alias table -> Statement '[] '[] schema0 schema1
@@ -458,7 +445,7 @@ update
458 :: HasTable table schema columns
445 :: HasTable table schema columns
459 => Alias table
446 => Alias table
460 -> Rec (Aliased (Maybe `Compose` Expression params '[table ::: columns])) columns
447 -> Rec (Aliased (Maybe `Compose` Expression params '[table ::: columns])) columns
461− -> Expression params '[table ::: columns] ('NotNull 'PGBool)
448+ -> Expression params '[table ::: columns] ('Required ('NotNull 'PGBool))
462 -> Statement params '[] schema schema
449 -> Statement params '[] schema schema
463update (Alias table) columns where' = UnsafeStatement $ mconcat
450update (Alias table) columns where' = UnsafeStatement $ mconcat
464 [ "UPDATE "
451 [ "UPDATE "
@@ -478,3 +465,51 @@ update (Alias table) columns where' = UnsafeStatement $ mconcat
478 , renderExpression expression
465 , renderExpression expression
480 Compose Nothing `As` _ -> Nothing
467 Compose Nothing `As` _ -> Nothing
470+{-----------------------------------------
472+-----------------------------------------}
474+newtype TypeExpression (ty :: ColumnType)
475+ = UnsafeTypeExpression { renderTypeExpression :: ByteString }
476+int2 :: TypeExpression ('Required ('Null 'PGInt2))
477+int2 = UnsafeTypeExpression "int2"
478+int4 :: TypeExpression ('Required ('Null 'PGInt4))
479+int4 = UnsafeTypeExpression "int4"
480+int8 :: TypeExpression ('Required ('Null 'PGInt8))
481+int8 = UnsafeTypeExpression "int8"
482+bool :: TypeExpression ('Required ('Null 'PGBool))
483+bool = UnsafeTypeExpression "bool"
484+text :: TypeExpression ('Required ('Null 'PGText))
485+text = UnsafeTypeExpression "text"
487+ :: TypeExpression ('Required ('Null ty))
488+ -> TypeExpression ('Required ('NotNull ty))
489+notNull ty = UnsafeTypeExpression $ renderTypeExpression ty <> " NOT NULL"
491+ :: Expression '[] '[] ('Required ty)
492+ -> TypeExpression ('Required ty)
493+ -> TypeExpression ('Optional ty)
494+default_ x ty = UnsafeTypeExpression $
495+ renderTypeExpression ty <> " DEFAULT " <> renderExpression x
496+serial :: TypeExpression ('Optional ('NotNull 'PGInt4))
497+serial = UnsafeTypeExpression "serial"
500+ :: KnownSymbol table
502+ -> Rec (Aliased TypeExpression) columns
503+ -> Statement '[] '[] schema ((table ::: columns) ': schema)
504+createTable (Alias table) columns = UnsafeStatement $ mconcat
506+ , fromString $ symbolVal' table
508+ , ByteString.intercalate ", " . recordToList $
509+ rmap (Const . renderColumn) columns
513+ renderColumn :: Aliased TypeExpression x -> ByteString
514+ renderColumn (ty `As` Alias column) =
515+ fromString (symbolVal' column) <> " " <> renderTypeExpression ty