@@ -56,7 +56,13 @@ module Squeal.PostgreSQL.Query
58 , FromClause (..)
58 , FromClause (..)
59− , renderFromClause
59+ , table
60 -- * Grouping
66 -- * Grouping
61 , By (By, By2)
67 , By (By, By2)
62 , renderBy
68 , renderBy
@@ -97,7 +103,7 @@ let
97 '["tab" ::: '[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4]]
103 '["tab" ::: '[] :=> '["col" ::: 'NoDef :=> 'Null 'PGint4]]
99 '["col" ::: 'Null 'PGint4]
105 '["col" ::: 'Null 'PGint4]
100− query = selectStar (from (Table (#tab `As` #t)))
106+ query = selectStar (from (table (#tab `As` #t)))
101in renderQuery query
107in renderQuery query
103"SELECT * FROM tab AS t"
109"SELECT * FROM tab AS t"
@@ -116,7 +122,7 @@ let
118 ((#col1 + #col2) `As` #sum :* #col1 `As` #col1 :* Nil)
124 ((#col1 + #col2) `As` #sum :* #col1 `As` #col1 :* Nil)
119− ( from (Table (#tab `As` #t))
125+ ( from (table (#tab `As` #t))
120 & where_ (#col1 .> #col2)
126 & where_ (#col1 .> #col2)
121 & where_ (#col2 .> 0) )
127 & where_ (#col2 .> 0) )
122in renderQuery query
128in renderQuery query
@@ -133,7 +139,7 @@ let
133 '["col" ::: 'Null 'PGint4]
139 '["col" ::: 'Null 'PGint4]
135 selectStar
141 selectStar
136− (from (Subquery (selectStar (from (Table (#tab `As` #t))) `As` #sub)))
142+ (from (subquery (selectStar (from (table (#tab `As` #t))) `As` #sub)))
137in renderQuery query
143in renderQuery query
139"SELECT * FROM (SELECT * FROM tab AS t) AS sub"
145"SELECT * FROM (SELECT * FROM tab AS t) AS sub"
@@ -147,7 +153,7 @@ let
148 '["col" ::: 'Null 'PGint4]
154 '["col" ::: 'Null 'PGint4]
149 query = selectStar
155 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)
151in renderQuery query
157in renderQuery query
153"SELECT * FROM tab AS t LIMIT 50 OFFSET 4"
159"SELECT * FROM tab AS t LIMIT 50 OFFSET 4"
@@ -161,7 +167,7 @@ let
161 '[ 'NotNull 'PGfloat8]
167 '[ 'NotNull 'PGfloat8]
162 '["col" ::: 'NotNull 'PGfloat8]
168 '["col" ::: 'NotNull 'PGfloat8]
163 query = selectStar
169 query = selectStar
164− (from (Table (#tab `As` #t)) & where_ (#col .> param @1))
170+ (from (table (#tab `As` #t)) & where_ (#col .> param @1))
165in renderQuery query
171in renderQuery query
167"SELECT * FROM tab AS t WHERE (col > ($1 :: float8))"
173"SELECT * FROM tab AS t WHERE (col > ($1 :: float8))"
@@ -179,7 +185,7 @@ let
179 , "col1" ::: 'NotNull 'PGint4 ]
185 , "col1" ::: 'NotNull 'PGint4 ]
181 select (sum_ #col2 `As` #sum :* #col1 `As` #col1 :* Nil)
187 select (sum_ #col2 `As` #sum :* #col1 `As` #col1 :* Nil)
182− ( from (Table (#tab `As` #table1))
188+ ( from (table (#tab `As` #table1))
183 & group (By #col1 :* Nil)
189 & group (By #col1 :* Nil)
184 & having (#col1 + sum_ #col2 .> 1) )
190 & having (#col1 + sum_ #col2 .> 1) )
185in renderQuery query
191in renderQuery query
@@ -195,7 +201,7 @@ let
196 '["col" ::: 'Null 'PGint4]
202 '["col" ::: 'Null 'PGint4]
197 query = selectStar
203 query = selectStar
198− (from (Table (#tab `As` #t)) & orderBy [#col & AscNullsFirst])
204+ (from (table (#tab `As` #t)) & orderBy [#col & AscNullsFirst])
199in renderQuery query
205in renderQuery query
201"SELECT * FROM tab AS t ORDER BY col ASC NULLS FIRST"
207"SELECT * FROM tab AS t ORDER BY col ASC NULLS FIRST"
@@ -235,10 +241,10 @@ let
235 ( #o ! #price `As` #order_price :*
241 ( #o ! #price `As` #order_price :*
236 #c ! #name `As` #customer_name :*
242 #c ! #name `As` #customer_name :*
237 #s ! #name `As` #shipper_name :* Nil )
243 #s ! #name `As` #shipper_name :* Nil )
238− ( from (Table (#orders `As` #o)
244+ ( from (table (#orders `As` #o)
239− & InnerJoin (Table (#customers `As` #c))
245+ & innerJoin (table (#customers `As` #c))
240 (#o ! #customer_id .== #c ! #id)
246 (#o ! #customer_id .== #c ! #id)
241− & InnerJoin (Table (#shippers `As` #s))
247+ & innerJoin (table (#shippers `As` #s))
242 (#o ! #shipper_id .== #s ! #id)) )
248 (#o ! #shipper_id .== #s ! #id)) )
243in renderQuery query
249in renderQuery query
@@ -253,7 +259,7 @@ let
254 '["col" ::: 'Null 'PGint4]
260 '["col" ::: 'Null 'PGint4]
255 query = selectDotStar #t1
261 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))))
257in renderQuery query
263in renderQuery query
259"SELECT t1.* FROM tab AS t1 CROSS JOIN tab AS t2"
265"SELECT t1.* FROM tab AS t1 CROSS JOIN tab AS t2"
@@ -267,14 +273,13 @@ let
268 '["col" ::: 'Null 'PGint4]
274 '["col" ::: 'Null 'PGint4]
270− selectStar (from (Table (#tab `As` #t)))
276+ selectStar (from (table (#tab `As` #t)))
271 `unionAll`
277 `unionAll`
272− selectStar (from (Table (#tab `As` #t)))
278+ selectStar (from (table (#tab `As` #t)))
273in renderQuery query
279in renderQuery query
275"(SELECT * FROM tab AS t) UNION ALL (SELECT * FROM tab AS t)"
281"(SELECT * FROM tab AS t) UNION ALL (SELECT * FROM tab AS t)"
278newtype Query
283newtype Query
279 (schema :: TablesType)
284 (schema :: TablesType)
280 (params :: [NullityType])
285 (params :: [NullityType])
@@ -411,8 +416,8 @@ selectDotStar
411 -> TableExpression schema params tables 'Ungrouped
416 -> TableExpression schema params tables 'Ungrouped
412 -- ^ intermediate virtual table
417 -- ^ intermediate virtual table
413 -> Query schema params columns
418 -> Query schema params columns
414−selectDotStar table tables = UnsafeQuery $
419+selectDotStar tab tables = UnsafeQuery $
415− "SELECT" <+> renderAlias table <> ".*" <+> renderTableExpression tables
420+ "SELECT" <+> renderAlias tab <> ".*" <+> renderTableExpression tables
417-- | A `selectDistinctDotStar` asks for all the columns of a particular table,
422-- | A `selectDistinctDotStar` asks for all the columns of a particular table,
418-- and eliminates duplicate rows.
423-- and eliminates duplicate rows.
@@ -423,8 +428,8 @@ selectDistinctDotStar
423 -> TableExpression schema params tables 'Ungrouped
428 -> TableExpression schema params tables 'Ungrouped
424 -- ^ intermediate virtual table
429 -- ^ intermediate virtual table
425 -> Query schema params columns
430 -> Query schema params columns
426−selectDistinctDotStar table tables = UnsafeQuery $
431+selectDistinctDotStar tab tables = UnsafeQuery $
427− "SELECT DISTINCT" <+> renderAlias table <> ".*"
432+ "SELECT DISTINCT" <+> renderAlias tab <> ".*"
428 <+> renderTableExpression tables
433 <+> renderTableExpression tables
430{-----------------------------------------
435{-----------------------------------------
@@ -590,93 +595,108 @@ FROM clauses
591A `FromClause` can be a table name, or a derived table such
596A `FromClause` can be a table name, or a derived table such
592as a subquery, a @JOIN@ construct, or complex combinations of these.
597as a subquery, a @JOIN@ construct, or complex combinations of these.
594−* A real `Table` is a table from the schema.
599+newtype FromClause schema params tables
595−
600+ = UnsafeFromClause { renderFromClause :: ByteString }
601+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
603+-- | A real `table` is a table from the schema.
605+ :: Aliased (Table schema) table
606+ -> FromClause schema params '[table]
607+table = UnsafeFromClause . renderAliasedAs renderTable
596−* `Subquery` derives a table from a `Query`.
609+-- | `subquery` derives a table from a `Query`.
598−* A joined table is a table derived from two other (real or derived) tables
611+ :: Aliased (Query schema params) table
599−according to the rules of the particular join type. `CrossJoin`, `InnerJoin`,
612+ -> FromClause schema params '[table]
600−`LeftOuterJoin`, `RightOuterJoin` and `FullOuterJoin` are available and can
613+subquery = UnsafeFromClause . renderAliasedAs (parenthesized . renderQuery)
601−be nested using the `&` operator to match the left-to-right sequencing of
614+
602−their placement in SQL.
604− * @t1 & CrossJoin t2@. For every possible combination of rows from
615+{- | @t1 & crossJoin t2@. For every possible combination of rows from
605 @t1@ and @t2@ (i.e., a Cartesian product), the joined table will contain
616 @t1@ and @t2@ (i.e., a Cartesian product), the joined table will contain
606 a row consisting of all columns in @t1@ followed by all columns in @t2@.
617 a row consisting of all columns in @t1@ followed by all columns in @t2@.
607 If the tables have @n@ and @m@ rows respectively, the joined table will
618 If the tables have @n@ and @m@ rows respectively, the joined table will
608 have @n * m@ rows.
619 have @n * m@ rows.
622+ :: FromClause schema params right
624+ -> FromClause schema params left
626+ -> FromClause schema params (Join left right)
627+crossJoin right left = UnsafeFromClause $
628+ renderFromClause left <+> "CROSS JOIN" <+> renderFromClause right
610− * @t1 & InnerJoin t2 on@. For each row @r1@ of @t1@, the joined
630+{- | @t1 & InnerJoin t2 on@. For each row @r1@ of @t1@, the joined
611 table has a row for each row in @t2@ that satisfies the @on@ condition
631 table has a row for each row in @t2@ that satisfies the @on@ condition
612 with @r1@
632 with @r1@
635+ :: FromClause schema params right
637+ -> Condition (Join left right) 'Ungrouped params
639+ -> FromClause schema params 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
614− * @t1 & LeftOuterJoin t2 on@. First, an inner join is performed.
646+{- | @t1 & LeftOuterJoin t2 on@. First, an inner join is performed.
615 Then, for each row in @t1@ that does not satisfy the @on@ condition with
647 Then, for each row in @t1@ that does not satisfy the @on@ condition with
616 any row in @t2@, a joined row is added with null values in columns of @t2@.
648 any row in @t2@, a joined row is added with null values in columns of @t2@.
617 Thus, the joined table always has at least one row for each row in @t1@.
649 Thus, the joined table always has at least one row for each row in @t1@.
652+ :: FromClause schema params right
654+ -> Condition (Join left right) 'Ungrouped params
656+ -> FromClause schema params 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
619− * @t1 & RightOuterJoin t2 on@. First, an inner join is performed.
663+{- | @t1 & RightOuterJoin t2 on@. First, an inner join is performed.
620 Then, for each row in @t2@ that does not satisfy the @on@ condition with
664 Then, for each row in @t2@ that does not satisfy the @on@ condition with
621 any row in @t1@, a joined row is added with null values in columns of @t1@.
665 any row in @t1@, a joined row is added with null values in columns of @t1@.
622 This is the converse of a left join: the result table will always
666 This is the converse of a left join: the result table will always
623 have a row for each row in @t2@.
667 have a row for each row in @t2@.
670+ :: FromClause schema params right
672+ -> Condition (Join left right) 'Ungrouped params
674+ -> FromClause schema params 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
625− * @t1 & FullOuterJoin t2 on@. First, an inner join is performed.
681+{- | @t1 & FullOuterJoin t2 on@. First, an inner join is performed.
626 Then, for each row in @t1@ that does not satisfy the @on@ condition with
682 Then, for each row in @t1@ that does not satisfy the @on@ condition with
627 any row in @t2@, a joined row is added with null values in columns of @t2@.
683 any row in @t2@, a joined row is added with null values in columns of @t2@.
628 Also, for each row of @t2@ that does not satisfy the join condition
684 Also, for each row of @t2@ that does not satisfy the join condition
629 with any row in @t1@, a joined row with null values in the columns of @t1@
685 with any row in @t1@, a joined row with null values in the columns of @t1@
630 is added.
686 is added.
632−data FromClause schema params tables where
688+fullOuterJoin
634− :: Aliased (Table schema) table
635− -> FromClause schema params '[table]
689+ :: FromClause schema params right
636− Subquery
690+ -- ^ right
637− :: Aliased (Query schema params) table
638− -> FromClause schema params '[table]
640− :: FromClause schema params right
641− -> FromClause schema params left
642− -> FromClause schema params (Join left right)
644− :: FromClause schema params right
645− -> Condition (Join left right) 'Ungrouped params
691+ -> Condition (Join left right) 'Ungrouped params
646− -> FromClause schema params left
692+ -- ^ @ON@ condition
647− -> FromClause schema params (Join left right)
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))
693+ -> FromClause schema params left
653− RightOuterJoin
694+ -- ^ left
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)
659− :: FromClause schema params right
660− -> Condition (Join left right) 'Ungrouped params
661− -> FromClause schema params left
695+ -> FromClause schema params
662− -> FromClause schema params
663− (Join (NullifyTables left) (NullifyTables right))
696+ (Join (NullifyTables left) (NullifyTables right))
664−
697+fullOuterJoin right on left = UnsafeFromClause $
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
677− renderJoin op right on left =
678− renderFromClause left <+> op <+> renderFromClause right
698+ renderFromClause left <+> "FULL OUTER JOIN" <+> renderFromClause right
679− <+> "ON" <+> renderExpression on
699+ <+> "ON" <+> renderExpression on
681{-----------------------------------------
701{-----------------------------------------
@@ -706,7 +726,7 @@ deriving instance Ord (By tables by)
706renderBy :: By tables tabcolty -> ByteString
726renderBy :: By tables tabcolty -> ByteString
707renderBy = \case
727renderBy = \case
708 By column -> renderAlias column
728 By column -> renderAlias column
709− By2 (table, column) -> renderAlias table <> "." <> renderAlias column
729+ By2 (tab, column) -> renderAlias tab <> "." <> renderAlias column
711-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
731-- | A `GroupByClause` indicates the `Grouping` of a `TableExpression`.
712-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.
732-- A `NoGroups` indicates `Ungrouped` while a `Group` indicates `Grouped`.