{-# language DuplicateRecordFields #-} {-# language FlexibleContexts #-} {-# language GADTs #-} {-# language NamedFieldPuns #-} {-# language RecordWildCards #-} {-# language StandaloneKindSignatures #-} {-# language StrictData #-} module Rel8.Statement.Insert ( Insert(..) , insert , ppInsert , ppInto ) where -- base import Data.Foldable ( toList ) import Data.Kind ( Type ) import Prelude -- opaleye import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye import qualified Opaleye.Internal.Tag as Opaleye -- pretty import Text.PrettyPrint ( Doc, (<+>), ($$), parens, text ) -- rel8 import Rel8.Query ( Query ) import Rel8.Schema.Name ( Name, Selects, ppColumn ) import Rel8.Schema.Table ( TableSchema(..), ppTable ) import Rel8.Statement (Statement) import Rel8.Statement.OnConflict ( OnConflict, ppOnConflict ) import Rel8.Statement.Returning (Returning, ppReturning, runReturning) import Rel8.Statement.Select ( ppRows ) import Rel8.Table ( Table ) import Rel8.Table.Name ( showNames ) -- transformers import Control.Monad.Trans.State.Strict (State) -- | The constituent parts of a SQL @INSERT@ statement. type Insert :: Type -> Type data Insert a where Insert :: Selects names exprs => { into :: TableSchema names -- ^ Which table to insert into. , rows :: Query exprs -- ^ The rows to insert. This can be an arbitrary query — use -- 'Rel8.values' insert a static list of rows. , onConflict :: OnConflict names -- ^ What to do if the inserted rows conflict with data already in the -- table. , returning :: Returning names a -- ^ What information to return on completion. } -> Insert a -- | Build an @INSERT@ 'Statement'. insert :: Insert a -> Statement a insert statement@Insert {returning} = runReturning (ppInsert statement) returning ppInsert :: Insert a -> State Opaleye.Tag Doc ppInsert Insert {..} = do rows' <- ppRows rows pure $ text "INSERT INTO" <+> ppInto into $$ rows' $$ ppOnConflict into onConflict $$ ppReturning into returning ppInto :: Table Name a => TableSchema a -> Doc ppInto table@TableSchema {columns} = ppTable table <+> parens (Opaleye.commaV ppColumn (toList (showNames columns)))