1{-# language DuplicateRecordFields #-}
2{-# language FlexibleContexts #-}
4{-# language NamedFieldPuns #-}
5{-# language ScopedTypeVariables #-}
6{-# language StandaloneKindSignatures #-}
7{-# language TypeApplications #-}
9module Rel8.Statement.Insert
17import Control.Exception ( throwIO )
18import Data.Kind ( Type )
19import Data.List.NonEmpty ( NonEmpty( (:|) ) )
23import Hasql.Connection ( Connection )
24import qualified Hasql.Decoders as Hasql
25import qualified Hasql.Encoders as Hasql
26import qualified Hasql.Session as Hasql
27import qualified Hasql.Statement as Hasql
30import qualified Opaleye.Internal.Manipulation as Opaleye
31import qualified Opaleye.Manipulation as Opaleye
32import Rel8.Schema.Table ( TableSchema )
33import Rel8.Statement.Returning ( Returning( Projection, NumberOfRowsAffected ) )
34import Rel8.Table ( fromColumns, toColumns )
35import Rel8.Table.Opaleye ( table, unpackspec )
36import Rel8.Table.Recontextualize ( Inserts, Selects )
37import Rel8.Table.Serialize ( Serializable, parse )
40import qualified Data.Text as Text ( pack )
41import Data.Text.Encoding ( encodeUtf8 )
44-- | The constituent parts of a SQL @INSERT@ statement.
45type Insert :: Type -> Type
47 Insert :: (Selects names exprs, Inserts exprs inserts) =>
48 { into :: TableSchema names
49 -- ^ Which table to insert into.
51 -- ^ The rows to insert.
52 , onConflict :: OnConflict
53 -- ^ What to do if the inserted rows conflict with data already in the
55 , returning :: Returning names a
56 -- ^ What information to return on completion.
61-- | @OnConflict@ allows you to add an @ON CONFLICT@ clause to an @INSERT@
64 = Abort -- ^ @ON CONFLICT ABORT@
65 | DoNothing -- ^ @ON CONFLICT DO NOTHING@
68-- | Run an @INSERT@ statement
72-- { into = authorSchema
73-- , rows = [ lit Author{ authorName = "Gabriel Gonzales", authorId = AuthorId 4, authorUrl = Just "https://haskellforall.com" } ]
74-- , onConflict = Abort
75-- , returning = NumberOfRowsAffected
79insert :: Connection -> Insert a -> IO a
80insert c Insert {into, rows, onConflict, returning} =
81 case (rows, returning) of
82 ([], NumberOfRowsAffected) -> pure 0
83 ([], Projection _) -> pure []
85 (x:xs, NumberOfRowsAffected) -> Hasql.run session c >>= either throwIO pure
87 session = Hasql.statement () statement
88 statement = Hasql.Statement bytes params decode prepare
89 bytes = encodeUtf8 $ Text.pack sql
90 params = Hasql.noParams
91 decode = Hasql.rowsAffected
93 sql = Opaleye.arrangeInsertManySql into' rows' onConflict'
95 into' = table $ toColumns <$> into
96 rows' = toColumns <$> x :| xs
98 (x:xs, Projection project) -> Hasql.run session c >>= either throwIO pure
100 session = Hasql.statement () statement
101 statement = Hasql.Statement bytes params decode prepare
102 bytes = encodeUtf8 $ Text.pack sql
103 params = Hasql.noParams
104 decode = decoder project
107 Opaleye.arrangeInsertManyReturningSql
114 into' = table $ toColumns <$> into
115 rows' = toColumns <$> x :| xs
116 project' = toColumns . project . fromColumns
121 DoNothing -> Just Opaleye.DoNothing
124 decoder :: forall exprs projection a. Serializable projection a
125 => (exprs -> projection) -> Hasql.Result [a]
126 decoder _ = Hasql.rowList (parse @projection @a)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list