hasql-1.10.3: Fast PostgreSQL driver with a flexible mapping API
Safe HaskellNone
LanguageHaskell2010

Hasql.Statement

Synopsis

Documentation

data Statement params result Source #

Specification of a strictly single-statement query, which can be parameterized and prepared. It encapsulates the mapping of parameters and results in association with an SQL template.

Following is an example of a declaration of a prepared statement with its associated codecs.

selectSum :: Statement (Int64, Int64) Int64
selectSum =
  preparable sql encoder decoder
  where
    sql =
      "select ($1 + $2)"
    encoder =
      (fst >$< Encoders.param (Encoders.nonNullable Encoders.int8)) <>
      (snd >$< Encoders.param (Encoders.nonNullable Encoders.int8))
    decoder =
      Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.int8))

The statement above accepts a product of two parameters of type Int64 and produces a single result of type Int64.

Instances

Instances details
Profunctor Statement Source # 
Instance details

Defined in Hasql.Engine.Statement

Methods

dimap :: (a -> b) -> (c -> d) -> Statement b c -> Statement a d Source #

lmap :: (a -> b) -> Statement b c -> Statement a c Source #

rmap :: (b -> c) -> Statement a b -> Statement a c Source #

(#.) :: forall a b c q. Coercible c b => q b c -> Statement a b -> Statement a c Source #

(.#) :: forall a b c q. Coercible b a => Statement b c -> q a b -> Statement a c Source #

Functor (Statement params) Source # 
Instance details

Defined in Hasql.Engine.Statement

Methods

fmap :: (a -> b) -> Statement params a -> Statement params b #

(<$) :: a -> Statement params b -> Statement params a #

Filterable (Statement params) Source # 
Instance details

Defined in Hasql.Engine.Statement

Methods

mapMaybe :: (a -> Maybe b) -> Statement params a -> Statement params b Source #

catMaybes :: Statement params (Maybe a) -> Statement params a Source #

filter :: (a -> Bool) -> Statement params a -> Statement params a Source #

drain :: Statement params a -> Statement params b Source #

preparable Source #

Arguments

:: Text

SQL template with parameters in positional notation ($1, $2, etc.)

-> Params params

Parameters encoder

-> Result result

Result decoder

-> Statement params result 

Construct a preparable statement.

Use this for statements that will be executed multiple times with different parameters. Preparable statements are cached by PostgreSQL, which avoids reconstructing the execution plan each time.

Suitable for applications with a limited amount of queries that don't generate SQL dynamically.

unpreparable Source #

Arguments

:: Text

SQL template with parameters in positional notation ($1, $2, etc.)

-> Params params

Parameters encoder

-> Result result

Result decoder

-> Statement params result 

Construct an unpreparable statement.

Use this for statements that are dynamically generated or executed only once. Unpreparable statements are not cached by PostgreSQL.

Suitable for dynamic SQL or one-off queries.

refineResult :: (a -> Either Text b) -> Statement params a -> Statement params b Source #

Refine the result of a statement, causing the running session to fail with the UnexpectedResultStatementError error in case of a refinement failure.

This function is especially useful for refining the results of statements produced with the "hasql-th" library.

toSql :: Statement params result -> Text Source #

Extract the SQL template from a statement.

Recipes

Insert many

Starting from PostgreSQL 9.4 there is an unnest function which we can use in an analogous way to haskell's zip to pass in multiple arrays of values to be zipped into the rows to insert as in the following example:

insertMultipleLocations :: Statement (Vector (UUID, Double, Double)) ()
insertMultipleLocations =
  preparable sql encoder decoder
  where
    sql =
      "insert into location (id, x, y) select * from unnest ($1, $2, $3)"
    encoder =
      Data.Vector.unzip3 >$<
        Contravariant.Extras.contrazip3
          (Encoders.param $ Encoders.nonNullable $ Encoders.foldableArray $ Encoders.nonNullable Encoders.uuid)
          (Encoders.param $ Encoders.nonNullable $ Encoders.foldableArray $ Encoders.nonNullable Encoders.float8)
          (Encoders.param $ Encoders.nonNullable $ Encoders.foldableArray $ Encoders.nonNullable Encoders.float8)
    decoder =
      Decoders.noResult

While this approach is much more efficient than executing a single-row insert-statement multiple times from within Session, a comparable performance can also be achieved by executing a single-insert statement from within a Pipeline.

IN and NOT IN

There is a common misconception that PostgreSQL supports array as the parameter for the IN operator. However Postgres only supports a syntactical list of values with it, i.e., you have to specify each option as an individual parameter. E.g., some_expression IN ($1, $2, $3).

Fortunately, Postgres does provide the expected functionality for arrays with other operators:

  • Use some_expression = ANY($1) instead of some_expression IN ($1)
  • Use some_expression <> ALL($1) instead of some_expression NOT IN ($1)

For details refer to the PostgreSQL docs.