@@ -6,8 +6,6 @@
66 , LambdaCase
77 , MagicHash
88 , OverloadedStrings
9− , PolyKinds
10− , ScopedTypeVariables
119 , TypeFamilies
1210 , TypeOperators
1311 , UndecidableInstances
@@ -62,8 +60,8 @@ instance {-# OVERLAPPING #-} KnownSymbol column
6260instance {-# OVERLAPPABLE #-} (KnownSymbol column, HasColumn column table ty)
6361 => HasColumn column (ty' ': table) ty
6462
65−instance HasColumn column columns ty
66− => IsLabel column (Expression params '[table ::: columns] ty) where
63+instance (HasColumn column columns ty, tables ~ '[table ::: columns])
64+ => IsLabel column (Expression params tables ty) where
6765 fromLabel = getColumn
6866
6967(.&.)
@@ -129,13 +127,25 @@ instance Boolean (Expression params tables 'PGBool) where
129127type instance BooleanOf (Expression params tables ty) =
130128 Expression params tables 'PGBool
131129
132−instance IfB (Expression params tables ty) where
133− ifB if_ then_ else_ = UnsafeExpression $ mconcat
134− [ "CASE WHEN ",renderExpression if_
135− , " THEN ",renderExpression then_
136− , " ELSE ",renderExpression else_
137− , " END"
130+caseWhenThenElse
131+ :: [(Expression params tables 'PGBool, Expression params tables ty)]
132+ -> Expression params tables ty
133+ -> Expression params tables ty
134+caseWhenThenElse whenThens else_ = UnsafeExpression $ mconcat
135+ [ "CASE"
136+ , mconcat
137+ [ mconcat
138+ [ " WHEN ", renderExpression when_
139+ , " THEN ", renderExpression then_
140+ ]
141+ | (when_,then_) <- whenThens
138142 ]
143+ , " ELSE ", renderExpression else_
144+ , " END"
145+ ]
146+
147+instance IfB (Expression params tables ty) where
148+ ifB if_ then_ else_ = caseWhenThenElse [(if_,then_)] else_
139149
140150instance EqB (Expression params tables ty) where
141151 (==*) = unsafeBinaryOp "="
@@ -167,120 +177,144 @@ crossJoin
167177 :: TableRef params schema '[table]
168178 -> TableRef params schema tables
169179 -> TableRef params schema (table ': tables)
170−crossJoin table tables = UnsafeTableRef $
171− renderTableRef tables <> " CROSS JOIN " <> renderTableRef table
180+crossJoin tab tabs = UnsafeTableRef $
181+ renderTableRef tabs <> " CROSS JOIN " <> renderTableRef tab
172182
173183innerJoin
174184 :: TableRef params schema '[table]
175185 -> Expression params (table ': tables) 'PGBool
176186 -> TableRef params schema tables
177187 -> TableRef params schema (table ': tables)
178−innerJoin table on tables = UnsafeTableRef $
179− renderTableRef tables
188+innerJoin tab on tabs = UnsafeTableRef $
189+ renderTableRef tabs
180190 <> " INNER JOIN " <>
181− renderTableRef table
191+ renderTableRef tab
182192 <> " ON " <>
183193 renderExpression on
184194
185−newtype Projection
186− (params :: [PGType])
187− (tables :: [(Symbol,[(Symbol,PGType)])])
188− (columns :: [(Symbol,PGType)]) =
189− UnsafeProjection { renderProjection :: ByteString }
190−
191−star :: Projection params '[table ::: columns] columns
192−star = UnsafeProjection "*"
193−
194−tableStar
195− :: HasTable table tables columns
196− => Alias table -> Projection params tables columns
197−tableStar (Alias table) = UnsafeProjection $
198− fromString (symbolVal' table) <> ".*"
195+data Clauses params tables = Clauses
196+ { whereClause :: Maybe (Expression params tables 'PGBool)
197+ , limitClause :: Maybe (Expression params '[] 'PGInt8)
198+ , offsetClause :: Maybe (Expression params '[] 'PGInt8)
199+ }
199200
200−project
201− :: Rec (Aliased (Expression params tables)) columns
202− -> Projection params tables columns
203−project
204− = UnsafeProjection
205− . ByteString.intercalate ", "
206− . recordToList
207− . rmap (Const . renderAliased renderExpression)
208−
209−data Tabulation
201+instance Monoid (Clauses params tables) where
202+ mempty = Clauses Nothing Nothing Nothing
203+ Clauses wh1 lim1 off1 `mappend` Clauses wh2 lim2 off2 = Clauses
204+ { whereClause = case (wh1,wh2) of
205+ (Nothing,Nothing) -> Nothing
206+ (Just w1,Nothing) -> Just w1
207+ (Nothing,Just w2) -> Just w2
208+ (Just w1,Just w2) -> Just (w1 &&* w2)
209+ , limitClause = case (lim1,lim2) of
210+ (Nothing,Nothing) -> Nothing
211+ (Just l1,Nothing) -> Just l1
212+ (Nothing,Just l2) -> Just l2
213+ (Just l1,Just l2) -> Just (l1 `minB` l2)
214+ , offsetClause = case (off1,off2) of
215+ (Nothing,Nothing) -> Nothing
216+ (Just o1,Nothing) -> Just o1
217+ (Nothing,Just o2) -> Just o2
218+ (Just o1,Just o2) -> Just (o1 + o2)
219+ }
220+
221+data TableExpression
210222 (params :: [PGType])
211223 (schema :: [(Symbol,[(Symbol,PGType)])])
212224 (tables :: [(Symbol,[(Symbol,PGType)])])
213− = Tabulation
214− { fromClause :: TableRef params schema tables
215− , whereClause :: Maybe (Expression params tables 'PGBool)
216− , limitClause :: Maybe (Expression params '[] 'PGInt8)
217− , offsetClause :: Maybe (Expression params '[] 'PGInt8)
225+ = TableExpression
226+ { tableRef :: TableRef params schema tables
227+ , clauses :: Clauses params tables
218228 }
219229
220−tabulation :: TableRef params schema tables -> Tabulation params schema tables
221−tabulation tab = Tabulation tab Nothing Nothing Nothing
230+tables
231+ :: TableRef params schema tables
232+ -> TableExpression params schema tables
233+tables tref = TableExpression tref mempty
222234
223−renderTabulation :: Tabulation params schema tables -> ByteString
224−renderTabulation (Tabulation fr wh lim off)= mconcat
225− [ renderTableRef fr
235+renderTabulation :: TableExpression params schema tables -> ByteString
236+renderTabulation (TableExpression tref (Clauses wh lim off))= mconcat
237+ [ renderTableRef tref
226238 , maybe "" ((" WHERE " <>) . renderExpression) wh
227239 , maybe "" ((" LIMIT " <>) . renderExpression) lim
228240 , maybe "" ((" OFFSET " <>) . renderExpression) off
229241 ]
230242
231−instance HasTable table schema columns
232− => IsLabel table (TableRef params schema '[table ::: columns]) where
243+instance (HasTable table schema columns, table ~ table')
244+ => IsLabel table (TableRef params schema '[table' ::: columns]) where
233245 fromLabel = getTable
234246
235−instance HasTable table schema columns
236− => IsLabel table (Tabulation params schema '[table ::: columns]) where
237− fromLabel p = Tabulation (getTable p) Nothing Nothing Nothing
247+instance (HasTable table schema columns, table ~ table')
248+ => IsLabel table (TableExpression params schema '[table' ::: columns]) where
249+ fromLabel p = TableExpression (getTable p) mempty
238250
239251where_
240252 :: Expression params tables 'PGBool
241− -> Tabulation params schema tables
242− -> Tabulation params schema tables
243−where_ condition tables = tables
244− { whereClause = case whereClause tables of
245− Nothing -> Just condition
246− Just conditions -> Just (conditions &&* condition)
247− }
253+ -> TableExpression params schema tables
254+ -> TableExpression params schema tables
255+where_ wh (TableExpression tabs clauses1) = TableExpression tabs
256+ (clauses1 <> Clauses (Just wh) Nothing Nothing)
248257
249258limit
250259 :: Expression params '[] 'PGInt8
251− -> Tabulation params schema tables
252− -> Tabulation params schema tables
253−limit n tables = tables
254− { limitClause = case limitClause tables of
255− Nothing -> Just n
256− Just n' -> Just (n' `minB` n)
257− }
260+ -> TableExpression params schema tables
261+ -> TableExpression params schema tables
262+limit lim (TableExpression tabs clauses1) = TableExpression tabs
263+ (clauses1 <> Clauses Nothing (Just lim) Nothing)
258264
259265offset
260266 :: Expression params '[] 'PGInt8
261− -> Tabulation params schema tables
262− -> Tabulation params schema tables
263−offset n tables = tables
264− { offsetClause = case offsetClause tables of
265− Nothing -> Just n
266− Just n' -> Just (n' + n)
267− }
267+ -> TableExpression params schema tables
268+ -> TableExpression params schema tables
269+offset off (TableExpression tabs clauses1) = TableExpression tabs
270+ (clauses1 <> Clauses Nothing Nothing (Just off))
271+
272+newtype Selection
273+ (params :: [PGType])
274+ (schema :: [(Symbol,[(Symbol,PGType)])])
275+ (columns :: [(Symbol,PGType)])
276+ = UnsafeSelection
277+ { renderSelection :: ByteString }
268278
269−newtype Selection params schema columns = UnsafeSelection
270− { renderSelection :: ByteString }
279+starFrom
280+ :: tables ~ '[table ::: columns]
281+ => TableExpression params schema tables
282+ -> Selection params schema columns
283+starFrom tabs = UnsafeSelection $ "* FROM " <> renderTabulation tabs
284+
285+tableStarFrom
286+ :: HasTable table tables columns
287+ => Alias table
288+ -> TableExpression params schema tables
289+ -> Selection params schema columns
290+Alias tab `tableStarFrom` tabs = UnsafeSelection $
291+ fromString (symbolVal' tab) <> ".* FROM" <> renderTabulation tabs
271292
272293from
273− :: Projection params tables columns
274− -> Tabulation params schema tables
294+ :: Rec (Aliased (Expression params tables)) columns
295+ -> TableExpression params schema tables
275296 -> Selection params schema columns
276−from projection tables = UnsafeSelection $
277− renderProjection projection <> " FROM " <> renderTabulation tables
297+list `from` tabs = UnsafeSelection $
298+ renderList list <> " FROM " <> renderTabulation tabs
299+ where
300+ renderList
301+ = ByteString.intercalate ", "
302+ . recordToList
303+ . rmap (Const . renderAliased renderExpression)
278304
279−newtype Query params schema0 schema1 columns = UnsafeQuery
280− { renderQuery :: ByteString }
305+newtype Query
306+ (params :: [PGType])
307+ (schema0 :: [(Symbol,[(Symbol,PGType)])])
308+ (schema1 :: [(Symbol,[(Symbol,PGType)])])
309+ (columns :: [(Symbol,PGType)])
310+ = UnsafeQuery { renderQuery :: ByteString }
281311
282−newtype PreparedQuery params schema0 schema1 columns = UnsafePreparedQuery
283− { renderPreparedQuery :: ByteString }
312+newtype PreparedQuery
313+ (params :: [PGType])
314+ (schema0 :: [(Symbol,[(Symbol,PGType)])])
315+ (schema1 :: [(Symbol,[(Symbol,PGType)])])
316+ (columns :: [(Symbol,PGType)])
317+ = UnsafePreparedQuery { renderPreparedQuery :: ByteString }
284318
285319select
286320 :: Selection params schema columns
@@ -289,18 +323,15 @@ select = UnsafeQuery . ("SELECT " <>) . (<> ";") . renderSelection
289323
290324subselect
291325 :: Aliased (Selection params schema) table
292− -> Tabulation params schema '[table]
293−subselect selection = Tabulation
294− { fromClause = UnsafeTableRef . ("SELECT " <>) $
326+ -> TableExpression params schema '[table]
327+subselect selection = TableExpression
328+ { tableRef = UnsafeTableRef . ("SELECT " <>) $
295329 renderAliased renderSelection selection
296− , whereClause = Nothing
297− , limitClause = Nothing
298− , offsetClause = Nothing
330+ , clauses = mempty
299331 }
300332
301333insertInto
302− :: forall schema columns table params
303− . HasTable table schema columns
334+ :: HasTable table schema columns
304335 => Alias table
305336 -> Rec (Aliased (Expression params '[])) columns
306337 -> Query params schema schema '[]