Skip to content

Commit 27e7989

Browse files
vrom911Dmitrii Kovanikov
authored andcommitted
[#3] Implement query functions (#4)
Resolves #3
1 parent cbfc6fa commit 27e7989

File tree

2 files changed

+69
-3
lines changed

2 files changed

+69
-3
lines changed

postgresql-simple-named.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ library
6969
build-depends: bytestring ^>= 0.10.8
7070
, mtl ^>= 2.2
7171
, postgresql-simple ^>= 0.6.2
72+
, resource-pool ^>= 0.2.3.2
7273
, text ^>= 1.2
7374

7475
test-suite postgresql-simple-named-test

src/PgNamed.hs

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,40 @@ queryNamed [sql|
2121
-}
2222

2323
module 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

3238
import Control.Monad.Except (MonadError (throwError))
39+
import Control.Monad.IO.Class (MonadIO (liftIO))
3340
import Data.Bifunctor (bimap)
3441
import Data.ByteString (ByteString)
3542
import Data.Char (isAlphaNum)
43+
import Data.Int (Int64)
3644
import Data.List (lookup)
37-
import Data.List.NonEmpty (NonEmpty (..))
45+
import Data.List.NonEmpty (NonEmpty (..), toList)
46+
import Data.Pool (Pool)
3847
import Data.Text (Text)
3948
import Data.Text.Encoding (decodeUtf8)
4049
import GHC.Exts (IsString)
4150

4251
import qualified Data.ByteString.Char8 as BS
52+
import qualified Data.Pool as Pool
4353
import qualified Database.PostgreSQL.Simple as PG
4454
import qualified Database.PostgreSQL.Simple.ToField as PG
4555
import qualified Database.PostgreSQL.Simple.Types as PG
4656

57+
4758
-- | Wrapper over name of the argument.
4859
newtype Name = Name
4960
{ unName :: Text
@@ -151,3 +162,57 @@ infix 7 =?
151162
(=?) :: (PG.ToField a) => Name -> a -> NamedParam
152163
n =? 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

Comments
 (0)