@@ -3,6 +3,7 @@
33 DataKinds
44 , FlexibleInstances
55 , FunctionalDependencies
6+ , GADTs
67 , LambdaCase
78 , MagicHash
89 , OverloadedStrings
@@ -158,77 +159,101 @@ instance OrdB (Expression params tables ty) where
158159 (<*) = unsafeBinaryOp "<"
159160 (<=*) = unsafeBinaryOp "<="
160161
161−newtype JoinExpression
162+newtype TableExpression
162163 (params :: [NullityType])
163164 (schema :: [(Symbol,[(Symbol,NullityType)])])
164− (tables :: [(Symbol,[(Symbol,NullityType)])])
165− = UnsafeJoinExpression { renderJoinExpression :: ByteString }
165+ (columns :: [(Symbol,NullityType)])
166+ = UnsafeTableExpression { renderTableExpression :: ByteString }
167+
168+data JoinExpression params schema tables where
169+ Table
170+ :: Aliased (TableExpression params schema) table
171+ -> JoinExpression params schema '[table]
172+ Subselect
173+ :: Aliased (Selection params schema) table
174+ -> JoinExpression params schema '[table]
175+ Cross
176+ :: Aliased (TableExpression params schema) table
177+ -> JoinExpression params schema tables
178+ -> JoinExpression params schema (table ': tables)
179+ Inner
180+ :: Aliased (TableExpression params schema) table
181+ -> Expression params (table ': tables) ('NotNull 'PGBool)
182+ -> JoinExpression params schema tables
183+ -> JoinExpression params schema (table ': tables)
184+
185+renderJoinExpression :: JoinExpression params schema tables -> ByteString
186+renderJoinExpression = \case
187+ Table table -> renderAliased renderTableExpression table
188+ Subselect selection -> "SELECT " <> renderAliased renderSelection selection
189+ Cross table tables -> mconcat
190+ [ renderJoinExpression tables
191+ , " CROSS JOIN "
192+ , renderAliased renderTableExpression table
193+ ]
194+ Inner table on tables -> mconcat
195+ [ renderJoinExpression tables
196+ , " INNER JOIN "
197+ , renderAliased renderTableExpression table
198+ , " ON "
199+ , renderExpression on
200+ ]
166201
167202class KnownSymbol table => HasTable table tables columns
168203 | table tables -> columns where
169− getTable :: Proxy# table -> JoinExpression params tables '[table ::: columns]
170− getTable table = UnsafeJoinExpression $ fromString $ symbolVal' table
204+ getTable :: Proxy# table -> TableExpression params tables columns
205+ getTable table = UnsafeTableExpression $ fromString $ symbolVal' table
171206instance {-# OVERLAPPING #-} KnownSymbol table
172207 => HasTable table ((table ::: columns) ': tables) columns
173208instance {-# OVERLAPPABLE #-}
174209 (KnownSymbol table, HasTable table schema columns)
175210 => HasTable table (table' ': schema) columns
176211
177−cross
178− :: JoinExpression params schema '[table]
179− -> JoinExpression params schema tables
180− -> JoinExpression params schema (table ': tables)
181−cross tab tabs = UnsafeJoinExpression $
182− renderJoinExpression tabs <> " CROSS JOIN " <> renderJoinExpression tab
183−
184−inner
185− :: JoinExpression params schema '[table]
186− -> Expression params (table ': tables) ('NotNull 'PGBool)
187− -> JoinExpression params schema tables
188− -> JoinExpression params schema (table ': tables)
189−inner tab on tabs = UnsafeJoinExpression $
190− renderJoinExpression tabs
191− <> " INNER JOIN " <>
192− renderJoinExpression tab
193− <> " ON " <>
194− renderExpression on
195−
196−leftOuter
197− :: JoinExpression params schema '[right]
198− -> Expression params (right ': left : tables) ('NotNull 'PGBool)
199− -> JoinExpression params schema (tables)
200− -> JoinExpression params schema (NullifyTable right ': left ': tables)
201−leftOuter tab on tabs = UnsafeJoinExpression $
202− renderJoinExpression tabs
203− <> " LEFT OUTER JOIN " <>
204− renderJoinExpression tab
205− <> " ON " <>
206− renderExpression on
207−
208−rightOuter
209− :: JoinExpression params schema '[right]
210− -> Expression params (right ': tables) ('NotNull 'PGBool)
211− -> JoinExpression params schema (left : tables)
212− -> JoinExpression params schema (right ': NullifyTable left ': tables)
213−rightOuter tab on tabs = UnsafeJoinExpression $
214− renderJoinExpression tabs
215− <> " RIGHT OUTER JOIN " <>
216− renderJoinExpression tab
217− <> " ON " <>
218− renderExpression on
219−
220−fullOuter
221− :: JoinExpression params schema '[right]
222− -> Expression params (right ': left ': tables) ('NotNull 'PGBool)
223− -> JoinExpression params schema (left : tables)
224− -> JoinExpression params schema
225− (NullifyTable right ': NullifyTable left ': tables)
226−fullOuter tab on tabs = UnsafeJoinExpression $
227− renderJoinExpression tabs
228− <> " FULL OUTER JOIN " <>
229− renderJoinExpression tab
230− <> " ON " <>
231− renderExpression on
212+instance HasTable table schema columns
213+ => IsLabel table (TableExpression params schema columns) where
214+ fromLabel = getTable
215+
216+instance HasTable table schema columns
217+ => IsLabel table (JoinExpression params schema '[table ::: columns]) where
218+ fromLabel p = Table $ fromLabel p
219+
220+
221+-- leftOuter
222+-- :: JoinExpression params schema '[right]
223+-- -> Expression params (right ': left : tables) ('NotNull 'PGBool)
224+-- -> JoinExpression params schema (tables)
225+-- -> JoinExpression params schema (NullifyTable right ': left ': tables)
226+-- leftOuter tab on tabs = UnsafeJoinExpression $
227+-- renderJoinExpression tabs
228+-- <> " LEFT OUTER JOIN " <>
229+-- renderJoinExpression tab
230+-- <> " ON " <>
231+-- renderExpression on
232+--
233+-- rightOuter
234+-- :: JoinExpression params schema '[right]
235+-- -> Expression params (right ': tables) ('NotNull 'PGBool)
236+-- -> JoinExpression params schema (left : tables)
237+-- -> JoinExpression params schema (right ': NullifyTable left ': tables)
238+-- rightOuter tab on tabs = UnsafeJoinExpression $
239+-- renderJoinExpression tabs
240+-- <> " RIGHT OUTER JOIN " <>
241+-- renderJoinExpression tab
242+-- <> " ON " <>
243+-- renderExpression on
244+--
245+-- fullOuter
246+-- :: JoinExpression params schema '[right]
247+-- -> Expression params (right ': left ': tables) ('NotNull 'PGBool)
248+-- -> JoinExpression params schema (left : tables)
249+-- -> JoinExpression params schema
250+-- (NullifyTable right ': NullifyTable left ': tables)
251+-- fullOuter tab on tabs = UnsafeJoinExpression $
252+-- renderJoinExpression tabs
253+-- <> " FULL OUTER JOIN " <>
254+-- renderJoinExpression tab
255+-- <> " ON " <>
256+-- renderExpression on
232257
233258data Clauses params tables = Clauses
234259 { whereClause :: Maybe (Expression params tables ('NotNull 'PGBool))
@@ -260,31 +285,27 @@ data FromExpression
260285 (params :: [NullityType])
261286 (schema :: [(Symbol,[(Symbol,NullityType)])])
262287 (tables :: [(Symbol,[(Symbol,NullityType)])])
263− = FromExpression
264− { joinExpression :: JoinExpression params schema tables
265− , clauses :: Clauses params tables
266− }
288+ = FromExpression
289+ { joinExpression :: JoinExpression params schema tables
290+ , clauses :: Clauses params tables
291+ }
267292
268293join
269294 :: JoinExpression params schema tables
270295 -> FromExpression params schema tables
271296join tref = FromExpression tref mempty
272297
273−renderTabulation :: FromExpression params schema tables -> ByteString
274−renderTabulation (FromExpression tref (Clauses wh lim off))= mconcat
298+renderFromExpression :: FromExpression params schema tables -> ByteString
299+renderFromExpression (FromExpression tref (Clauses wh lim off))= mconcat
275300 [ renderJoinExpression tref
276301 , maybe "" ((" WHERE " <>) . renderExpression) wh
277302 , maybe "" ((" LIMIT " <>) . renderExpression) lim
278303 , maybe "" ((" OFFSET " <>) . renderExpression) off
279304 ]
280305
281−instance (HasTable table schema columns, table ~ table')
282− => IsLabel table (JoinExpression params schema '[table' ::: columns]) where
283− fromLabel = getTable
284−
285306instance (HasTable table schema columns, table ~ table')
286307 => IsLabel table (FromExpression params schema '[table' ::: columns]) where
287− fromLabel p = FromExpression (getTable p) mempty
308+ fromLabel p = FromExpression (fromLabel p) mempty
288309
289310where_
290311 :: Expression params tables ('NotNull 'PGBool)
@@ -311,14 +332,13 @@ newtype Selection
311332 (params :: [NullityType])
312333 (schema :: [(Symbol,[(Symbol,NullityType)])])
313334 (columns :: [(Symbol,NullityType)])
314− = UnsafeSelection
315− { renderSelection :: ByteString }
335+ = UnsafeSelection { renderSelection :: ByteString }
316336
317337starFrom
318338 :: tables ~ '[table ::: columns]
319339 => FromExpression params schema tables
320340 -> Selection params schema columns
321−starFrom tabs = UnsafeSelection $ "* FROM " <> renderTabulation tabs
341+starFrom tabs = UnsafeSelection $ "* FROM " <> renderFromExpression tabs
322342
323343dotStarFrom
324344 :: HasTable table tables columns
@@ -326,14 +346,14 @@ dotStarFrom
326346 -> FromExpression params schema tables
327347 -> Selection params schema columns
328348Alias tab `dotStarFrom` tabs = UnsafeSelection $
329− fromString (symbolVal' tab) <> ".* FROM" <> renderTabulation tabs
349+ fromString (symbolVal' tab) <> ".* FROM " <> renderFromExpression tabs
330350
331351from
332352 :: Rec (Aliased (Expression params tables)) columns
333353 -> FromExpression params schema tables
334354 -> Selection params schema columns
335355list `from` tabs = UnsafeSelection $
336− renderList list <> " FROM " <> renderTabulation tabs
356+ renderList list <> " FROM " <> renderFromExpression tabs
337357 where
338358 renderList
339359 = ByteString.intercalate ", "
@@ -363,8 +383,7 @@ subselect
363383 :: Aliased (Selection params schema) table
364384 -> FromExpression params schema '[table]
365385subselect selection = FromExpression
366− { joinExpression = UnsafeJoinExpression . ("SELECT " <>) $
367− renderAliased renderSelection selection
386+ { joinExpression = Subselect selection
368387 , clauses = mempty
369388 }
370389