@@ -21,29 +21,40 @@ queryNamed [sql|
2121-}
2222
2323module PgNamed
24- ( NamedParam (.. )
24+ ( -- * Named data types and smart constructors
25+ NamedParam (.. )
2526 , Name (.. )
27+ , (=?)
2628
29+ -- * Functions to deal with named parameters
2730 , extractNames
2831 , namesToRow
29- , (=?)
32+
33+ -- * Database querying functions with named parameters
34+ , queryNamed
35+ , executeNamed
3036 ) where
3137
3238import Control.Monad.Except (MonadError (throwError ))
39+ import Control.Monad.IO.Class (MonadIO (liftIO ))
3340import Data.Bifunctor (bimap )
3441import Data.ByteString (ByteString )
3542import Data.Char (isAlphaNum )
43+ import Data.Int (Int64 )
3644import Data.List (lookup )
37- import Data.List.NonEmpty (NonEmpty (.. ))
45+ import Data.List.NonEmpty (NonEmpty (.. ), toList )
46+ import Data.Pool (Pool )
3847import Data.Text (Text )
3948import Data.Text.Encoding (decodeUtf8 )
4049import GHC.Exts (IsString )
4150
4251import qualified Data.ByteString.Char8 as BS
52+ import qualified Data.Pool as Pool
4353import qualified Database.PostgreSQL.Simple as PG
4454import qualified Database.PostgreSQL.Simple.ToField as PG
4555import qualified Database.PostgreSQL.Simple.Types as PG
4656
57+
4758-- | Wrapper over name of the argument.
4859newtype Name = Name
4960 { unName :: Text
@@ -151,3 +162,57 @@ infix 7 =?
151162(=?) :: (PG. ToField a ) => Name -> a -> NamedParam
152163n =? a = NamedParam n $ PG. toField a
153164{-# INLINE (=?) #-}
165+
166+ {- | Queries the database with a given query and named parameters
167+ and expects a list of rows in return.
168+
169+ @
170+ queryNamed dbPool [sql|
171+ SELECT id FROM table
172+ WHERE foo = ?foo
173+ |] [ "foo" '=?' "bar" ]
174+ @
175+ -}
176+ queryNamed
177+ :: (MonadIO m , WithError m , PG. FromRow res )
178+ => Pool PG. Connection -- ^ Database connection pool
179+ -> PG. Query -- ^ Query with named parameters inside
180+ -> [NamedParam ] -- ^ The list of named parameters to be used in the query
181+ -> m [res ] -- ^ Resulting rows
182+ queryNamed pool qNamed params =
183+ withNamedArgs qNamed params >>= \ (q, actions) ->
184+ liftIO $ Pool. withResource pool (\ conn -> PG. query conn q (toList actions))
185+
186+ {- | Modifies the database with a given query and named parameters
187+ and expects a number of the rows affected.
188+
189+ @
190+ executeNamed dbPool [sql|
191+ UPDATE table
192+ SET foo = 'bar'
193+ WHERE id = ?id
194+ |] [ "id" '=?' someId ]
195+ @
196+ -}
197+ executeNamed
198+ :: (MonadIO m , WithError m )
199+ => Pool PG. Connection -- ^ Database connection pool
200+ -> PG. Query -- ^ Query with named parameters inside
201+ -> [NamedParam ] -- ^ The list of named parameters to be used in the query
202+ -> m Int64 -- ^ Number of the rows affected by the given query
203+ executeNamed pool qNamed params =
204+ withNamedArgs qNamed params >>= \ (q, actions) ->
205+ liftIO $ Pool. withResource pool (\ conn -> PG. execute conn q (toList actions))
206+
207+ -- | Helper to use named parameters.
208+ withNamedArgs
209+ :: WithError m
210+ => PG. Query
211+ -> [NamedParam ]
212+ -> m (PG. Query , NonEmpty PG. Action )
213+ withNamedArgs qNamed namedArgs = do
214+ (q, names) <- case extractNames qNamed of
215+ Left errType -> throwError errType
216+ Right r -> pure r
217+ args <- namesToRow names namedArgs
218+ pure (q, args)
0 commit comments