opaleye-0.5.2.1: src/Opaleye/RunQuery.hs
{-# LANGUAGE FlexibleContexts #-}
module Opaleye.RunQuery (module Opaleye.RunQuery,
QueryRunner,
-- * Datatypes
IRQ.QueryRunnerColumn,
IRQ.QueryRunnerColumnDefault (..),
-- * Creating now 'QueryRunnerColumn's
IRQ.fieldQueryRunnerColumn,
IRQ.fieldParserQueryRunnerColumn) where
import qualified Database.PostgreSQL.Simple as PGS
import qualified Database.PostgreSQL.Simple.FromRow as FR
import qualified Data.String as String
import Opaleye.Column (Column)
import qualified Opaleye.Sql as S
import Opaleye.QueryArr (Query)
import Opaleye.Internal.RunQuery (QueryRunner(QueryRunner))
import qualified Opaleye.Internal.RunQuery as IRQ
import qualified Opaleye.Internal.QueryArr as Q
import qualified Data.Profunctor as P
import qualified Data.Profunctor.Product.Default as D
-- * Running 'Query's
-- | @runQuery@'s use of the 'D.Default' typeclass means that the
-- compiler will have trouble inferring types. It is strongly
-- recommended that you provide full type signatures when using
-- @runQuery@.
--
-- Example type specialization:
--
-- @
-- runQuery :: Query (Column 'Opaleye.PGTypes.PGInt4', Column 'Opaleye.PGTypes.PGText') -> IO [(Int, String)]
-- @
--
-- Assuming the @makeAdaptorAndInstance@ splice has been run for the product type @Foo@:
--
-- @
-- runQuery :: Query (Foo (Column 'Opaleye.PGTypes.PGInt4') (Column 'Opaleye.PGTypes.PGText') (Column 'Opaleye.PGTypes.PGBool')
-- -> IO [Foo Int String Bool]
-- @
--
-- Opaleye types are converted to Haskell types based on instances of
-- the 'Opaleye.Internal.RunQuery.QueryRunnerColumnDefault' typeclass.
runQuery :: D.Default QueryRunner columns haskells
=> PGS.Connection
-> Query columns
-> IO [haskells]
runQuery = runQueryExplicit D.def
-- | @runQueryFold@ streams the results of a query incrementally and consumes
-- the results with a left fold.
--
-- This fold is /not/ strict. The stream consumer is responsible for
-- forcing the evaluation of its result to avoid space leaks.
runQueryFold
:: D.Default QueryRunner columns haskells
=> PGS.Connection
-> Query columns
-> b
-> (b -> haskells -> IO b)
-> IO b
runQueryFold = runQueryFoldExplicit D.def
-- * Creating new 'QueryRunnerColumn's
-- | Use 'queryRunnerColumn' to make an instance to allow you to run queries on
-- your own datatypes. For example:
--
-- @
-- newtype Foo = Foo Int
--
-- instance QueryRunnerColumnDefault Foo Foo where
-- queryRunnerColumnDefault =
-- queryRunnerColumn ('Opaleye.Column.unsafeCoerceColumn'
-- :: Column Foo -> Column PGInt4)
-- Foo
-- queryRunnerColumnDefault
-- @
queryRunnerColumn :: (Column a' -> Column a) -> (b -> b')
-> IRQ.QueryRunnerColumn a b -> IRQ.QueryRunnerColumn a' b'
queryRunnerColumn colF haskellF qrc = IRQ.QueryRunnerColumn (P.lmap colF u)
(fmapFP haskellF fp)
where IRQ.QueryRunnerColumn u fp = qrc
fmapFP = fmap . fmap . fmap
-- * Explicit versions
runQueryExplicit :: QueryRunner columns haskells
-> PGS.Connection
-> Query columns
-> IO [haskells]
runQueryExplicit qr conn q = maybe (return []) (PGS.queryWith_ parser conn) sql
where (sql, parser) = prepareQuery qr q
runQueryFoldExplicit
:: QueryRunner columns haskells
-> PGS.Connection
-> Query columns
-> b
-> (b -> haskells -> IO b)
-> IO b
runQueryFoldExplicit qr conn q z f = case sql of
Nothing -> return z
Just sql' -> PGS.foldWith_ parser conn sql' z f
where (sql, parser) = prepareQuery qr q
-- * Deprecated functions
-- | For internal use only. Do not use. Will be deprecated in
-- version 0.6.
prepareQuery :: QueryRunner columns haskells -> Query columns -> (Maybe PGS.Query, FR.RowParser haskells)
prepareQuery qr@(QueryRunner u _ _) q = (sql, parser)
where sql :: Maybe PGS.Query
sql = fmap String.fromString (S.showSqlForPostgresExplicit u q)
-- FIXME: We're doing work twice here
(b, _, _) = Q.runSimpleQueryArrStart q ()
parser = IRQ.prepareRowParser qr b