-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | An efficient PostgreSQL driver with a flexible mapping API -- -- Root of the "hasql" ecosystem. For details and tutorials see the -- readme. The API comes free from all kinds of exceptions. All -- error-reporting is explicit and is presented using the Either -- type. -- -- This library requires to have the "libpq" library installed on the -- running system. It comes distributed with PostgreSQL. To be able to -- use the "Pipeline" feature you'll need "libpq" of version >14. This -- feature does not however put any requirements on the version of the -- PostgreSQL server. @package hasql @version 1.7 -- | A DSL for declaration of statement parameter encoders. -- -- For compactness of names all the types defined here imply being an -- encoder. E.g., the Array type is an encoder of arrays, -- not the data-structure itself. module Hasql.Encoders -- | Encoder of some representation of a parameters product. -- -- Has instances of Contravariant, Divisible and -- Monoid, which you can use to compose multiple parameters -- together. E.g., -- --
--   someParamsEncoder :: Params (Int64, Maybe Text)
--   someParamsEncoder =
--     (fst >$< param (nonNullable int8)) <>
--     (snd >$< param (nullable text))
--   
-- -- As a general solution for tuples of any arity, instead of fst -- and snd, consider the functions of the contrazip -- family from the "contravariant-extras" package. E.g., here's how you -- can achieve the same as the above: -- --
--   someParamsEncoder :: Params (Int64, Maybe Text)
--   someParamsEncoder =
--     contrazip2 (param (nonNullable int8)) (param (nullable text))
--   
-- -- Here's how you can implement encoders for custom composite types: -- --
--   data Person = Person { name :: Text, gender :: Gender, age :: Int }
--   
--   data Gender = Male | Female
--   
--   personParams :: Params Person
--   personParams =
--     (name >$< param (nonNullable text)) <>
--     (gender >$< param (nonNullable genderValue)) <>
--     (fromIntegral . age >$< param (nonNullable int8))
--   
--   genderValue :: Value Gender
--   genderValue = enum genderText text where
--     genderText gender = case gender of
--       Male -> "male"
--       Female -> "female"
--   
data Params a -- | No parameters. Same as mempty and conquered. noParams :: Params () -- | Lift a single parameter encoder, with its nullability specified, -- associating it with a single placeholder. param :: NullableOrNot Value a -> Params a -- | Extensional specification of nullability over a generic encoder. data NullableOrNot (encoder :: Type -> Type) a -- | Specify that an encoder produces a non-nullable value. nonNullable :: encoder a -> NullableOrNot encoder a -- | Specify that an encoder produces a nullable value. nullable :: encoder a -> NullableOrNot encoder (Maybe a) -- | Value encoder. data Value a -- | Encoder of BOOL values. bool :: Value Bool -- | Encoder of INT2 values. int2 :: Value Int16 -- | Encoder of INT4 values. int4 :: Value Int32 -- | Encoder of INT8 values. int8 :: Value Int64 -- | Encoder of FLOAT4 values. float4 :: Value Float -- | Encoder of FLOAT8 values. float8 :: Value Double -- | Encoder of NUMERIC values. numeric :: Value Scientific -- | Encoder of CHAR values. -- -- Note that it supports Unicode values and identifies itself under the -- TEXT OID because of that. char :: Value Char -- | Encoder of TEXT values. text :: Value Text -- | Encoder of BYTEA values. bytea :: Value ByteString -- | Encoder of DATE values. date :: Value Day -- | Encoder of TIMESTAMP values. timestamp :: Value LocalTime -- | Encoder of TIMESTAMPTZ values. timestamptz :: Value UTCTime -- | Encoder of TIME values. time :: Value TimeOfDay -- | Encoder of TIMETZ values. timetz :: Value (TimeOfDay, TimeZone) -- | Encoder of INTERVAL values. interval :: Value DiffTime -- | Encoder of UUID values. uuid :: Value UUID -- | Encoder of INET values. inet :: Value (NetAddr IP) -- | Encoder of JSON values from JSON AST. json :: Value Value -- | Encoder of JSON values from raw JSON. jsonBytes :: Value ByteString -- | Encoder of JSON values from raw JSON as lazy ByteString. jsonLazyBytes :: Value ByteString -- | Encoder of JSONB values from JSON AST. jsonb :: Value Value -- | Encoder of JSONB values from raw JSON. jsonbBytes :: Value ByteString -- | Encoder of JSONB values from raw JSON as lazy ByteString. jsonbLazyBytes :: Value ByteString -- | Encoder of NAME values. name :: Value Text -- | Encoder of OID values. oid :: Value Int32 -- | Given a function, which maps a value into a textual enum label used on -- the DB side, produces an encoder of that value. enum :: (a -> Text) -> Value a -- | Variation of enum with unknown OID. This function does not -- identify the type to Postgres, so Postgres must be able to derive the -- type from context. When you find yourself in such situation just -- provide an explicit type in the query using the :: operator. unknownEnum :: (a -> Text) -> Value a -- | Identifies the value with the PostgreSQL's "unknown" type, thus -- leaving it up to Postgres to infer the actual type of the value. -- -- The value transimitted is any value encoded in the Postgres' Text data -- format. For reference, see the Formats and Format Codes section -- of the Postgres' documentation. -- -- Warning: Do not use this as part of composite encoders like -- array since it is the only encoder that doesn't use the binary -- format. unknown :: Value ByteString -- | Lift an array encoder into a value encoder. array :: Array a -> Value a -- | Lift a value encoder of element into a unidimensional array encoder of -- a foldable value. -- -- This function is merely a shortcut to the following expression: -- --
--   (array . dimension foldl' . element)
--   
-- -- You can use it like this: -- --
--   vectorOfInts :: Value (Vector Int64)
--   vectorOfInts = foldableArray (nonNullable int8)
--   
-- -- Please notice that in case of multidimensional arrays nesting -- foldableArray encoder won't work. You have to explicitly -- construct the array encoder using array. foldableArray :: Foldable foldable => NullableOrNot Value element -> Value (foldable element) -- | Lift a composite encoder into a value encoder. composite :: Composite a -> Value a -- | Generic array encoder. -- -- Here's an example of its usage: -- --
--   someParamsEncoder :: Params [[Int64]]
--   someParamsEncoder = param (nonNullable (array (dimension foldl' (dimension foldl' (element (nonNullable int8))))))
--   
-- -- Please note that the PostgreSQL IN keyword does not accept an -- array, but rather a syntactical list of values, thus this encoder is -- not suited for that. Use a value = ANY($1) condition instead. data Array a -- | Lifts a Value encoder into an Array encoder. element :: NullableOrNot Value a -> Array a -- | Encoder of an array dimension, which thus provides support for -- multidimensional arrays. -- -- Accepts: -- -- dimension :: (forall a. () => (a -> b -> a) -> a -> c -> a) -> Array b -> Array c -- | Composite or row-types encoder. data Composite a -- | Single field of a row-type. field :: NullableOrNot Value a -> Composite a -- | A DSL for declaration of result decoders. module Hasql.Decoders -- | Decoder of a query result. data Result a -- | Decode no value from the result. -- -- Useful for statements like INSERT or CREATE. noResult :: Result () -- | Get the amount of rows affected by such statements as UPDATE -- or DELETE. rowsAffected :: Result Int64 -- | Exactly one row. Will raise the UnexpectedAmountOfRows error if -- it's any other. singleRow :: Row a -> Result a -- | Maybe one row or none. rowMaybe :: Row a -> Result (Maybe a) -- | Zero or more rows packed into the vector. -- -- It's recommended to prefer this function to rowList, since it -- performs notably better. rowVector :: Row a -> Result (Vector a) -- | Zero or more rows packed into the list. rowList :: Row a -> Result [a] -- | Foldl multiple rows. foldlRows :: (a -> b -> a) -> a -> Row b -> Result a -- | Foldr multiple rows. foldrRows :: (b -> a -> a) -> a -> Row b -> Result a -- | Decoder of an individual row, which gets composed of column value -- decoders. -- -- E.g.: -- --
--   x :: Row (Maybe Int64, Text, TimeOfDay)
--   x = (,,) <$> (column . nullable) int8 <*> (column . nonNullable) text <*> (column . nonNullable) time
--   
data Row a -- | Lift an individual value decoder to a composable row decoder. column :: NullableOrNot Value a -> Row a -- | Extensional specification of nullability over a generic decoder. data NullableOrNot (decoder :: Type -> Type) a -- | Specify that a decoder produces a non-nullable value. nonNullable :: decoder a -> NullableOrNot decoder a -- | Specify that a decoder produces a nullable value. nullable :: decoder a -> NullableOrNot decoder (Maybe a) -- | Decoder of a value. data Value a -- | Decoder of the BOOL values. bool :: Value Bool -- | Decoder of the INT2 values. int2 :: Value Int16 -- | Decoder of the INT4 values. int4 :: Value Int32 -- | Decoder of the INT8 values. int8 :: Value Int64 -- | Decoder of the FLOAT4 values. float4 :: Value Float -- | Decoder of the FLOAT8 values. float8 :: Value Double -- | Decoder of the NUMERIC values. numeric :: Value Scientific -- | Decoder of the CHAR values. Note that it supports Unicode -- values. char :: Value Char -- | Decoder of the TEXT values. text :: Value Text -- | Decoder of the BYTEA values. bytea :: Value ByteString -- | Decoder of the DATE values. date :: Value Day -- | Decoder of the TIMESTAMP values. timestamp :: Value LocalTime -- | Decoder of the TIMESTAMPTZ values. -- -- NOTICE -- -- Postgres does not store the timezone information of -- TIMESTAMPTZ. Instead it stores a UTC value and performs -- silent conversions to the currently set timezone, when dealt with in -- the text format. However this library bypasses the silent conversions -- and communicates with Postgres using the UTC values directly. timestamptz :: Value UTCTime -- | Decoder of the TIME values. time :: Value TimeOfDay -- | Decoder of the TIMETZ values. -- -- Unlike in case of TIMESTAMPTZ, Postgres does store the -- timezone information for TIMETZ. However the Haskell's "time" -- library does not contain any composite type, that fits the task, so we -- use a pair of TimeOfDay and TimeZone to represent a -- value on the Haskell's side. timetz :: Value (TimeOfDay, TimeZone) -- | Decoder of the INTERVAL values. interval :: Value DiffTime -- | Decoder of the UUID values. uuid :: Value UUID -- | Decoder of the INET values. inet :: Value (NetAddr IP) -- | Decoder of the JSON values into a JSON AST. json :: Value Value -- | Decoder of the JSON values into a raw JSON ByteString. jsonBytes :: (ByteString -> Either Text a) -> Value a -- | Decoder of the JSONB values into a JSON AST. jsonb :: Value Value -- | Decoder of the JSONB values into a raw JSON -- ByteString. jsonbBytes :: (ByteString -> Either Text a) -> Value a -- | Lift an Array decoder to a Value decoder. array :: Array a -> Value a -- | Lift a value decoder of element into a unidimensional array decoder -- producing a list. -- -- This function is merely a shortcut to the following expression: -- --
--   (array . dimension Control.Monad.replicateM . element)
--   
-- -- Please notice that in case of multidimensional arrays nesting -- listArray decoder won't work. You have to explicitly construct -- the array decoder using array. listArray :: NullableOrNot Value element -> Value [element] -- | Lift a value decoder of element into a unidimensional array decoder -- producing a generic vector. -- -- This function is merely a shortcut to the following expression: -- --
--   (array . dimension Data.Vector.Generic.replicateM . element)
--   
-- -- Please notice that in case of multidimensional arrays nesting -- vectorArray decoder won't work. You have to explicitly -- construct the array decoder using array. vectorArray :: Vector vector element => NullableOrNot Value element -> Value (vector element) -- | Lift a Composite decoder to a Value decoder. composite :: Composite a -> Value a -- | A generic decoder of HSTORE values. -- -- Here's how you can use it to construct a specific value: -- --
--   x :: Value [(Text, Maybe Text)]
--   x = hstore replicateM
--   
hstore :: (forall (m :: Type -> Type). Monad m => Int -> m (Text, Maybe Text) -> m a) -> Value a -- | Given a partial mapping from text to value, produces a decoder of that -- value. enum :: (Text -> Maybe a) -> Value a -- | Lift a custom value decoder function to a Value decoder. custom :: (Bool -> ByteString -> Either Text a) -> Value a -- | Refine a value decoder, lifting the possible error to the session -- level. refine :: (a -> Either Text b) -> Value a -> Value b -- | A generic array decoder. -- -- Here's how you can use it to produce a specific array value decoder: -- --
--   x :: Value [[Text]]
--   x = array (dimension replicateM (dimension replicateM (element (nonNullable text))))
--   
data Array a -- | A function for parsing a dimension of an array. Provides support for -- multi-dimensional arrays. -- -- Accepts: -- -- dimension :: (forall (m :: Type -> Type). Monad m => Int -> m a -> m b) -> Array a -> Array b -- | Lift a Value decoder into an Array decoder for parsing -- of leaf values. element :: NullableOrNot Value a -> Array a -- | Composable decoder of composite values (rows, records). data Composite a -- | Lift a Value decoder into a Composite decoder for -- parsing of component values. field :: NullableOrNot Value a -> Composite a -- | This module provides a low-level effectful API dealing with the -- connections to the database. module Hasql.Connection -- | A single connection to the database. data Connection -- | Possible details of the connection acquistion error. type ConnectionError = Maybe ByteString -- | Acquire a connection using the provided settings encoded according to -- the PostgreSQL format. acquire :: Settings -> IO (Either ConnectionError Connection) -- | Release the connection. release :: Connection -> IO () -- | All settings encoded in a single byte-string according to the -- PostgreSQL format. type Settings = ByteString -- | Encode a host, a port, a user, a password and a database into the -- PostgreSQL settings byte-string. settings :: ByteString -> Word16 -> ByteString -> ByteString -> ByteString -> Settings -- | Execute an operation on the raw libpq Connection. -- -- The access to the connection is exclusive. withLibPQConnection :: Connection -> (Connection -> IO a) -> IO a module Hasql.Statement -- | 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 =
--     Statement sql encoder decoder True
--     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. data Statement params result Statement :: ByteString -> Params params -> Result result -> Bool -> Statement params result -- | Refine the result of a statement, causing the running session to fail -- with the UnexpectedResult error in case of a refinement -- failure. -- -- This function is especially useful for refining the results of -- statements produced with the "hasql-th" library. refineResult :: (a -> Either Text b) -> Statement params a -> Statement params b instance GHC.Base.Functor (Hasql.Statement.Statement params) instance Data.Profunctor.Unsafe.Profunctor Hasql.Statement.Statement module Hasql.Session -- | A batch of actions to be executed in the context of a database -- connection. data Session a -- | Possibly a multi-statement query, which however cannot be -- parameterized or prepared, nor can any results of it be collected. sql :: ByteString -> Session () -- | Execute a statement by providing parameters to it. statement :: params -> Statement params result -> Session result -- | Execute a pipeline. pipeline :: Pipeline result -> Session result -- | Executes a bunch of commands on the provided connection. run :: Session a -> Connection -> IO (Either SessionError a) -- | Error during execution of a session. data SessionError -- | Error during the execution of a query. Comes packed with the query -- template and a textual representation of the provided params. QueryError :: ByteString -> [Text] -> CommandError -> SessionError -- | Error during the execution of a pipeline. PipelineError :: CommandError -> SessionError -- | An error of some command in the session. data CommandError -- | An error on the client-side, with a message generated by the "libpq" -- library. Usually indicates problems with connection. ClientError :: Maybe ByteString -> CommandError -- | Some error with a command result. ResultError :: ResultError -> CommandError -- | An error with a command result. data ResultError -- | An error reported by the DB. ServerError :: ByteString -> ByteString -> Maybe ByteString -> Maybe ByteString -> Maybe Int -> ResultError -- | The database returned an unexpected result. Indicates an improper -- statement or a schema mismatch. UnexpectedResult :: Text -> ResultError -- | An error of the row reader, preceded by the indexes of the row and -- column. RowError :: Int -> Int -> RowError -> ResultError -- | An unexpected amount of rows. UnexpectedAmountOfRows :: Int -> ResultError -- | An error during the decoding of a specific row. data RowError -- | Appears on the attempt to parse more columns than there are in the -- result. EndOfInput :: RowError -- | Appears on the attempt to parse a NULL as some value. UnexpectedNull :: RowError -- | Appears when a wrong value parser is used. Comes with the error -- details. ValueError :: Text -> RowError module Hasql.Pipeline -- | Composable abstraction over the execution of queries in the -- pipeline mode. -- -- It allows you to issue multiple queries to the server in much fewer -- network transactions. If the amounts of sent and received data do not -- surpass the buffer sizes in the driver and on the server it will be -- just a single roundtrip. Typically the buffer size is 8KB. -- -- This execution mode is much more efficient than running queries -- directly from Session, because in session every statement -- execution involves a dedicated network roundtrip. An obvious question -- rises then: why not execute all queries like that? -- -- In situations where the parameters depend on the result of another -- query it is impossible to execute them in parallel, because the client -- needs to receive the results of one query before sending the request -- to execute the next. This reasoning is essentially the same as the one -- for the difference between Applicative and Monad. That's -- why Pipeline does not have the Monad instance. -- -- To execute Pipeline lift it into Session via -- pipeline. -- -- Attention: using this feature requires "libpq" of version -- >14. -- --

Examples

-- --

Insert-Many or Batch-Insert

-- -- You can use pipeline to turn a single-row insert query into an -- efficient multi-row insertion session. In effect this should be -- comparable in performance to issuing a single multi-row insert -- statement. -- -- Given the following definition in a Statements module: -- --
--   insertOrder :: Statement OrderDetails OrderId
--   
-- -- You can lift it into the following session -- --
--   insertOrders :: [OrderDetails] -> Session [OrderId]
--   insertOrders songs =
--     pipeline $
--       forM songs $ song ->
--         statement song Statements.insertOrder
--   
-- --

Combining Queries

-- -- Given the following definitions in a Statements module: -- --
--   selectOrderDetails :: Statement OrderId (Maybe OrderDetails)
--   selectOrderProducts :: Statement OrderId [OrderProduct]
--   selectOrderFinancialTransactions :: Statement OrderId [FinancialTransaction]
--   
-- -- You can combine them into a session using the ApplicativeDo -- extension as follows: -- --
--   selectEverythingAboutOrder :: OrderId -> Session (Maybe OrderDetails, [OrderProduct], [FinancialTransaction])
--   selectEverythingAboutOrder orderId =
--     pipeline $ do
--       details <- statement orderId Statements.selectOrderDetails
--       products <- statement orderId Statements.selectOrderProducts
--       transactions <- statement orderId Statements.selectOrderFinancialTransactions
--       pure (details, products, transactions)
--   
data Pipeline a -- | Execute a statement in pipelining mode. statement :: params -> Statement params result -> Pipeline result