@@ -27,6 +27,7 @@ module Squeal.PostgreSQL.Manipulation
27 , ColumnValue (..)
27 , ColumnValue (..)
28 , ReturningClause (ReturningStar, Returning)
28 , ReturningClause (ReturningStar, Returning)
29 , ConflictClause (OnConflictDoRaise, OnConflictDoNothing, OnConflictDoUpdate)
29 , ConflictClause (OnConflictDoRaise, OnConflictDoNothing, OnConflictDoUpdate)
30+ , ConflictTarget (OnConstraint, UniqueIndexOn)
30 -- * Insert
31 -- * Insert
31 , insertRows
32 , insertRows
32 , insertRow
33 , insertRow
@@ -46,6 +47,7 @@ module Squeal.PostgreSQL.Manipulation
47import Control.DeepSeq
48import Control.DeepSeq
48import Data.ByteString hiding (foldr)
49import Data.ByteString hiding (foldr)
50+import GHC.TypeLits (KnownSymbol)
50import qualified Generics.SOP as SOP
52import qualified Generics.SOP as SOP
51import qualified GHC.Generics as GHC
53import qualified GHC.Generics as GHC
@@ -120,12 +122,13 @@ let
120 (Set 2 `as` #col1 :* Set 4 `as` #col2)
122 (Set 2 `as` #col1 :* Set 4 `as` #col2)
121 [Set 6 `as` #col1 :* Set 8 `as` #col2]
123 [Set 6 `as` #col1 :* Set 8 `as` #col2]
122 (OnConflictDoUpdate
124 (OnConflictDoUpdate
125+ (UniqueIndexOn #col1)
123 (Set 2 `as` #col1 :* Same `as` #col2)
126 (Set 2 `as` #col1 :* Same `as` #col2)
124 [#col1 .== #col2])
127 [#col1 .== #col2])
125 (Returning $ (#col1 + #col2) `as` #sum)
128 (Returning $ (#col1 + #col2) `as` #sum)
126in printSQL manipulation
129in printSQL manipulation
128−INSERT INTO "tab" ("col1", "col2") VALUES (2, 4), (6, 8) ON CONFLICT DO UPDATE SET "col1" = 2 WHERE ("col1" = "col2") RETURNING ("col1" + "col2") AS "sum"
131+INSERT INTO "tab" ("col1", "col2") VALUES (2, 4), (6, 8) ON CONFLICT ("col1") DO UPDATE SET "col1" = 2 WHERE ("col1" = "col2") RETURNING ("col1" + "col2") AS "sum"
130query insert:
133query insert:
@@ -387,10 +390,26 @@ data ConflictClause
387 OnConflictDoNothing :: ConflictClause schema table params
390 OnConflictDoNothing :: ConflictClause schema table params
388 OnConflictDoUpdate
391 OnConflictDoUpdate
389 :: (row ~ TableToRow table, columns ~ TableToColumns table)
392 :: (row ~ TableToRow table, columns ~ TableToColumns table)
393+ => ConflictTarget table
390− => NP (Aliased (ColumnValue schema row params)) columns
394+ -> NP (Aliased (ColumnValue schema row params)) columns
391 -> [Condition schema '[t ::: row] 'Ungrouped params]
395 -> [Condition schema '[t ::: row] 'Ungrouped params]
392 -> ConflictClause schema table params
396 -> ConflictClause schema table params
398+-- | A 'ConflictTarget' specifies the constraint violation that triggers an
399+-- 'OnConflictDoUpdate'.
400+data ConflictTarget (table :: TableType) where
401+ -- | An explicitly named constraint.
403+ :: (Has constraintName constraints constraint)
404+ => Alias constraintName
405+ -> ConflictTarget '(constraints, columns)
406+ -- | Match each unique index with precisely the following columns.
408+ :: ( HasAll columnNames columns columnTypes
409+ , SOP.All KnownSymbol columnNames )
410+ => NP Alias columnNames
411+ -> ConflictTarget '(constraints, columns)
394-- | Render a `ConflictClause`.
413-- | Render a `ConflictClause`.
395renderConflictClause
414renderConflictClause
396 :: SOP.SListI (TableToColumns table)
415 :: SOP.SListI (TableToColumns table)
@@ -399,8 +418,10 @@ renderConflictClause
399renderConflictClause = \case
418renderConflictClause = \case
400 OnConflictDoRaise -> ""
419 OnConflictDoRaise -> ""
401 OnConflictDoNothing -> " ON CONFLICT DO NOTHING"
420 OnConflictDoNothing -> " ON CONFLICT DO NOTHING"
402− OnConflictDoUpdate updates whs'
421+ OnConflictDoUpdate target updates whs'
423+ <+> renderTarget target
403− -> " ON CONFLICT DO UPDATE SET"
424+ <+> "DO UPDATE SET"
404 <+> renderCommaSeparatedMaybe renderUpdate updates
425 <+> renderCommaSeparatedMaybe renderUpdate updates
405 <> case whs' of
426 <> case whs' of
@@ -415,6 +436,14 @@ renderConflictClause = \case
415 renderAlias column <+> "=" <+> "DEFAULT"
436 renderAlias column <+> "=" <+> "DEFAULT"
416 Set expression `As` column -> Just $
437 Set expression `As` column -> Just $
417 renderAlias column <+> "=" <+> renderExpression expression
438 renderAlias column <+> "=" <+> renderExpression expression
440+ :: ConflictTarget table
442+ renderTarget = \case
443+ OnConstraint name ->
444+ "ON CONSTRAINT" <+> renderAlias name
445+ UniqueIndexOn columns ->
446+ parenthesized (commaSeparated (renderAliases columns))
419{-----------------------------------------
448{-----------------------------------------
420UPDATE statements
449UPDATE statements