on dev help sign in
use default in select
commit4110e02bd44df40dab1687fb9f98e2b031c11b27 authorEitan Chatav <eitan.chatav@gmail.com> dateTue 4 Dec 2018, 15:43 (8 years ago) parentf487240
3 files changed+35−22
squeal-postgresql/src/Squeal/PostgreSQL.hs+11−20 squeal-postgresql/src/Squeal/PostgreSQL/Manipulation.hs+10−2 squeal-postgresql/src/Squeal/PostgreSQL/Render.hs+14
squeal-postgresql/src/Squeal/PostgreSQL.hs+11−20
@@ -12,7 +12,7 @@ First, we need some language extensions because Squeal uses modern GHC
1212features.
1313
1414>>> :set -XDataKinds -XDeriveGeneric -XOverloadedLabels
15−>>> :set -XOverloadedStrings -XTypeApplications -XTypeOperators
15+>>> :set -XOverloadedStrings -XTypeApplications -XTypeOperators -XGADTs
1616
1717We'll need some imports.
1818
@@ -117,25 +117,18 @@ of our inserts.
117117
118118>>> :{
119119let
120− insertUser :: Manipulation Schema '[ 'NotNull 'PGtext ] '[ "fromOnly" ::: 'NotNull 'PGint4 ]
121− insertUser = insertInto #users
122− (Values_ (defaultAs #id :* param @1 `as` #name))
123− (OnConflict (OnConstraint #pk_users) DoNothing) (Returning (#id `as` #fromOnly))
124−:}
125−
126−>>> :{
127−let
128− insertEmail :: Manipulation Schema '[ 'NotNull 'PGint4, 'Null 'PGtext] '[]
129− insertEmail = insertInto #emails
130− (Values_ (defaultAs #id :* param @1 `as` #user_id :* param @2 `as` #email))
131− (OnConflict (OnConstraint #pk_emails) DoNothing) (Returning Nil)
120+ insertUser :: Manipulation Schema '[ 'NotNull 'PGtext, 'Null 'PGtext ] '[]
121+ insertUser = with (u `as` #u) e
122+ where
123+ u = insertInto #users
124+ (Values_ (defaultAs #id :* param @1 `as` #name))
125+ OnConflictDoRaise (Returning (#id :* param @2 `as` #email))
126+ e = insertInto_ #emails
127+ (Select (defaultAs #id :* #u ! #id `as` #user_id :* #u ! #email) (from (view #u)))
132128:}
133129
134130>>> printSQL insertUser
135−INSERT INTO "users" ("id", "name") VALUES (DEFAULT, ($1 :: text)) ON CONFLICT ON CONSTRAINT "pk_users" DO NOTHING RETURNING "id" AS "fromOnly"
136−
137−>>> printSQL insertEmail
138−INSERT INTO "emails" ("id", "user_id", "email") VALUES (DEFAULT, ($1 :: int4), ($2 :: text)) ON CONFLICT ON CONSTRAINT "pk_emails" DO NOTHING
131+WITH "u" AS (INSERT INTO "users" ("id", "name") VALUES (DEFAULT, ($1 :: text)) RETURNING "id" AS "id", ($2 :: text) AS "email") INSERT INTO "emails" ("user_id", "email") SELECT "u"."id", "u"."email" FROM "u" AS "u"
139132
140133Next we write a `Query` to retrieve users from the database. We're not
141134interested in the ids here, just the usernames and email addresses. We
@@ -191,9 +184,7 @@ transformer and when the schema doesn't change we can use `Monad` and
191184let
192185 session :: PQ Schema Schema IO ()
193186 session = do
194− idResults <- traversePrepared insertUser (Only . userName <$> users)
195− ids <- traverse (fmap fromOnly . getRow 0) idResults
196− traversePrepared_ insertEmail (zip (ids :: [Int32]) (userEmail <$> users))
187+ _ <- traversePrepared_ insertUser users
197188 usersResult <- runQuery getUsers
198189 usersRows <- getRows usersResult
199190 liftBase $ print (usersRows :: [User])
squeal-postgresql/src/Squeal/PostgreSQL/Manipulation.hs+10−2
@@ -318,12 +318,20 @@ renderQueryClause = \case
318318 ( parenthesized
319319 . renderCommaSeparated renderValuePart <$> row0 : rows )
320320 Select row0 tab ->
321− parenthesized (renderCommaSeparated renderAliasPart row0)
321+ parenthesized (renderCommaSeparatedMaybe renderAliasPartMaybe row0)
322322 <+> "SELECT"
323− <+> renderCommaSeparated renderValuePart row0
323+ <+> renderCommaSeparatedMaybe renderValuePartMaybe row0
324324 <+> renderTableExpression tab
325325 Subquery qry -> renderQuery qry
326326 where
327+ renderAliasPartMaybe, renderValuePartMaybe
328+ :: ColumnExpression schema from grp params column -> Maybe ByteString
329+ renderAliasPartMaybe = \case
330+ DefaultAs _ -> Nothing
331+ Specific (_ `As` name) -> Just $ renderAlias name
332+ renderValuePartMaybe = \case
333+ DefaultAs _ -> Nothing
334+ Specific (value `As` _) -> Just $ renderExpression value
327335 renderAliasPart, renderValuePart
328336 :: ColumnExpression schema from grp params column -> ByteString
329337 renderAliasPart = \case
squeal-postgresql/src/Squeal/PostgreSQL/Render.hs+14
@@ -27,6 +27,7 @@ module Squeal.PostgreSQL.Render
2727 , singleQuotedText
2828 , singleQuotedUtf8
2929 , renderCommaSeparated
30+ , renderCommaSeparatedMaybe
3031 , renderNat
3132 , renderSymbol
3233 , RenderSQL (..)
@@ -35,6 +36,7 @@ module Squeal.PostgreSQL.Render
3536
3637import Control.Monad.Base
3738import Data.ByteString (ByteString)
39+import Data.Maybe (catMaybes)
3840import Data.Monoid ((<>))
3941import Data.Text (Text)
4042import Generics.SOP
@@ -80,6 +82,18 @@ renderCommaSeparated render
8082 . hcollapse
8183 . hmap (K . render)
8284
85+-- | Comma separate the `Maybe` renderings of a heterogeneous list, dropping
86+-- `Nothing`s.
87+renderCommaSeparatedMaybe
88+ :: SListI xs
89+ => (forall x. expression x -> Maybe ByteString)
90+ -> NP expression xs -> ByteString
91+renderCommaSeparatedMaybe render
92+ = commaSeparated
93+ . catMaybes
94+ . hcollapse
95+ . hmap (K . render)
96+
8397-- | Render a promoted `Nat`.
8498renderNat :: forall n. KnownNat n => ByteString
8599renderNat = fromString (show (natVal' (proxy# :: Proxy# n)))