on dev help sign in
docs & finalize FromClause
commitb17b787cf0324e1ea2921ded86b44ae04e788654 authorEitan Chatav <eitan.chatav@gmail.com> dateSat 24 Feb 2018, 12:03 (9 years ago) parentf9b7581
7 files changed+184−131
squeal-postgresql/exe/Example.hs+2−2 squeal-postgresql/squeal-postgresql.cabal+1 squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+25−12 squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs+3 squeal-postgresql/src/Squeal/PostgreSQL/Manipulation.hs+40−29 squeal-postgresql/src/Squeal/PostgreSQL/Query.hs+108−88 squeal-postgresql/src/Squeal/PostgreSQL/Schema.hs+5
squeal-postgresql/exe/Example.hs+2−2
@@ -79,8 +79,8 @@ getUsers :: Query Schema '[]
7979 , "userVec" ::: 'NotNull ('PGarray 'PGint2)]
8080getUsers = select
8181 (#u ! #name `As` #userName :* #e ! #email `As` #userEmail :* #u ! #vec `As` #userVec :* Nil)
82− ( from (Table (#users `As` #u)
83− & InnerJoin (Table (#emails `As` #e))
82+ ( from (table (#users `As` #u)
83+ & innerJoin (table (#emails `As` #e))
8484 (#u ! #id .== #e ! #user_id)) )
8585
8686data User = User { userName :: Text, userEmail :: Maybe Text, userVec :: Vector (Maybe Int16) }
squeal-postgresql/squeal-postgresql.cabal+1
@@ -76,3 +76,4 @@ executable squeal-postgresql-example
7676 , text >= 1.2.2.2 && < 2
7777 , transformers >= 0.5.2.0 && < 1
7878 , transformers-base >= 0.4.4 && < 1
79+ , vector
squeal-postgresql/src/Squeal/PostgreSQL/Definition.hs+25−12
@@ -160,18 +160,6 @@ newtype TableConstraintExpression
160160 { renderTableConstraintExpression :: ByteString }
161161 deriving (GHC.Generic,Show,Eq,Ord,NFData)
162162
163−data Column
164− (columns :: ColumnsType)
165− (column :: (Symbol,ColumnType))
166− where
167− Column
168− :: Has column columns ty
169− => Alias column
170− -> Column columns (column ::: ty)
171−
172−renderColumn :: Column columns column -> ByteString
173−renderColumn (Column column) = renderAlias column
174−
175163-- | A `check` constraint is the most generic `TableConstraint` type.
176164-- It allows you to specify that the value in a certain column must satisfy
177165-- a Boolean (truth-value) expression.
@@ -191,6 +179,20 @@ check
191179check condition = UnsafeTableConstraintExpression $
192180 "CHECK" <+> parenthesized (renderExpression condition)
193181
182+-- | @Column columns column@ is a witness that `column` is in `columns`.
183+data Column
184+ (columns :: ColumnsType)
185+ (column :: (Symbol,ColumnType))
186+ where
187+ Column
188+ :: Has column columns ty
189+ => Alias column
190+ -> Column columns (column ::: ty)
191+
192+-- | Render a `Column`.
193+renderColumn :: Column columns column -> ByteString
194+renderColumn (Column column) = renderAlias column
195+
194196-- | A `unique` constraint ensure that the data contained in a column,
195197-- or a group of columns, is unique among all the rows in the table.
196198--
@@ -400,6 +402,17 @@ addConstraint constraintName constraint = UnsafeAlterTable $
400402 "ADD" <+> "CONSTRAINT" <+> renderAlias constraintName
401403 <+> renderTableConstraintExpression constraint
402404
405+-- | A `dropConstraint` drops a table constraint.
406+--
407+-- >>> :{
408+-- let
409+-- definition :: Definition
410+-- '["tab" ::: '["positive" ::: Check ] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4]]
411+-- '["tab" ::: '[] :=> '["col" ::: 'NoDef :=> 'NotNull 'PGint4]]
412+-- definition = alterTable #tab (dropConstraint #positive)
413+-- in renderDefinition definition
414+-- :}
415+-- "ALTER TABLE tab DROP CONSTRAINT positive;"
403416dropConstraint
404417 :: KnownSymbol constraintName
405418 => Alias constraintName
squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs+3
@@ -344,8 +344,11 @@ nullIf
344344nullIf x y = UnsafeExpression $ "NULL IF" <+> parenthesized
345345 (renderExpression x <> ", " <> renderExpression y)
346346
347+-- | >>> renderExpression $ array [null_, unNull false, unNull true]
348+-- "ARRAY[NULL, FALSE, TRUE]"
347349array
348350 :: [Expression tables grouping params ('Null ty)]
351+ -- ^ array elements
349352 -> Expression tables grouping params (nullity ('PGarray ty))
350353array xs = UnsafeExpression $
351354 "ARRAY[" <> commaSeparated (renderExpression <$> xs) <> "]"
squeal-postgresql/src/Squeal/PostgreSQL/Manipulation.hs+40−29
@@ -133,27 +133,6 @@ in renderManipulation manipulation
133133:}
134134"INSERT INTO tab (col1, col2) VALUES (2, DEFAULT) RETURNING col1 AS fromOnly;"
135135
136−query insert:
137−
138−>>> :{
139−let
140− manipulation :: Manipulation
141− '[ "tab" ::: '[] :=>
142− '[ "col1" ::: 'NoDef :=> 'NotNull 'PGint4
143− , "col2" ::: 'NoDef :=> 'NotNull 'PGint4
144− ]
145− , "other_tab" ::: '[] :=>
146− '[ "col1" ::: 'NoDef :=> 'NotNull 'PGint4
147− , "col2" ::: 'NoDef :=> 'NotNull 'PGint4
148− ]
149− ] '[] '[]
150− manipulation =
151− insertQuery_ #tab
152− (selectStar (from (Table (#other_tab `As` #t))))
153−in renderManipulation manipulation
154−:}
155−"INSERT INTO tab SELECT * FROM other_tab AS t;"
156−
157136upsert:
158137
159138>>> :{
@@ -204,6 +183,7 @@ insertRows tab row rows conflict returning = UnsafeManipulation $
204183 Default -> "DEFAULT"
205184 Set expression -> renderExpression expression
206185
186+-- | Insert a single row.
207187insertRow
208188 :: ( SOP.SListI columns
209189 , SOP.SListI results
@@ -217,6 +197,7 @@ insertRow
217197 -> Manipulation schema params results
218198insertRow tab row = insertRows tab row []
219199
200+-- | Insert multiple rows returning `Nil` and raising an error on conflicts.
220201insertRows_
221202 :: ( SOP.SListI columns
222203 , Has tab schema table
@@ -228,6 +209,7 @@ insertRows_
228209insertRows_ tab row rows =
229210 insertRows tab row rows OnConflictDoRaise (Returning Nil)
230211
212+-- | Insert a single row returning `Nil` and raising an error on conflicts.
231213insertRow_
232214 :: ( SOP.SListI columns
233215 , Has tab schema table
@@ -237,6 +219,27 @@ insertRow_
237219 -> Manipulation schema params '[]
238220insertRow_ tab row = insertRow tab row OnConflictDoRaise (Returning Nil)
239221
222+{- | Insert a query.
223+
224+>>> :{
225+let
226+ manipulation :: Manipulation
227+ '[ "tab" ::: '[] :=>
228+ '[ "col1" ::: 'NoDef :=> 'NotNull 'PGint4
229+ , "col2" ::: 'NoDef :=> 'NotNull 'PGint4
230+ ]
231+ , "other_tab" ::: '[] :=>
232+ '[ "col1" ::: 'NoDef :=> 'NotNull 'PGint4
233+ , "col2" ::: 'NoDef :=> 'NotNull 'PGint4
234+ ]
235+ ] '[] '[]
236+ manipulation =
237+ insertQuery_ #tab
238+ (selectStar (from (table (#other_tab `As` #t))))
239+in renderManipulation manipulation
240+:}
241+"INSERT INTO tab SELECT * FROM other_tab AS t;"
242+-}
240243insertQuery
241244 :: ( SOP.SListI columns
242245 , SOP.SListI results
@@ -254,6 +257,7 @@ insertQuery tab query conflict returning = UnsafeManipulation $
254257 <> renderConflictClause conflict
255258 <> renderReturningClause returning
256259
260+-- | Insert a query returning `Nil` and raising an error on conflicts.
257261insertQuery_
258262 :: ( SOP.SListI columns
259263 , Has tab schema table
@@ -264,6 +268,11 @@ insertQuery_
264268insertQuery_ tab query =
265269 insertQuery tab query OnConflictDoRaise (Returning Nil)
266270
271+-- | `ColumnValue`s are values to insert or update in a row
272+-- `Same` updates with the same value.
273+-- `Default` inserts or updates with the @DEFAULT@ value
274+-- `Set` a value to be an `Expression`, relative to the given
275+-- row for an update, and closed for an insert.
267276data ColumnValue
268277 (columns :: RelationType)
269278 (params :: [NullityType])
@@ -351,6 +360,9 @@ renderConflictClause = \case
351360UPDATE statements
352361-----------------------------------------}
353362
363+-- | An `update` command changes the values of the specified columns
364+-- in all rows that satisfy the condition.
365+--
354366update
355367 :: ( SOP.SListI columns
356368 , SOP.SListI results
@@ -363,9 +375,9 @@ update
363375 -- ^ condition under which to perform update on a row
364376 -> ReturningClause columns params results -- ^ results to return
365377 -> Manipulation schema params results
366−update table columns wh returning = UnsafeManipulation $
378+update tab columns wh returning = UnsafeManipulation $
367379 "UPDATE"
368− <+> renderAlias table
380+ <+> renderAlias tab
369381 <+> "SET"
370382 <+> renderCommaSeparatedMaybe renderUpdate columns
371383 <+> "WHERE" <+> renderExpression wh
@@ -381,9 +393,7 @@ update table columns wh returning = UnsafeManipulation $
381393 Set expression `As` column -> Just $
382394 renderAlias column <+> "=" <+> renderExpression expression
383395
384−-- | An `update` command changes the values of the specified columns
385−-- in all rows that satisfy the condition.
386−--
396+-- | Update a row returning `Nil`.
387397-- >>> :{
388398-- let
389399-- manipulation :: Manipulation
@@ -406,7 +416,7 @@ update_
406416 -> Condition '[tab ::: ColumnsToRelation columns] 'Ungrouped params
407417 -- ^ condition under which to perform update on a row
408418 -> Manipulation schema params '[]
409−update_ table columns wh = update table columns wh (Returning Nil)
419+update_ tab columns wh = update tab columns wh (Returning Nil)
410420
411421{-----------------------------------------
412422DELETE statements
@@ -435,11 +445,12 @@ deleteFrom
435445 -- ^ condition under which to delete a row
436446 -> ReturningClause columns params results -- ^ results to return
437447 -> Manipulation schema params results
438−deleteFrom table wh returning = UnsafeManipulation $
439− "DELETE FROM" <+> renderAlias table
448+deleteFrom tab wh returning = UnsafeManipulation $
449+ "DELETE FROM" <+> renderAlias tab
440450 <+> "WHERE" <+> renderExpression wh
441451 <> renderReturningClause returning
442452
453+-- | Delete rows returning `Nil`.
443454deleteFrom_
444455 :: ( Has tab schema table
445456 , columns ~ TableToColumns table )
squeal-postgresql/src/Squeal/PostgreSQL/Query.hs+108−88
@@ -56,7 +56,13 @@ module Squeal.PostgreSQL.Query
5656 , offset
5757 -- * From
5858 , FromClause (..)
59− , renderFromClause
59+ , table
60+ , subquery
61+ , crossJoin
62+ , innerJoin
63+ , leftOuterJoin
64+ , rightOuterJoin
65+ , fullOuterJoin
6066 -- * Grouping
6167 , By (By, By2)
6268 , renderBy
@@ -97,7 +103,7 @@ let
97103 '["tab" ::: '[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4]]
98104 '[]
99105 '["col" ::: 'Null 'PGint4]
100− query = selectStar (from (Table (#tab `As` #t)))
106+ query = selectStar (from (table (#tab `As` #t)))
101107in renderQuery query
102108:}
103109"SELECT * FROM tab AS t"
@@ -116,7 +122,7 @@ let
116122 query =
117123 select
118124 ((#col1 + #col2) `As` #sum :* #col1 `As` #col1 :* Nil)
119− ( from (Table (#tab `As` #t))
125+ ( from (table (#tab `As` #t))
120126 & where_ (#col1 .> #col2)
121127 & where_ (#col2 .> 0) )
122128in renderQuery query
@@ -133,7 +139,7 @@ let
133139 '["col" ::: 'Null 'PGint4]
134140 query =
135141 selectStar
136− (from (Subquery (selectStar (from (Table (#tab `As` #t))) `As` #sub)))
142+ (from (subquery (selectStar (from (table (#tab `As` #t))) `As` #sub)))
137143in renderQuery query
138144:}
139145"SELECT * FROM (SELECT * FROM tab AS t) AS sub"
@@ -147,7 +153,7 @@ let
147153 '[]
148154 '["col" ::: 'Null 'PGint4]
149155 query = selectStar
150− (from (Table (#tab `As` #t)) & limit 100 & offset 2 & limit 50 & offset 2)
156+ (from (table (#tab `As` #t)) & limit 100 & offset 2 & limit 50 & offset 2)
151157in renderQuery query
152158:}
153159"SELECT * FROM tab AS t LIMIT 50 OFFSET 4"
@@ -161,7 +167,7 @@ let
161167 '[ 'NotNull 'PGfloat8]
162168 '["col" ::: 'NotNull 'PGfloat8]
163169 query = selectStar
164− (from (Table (#tab `As` #t)) & where_ (#col .> param @1))
170+ (from (table (#tab `As` #t)) & where_ (#col .> param @1))
165171in renderQuery query
166172:}
167173"SELECT * FROM tab AS t WHERE (col > ($1 :: float8))"
@@ -179,7 +185,7 @@ let
179185 , "col1" ::: 'NotNull 'PGint4 ]
180186 query =
181187 select (sum_ #col2 `As` #sum :* #col1 `As` #col1 :* Nil)
182− ( from (Table (#tab `As` #table1))
188+ ( from (table (#tab `As` #table1))
183189 & group (By #col1 :* Nil)
184190 & having (#col1 + sum_ #col2 .> 1) )
185191in renderQuery query
@@ -195,7 +201,7 @@ let
195201 '[]
196202 '["col" ::: 'Null 'PGint4]
197203 query = selectStar
198− (from (Table (#tab `As` #t)) & orderBy [#col & AscNullsFirst])
204+ (from (table (#tab `As` #t)) & orderBy [#col & AscNullsFirst])
199205in renderQuery query
200206:}
201207"SELECT * FROM tab AS t ORDER BY col ASC NULLS FIRST"
@@ -235,10 +241,10 @@ let
235241 ( #o ! #price `As` #order_price :*
236242 #c ! #name `As` #customer_name :*
237243 #s ! #name `As` #shipper_name :* Nil )
238− ( from (Table (#orders `As` #o)
239− & InnerJoin (Table (#customers `As` #c))
244+ ( from (table (#orders `As` #o)
245+ & innerJoin (table (#customers `As` #c))
240246 (#o ! #customer_id .== #c ! #id)
241− & InnerJoin (Table (#shippers `As` #s))
247+ & innerJoin (table (#shippers `As` #s))
242248 (#o ! #shipper_id .== #s ! #id)) )
243249in renderQuery query
244250:}
@@ -253,7 +259,7 @@ let
253259 '[]
254260 '["col" ::: 'Null 'PGint4]
255261 query = selectDotStar #t1
256− (from (Table (#tab `As` #t1) & CrossJoin (Table (#tab `As` #t2))))
262+ (from (table (#tab `As` #t1) & crossJoin (table (#tab `As` #t2))))
257263in renderQuery query
258264:}
259265"SELECT t1.* FROM tab AS t1 CROSS JOIN tab AS t2"
@@ -267,14 +273,13 @@ let
267273 '[]
268274 '["col" ::: 'Null 'PGint4]
269275 query =
270− selectStar (from (Table (#tab `As` #t)))
276+ selectStar (from (table (#tab `As` #t)))
271277 `unionAll`
272− selectStar (from (Table (#tab `As` #t)))
278+ selectStar (from (table (#tab `As` #t)))
273279in renderQuery query
274280:}
275281"(SELECT * FROM tab AS t) UNION ALL (SELECT * FROM tab AS t)"
276282-}
277−
278283newtype Query
279284 (schema :: TablesType)
280285 (params :: [NullityType])
@@ -411,8 +416,8 @@ selectDotStar
411416 -> TableExpression schema params tables 'Ungrouped
412417 -- ^ intermediate virtual table
413418 -> Query schema params columns
414−selectDotStar table tables = UnsafeQuery $
415− "SELECT" <+> renderAlias table <> ".*" <+> renderTableExpression tables
419+selectDotStar tab tables = UnsafeQuery $
420+ "SELECT" <+> renderAlias tab <> ".*" <+> renderTableExpression tables
416421
417422-- | A `selectDistinctDotStar` asks for all the columns of a particular table,
418423-- and eliminates duplicate rows.
@@ -423,8 +428,8 @@ selectDistinctDotStar
423428 -> TableExpression schema params tables 'Ungrouped
424429 -- ^ intermediate virtual table
425430 -> Query schema params columns
426−selectDistinctDotStar table tables = UnsafeQuery $
427− "SELECT DISTINCT" <+> renderAlias table <> ".*"
431+selectDistinctDotStar tab tables = UnsafeQuery $
432+ "SELECT DISTINCT" <+> renderAlias tab <> ".*"
428433 <+> renderTableExpression tables
429434
430435{-----------------------------------------
@@ -590,93 +595,108 @@ FROM clauses
590595{- |
591596A `FromClause` can be a table name, or a derived table such
592597as a subquery, a @JOIN@ construct, or complex combinations of these.
593−
594−* A real `Table` is a table from the schema.
595−
596−* `Subquery` derives a table from a `Query`.
597−
598−* A joined table is a table derived from two other (real or derived) tables
599−according to the rules of the particular join type. `CrossJoin`, `InnerJoin`,
600−`LeftOuterJoin`, `RightOuterJoin` and `FullOuterJoin` are available and can
601−be nested using the `&` operator to match the left-to-right sequencing of
602−their placement in SQL.
603−
604− * @t1 & CrossJoin t2@. For every possible combination of rows from
598+-}
599+newtype FromClause schema params tables
600+ = UnsafeFromClause { renderFromClause :: ByteString }
601+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
602+
603+-- | A real `table` is a table from the schema.
604+table
605+ :: Aliased (Table schema) table
606+ -> FromClause schema params '[table]
607+table = UnsafeFromClause . renderAliasedAs renderTable
608+
609+-- | `subquery` derives a table from a `Query`.
610+subquery
611+ :: Aliased (Query schema params) table
612+ -> FromClause schema params '[table]
613+subquery = UnsafeFromClause . renderAliasedAs (parenthesized . renderQuery)
614+
615+{- | @t1 & crossJoin t2@. For every possible combination of rows from
605616 @t1@ and @t2@ (i.e., a Cartesian product), the joined table will contain
606617 a row consisting of all columns in @t1@ followed by all columns in @t2@.
607618 If the tables have @n@ and @m@ rows respectively, the joined table will
608619 have @n * m@ rows.
609−
610− * @t1 & InnerJoin t2 on@. For each row @r1@ of @t1@, the joined
620+-}
621+crossJoin
622+ :: FromClause schema params right
623+ -- ^ right
624+ -> FromClause schema params left
625+ -- ^ left
626+ -> FromClause schema params (Join left right)
627+crossJoin right left = UnsafeFromClause $
628+ renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
629+
630+{- | @t1 & InnerJoin t2 on@. For each row @r1@ of @t1@, the joined
611631 table has a row for each row in @t2@ that satisfies the @on@ condition
612632 with @r1@
613−
614− * @t1 & LeftOuterJoin t2 on@. First, an inner join is performed.
633+-}
634+innerJoin
635+ :: FromClause schema params right
636+ -- ^ right
637+ -> Condition (Join left right) 'Ungrouped params
638+ -- ^ @ON@ condition
639+ -> FromClause schema params left
640+ -- ^ left
641+ -> FromClause schema params (Join left right)
642+innerJoin right on left = UnsafeFromClause $
643+ renderFromClause left <+> "INNER JOIN" <+> renderFromClause right
644+ <+> "ON" <+> renderExpression on
645+
646+{- | @t1 & LeftOuterJoin t2 on@. First, an inner join is performed.
615647 Then, for each row in @t1@ that does not satisfy the @on@ condition with
616648 any row in @t2@, a joined row is added with null values in columns of @t2@.
617649 Thus, the joined table always has at least one row for each row in @t1@.
618−
619− * @t1 & RightOuterJoin t2 on@. First, an inner join is performed.
650+-}
651+leftOuterJoin
652+ :: FromClause schema params right
653+ -- ^ right
654+ -> Condition (Join left right) 'Ungrouped params
655+ -- ^ @ON@ condition
656+ -> FromClause schema params left
657+ -- ^ left
658+ -> FromClause schema params (Join left (NullifyTables right))
659+leftOuterJoin right on left = UnsafeFromClause $
660+ renderFromClause left <+> "LEFT OUTER JOIN" <+> renderFromClause right
661+ <+> "ON" <+> renderExpression on
662+
663+{- | @t1 & RightOuterJoin t2 on@. First, an inner join is performed.
620664 Then, for each row in @t2@ that does not satisfy the @on@ condition with
621665 any row in @t1@, a joined row is added with null values in columns of @t1@.
622666 This is the converse of a left join: the result table will always
623667 have a row for each row in @t2@.
624−
625− * @t1 & FullOuterJoin t2 on@. First, an inner join is performed.
668+-}
669+rightOuterJoin
670+ :: FromClause schema params right
671+ -- ^ right
672+ -> Condition (Join left right) 'Ungrouped params
673+ -- ^ @ON@ condition
674+ -> FromClause schema params left
675+ -- ^ left
676+ -> FromClause schema params (Join (NullifyTables left) right)
677+rightOuterJoin right on left = UnsafeFromClause $
678+ renderFromClause left <+> "RIGHT OUTER JOIN" <+> renderFromClause right
679+ <+> "ON" <+> renderExpression on
680+
681+{- | @t1 & FullOuterJoin t2 on@. First, an inner join is performed.
626682 Then, for each row in @t1@ that does not satisfy the @on@ condition with
627683 any row in @t2@, a joined row is added with null values in columns of @t2@.
628684 Also, for each row of @t2@ that does not satisfy the join condition
629685 with any row in @t1@, a joined row with null values in the columns of @t1@
630686 is added.
631687-}
632−data FromClause schema params tables where
633− Table
634− :: Aliased (Table schema) table
635− -> FromClause schema params '[table]
636− Subquery
637− :: Aliased (Query schema params) table
638− -> FromClause schema params '[table]
639− CrossJoin
640− :: FromClause schema params right
641− -> FromClause schema params left
642− -> FromClause schema params (Join left right)
643− InnerJoin
644− :: FromClause schema params right
645− -> Condition (Join left right) 'Ungrouped params
646− -> FromClause schema params left
647− -> FromClause schema params (Join left right)
648− LeftOuterJoin
649− :: FromClause schema params right
650− -> Condition (Join left right) 'Ungrouped params
651− -> FromClause schema params left
652− -> FromClause schema params (Join left (NullifyTables right))
653− RightOuterJoin
654− :: FromClause schema params right
655− -> Condition (Join left right) 'Ungrouped params
656− -> FromClause schema params left
657− -> FromClause schema params (Join (NullifyTables left) right)
658− FullOuterJoin
659− :: FromClause schema params right
660− -> Condition (Join left right) 'Ungrouped params
661− -> FromClause schema params left
662− -> FromClause schema params
663− (Join (NullifyTables left) (NullifyTables right))
664−
665−-- | Renders a `FromClause`.
666−renderFromClause :: FromClause schema params tables -> ByteString
667−renderFromClause = \case
668− Table table -> renderAliasedAs renderTable table
669− Subquery selection -> renderAliasedAs (parenthesized . renderQuery) selection
670− CrossJoin right left ->
671− renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
672− InnerJoin right on left -> renderJoin "INNER JOIN" right on left
673− LeftOuterJoin right on left -> renderJoin "LEFT OUTER JOIN" right on left
674− RightOuterJoin right on left -> renderJoin "RIGHT OUTER JOIN" right on left
675− FullOuterJoin right on left -> renderJoin "FULL OUTER JOIN" right on left
676− where
677− renderJoin op right on left =
678− renderFromClause left <+> op <+> renderFromClause right
679− <+> "ON" <+> renderExpression on
688+fullOuterJoin
689+ :: FromClause schema params right
690+ -- ^ right
691+ -> Condition (Join left right) 'Ungrouped params
692+ -- ^ @ON@ condition
693+ -> FromClause schema params left
694+ -- ^ left
695+ -> FromClause schema params
696+ (Join (NullifyTables left) (NullifyTables right))
697+fullOuterJoin right on left = UnsafeFromClause $
698+ renderFromClause left <+> "FULL OUTER JOIN" <+> renderFromClause right
699+ <+> "ON" <+> renderExpression on
680700
681701{-----------------------------------------
682702Grouping
@@ -706,7 +726,7 @@ deriving instance Ord (By tables by)
706726renderBy :: By tables tabcolty -> ByteString
707727renderBy = \case
708728 By column -> renderAlias column
709− By2 (table, column) -> renderAlias table <> "." <> renderAlias column
729+ By2 (tab, column) -> renderAlias tab <> "." <> renderAlias column
710730
711731-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
712732-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
squeal-postgresql/src/Squeal/PostgreSQL/Schema.hs+5
@@ -126,6 +126,7 @@ data PGType
126126 | PGarrayN Nat PGType -- ^ fixed length array
127127 | UnsafePGType Symbol -- ^ an escape hatch for unsupported PostgreSQL types
128128
129+-- | The object identifier of a `PGType`.
129130class Oid (ty :: PGType) where oid :: proxy ty -> Word32
130131instance Oid 'PGbool where oid _ = 16
131132instance Oid 'PGint2 where oid _ = 21
@@ -372,9 +373,13 @@ type family Create alias x xs where
372373 Create alias x '[] = '[alias ::: x]
373374 Create alias y (x ': xs) = x ': Create alias y xs
374375
376+-- | Add a column to a `TableType` with
377+-- `Squeal.PostgreSQL.Definition.addColumn`.
375378type family AddColumn alias x y where
376379 AddColumn alias x (constraints :=> xs) = constraints :=> Create alias x xs
377380
381+-- | Add a constraint to a `TableType` with
382+-- `Squeal.PostgreSQL.Definition.addConstraint`.
378383type family AddConstraint alias x y where
379384 AddConstraint alias x (constraints :=> xs) = Create alias x constraints :=> xs
380385