packages feed

hasql 1.1.1 → 1.2

raw patch · 22 files changed

+575/−629 lines, 22 filesdep +text-builderdep ~tastydep ~tasty-hunitdep ~tasty-quickcheckPVP ok

version bump matches the API change (PVP)

Dependencies added: text-builder

Dependency ranges changed: tasty, tasty-hunit, tasty-quickcheck

API changes (from Hackage documentation)

- Hasql.Decoders: arrayDimension :: (forall m. Monad m => Int -> m a -> m b) -> Array a -> Array b
- Hasql.Decoders: arrayNullableValue :: Value a -> Array (Maybe a)
- Hasql.Decoders: arrayValue :: Value a -> Array a
- Hasql.Decoders: compositeNullableValue :: Value a -> Composite (Maybe a)
- Hasql.Decoders: compositeValue :: Value a -> Composite a
- Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value (Data.Time.LocalTime.TimeOfDay.TimeOfDay, Data.Time.LocalTime.TimeZone.TimeZone))
- Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value Data.Time.Clock.Scale.DiffTime)
- Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value Data.Time.Clock.UTC.UTCTime)
- Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value Data.Time.LocalTime.LocalTime.LocalTime)
- Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value Data.Time.LocalTime.TimeOfDay.TimeOfDay)
- Hasql.Decoders: maybeRow :: Row a -> Result (Maybe a)
- Hasql.Decoders: nullableValue :: Value a -> Row (Maybe a)
- Hasql.Decoders: rowsList :: Row a -> Result [a]
- Hasql.Decoders: rowsVector :: Row a -> Result (Vector a)
- Hasql.Decoders: value :: Value a -> Row a
- Hasql.Encoders: arrayDimension :: (forall a. (a -> b -> a) -> a -> c -> a) -> Array b -> Array c
- Hasql.Encoders: arrayNullableValue :: Value a -> Array (Maybe a)
- Hasql.Encoders: arrayValue :: Value a -> Array a
- Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value (Data.Time.LocalTime.TimeOfDay.TimeOfDay, Data.Time.LocalTime.TimeZone.TimeZone))
- Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value Data.Time.Clock.Scale.DiffTime)
- Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value Data.Time.Clock.UTC.UTCTime)
- Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value Data.Time.LocalTime.LocalTime.LocalTime)
- Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value Data.Time.LocalTime.TimeOfDay.TimeOfDay)
- Hasql.Encoders: nullableValue :: Value a -> Params (Maybe a)
- Hasql.Encoders: value :: Value a -> Params a
- Hasql.Query: statement :: ByteString -> Params a -> Result b -> Bool -> Query a b
- Hasql.Session: data Error
+ Hasql.Decoders: column :: Value a -> Row a
+ Hasql.Decoders: dimension :: (forall m. Monad m => Int -> m a -> m b) -> Array a -> Array b
+ Hasql.Decoders: element :: Value a -> Array a
+ Hasql.Decoders: field :: Value a -> Composite a
+ Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone))
+ Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value Data.Time.Clock.Internal.DiffTime.DiffTime)
+ Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value Data.Time.Clock.Internal.UTCTime.UTCTime)
+ Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value Data.Time.LocalTime.Internal.LocalTime.LocalTime)
+ Hasql.Decoders: instance Data.Default.Class.Default (Hasql.Decoders.Value Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay)
+ Hasql.Decoders: nullableColumn :: Value a -> Row (Maybe a)
+ Hasql.Decoders: nullableElement :: Value a -> Array (Maybe a)
+ Hasql.Decoders: nullableField :: Value a -> Composite (Maybe a)
+ Hasql.Decoders: rowList :: Row a -> Result [a]
+ Hasql.Decoders: rowMaybe :: Row a -> Result (Maybe a)
+ Hasql.Decoders: rowVector :: Row a -> Result (Vector a)
+ Hasql.Encoders: dimension :: (forall a. (a -> b -> a) -> a -> c -> a) -> Array b -> Array c
+ Hasql.Encoders: element :: Value a -> Array a
+ Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value (Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay, Data.Time.LocalTime.Internal.TimeZone.TimeZone))
+ Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value Data.Time.Clock.Internal.DiffTime.DiffTime)
+ Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value Data.Time.Clock.Internal.UTCTime.UTCTime)
+ Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value Data.Time.LocalTime.Internal.LocalTime.LocalTime)
+ Hasql.Encoders: instance Data.Default.Class.Default (Hasql.Encoders.Value Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay)
+ Hasql.Encoders: nullableElement :: Value a -> Array (Maybe a)
+ Hasql.Encoders: nullableParam :: Value a -> Params (Maybe a)
+ Hasql.Encoders: param :: Value a -> Params a
+ Hasql.Query: Query :: ByteString -> (Params a) -> (Result b) -> Bool -> Query a b
+ Hasql.Query: instance Data.Profunctor.Unsafe.Profunctor Hasql.Query.Query
+ Hasql.Query: instance GHC.Base.Functor (Hasql.Query.Query a)
+ Hasql.Session: QueryError :: ByteString -> [Text] -> CommandError -> QueryError
+ Hasql.Session: data CommandError
+ Hasql.Session: data QueryError
- Hasql.Session: ClientError :: !(Maybe ByteString) -> Error
+ Hasql.Session: ClientError :: (Maybe ByteString) -> CommandError
- Hasql.Session: ResultError :: !ResultError -> Error
+ Hasql.Session: ResultError :: ResultError -> CommandError
- Hasql.Session: RowError :: !Int -> !RowError -> ResultError
+ Hasql.Session: RowError :: Int -> RowError -> ResultError
- Hasql.Session: ServerError :: !ByteString -> !ByteString -> !(Maybe ByteString) -> !(Maybe ByteString) -> ResultError
+ Hasql.Session: ServerError :: ByteString -> ByteString -> (Maybe ByteString) -> (Maybe ByteString) -> ResultError
- Hasql.Session: UnexpectedAmountOfRows :: !Int -> ResultError
+ Hasql.Session: UnexpectedAmountOfRows :: Int -> ResultError
- Hasql.Session: UnexpectedResult :: !Text -> ResultError
+ Hasql.Session: UnexpectedResult :: Text -> ResultError
- Hasql.Session: ValueError :: !Text -> RowError
+ Hasql.Session: ValueError :: Text -> RowError
- Hasql.Session: query :: a -> Query a b -> Session b
+ Hasql.Session: query :: params -> Query params result -> Session result
- Hasql.Session: run :: Session a -> Connection -> IO (Either Error a)
+ Hasql.Session: run :: Session a -> Connection -> IO (Either QueryError a)

Files

benchmarks/Main.hs view
@@ -69,7 +69,7 @@  queryWithSingleRow :: C.Query () (Int64, Int64) queryWithSingleRow =-  C.statement template encoder decoder True+  C.Query template encoder decoder True   where     template =       "SELECT 1, 2"@@ -79,29 +79,29 @@       D.singleRow row       where         row =-          tuple <$> D.value D.int8 <*> D.value D.int8+          tuple <$> D.column D.int8 <*> D.column D.int8           where             tuple !a !b =               (a, b)  queryWithManyRows :: (D.Row (Int64, Int64) -> D.Result result) -> C.Query () result queryWithManyRows decoder =-  C.statement template encoder (decoder rowDecoder) True+  C.Query template encoder (decoder rowDecoder) True   where     template =       "SELECT generate_series(0,1000) as a, generate_series(1000,2000) as b"     encoder =       conquer     rowDecoder =-      tuple <$> D.value D.int8 <*> D.value D.int8+      tuple <$> D.column D.int8 <*> D.column D.int8       where         tuple !a !b =           (a, b)  queryWithManyRowsInVector :: C.Query () (Vector (Int64, Int64)) queryWithManyRowsInVector =-  queryWithManyRows D.rowsVector+  queryWithManyRows D.rowVector  queryWithManyRowsInList :: C.Query () (List (Int64, Int64)) queryWithManyRowsInList =-  queryWithManyRows D.rowsList+  queryWithManyRows D.rowList
hasql.cabal view
@@ -1,7 +1,7 @@ name:   hasql version:-  1.1.1+  1.2 category:   Hasql, Database, PostgreSQL synopsis:@@ -47,11 +47,17 @@     Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples   default-language:     Haskell2010+  exposed-modules:+    Hasql.Decoders+    Hasql.Encoders+    Hasql.Connection+    Hasql.Query+    Hasql.Session   other-modules:     Hasql.Private.Prelude+    Hasql.Private.Errors     Hasql.Private.PTI     Hasql.Private.IO-    Hasql.Private.Query     Hasql.Private.Session     Hasql.Private.Connection     Hasql.Private.PreparedStatementRegistry@@ -66,12 +72,6 @@     Hasql.Private.Encoders.Array     Hasql.Private.Encoders.Value     Hasql.Private.Encoders.Params-  exposed-modules:-    Hasql.Decoders-    Hasql.Encoders-    Hasql.Connection-    Hasql.Query-    Hasql.Session   build-depends:     -- parsing:     attoparsec >= 0.10 && < 0.14,@@ -85,6 +85,7 @@     vector >= 0.10 && < 0.13,     hashtables >= 1.1 && < 2,     text >= 1 && < 2,+    text-builder >= 0.5.1 && < 0.6,     bytestring >= 0.10 && < 0.11,     hashable >= 1.2 && < 1.3,     -- control:@@ -123,9 +124,9 @@     -- database:     hasql,     -- testing:-    tasty >= 0.12 && < 0.13,-    tasty-quickcheck >= 0.9 && < 0.10,-    tasty-hunit >= 0.9 && < 0.10,+    tasty >= 0.12 && < 2,+    tasty-quickcheck >= 0.9 && < 0.11,+    tasty-hunit >= 0.9 && < 0.11,     quickcheck-instances >= 0.3.11 && < 0.4,     QuickCheck >= 2.8.1 && < 3,     -- general:
library/Hasql/Decoders.hs view
@@ -8,16 +8,16 @@   rowsAffected,   singleRow,   -- ** Specialized multi-row results-  maybeRow,-  rowsVector,-  rowsList,+  rowMaybe,+  rowVector,+  rowList,   -- ** Multi-row traversers   foldlRows,   foldrRows,   -- * Row   Row,-  value,-  nullableValue,+  column,+  nullableColumn,   -- * Value   Value,   bool,@@ -49,13 +49,13 @@   custom,   -- * Array   Array,-  arrayDimension,-  arrayValue,-  arrayNullableValue,+  dimension,+  element,+  nullableElement,   -- * Composite   Composite,-  compositeValue,-  compositeNullableValue,+  field,+  nullableField, ) where @@ -82,7 +82,7 @@   deriving (Functor)  -- |--- Decode no value from the result.+-- Decode no column from the result. --  -- Useful for statements like @INSERT@ or @CREATE@. -- @@ -134,28 +134,28 @@ -- | -- Maybe one row or none. -- -{-# INLINABLE maybeRow #-}-maybeRow :: Row a -> Result (Maybe a)-maybeRow (Row row) =+{-# INLINABLE rowMaybe #-}+rowMaybe :: Row a -> Result (Maybe a)+rowMaybe (Row row) =   Result (Results.single (Result.maybe row))  -- | -- Zero or more rows packed into the vector. -- --- It's recommended to prefer this function to 'rowsList',+-- It's recommended to prefer this function to 'rowList', -- since it performs notably better. -- -{-# INLINABLE rowsVector #-}-rowsVector :: Row a -> Result (Vector a)-rowsVector (Row row) =+{-# INLINABLE rowVector #-}+rowVector :: Row a -> Result (Vector a)+rowVector (Row row) =   Result (Results.single (Result.vector row))  -- | -- Zero or more rows packed into the list. -- -{-# INLINABLE rowsList #-}-rowsList :: Row a -> Result [a]-rowsList =+{-# INLINABLE rowList #-}+rowList :: Row a -> Result [a]+rowList =   foldrRows strictCons []  @@ -174,23 +174,23 @@   def =     rowsAffected --- | Maps to @('maybeRow' def)@.+-- | Maps to @('rowMaybe' def)@. instance Default (Row a) => Default (Result (Maybe a)) where   {-# INLINE def #-}   def =-    maybeRow def+    rowMaybe def --- | Maps to @('rowsVector' def)@.+-- | Maps to @('rowVector' def)@. instance Default (Row a) => Default (Result (Vector a)) where   {-# INLINE def #-}   def =-    rowsVector def+    rowVector def --- | Maps to @('rowsList' def)@.+-- | Maps to @('rowList' def)@. instance Default (Row a) => Default (Result ([] a)) where   {-# INLINE def #-}   def =-    rowsList def+    rowList def  -- | Maps to @(fmap Identity ('singleRow' def)@. instance Default (Row a) => Default (Result (Identity a)) where@@ -204,32 +204,32 @@  -- | -- Decoder of an individual row,--- which gets composed of column value decoders.+-- which gets composed of column column decoders. --  -- E.g.: --  -- >x :: Row (Maybe Int64, Text, TimeOfDay) -- >x =--- >  (,,) <$> nullableValue int8 <*> value text <*> value time+-- >  (,,) <$> nullableColumn int8 <*> column text <*> column time --  newtype Row a =   Row (Row.Row a)   deriving (Functor, Applicative, Monad)  -- |--- Lift an individual non-nullable value decoder to a composable row decoder.+-- Lift an individual non-nullable column decoder to a composable row decoder. -- -{-# INLINABLE value #-}-value :: Value a -> Row a-value (Value imp) =+{-# INLINABLE column #-}+column :: Value a -> Row a+column (Value imp) =   Row (Row.nonNullValue imp)  -- |--- Lift an individual nullable value decoder to a composable row decoder.+-- Lift an individual nullable column decoder to a composable row decoder. -- -{-# INLINABLE nullableValue #-}-nullableValue :: Value a -> Row (Maybe a)-nullableValue (Value imp) =+{-# INLINABLE nullableColumn #-}+nullableColumn :: Value a -> Row (Maybe a)+nullableColumn (Value imp) =   Row (Row.value imp)  @@ -239,35 +239,35 @@ instance Default (Value a) => Default (Row (Identity a)) where   {-# INLINE def #-}   def =-    fmap Identity (value def)+    fmap Identity (column def)  instance Default (Value a) => Default (Row (Maybe a)) where   {-# INLINE def #-}   def =-    nullableValue def+    nullableColumn def  instance (Default (Value a1), Default (Value a2)) => Default (Row (a1, a2)) where   {-# INLINE def #-}   def =-    ap (fmap (,) (value def)) (value def)+    ap (fmap (,) (column def)) (column def)   -- * Value -------------------------  -- |--- Decoder of an individual value.+-- Decoder of an individual column. --  newtype Value a =   Value (Value.Value a)   deriving (Functor)  --- ** Plain value decoders+-- ** Plain column decoders -------------------------  -- |--- Decoder of the @BOOL@ values.+-- Decoder of the @BOOL@ columns. --  {-# INLINABLE bool #-} bool :: Value Bool@@ -275,7 +275,7 @@   Value (Value.decoder (const A.bool))  -- |--- Decoder of the @INT2@ values.+-- Decoder of the @INT2@ columns. --  {-# INLINABLE int2 #-} int2 :: Value Int16@@ -283,7 +283,7 @@   Value (Value.decoder (const A.int))  -- |--- Decoder of the @INT4@ values.+-- Decoder of the @INT4@ columns. --  {-# INLINABLE int4 #-} int4 :: Value Int32@@ -291,7 +291,7 @@   Value (Value.decoder (const A.int))  -- |--- Decoder of the @INT8@ values.+-- Decoder of the @INT8@ columns. --  {-# INLINABLE int8 #-} int8 :: Value Int64@@ -300,7 +300,7 @@   Value (Value.decoder (const ({-# SCC "int8.int" #-} A.int)))  -- |--- Decoder of the @FLOAT4@ values.+-- Decoder of the @FLOAT4@ columns. --  {-# INLINABLE float4 #-} float4 :: Value Float@@ -308,7 +308,7 @@   Value (Value.decoder (const A.float4))  -- |--- Decoder of the @FLOAT8@ values.+-- Decoder of the @FLOAT8@ columns. --  {-# INLINABLE float8 #-} float8 :: Value Double@@ -316,7 +316,7 @@   Value (Value.decoder (const A.float8))  -- |--- Decoder of the @NUMERIC@ values.+-- Decoder of the @NUMERIC@ columns. --  {-# INLINABLE numeric #-} numeric :: Value B.Scientific@@ -324,15 +324,15 @@   Value (Value.decoder (const A.numeric))  -- |--- Decoder of the @CHAR@ values.--- Note that it supports UTF-8 values.+-- Decoder of the @CHAR@ columns.+-- Note that it supports UTF-8 columns. {-# INLINABLE char #-} char :: Value Char char =   Value (Value.decoder (const A.char))  -- |--- Decoder of the @TEXT@ values.+-- Decoder of the @TEXT@ columns. --  {-# INLINABLE text #-} text :: Value Text@@ -340,7 +340,7 @@   Value (Value.decoder (const A.text_strict))  -- |--- Decoder of the @BYTEA@ values.+-- Decoder of the @BYTEA@ columns. --  {-# INLINABLE bytea #-} bytea :: Value ByteString@@ -348,7 +348,7 @@   Value (Value.decoder (const A.bytea_strict))  -- |--- Decoder of the @DATE@ values.+-- Decoder of the @DATE@ columns. --  {-# INLINABLE date #-} date :: Value B.Day@@ -356,7 +356,7 @@   Value (Value.decoder (const A.date))  -- |--- Decoder of the @TIMESTAMP@ values.+-- Decoder of the @TIMESTAMP@ columns. --  {-# INLINABLE timestamp #-} timestamp :: Value B.LocalTime@@ -364,22 +364,22 @@   Value (Value.decoder (Prelude.bool A.timestamp_float A.timestamp_int))  -- |--- Decoder of the @TIMESTAMPTZ@ values.+-- Decoder of the @TIMESTAMPTZ@ columns. --  -- /NOTICE/ --  -- Postgres does not store the timezone information of @TIMESTAMPTZ@.--- Instead it stores a UTC value and performs silent conversions+-- Instead it stores a UTC column 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.+-- and communicates with Postgres using the UTC columns directly. {-# INLINABLE timestamptz #-} timestamptz :: Value B.UTCTime timestamptz =   Value (Value.decoder (Prelude.bool A.timestamptz_float A.timestamptz_int))  -- |--- Decoder of the @TIME@ values.+-- Decoder of the @TIME@ columns. --  {-# INLINABLE time #-} time :: Value B.TimeOfDay@@ -387,20 +387,20 @@   Value (Value.decoder (Prelude.bool A.time_float A.time_int))  -- |--- Decoder of the @TIMETZ@ values.+-- Decoder of the @TIMETZ@ columns. --  -- 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.+-- to represent a column on the Haskell's side. {-# INLINABLE timetz #-} timetz :: Value (B.TimeOfDay, B.TimeZone) timetz =   Value (Value.decoder (Prelude.bool A.timetz_float A.timetz_int))  -- |--- Decoder of the @INTERVAL@ values.+-- Decoder of the @INTERVAL@ columns. --  {-# INLINABLE interval #-} interval :: Value B.DiffTime@@ -408,7 +408,7 @@   Value (Value.decoder (Prelude.bool A.interval_float A.interval_int))  -- |--- Decoder of the @UUID@ values.+-- Decoder of the @UUID@ columns. --  {-# INLINABLE uuid #-} uuid :: Value B.UUID@@ -416,7 +416,7 @@   Value (Value.decoder (const A.uuid))  -- |--- Decoder of the @INET@ values.+-- Decoder of the @INET@ columns. -- {-# INLINABLE inet #-} inet :: Value (B.NetAddr B.IP)@@ -424,7 +424,7 @@   Value (Value.decoder (const A.inet))  -- |--- Decoder of the @JSON@ values into a JSON AST.+-- Decoder of the @JSON@ columns into a JSON AST. --  {-# INLINABLE json #-} json :: Value B.Value@@ -432,7 +432,7 @@   Value (Value.decoder (const A.json_ast))  -- |--- Decoder of the @JSON@ values into a raw JSON 'ByteString'.+-- Decoder of the @JSON@ columns into a raw JSON 'ByteString'. --  {-# INLINABLE jsonBytes #-} jsonBytes :: (ByteString -> Either Text a) -> Value a@@ -440,7 +440,7 @@   Value (Value.decoder (const (A.json_bytes fn)))  -- |--- Decoder of the @JSONB@ values into a JSON AST.+-- Decoder of the @JSONB@ columns into a JSON AST. --  {-# INLINABLE jsonb #-} jsonb :: Value B.Value@@ -448,7 +448,7 @@   Value (Value.decoder (const A.jsonb_ast))  -- |--- Decoder of the @JSONB@ values into a raw JSON 'ByteString'.+-- Decoder of the @JSONB@ columns into a raw JSON 'ByteString'. --  {-# INLINABLE jsonbBytes #-} jsonbBytes :: (ByteString -> Either Text a) -> Value a@@ -456,7 +456,7 @@   Value (Value.decoder (const (A.jsonb_bytes fn)))  -- |--- Lifts a custom value decoder function to a 'Value' decoder.+-- Lifts a custom column decoder function to a 'Value' decoder. --  {-# INLINABLE custom #-} custom :: (Bool -> ByteString -> Either Text a) -> Value a@@ -464,7 +464,7 @@   Value (Value.decoderFn fn)  --- ** Composite value decoders+-- ** Composite column decoders -------------------------  -- |@@ -484,9 +484,9 @@   Value (Value.decoder (Composite.run imp))  -- |--- A generic decoder of @HSTORE@ values.+-- A generic decoder of @HSTORE@ columns. -- --- Here's how you can use it to construct a specific value:+-- Here's how you can use it to construct a specific column: --  -- @ -- x :: Value [(Text, Maybe Text)]@@ -500,8 +500,8 @@   Value (Value.decoder (const (A.hstore replicateM A.text_strict A.text_strict)))  -- |--- Given a partial mapping from text to value,--- produces a decoder of that value.+-- Given a partial mapping from text to column,+-- produces a decoder of that column. enum :: (Text -> Maybe a) -> Value a enum mapping =   Value (Value.decoder (const (A.enum mapping)))@@ -643,12 +643,12 @@ -- | -- A generic array decoder. -- --- Here's how you can use it to produce a specific array value decoder:+-- Here's how you can use it to produce a specific array column decoder: --  -- @ -- x :: Value [[Text]] -- x =---   array (arrayDimension 'replicateM' (arrayDimension 'replicateM' (arrayValue text)))+--   array (dimension 'replicateM' (dimension 'replicateM' (element text))) -- @ --  newtype Array a =@@ -663,28 +663,28 @@ --  -- * An implementation of the @replicateM@ function -- (@Control.Monad.'Control.Monad.replicateM'@, @Data.Vector.'Data.Vector.replicateM'@),--- which determines the output value.+-- which determines the output column. -- --- * A decoder of its components, which can be either another 'arrayDimension',--- 'arrayValue' or 'arrayNullableValue'.+-- * A decoder of its components, which can be either another 'dimension',+-- 'element' or 'nullableElement'. -- -{-# INLINABLE arrayDimension #-}-arrayDimension :: (forall m. Monad m => Int -> m a -> m b) -> Array a -> Array b-arrayDimension replicateM (Array imp) =+{-# INLINABLE dimension #-}+dimension :: (forall m. Monad m => Int -> m a -> m b) -> Array a -> Array b+dimension replicateM (Array imp) =   Array (Array.dimension replicateM imp)  -- |--- Lift a 'Value' decoder into an 'Array' decoder for parsing of non-nullable leaf values.-{-# INLINABLE arrayValue #-}-arrayValue :: Value a -> Array a-arrayValue (Value imp) =+-- Lift a 'Value' decoder into an 'Array' decoder for parsing of non-nullable leaf columns.+{-# INLINABLE element #-}+element :: Value a -> Array a+element (Value imp) =   Array (Array.nonNullValue (Value.run imp))  -- |--- Lift a 'Value' decoder into an 'Array' decoder for parsing of nullable leaf values.-{-# INLINABLE arrayNullableValue #-}-arrayNullableValue :: Value a -> Array (Maybe a)-arrayNullableValue (Value imp) =+-- Lift a 'Value' decoder into an 'Array' decoder for parsing of nullable leaf columns.+{-# INLINABLE nullableElement #-}+nullableElement :: Value a -> Array (Maybe a)+nullableElement (Value imp) =   Array (Array.value (Value.run imp))  @@ -692,22 +692,22 @@ -------------------------  -- |--- Composable decoder of composite values (rows, records).+-- Composable decoder of composite columns (rows, records). newtype Composite a =   Composite (Composite.Composite a)   deriving (Functor, Applicative, Monad)  -- |--- Lift a 'Value' decoder into a 'Composite' decoder for parsing of non-nullable leaf values.-{-# INLINABLE compositeValue #-}-compositeValue :: Value a -> Composite a-compositeValue (Value imp) =+-- Lift a 'Value' decoder into a 'Composite' decoder for parsing of non-nullable leaf columns.+{-# INLINABLE field #-}+field :: Value a -> Composite a+field (Value imp) =   Composite (Composite.nonNullValue (Value.run imp))  -- |--- Lift a 'Value' decoder into a 'Composite' decoder for parsing of nullable leaf values.-{-# INLINABLE compositeNullableValue #-}-compositeNullableValue :: Value a -> Composite (Maybe a)-compositeNullableValue (Value imp) =+-- Lift a 'Value' decoder into a 'Composite' decoder for parsing of nullable leaf columns.+{-# INLINABLE nullableField #-}+nullableField :: Value a -> Composite (Maybe a)+nullableField (Value imp) =   Composite (Composite.value (Value.run imp)) 
library/Hasql/Encoders.hs view
@@ -5,8 +5,8 @@   -- * Params   Params,   unit,-  value,-  nullableValue,+  param,+  nullableParam,   -- * Value   Value,   bool,@@ -36,9 +36,9 @@   unknown,   -- * Array   Array,-  arrayValue,-  arrayNullableValue,-  arrayDimension,+  element,+  nullableElement,+  dimension,   -- ** Insert Many   -- $insertMany )@@ -47,6 +47,7 @@ import Hasql.Private.Prelude hiding (bool) import qualified PostgreSQL.Binary.Encoding as A import qualified PostgreSQL.Binary.Data as B+import qualified Text.Builder as C import qualified Hasql.Private.Encoders.Params as Params import qualified Hasql.Private.Encoders.Value as Value import qualified Hasql.Private.Encoders.Array as Array@@ -67,7 +68,7 @@ -- someParamsEncoder :: 'Params' (Int64, Maybe Text) -- someParamsEncoder = --   'contramap' 'fst' ('value' 'int8') '<>'---   'contramap' 'snd' ('nullableValue' 'text')+--   'contramap' 'snd' ('nullableParam' 'text') -- @ --  -- As a general solution for tuples of any arity, instead of 'fst' and 'snd',@@ -78,7 +79,7 @@ -- @ -- someParamsEncoder :: 'Params' (Int64, Maybe Text) -- someParamsEncoder =---   'contrazip2' ('value' 'int8') ('nullableValue' 'text')+--   'contrazip2' ('value' 'int8') ('nullableParam' 'text') -- @ --  -- Here's how you can implement encoders for custom composite types:@@ -121,17 +122,17 @@ -- | -- Lift an individual value encoder to a parameters encoder. -- -{-# INLINABLE value #-}-value :: Value a -> Params a-value (Value x) =+{-# INLINABLE param #-}+param :: Value a -> Params a+param (Value x) =   Params (Params.value x)  -- | -- Lift an individual nullable value encoder to a parameters encoder. -- -{-# INLINABLE nullableValue #-}-nullableValue :: Value a -> Params (Maybe a)-nullableValue (Value x) =+{-# INLINABLE nullableParam #-}+nullableParam :: Value a -> Params (Maybe a)+nullableParam (Value x) =   Params (Params.nullableValue x)  @@ -148,27 +149,27 @@ instance Default (Value a) => Default (Params (Identity a)) where   {-# INLINE def #-}   def =-    contramap runIdentity (value def)+    contramap runIdentity (param def)  instance (Default (Value a1), Default (Value a2)) => Default (Params (a1, a2)) where   {-# INLINE def #-}   def =-    contrazip2 (value def) (value def)+    contrazip2 (param def) (param def)  instance (Default (Value a1), Default (Value a2), Default (Value a3)) => Default (Params (a1, a2, a3)) where   {-# INLINE def #-}   def =-    contrazip3 (value def) (value def) (value def)+    contrazip3 (param def) (param def) (param def)  instance (Default (Value a1), Default (Value a2), Default (Value a3), Default (Value a4)) => Default (Params (a1, a2, a3, a4)) where   {-# INLINE def #-}   def =-    contrazip4 (value def) (value def) (value def) (value def)+    contrazip4 (param def) (param def) (param def) (param def)  instance (Default (Value a1), Default (Value a2), Default (Value a3), Default (Value a4), Default (Value a5)) => Default (Params (a1, a2, a3, a4, a5)) where   {-# INLINE def #-}   def =-    contrazip5 (value def) (value def) (value def) (value def) (value def)+    contrazip5 (param def) (param def) (param def) (param def) (param def)   -- * Value Encoder@@ -187,49 +188,49 @@ {-# INLINABLE bool #-} bool :: Value Bool bool =-  Value (Value.unsafePTI PTI.bool (const A.bool))+  Value (Value.unsafePTIWithShow PTI.bool (const A.bool))  -- | -- Encoder of @INT2@ values. {-# INLINABLE int2 #-} int2 :: Value Int16 int2 =-  Value (Value.unsafePTI PTI.int2 (const A.int2_int16))+  Value (Value.unsafePTIWithShow PTI.int2 (const A.int2_int16))  -- | -- Encoder of @INT4@ values. {-# INLINABLE int4 #-} int4 :: Value Int32 int4 =-  Value (Value.unsafePTI PTI.int4 (const A.int4_int32))+  Value (Value.unsafePTIWithShow PTI.int4 (const A.int4_int32))  -- | -- Encoder of @INT8@ values. {-# INLINABLE int8 #-} int8 :: Value Int64 int8 =-  Value (Value.unsafePTI PTI.int8 (const A.int8_int64))+  Value (Value.unsafePTIWithShow PTI.int8 (const A.int8_int64))  -- | -- Encoder of @FLOAT4@ values. {-# INLINABLE float4 #-} float4 :: Value Float float4 =-  Value (Value.unsafePTI PTI.float4 (const A.float4))+  Value (Value.unsafePTIWithShow PTI.float4 (const A.float4))  -- | -- Encoder of @FLOAT8@ values. {-# INLINABLE float8 #-} float8 :: Value Double float8 =-  Value (Value.unsafePTI PTI.float8 (const A.float8))+  Value (Value.unsafePTIWithShow PTI.float8 (const A.float8))  -- | -- Encoder of @NUMERIC@ values. {-# INLINABLE numeric #-} numeric :: Value B.Scientific numeric =-  Value (Value.unsafePTI PTI.numeric (const A.numeric))+  Value (Value.unsafePTIWithShow PTI.numeric (const A.numeric))  -- | -- Encoder of @CHAR@ values.@@ -238,113 +239,115 @@ {-# INLINABLE char #-} char :: Value Char char =-  Value (Value.unsafePTI PTI.text (const A.char_utf8))+  Value (Value.unsafePTIWithShow PTI.text (const A.char_utf8))  -- | -- Encoder of @TEXT@ values. {-# INLINABLE text #-} text :: Value Text text =-  Value (Value.unsafePTI PTI.text (const A.text_strict))+  Value (Value.unsafePTIWithShow PTI.text (const A.text_strict))  -- | -- Encoder of @BYTEA@ values. {-# INLINABLE bytea #-} bytea :: Value ByteString bytea =-  Value (Value.unsafePTI PTI.bytea (const A.bytea_strict))+  Value (Value.unsafePTIWithShow PTI.bytea (const A.bytea_strict))  -- | -- Encoder of @DATE@ values. {-# INLINABLE date #-} date :: Value B.Day date =-  Value (Value.unsafePTI PTI.date (const A.date))+  Value (Value.unsafePTIWithShow PTI.date (const A.date))  -- | -- Encoder of @TIMESTAMP@ values. {-# INLINABLE timestamp #-} timestamp :: Value B.LocalTime timestamp =-  Value (Value.unsafePTI PTI.timestamp (Prelude.bool A.timestamp_float A.timestamp_int))+  Value (Value.unsafePTIWithShow PTI.timestamp (Prelude.bool A.timestamp_float A.timestamp_int))  -- | -- Encoder of @TIMESTAMPTZ@ values. {-# INLINABLE timestamptz #-} timestamptz :: Value B.UTCTime timestamptz =-  Value (Value.unsafePTI PTI.timestamptz (Prelude.bool A.timestamptz_float A.timestamptz_int))+  Value (Value.unsafePTIWithShow PTI.timestamptz (Prelude.bool A.timestamptz_float A.timestamptz_int))  -- | -- Encoder of @TIME@ values. {-# INLINABLE time #-} time :: Value B.TimeOfDay time =-  Value (Value.unsafePTI PTI.time (Prelude.bool A.time_float A.time_int))+  Value (Value.unsafePTIWithShow PTI.time (Prelude.bool A.time_float A.time_int))  -- | -- Encoder of @TIMETZ@ values. {-# INLINABLE timetz #-} timetz :: Value (B.TimeOfDay, B.TimeZone) timetz =-  Value (Value.unsafePTI PTI.timetz (Prelude.bool A.timetz_float A.timetz_int))+  Value (Value.unsafePTIWithShow PTI.timetz (Prelude.bool A.timetz_float A.timetz_int))  -- | -- Encoder of @INTERVAL@ values. {-# INLINABLE interval #-} interval :: Value B.DiffTime interval =-  Value (Value.unsafePTI PTI.interval (Prelude.bool A.interval_float A.interval_int))+  Value (Value.unsafePTIWithShow PTI.interval (Prelude.bool A.interval_float A.interval_int))  -- | -- Encoder of @UUID@ values. {-# INLINABLE uuid #-} uuid :: Value B.UUID uuid =-  Value (Value.unsafePTI PTI.uuid (const A.uuid))+  Value (Value.unsafePTIWithShow PTI.uuid (const A.uuid))  -- | -- Encoder of @INET@ values. {-# INLINABLE inet #-} inet :: Value (B.NetAddr B.IP) inet =-  Value (Value.unsafePTI PTI.inet (const A.inet))+  Value (Value.unsafePTIWithShow PTI.inet (const A.inet))  -- | -- Encoder of @JSON@ values from JSON AST. {-# INLINABLE json #-} json :: Value B.Value json =-  Value (Value.unsafePTI PTI.json (const A.json_ast))+  Value (Value.unsafePTIWithShow PTI.json (const A.json_ast))  -- | -- Encoder of @JSON@ values from raw JSON. {-# INLINABLE jsonBytes #-} jsonBytes :: Value ByteString jsonBytes =-  Value (Value.unsafePTI PTI.json (const A.json_bytes))+  Value (Value.unsafePTIWithShow PTI.json (const A.json_bytes))  -- | -- Encoder of @JSONB@ values from JSON AST. {-# INLINABLE jsonb #-} jsonb :: Value B.Value jsonb =-  Value (Value.unsafePTI PTI.jsonb (const A.jsonb_ast))+  Value (Value.unsafePTIWithShow PTI.jsonb (const A.jsonb_ast))  -- | -- Encoder of @JSONB@ values from raw JSON. {-# INLINABLE jsonbBytes #-} jsonbBytes :: Value ByteString jsonbBytes =-  Value (Value.unsafePTI PTI.jsonb (const A.jsonb_bytes))+  Value (Value.unsafePTIWithShow PTI.jsonb (const A.jsonb_bytes))  -- | -- Unlifts the 'Array' encoder to the plain 'Value' encoder. {-# INLINABLE array #-} array :: Array a -> Value a-array (Array imp) =-  Array.run imp & \(arrayOID, encoder') ->-    Value (Value.Value arrayOID arrayOID encoder')+array (Array (Array.Array valueOID arrayOID arrayEncoder renderer)) =+  let+    encoder env input =+      A.array (PTI.oidWord32 valueOID) (arrayEncoder env input)+    in Value (Value.Value arrayOID arrayOID encoder renderer)  -- | -- Given a function,@@ -353,7 +356,7 @@ {-# INLINABLE enum #-} enum :: (a -> Text) -> Value a enum mapping =-  Value (Value.unsafePTI PTI.text (const (A.text_strict . mapping)))+  Value (Value.unsafePTI PTI.text (const (A.text_strict . mapping)) (C.text . mapping))  -- | -- Identifies the value with the PostgreSQL's \"unknown\" type,@@ -366,7 +369,7 @@ {-# INLINABLE unknown #-} unknown :: Value ByteString unknown =-  Value (Value.unsafePTI PTI.unknown (const A.bytea_strict))+  Value (Value.unsafePTIWithShow PTI.unknown (const A.bytea_strict))   -- ** Instances@@ -491,7 +494,7 @@ --  -- >x :: Value [[Int64]] -- >x =--- >  array (arrayDimension foldl' (arrayDimension foldl' (arrayValue int8)))+-- >  array (dimension foldl' (dimension foldl' (element 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 **field** = ANY($1) query instead.@@ -501,17 +504,17 @@  -- | -- Lifts the 'Value' encoder into the 'Array' encoder of a non-nullable value.-{-# INLINABLE arrayValue #-}-arrayValue :: Value a -> Array a-arrayValue (Value (Value.Value elementOID arrayOID encoder')) =-  Array (Array.value elementOID arrayOID encoder')+{-# INLINABLE element #-}+element :: Value a -> Array a+element (Value (Value.Value elementOID arrayOID encoder renderer)) =+  Array (Array.value elementOID arrayOID encoder renderer)  -- | -- Lifts the 'Value' encoder into the 'Array' encoder of a nullable value.-{-# INLINABLE arrayNullableValue #-}-arrayNullableValue :: Value a -> Array (Maybe a)-arrayNullableValue (Value (Value.Value elementOID arrayOID encoder')) =-  Array (Array.nullableValue elementOID arrayOID encoder')+{-# INLINABLE nullableElement #-}+nullableElement :: Value a -> Array (Maybe a)+nullableElement (Value (Value.Value elementOID arrayOID encoder renderer)) =+  Array (Array.nullableValue elementOID arrayOID encoder renderer)  -- | -- An encoder of an array dimension,@@ -523,12 +526,12 @@ -- such as @Data.Foldable.'foldl''@, -- which determines the input value. -- --- * A component encoder, which can be either another 'arrayDimension',--- 'arrayValue' or 'arrayNullableValue'.+-- * A component encoder, which can be either another 'dimension',+-- 'element' or 'nullableElement'. -- -{-# INLINABLE arrayDimension #-}-arrayDimension :: (forall a. (a -> b -> a) -> a -> c -> a) -> Array b -> Array c-arrayDimension foldl (Array imp) =+{-# INLINABLE dimension #-}+dimension :: (forall a. (a -> b -> a) -> a -> c -> a) -> Array b -> Array c+dimension foldl (Array imp) =   Array (Array.dimension foldl imp)  -- $insertMany@@ -550,7 +553,7 @@ --         contrazip3 (vector Encoders.uuid) (vector Encoders.float8) (vector Encoders.float8) --         where --           vector value =---             Encoders.value (Encoders.array (Encoders.arrayDimension foldl' (Encoders.arrayValue value)))+--             Encoders.value (Encoders.array (Encoders.dimension foldl' (Encoders.element value))) --       decoder = --         Decoders.unit -- @
library/Hasql/Private/Decoders/Result.hs view
@@ -1,6 +1,7 @@ module Hasql.Private.Decoders.Result where  import Hasql.Private.Prelude hiding (maybe, many)+import Hasql.Private.Errors import qualified Database.PostgreSQL.LibPQ as LibPQ import qualified Hasql.Private.Decoders.Row as Row import qualified Data.Attoparsec.ByteString.Char8 as Attoparsec@@ -11,42 +12,11 @@   newtype Result a =-  Result (ReaderT (Bool, LibPQ.Result) (ExceptT Error IO) a)+  Result (ReaderT (Bool, LibPQ.Result) (ExceptT ResultError IO) a)   deriving (Functor, Applicative, Monad) -data Error =-  -- | -  -- An error reported by the DB. Code, message, details, hint.-  -- -  -- * The SQLSTATE code for the error. The SQLSTATE code identifies the type of error that has occurred; -  -- it can be used by front-end applications to perform specific operations (such as error handling) -  -- in response to a particular database error. -  -- For a list of the possible SQLSTATE codes, see Appendix A.-  -- This field is not localizable, and is always present.-  -- -  -- * The primary human-readable error message (typically one line). Always present.-  -- -  -- * Detail: an optional secondary error message carrying more detail about the problem. -  -- Might run to multiple lines.-  -- -  -- * Hint: an optional suggestion what to do about the problem. -  -- This is intended to differ from detail in that it offers advice (potentially inappropriate) -  -- rather than hard facts. Might run to multiple lines.-  ServerError !ByteString !ByteString !(Maybe ByteString) !(Maybe ByteString) |-  -- |-  -- The database returned an unexpected result.-  -- Indicates an improper statement or a schema mismatch.-  UnexpectedResult !Text |-  -- |-  -- An error of the row reader, preceded by the index of the row.-  RowError !Int !Row.Error |-  -- |-  -- An unexpected amount of rows.-  UnexpectedAmountOfRows !Int-  deriving (Show)- {-# INLINE run #-}-run :: Result a -> (Bool, LibPQ.Result) -> IO (Either Error a)+run :: Result a -> (Bool, LibPQ.Result) -> IO (Either ResultError a) run (Result reader) env =   runExceptT (runReaderT reader env) 
library/Hasql/Private/Decoders/Results.hs view
@@ -12,6 +12,7 @@ module Hasql.Private.Decoders.Results where  import Hasql.Private.Prelude hiding (maybe, many)+import Hasql.Private.Errors import qualified Database.PostgreSQL.LibPQ as LibPQ import qualified Hasql.Private.Prelude as Prelude import qualified Hasql.Private.Decoders.Result as Result@@ -19,20 +20,12 @@   newtype Results a =-  Results (ReaderT (Bool, LibPQ.Connection) (ExceptT Error IO) a)+  Results (ReaderT (Bool, LibPQ.Connection) (ExceptT CommandError IO) a)   deriving (Functor, Applicative, Monad) -data Error =-  -- |-  -- An error on the client-side,-  -- with a message generated by the \"libpq\" library.-  -- Usually indicates problems with the connection.-  ClientError !(Maybe ByteString) |-  ResultError !Result.Error-  deriving (Show)  {-# INLINE run #-}-run :: Results a -> (Bool, LibPQ.Connection) -> IO (Either Error a)+run :: Results a -> (Bool, LibPQ.Connection) -> IO (Either CommandError a) run (Results stack) env =   runExceptT (runReaderT stack env) 
library/Hasql/Private/Decoders/Row.hs view
@@ -1,37 +1,32 @@ module Hasql.Private.Decoders.Row where  import Hasql.Private.Prelude+import Hasql.Private.Errors import qualified Database.PostgreSQL.LibPQ as LibPQ import qualified PostgreSQL.Binary.Decoding as A import qualified Hasql.Private.Decoders.Value as Value   newtype Row a =-  Row (ReaderT Env (ExceptT Error IO) a)+  Row (ReaderT Env (ExceptT RowError IO) a)   deriving (Functor, Applicative, Monad)  data Env =   Env !LibPQ.Result !LibPQ.Row !LibPQ.Column !Bool !(IORef LibPQ.Column) -data Error =-  EndOfInput |-  UnexpectedNull |-  ValueError !Text-  deriving (Show) - -- * Functions -------------------------  {-# INLINE run #-}-run :: Row a -> (LibPQ.Result, LibPQ.Row, LibPQ.Column, Bool) -> IO (Either Error a)+run :: Row a -> (LibPQ.Result, LibPQ.Row, LibPQ.Column, Bool) -> IO (Either RowError a) run (Row impl) (result, row, columnsAmount, integerDatetimes) =   do     columnRef <- newIORef 0     runExceptT (runReaderT impl (Env result row columnsAmount integerDatetimes columnRef))  {-# INLINE error #-}-error :: Error -> Row a+error :: RowError -> Row a error x =   Row (ReaderT (const (ExceptT (pure (Left x))))) 
library/Hasql/Private/Encoders/Array.hs view
@@ -3,28 +3,43 @@ import Hasql.Private.Prelude import qualified PostgreSQL.Binary.Encoding as A import qualified Hasql.Private.PTI as B+import qualified Text.Builder as C   data Array a =-  Array B.OID B.OID (Bool -> a -> A.Array)--{-# INLINE run #-}-run :: Array a -> (B.OID, Bool -> a -> A.Encoding)-run (Array valueOID arrayOID encoder) =-  (arrayOID, \env input -> A.array (B.oidWord32 valueOID) (encoder env input))+  Array B.OID B.OID (Bool -> a -> A.Array) (a -> C.Builder)  {-# INLINE value #-}-value :: B.OID -> B.OID -> (Bool -> a -> A.Encoding) -> Array a+value :: B.OID -> B.OID -> (Bool -> a -> A.Encoding) -> (a -> C.Builder) -> Array a value valueOID arrayOID encoder =   Array valueOID arrayOID (\params -> A.encodingArray . encoder params)  {-# INLINE nullableValue #-}-nullableValue :: B.OID -> B.OID -> (Bool -> a -> A.Encoding) -> Array (Maybe a)-nullableValue valueOID arrayOID encoder =-  Array valueOID arrayOID (\params -> maybe A.nullArray (A.encodingArray . encoder params))+nullableValue :: B.OID -> B.OID -> (Bool -> a -> A.Encoding) -> (a -> C.Builder) -> Array (Maybe a)+nullableValue valueOID arrayOID encoder renderer =+  let+    maybeEncoder params =+      maybe A.nullArray (A.encodingArray . encoder params)+    maybeRenderer =+      maybe (C.string "null") renderer+    in Array valueOID arrayOID maybeEncoder maybeRenderer  {-# INLINE dimension #-} dimension :: (forall a. (a -> b -> a) -> a -> c -> a) -> Array b -> Array c-dimension fold (Array valueOID arrayOID encoder) =-  Array valueOID arrayOID (\params -> A.dimensionArray fold (encoder params))-+dimension fold (Array valueOID arrayOID elEncoder elRenderer) =+  let+    encoder el =+      A.dimensionArray fold (elEncoder el)+    renderer els =+      let+        folded =+          let+            step builder el =+              if C.null builder+                then C.char '[' <> elRenderer el+                else builder <> C.string ", " <> elRenderer el+            in fold step mempty els+        in if C.null folded+          then C.string "[]"+          else folded <> C.char ']'+    in Array valueOID arrayOID encoder renderer
library/Hasql/Private/Encoders/Params.hs view
@@ -5,52 +5,29 @@ import qualified PostgreSQL.Binary.Encoding as B import qualified Hasql.Private.Encoders.Value as C import qualified Hasql.Private.PTI as D+import qualified Text.Builder as E   -- | -- Encoder of some representation of a parameters product. newtype Params a =-  Params (Op (DList (A.Oid, Bool -> Maybe ByteString)) a)+  Params (Op (DList (A.Oid, A.Format, Bool -> Maybe ByteString, Text)) a)   deriving (Contravariant, Divisible, Decidable, Monoid)  instance Semigroup (Params a) -run :: Params a -> a -> DList (A.Oid, Bool -> Maybe ByteString)-run (Params (Op op)) params =-  {-# SCC "run" #-} -  op params--run' :: Params a -> a -> Bool -> ([A.Oid], [Maybe (ByteString, A.Format)])-run' (Params (Op op)) params integerDatetimes =-  {-# SCC "run'" #-} -  foldr step ([], []) (op params)-  where-    step (oid, bytesGetter) ~(oidList, bytesAndFormatList) =-      (,)-        (oid : oidList)-        (fmap (\bytes -> (bytes, format oid)) (bytesGetter integerDatetimes) : bytesAndFormatList)--run'' :: Params a -> a -> Bool -> [Maybe (A.Oid, ByteString, A.Format)]-run'' (Params (Op op)) params integerDatetimes =-  {-# SCC "run''" #-} -  foldr step [] (op params)-  where-    step a b =-      mapping a : b-      where-        mapping (oid, bytesGetter) =-          (,,) <$> pure oid <*> bytesGetter integerDatetimes <*> pure (format oid)--format :: A.Oid -> A.Format-format oid = case oid of-  A.Oid 705 -> A.Text -- is unknown-  _         -> A.Binary- value :: C.Value a -> Params a value =   contramap Just . nullableValue  nullableValue :: C.Value a -> Params (Maybe a)-nullableValue (C.Value valueOID arrayOID encoder) =-  Params $ Op $ \input -> -    pure (D.oidPQ valueOID, \env -> fmap (B.encodingBytes . encoder env) input)+nullableValue (C.Value valueOID arrayOID encode render) =+  Params $ Op $ \ input ->+  let+    D.OID _ pqOid format =+      valueOID+    encoder env =+      fmap (B.encodingBytes . encode env) input+    rendering =+      maybe "null" (E.run . render) input+    in pure (pqOid, format, encoder, rendering)
library/Hasql/Private/Encoders/Value.hs view
@@ -3,24 +3,23 @@ import Hasql.Private.Prelude import qualified PostgreSQL.Binary.Encoding as B import qualified Hasql.Private.PTI as PTI+import qualified Text.Builder as C   data Value a =-  Value PTI.OID PTI.OID (Bool -> a -> B.Encoding)+  Value PTI.OID PTI.OID (Bool -> a -> B.Encoding) (a -> C.Builder)  instance Contravariant Value where   {-# INLINE contramap #-}-  contramap f (Value valueOID arrayOID encoder) =-    Value valueOID arrayOID (\integerDatetimes input -> encoder integerDatetimes (f input))--{-# INLINE run #-}-run :: Value a -> (PTI.OID, PTI.OID, Bool -> a -> B.Encoding)-run (Value valueOID arrayOID encoder') =-  (valueOID, arrayOID, encoder')+  contramap f (Value valueOID arrayOID encode render) =+    Value valueOID arrayOID (\integerDatetimes input -> encode integerDatetimes (f input)) (render . f)  {-# INLINE unsafePTI #-}-unsafePTI :: PTI.PTI -> (Bool -> a -> B.Encoding) -> Value a-unsafePTI pti encoder' =-  Value (PTI.ptiOID pti) (fromMaybe ($bug "No array OID") (PTI.ptiArrayOID pti)) encoder'-+unsafePTI :: PTI.PTI -> (Bool -> a -> B.Encoding) -> (a -> C.Builder) -> Value a+unsafePTI pti =+  Value (PTI.ptiOID pti) (fromMaybe ($bug "No array OID") (PTI.ptiArrayOID pti)) +{-# INLINE unsafePTIWithShow #-}+unsafePTIWithShow :: Show a => PTI.PTI -> (Bool -> a -> B.Encoding) -> Value a+unsafePTIWithShow pti encode =+  unsafePTI pti encode (C.string . show)
+ library/Hasql/Private/Errors.hs view
@@ -0,0 +1,88 @@+-- |+-- An API for retrieval of multiple results.+-- Can be used to handle:+-- +-- * A single result,+-- +-- * Individual results of a multi-statement query+-- with the help of "Applicative" and "Monad",+-- +-- * Row-by-row fetching.+-- +module Hasql.Private.Errors where++import Hasql.Private.Prelude+++-- |+-- An error during the execution of a query.+-- Comes packed with the query template and a textual representation of the provided params.+data QueryError =+  QueryError ByteString [Text] CommandError+  deriving (Show, Eq)++-- |+-- 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) |+  -- |+  -- Some error with a command result.+  ResultError ResultError+  deriving (Show, Eq)++-- |+-- An error with a command result.+data ResultError =+  -- | +  -- An error reported by the DB.+  -- Consists of the following: Code, message, details, hint.+  -- +  -- * __Code__.+  -- The SQLSTATE code for the error.+  -- It's recommended to use+  -- <http://hackage.haskell.org/package/postgresql-error-codes the "postgresql-error-codes" package>+  -- to work with those.+  -- +  -- * __Message__.+  -- The primary human-readable error message (typically one line). Always present.+  -- +  -- * __Details__.+  -- An optional secondary error message carrying more detail about the problem. +  -- Might run to multiple lines.+  -- +  -- * __Hint__.+  -- An optional suggestion on what to do about the problem. +  -- This is intended to differ from detail in that it offers advice (potentially inappropriate) +  -- rather than hard facts.+  -- Might run to multiple lines.+  ServerError ByteString ByteString (Maybe ByteString) (Maybe ByteString) |+  -- |+  -- The database returned an unexpected result.+  -- Indicates an improper statement or a schema mismatch.+  UnexpectedResult Text |+  -- |+  -- An error of the row reader, preceded by the index of the row.+  RowError Int RowError |+  -- |+  -- An unexpected amount of rows.+  UnexpectedAmountOfRows Int+  deriving (Show, Eq)++-- |+-- 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 |+  -- |+  -- Appears on the attempt to parse a @NULL@ as some value.+  UnexpectedNull |+  -- |+  -- Appears when a wrong value parser is used.+  -- Comes with the error details.+  ValueError Text+  deriving (Show, Eq)
library/Hasql/Private/IO.hs view
@@ -4,6 +4,7 @@ where  import Hasql.Private.Prelude+import Hasql.Private.Errors import qualified Database.PostgreSQL.LibPQ as LibPQ import qualified Hasql.Private.Commands as Commands import qualified Hasql.Private.PreparedStatementRegistry as PreparedStatementRegistry@@ -58,7 +59,7 @@   void $ LibPQ.exec c (Commands.asBytes (Commands.setEncodersToUTF8 <> Commands.setMinClientMessagesToWarning))  {-# INLINE getResults #-}-getResults :: LibPQ.Connection -> Bool -> ResultsDecoders.Results a -> IO (Either ResultsDecoders.Error a)+getResults :: LibPQ.Connection -> Bool -> ResultsDecoders.Results a -> IO (Either CommandError a) getResults connection integerDatetimes decoder =   {-# SCC "getResults" #-}    (<*) <$> get <*> dropRemainders@@ -72,7 +73,7 @@ getPreparedStatementKey ::   LibPQ.Connection -> PreparedStatementRegistry.PreparedStatementRegistry ->   ByteString -> [LibPQ.Oid] ->-  IO (Either ResultsDecoders.Error ByteString)+  IO (Either CommandError ByteString) getPreparedStatementKey connection registry template oidList =   {-# SCC "getPreparedStatementKey" #-}    PreparedStatementRegistry.update localKey onNewRemoteKey onOldRemoteKey registry@@ -99,33 +100,50 @@       pure (pure key)  {-# INLINE checkedSend #-}-checkedSend :: LibPQ.Connection -> IO Bool -> IO (Either ResultsDecoders.Error ())+checkedSend :: LibPQ.Connection -> IO Bool -> IO (Either CommandError ()) checkedSend connection send =   send >>= \case-    False -> fmap (Left . ResultsDecoders.ClientError) $ LibPQ.errorMessage connection+    False -> fmap (Left . ClientError) $ LibPQ.errorMessage connection     True -> pure (Right ())  {-# INLINE sendPreparedParametricQuery #-} sendPreparedParametricQuery ::   LibPQ.Connection ->   PreparedStatementRegistry.PreparedStatementRegistry ->+  Bool ->   ByteString ->-  [LibPQ.Oid] ->-  [Maybe (ByteString, LibPQ.Format)] ->-  IO (Either ResultsDecoders.Error ())-sendPreparedParametricQuery connection registry template oidList valueAndFormatList =-  runExceptT $ do-    key <- ExceptT $ getPreparedStatementKey connection registry template oidList-    ExceptT $ checkedSend connection $ LibPQ.sendQueryPrepared connection key valueAndFormatList LibPQ.Binary+  ParamsEncoders.Params a ->+  a ->+  IO (Either CommandError ())+sendPreparedParametricQuery connection registry integerDatetimes template (ParamsEncoders.Params (Op encoderOp)) input =+  let+    (oidList, valueAndFormatList) =+      let+        step (oid, format, encoder, _) ~(oidList, bytesAndFormatList) =+          (,)+            (oid : oidList)+            (fmap (\bytes -> (bytes, format)) (encoder integerDatetimes) : bytesAndFormatList)+        in foldr step ([], []) (encoderOp input)+    in runExceptT $ do+      key <- ExceptT $ getPreparedStatementKey connection registry template oidList+      ExceptT $ checkedSend connection $ LibPQ.sendQueryPrepared connection key valueAndFormatList LibPQ.Binary  {-# INLINE sendUnpreparedParametricQuery #-} sendUnpreparedParametricQuery ::   LibPQ.Connection ->+  Bool ->   ByteString ->-  [Maybe (LibPQ.Oid, ByteString, LibPQ.Format)] ->-  IO (Either ResultsDecoders.Error ())-sendUnpreparedParametricQuery connection template paramList =-  checkedSend connection $ LibPQ.sendQueryParams connection template paramList LibPQ.Binary+  ParamsEncoders.Params a ->+  a ->+  IO (Either CommandError ())+sendUnpreparedParametricQuery connection integerDatetimes template (ParamsEncoders.Params (Op encoderOp)) input =+  let+    params =+      let+        step (oid, format, encoder, _) acc =+          ((,,) <$> pure oid <*> encoder integerDatetimes <*> pure format) : acc+        in foldr step [] (encoderOp input)+    in checkedSend connection $ LibPQ.sendQueryParams connection template params LibPQ.Binary  {-# INLINE sendParametricQuery #-} sendParametricQuery ::@@ -136,24 +154,14 @@   ParamsEncoders.Params a ->   Bool ->   a ->-  IO (Either ResultsDecoders.Error ())+  IO (Either CommandError ()) sendParametricQuery connection integerDatetimes registry template encoder prepared params =   {-# SCC "sendParametricQuery" #-}    if prepared-    then-      let-        (oidList, valueAndFormatList) =-          ParamsEncoders.run' encoder params integerDatetimes-        in-          sendPreparedParametricQuery connection registry template oidList valueAndFormatList-    else-      let-        paramList =-          ParamsEncoders.run'' encoder params integerDatetimes-        in-          sendUnpreparedParametricQuery connection template paramList+    then sendPreparedParametricQuery connection registry integerDatetimes template encoder params+    else sendUnpreparedParametricQuery connection integerDatetimes template encoder params  {-# INLINE sendNonparametricQuery #-}-sendNonparametricQuery :: LibPQ.Connection -> ByteString -> IO (Either ResultsDecoders.Error ())+sendNonparametricQuery :: LibPQ.Connection -> ByteString -> IO (Either CommandError ()) sendNonparametricQuery connection sql =   checkedSend connection $ LibPQ.sendQuery connection sql
library/Hasql/Private/PTI.hs view
@@ -8,87 +8,87 @@ data PTI = PTI { ptiOID :: !OID, ptiArrayOID :: !(Maybe OID) }  -- | A Word32 and a LibPQ representation of an OID-data OID = OID { oidWord32 :: !Word32, oidPQ :: !LibPQ.Oid }+data OID = OID { oidWord32 :: !Word32, oidPQ :: !LibPQ.Oid, oidFormat :: !LibPQ.Format } -mkOID :: Word32 -> OID-mkOID x =-  OID x ((LibPQ.Oid . fromIntegral) x)+mkOID :: LibPQ.Format -> Word32 -> OID+mkOID format x =+  OID x ((LibPQ.Oid . fromIntegral) x) format -mkPTI :: Word32 -> Maybe Word32 -> PTI-mkPTI oid arrayOID =-  PTI (mkOID oid) (fmap mkOID arrayOID)+mkPTI :: LibPQ.Format -> Word32 -> Maybe Word32 -> PTI+mkPTI format oid arrayOID =+  PTI (mkOID format oid) (fmap (mkOID format) arrayOID)   -- * Constants ------------------------- -abstime         = mkPTI 702  (Just 1023)-aclitem         = mkPTI 1033 (Just 1034)-bit             = mkPTI 1560 (Just 1561)-bool            = mkPTI 16   (Just 1000)-box             = mkPTI 603  (Just 1020)-bpchar          = mkPTI 1042 (Just 1014)-bytea           = mkPTI 17   (Just 1001)-char            = mkPTI 18   (Just 1002)-cid             = mkPTI 29   (Just 1012)-cidr            = mkPTI 650  (Just 651)-circle          = mkPTI 718  (Just 719)-cstring         = mkPTI 2275 (Just 1263)-date            = mkPTI 1082 (Just 1182)-daterange       = mkPTI 3912 (Just 3913)-float4          = mkPTI 700  (Just 1021)-float8          = mkPTI 701  (Just 1022)-gtsvector       = mkPTI 3642 (Just 3644)-inet            = mkPTI 869  (Just 1041)-int2            = mkPTI 21   (Just 1005)-int2vector      = mkPTI 22   (Just 1006)-int4            = mkPTI 23   (Just 1007)-int4range       = mkPTI 3904 (Just 3905)-int8            = mkPTI 20   (Just 1016)-int8range       = mkPTI 3926 (Just 3927)-interval        = mkPTI 1186 (Just 1187)-json            = mkPTI 114  (Just 199)-jsonb           = mkPTI 3802 (Just 3807)-line            = mkPTI 628  (Just 629)-lseg            = mkPTI 601  (Just 1018)-macaddr         = mkPTI 829  (Just 1040)-money           = mkPTI 790  (Just 791)-name            = mkPTI 19   (Just 1003)-numeric         = mkPTI 1700 (Just 1231)-numrange        = mkPTI 3906 (Just 3907)-oid             = mkPTI 26   (Just 1028)-oidvector       = mkPTI 30   (Just 1013)-path            = mkPTI 602  (Just 1019)-point           = mkPTI 600  (Just 1017)-polygon         = mkPTI 604  (Just 1027)-record          = mkPTI 2249 (Just 2287)-refcursor       = mkPTI 1790 (Just 2201)-regclass        = mkPTI 2205 (Just 2210)-regconfig       = mkPTI 3734 (Just 3735)-regdictionary   = mkPTI 3769 (Just 3770)-regoper         = mkPTI 2203 (Just 2208)-regoperator     = mkPTI 2204 (Just 2209)-regproc         = mkPTI 24   (Just 1008)-regprocedure    = mkPTI 2202 (Just 2207)-regtype         = mkPTI 2206 (Just 2211)-reltime         = mkPTI 703  (Just 1024)-text            = mkPTI 25   (Just 1009)-tid             = mkPTI 27   (Just 1010)-time            = mkPTI 1083 (Just 1183)-timestamp       = mkPTI 1114 (Just 1115)-timestamptz     = mkPTI 1184 (Just 1185)-timetz          = mkPTI 1266 (Just 1270)-tinterval       = mkPTI 704  (Just 1025)-tsquery         = mkPTI 3615 (Just 3645)-tsrange         = mkPTI 3908 (Just 3909)-tstzrange       = mkPTI 3910 (Just 3911)-tsvector        = mkPTI 3614 (Just 3643)-txid_snapshot   = mkPTI 2970 (Just 2949)-unknown         = mkPTI 705  (Just 705)-uuid            = mkPTI 2950 (Just 2951)-varbit          = mkPTI 1562 (Just 1563)-varchar         = mkPTI 1043 (Just 1015)-void            = mkPTI 2278 Nothing-xid             = mkPTI 28   (Just 1011)-xml             = mkPTI 142  (Just 143)+abstime         = mkPTI LibPQ.Binary 702  (Just 1023)+aclitem         = mkPTI LibPQ.Binary 1033 (Just 1034)+bit             = mkPTI LibPQ.Binary 1560 (Just 1561)+bool            = mkPTI LibPQ.Binary 16   (Just 1000)+box             = mkPTI LibPQ.Binary 603  (Just 1020)+bpchar          = mkPTI LibPQ.Binary 1042 (Just 1014)+bytea           = mkPTI LibPQ.Binary 17   (Just 1001)+char            = mkPTI LibPQ.Binary 18   (Just 1002)+cid             = mkPTI LibPQ.Binary 29   (Just 1012)+cidr            = mkPTI LibPQ.Binary 650  (Just 651)+circle          = mkPTI LibPQ.Binary 718  (Just 719)+cstring         = mkPTI LibPQ.Binary 2275 (Just 1263)+date            = mkPTI LibPQ.Binary 1082 (Just 1182)+daterange       = mkPTI LibPQ.Binary 3912 (Just 3913)+float4          = mkPTI LibPQ.Binary 700  (Just 1021)+float8          = mkPTI LibPQ.Binary 701  (Just 1022)+gtsvector       = mkPTI LibPQ.Binary 3642 (Just 3644)+inet            = mkPTI LibPQ.Binary 869  (Just 1041)+int2            = mkPTI LibPQ.Binary 21   (Just 1005)+int2vector      = mkPTI LibPQ.Binary 22   (Just 1006)+int4            = mkPTI LibPQ.Binary 23   (Just 1007)+int4range       = mkPTI LibPQ.Binary 3904 (Just 3905)+int8            = mkPTI LibPQ.Binary 20   (Just 1016)+int8range       = mkPTI LibPQ.Binary 3926 (Just 3927)+interval        = mkPTI LibPQ.Binary 1186 (Just 1187)+json            = mkPTI LibPQ.Binary 114  (Just 199)+jsonb           = mkPTI LibPQ.Binary 3802 (Just 3807)+line            = mkPTI LibPQ.Binary 628  (Just 629)+lseg            = mkPTI LibPQ.Binary 601  (Just 1018)+macaddr         = mkPTI LibPQ.Binary 829  (Just 1040)+money           = mkPTI LibPQ.Binary 790  (Just 791)+name            = mkPTI LibPQ.Binary 19   (Just 1003)+numeric         = mkPTI LibPQ.Binary 1700 (Just 1231)+numrange        = mkPTI LibPQ.Binary 3906 (Just 3907)+oid             = mkPTI LibPQ.Binary 26   (Just 1028)+oidvector       = mkPTI LibPQ.Binary 30   (Just 1013)+path            = mkPTI LibPQ.Binary 602  (Just 1019)+point           = mkPTI LibPQ.Binary 600  (Just 1017)+polygon         = mkPTI LibPQ.Binary 604  (Just 1027)+record          = mkPTI LibPQ.Binary 2249 (Just 2287)+refcursor       = mkPTI LibPQ.Binary 1790 (Just 2201)+regclass        = mkPTI LibPQ.Binary 2205 (Just 2210)+regconfig       = mkPTI LibPQ.Binary 3734 (Just 3735)+regdictionary   = mkPTI LibPQ.Binary 3769 (Just 3770)+regoper         = mkPTI LibPQ.Binary 2203 (Just 2208)+regoperator     = mkPTI LibPQ.Binary 2204 (Just 2209)+regproc         = mkPTI LibPQ.Binary 24   (Just 1008)+regprocedure    = mkPTI LibPQ.Binary 2202 (Just 2207)+regtype         = mkPTI LibPQ.Binary 2206 (Just 2211)+reltime         = mkPTI LibPQ.Binary 703  (Just 1024)+text            = mkPTI LibPQ.Binary 25   (Just 1009)+tid             = mkPTI LibPQ.Binary 27   (Just 1010)+time            = mkPTI LibPQ.Binary 1083 (Just 1183)+timestamp       = mkPTI LibPQ.Binary 1114 (Just 1115)+timestamptz     = mkPTI LibPQ.Binary 1184 (Just 1185)+timetz          = mkPTI LibPQ.Binary 1266 (Just 1270)+tinterval       = mkPTI LibPQ.Binary 704  (Just 1025)+tsquery         = mkPTI LibPQ.Binary 3615 (Just 3645)+tsrange         = mkPTI LibPQ.Binary 3908 (Just 3909)+tstzrange       = mkPTI LibPQ.Binary 3910 (Just 3911)+tsvector        = mkPTI LibPQ.Binary 3614 (Just 3643)+txid_snapshot   = mkPTI LibPQ.Binary 2970 (Just 2949)+unknown         = mkPTI LibPQ.Text   705  (Just 705)+uuid            = mkPTI LibPQ.Binary 2950 (Just 2951)+varbit          = mkPTI LibPQ.Binary 1562 (Just 1563)+varchar         = mkPTI LibPQ.Binary 1043 (Just 1015)+void            = mkPTI LibPQ.Binary 2278 Nothing+xid             = mkPTI LibPQ.Binary 28   (Just 1011)+xml             = mkPTI LibPQ.Binary 142  (Just 143) 
− library/Hasql/Private/Query.hs
@@ -1,61 +0,0 @@-module Hasql.Private.Query-where--import Hasql.Private.Prelude-import qualified Database.PostgreSQL.LibPQ as LibPQ-import qualified Hasql.Private.IO as IO-import qualified Hasql.Private.Connection as Connection-import qualified Hasql.Private.Decoders.Results as Decoders.Results-import qualified Hasql.Private.Encoders.Params as Encoders.Params----- |--- An abstraction over parametric queries.--- --- It is composable using--- the standard interfaces of the category theory,--- which it has instances of.--- E.g., here's how you can compose queries--- using the Arrow notation:--- --- @--- -- |--- -- Given an Update query,--- -- which uses the \@fmap (> 0) 'Decoders.Results.rowsAffected'\@ decoder--- -- to detect, whether it had any effect,--- -- and an Insert query,--- -- produces a query which performs Upsert.--- composeUpsert :: Query a Bool -> Query a () -> Query a ()--- composeUpsert update insert =---   proc params -> do---     updated <- update -< params---     if updated---       then 'returnA' -< ()---       else insert -< params--- @-newtype Query a b =-  Query (Kleisli (ReaderT Connection.Connection (ExceptT Decoders.Results.Error IO)) a b)-  deriving (Category, Arrow, ArrowChoice, ArrowLoop, ArrowApply)--instance Functor (Query a) where-  {-# INLINE fmap #-}-  fmap =-    (^<<)--instance Profunctor Query where-  {-# INLINE lmap #-}-  lmap =-    (^>>)-  {-# INLINE rmap #-}-  rmap =-    (^<<)--statement :: ByteString -> Encoders.Params.Params a -> Decoders.Results.Results b -> Bool -> Query a b-statement template encoder decoder preparable =-  Query $ Kleisli $ \params -> -    ReaderT $ \(Connection.Connection pqConnectionRef integerDatetimes registry) -> -      ExceptT $ withMVar pqConnectionRef $ \pqConnection -> do-        r1 <- IO.sendParametricQuery pqConnection integerDatetimes registry template encoder preparable params-        r2 <- IO.getResults pqConnection integerDatetimes decoder-        return $ r1 *> r2-
library/Hasql/Private/Session.hs view
@@ -2,24 +2,26 @@ where  import Hasql.Private.Prelude+import Hasql.Private.Errors import qualified Database.PostgreSQL.LibPQ as LibPQ import qualified Hasql.Private.Decoders.Results as Decoders.Results import qualified Hasql.Private.Decoders.Result as Decoders.Result+import qualified Hasql.Private.Encoders.Params as Encoders.Params import qualified Hasql.Private.Settings as Settings import qualified Hasql.Private.IO as IO-import qualified Hasql.Private.Query as Query+import qualified Hasql.Query as Query import qualified Hasql.Private.Connection as Connection   -- | -- A batch of actions to be executed in the context of a database connection. newtype Session a =-  Session (ReaderT Connection.Connection (ExceptT Error IO) a)-  deriving (Functor, Applicative, Monad, MonadError Error, MonadIO)+  Session (ReaderT Connection.Connection (ExceptT QueryError IO) a)+  deriving (Functor, Applicative, Monad, MonadError QueryError, MonadIO)  -- | -- Executes a bunch of commands on the provided connection.-run :: Session a -> Connection.Connection -> IO (Either Error a)+run :: Session a -> Connection.Connection -> IO (Either QueryError a) run (Session impl) connection =   runExceptT $   runReaderT impl connection@@ -31,87 +33,27 @@ sql :: ByteString -> Session () sql sql =   Session $ ReaderT $ \(Connection.Connection pqConnectionRef integerDatetimes registry) ->-    ExceptT $ fmap (mapLeft unsafeCoerce) $ withMVar pqConnectionRef $ \pqConnection -> do+    ExceptT $ fmap (mapLeft (QueryError sql [])) $ withMVar pqConnectionRef $ \pqConnection -> do       r1 <- IO.sendNonparametricQuery pqConnection sql       r2 <- IO.getResults pqConnection integerDatetimes decoder       return $ r1 *> r2   where     decoder =-      Decoders.Results.single $-      Decoders.Result.unit+      Decoders.Results.single Decoders.Result.unit  -- | -- Parameters and a specification of the parametric query to apply them to.-query :: a -> Query.Query a b -> Session b-query input (Query.Query (Kleisli impl)) =-  Session $ unsafeCoerce $ impl input----- * Error------------------------------ |--- An error of some command in the session.-data Error =-  -- |-  -- An error on the client-side,-  -- with a message generated by the \"libpq\" library.-  -- Usually indicates problems with connection.-  ClientError !(Maybe ByteString) |-  -- |-  -- Some error with a command result.-  ResultError !ResultError-  deriving (Show, Eq)---- |--- An error with a command result.-data ResultError =-  -- | -  -- An error reported by the DB.-  -- Consists of the following: Code, message, details, hint.-  -- -  -- * __Code__.-  -- The SQLSTATE code for the error.-  -- It's recommended to use-  -- <http://hackage.haskell.org/package/postgresql-error-codes the "postgresql-error-codes" package>-  -- to work with those.-  -- -  -- * __Message__.-  -- The primary human-readable error message (typically one line). Always present.-  -- -  -- * __Details__.-  -- An optional secondary error message carrying more detail about the problem. -  -- Might run to multiple lines.-  -- -  -- * __Hint__.-  -- An optional suggestion on what to do about the problem. -  -- This is intended to differ from detail in that it offers advice (potentially inappropriate) -  -- rather than hard facts.-  -- Might run to multiple lines.-  ServerError !ByteString !ByteString !(Maybe ByteString) !(Maybe ByteString) |-  -- |-  -- The database returned an unexpected result.-  -- Indicates an improper statement or a schema mismatch.-  UnexpectedResult !Text |-  -- |-  -- An error of the row reader, preceded by the index of the row.-  RowError !Int !RowError |-  -- |-  -- An unexpected amount of rows.-  UnexpectedAmountOfRows !Int-  deriving (Show, Eq)---- |--- 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 |-  -- |-  -- Appears on the attempt to parse a @NULL@ as some value.-  UnexpectedNull |-  -- |-  -- Appears when a wrong value parser is used.-  -- Comes with the error details.-  ValueError !Text-  deriving (Show, Eq)+query :: params -> Query.Query params result -> Session result+query input (Query.Query template encoder decoder preparable) =+  Session $ ReaderT $ \(Connection.Connection pqConnectionRef integerDatetimes registry) ->+    ExceptT $ fmap (mapLeft (QueryError template inputReps)) $ withMVar pqConnectionRef $ \pqConnection -> do+      r1 <- IO.sendParametricQuery pqConnection integerDatetimes registry template (unsafeCoerce encoder) preparable input+      r2 <- IO.getResults pqConnection integerDatetimes (unsafeCoerce decoder)+      return $ r1 *> r2+  where+    inputReps =+      let+        Encoders.Params.Params (Op encoderOp) = (unsafeCoerce encoder)+        step (_, _, _, rendering) acc =+          rendering : acc+        in foldr step [] (encoderOp input)
library/Hasql/Query.hs view
@@ -1,19 +1,11 @@ module Hasql.Query-(-  Query.Query,-  statement,-) where  import Hasql.Private.Prelude-import qualified Hasql.Private.Query as Query-import qualified Hasql.Private.Decoders.Results as Decoders.Results import qualified Hasql.Decoders as Decoders-import qualified Hasql.Private.Encoders.Params as Encoders.Params import qualified Hasql.Encoders as Encoders  - -- | -- A specification of a strictly single-statement query, which can be parameterized and prepared. -- @@ -34,9 +26,9 @@ -- Following is an example of the declaration of a prepared statement with its associated codecs. --  -- @--- selectSum :: Hasql.Query.'Query.Query' (Int64, Int64) Int64+-- selectSum :: Hasql.Query.'Query' (Int64, Int64) Int64 -- selectSum =---   Hasql.Query.'statement' sql encoder decoder True+--   Hasql.Query.'Query' sql encoder decoder True --   where --     sql = --       "select ($1 + $2)"@@ -50,8 +42,14 @@ -- The statement above accepts a product of two parameters of type 'Int64' -- and produces a single result of type 'Int64'. -- -{-# INLINE statement #-}-statement :: ByteString -> Encoders.Params a -> Decoders.Result b -> Bool -> Query.Query a b-statement =-  unsafeCoerce Query.statement+data Query a b =+  Query ByteString (Encoders.Params a) (Decoders.Result b) Bool +instance Functor (Query a) where+  {-# INLINE fmap #-}+  fmap = rmap++instance Profunctor Query where+  {-# INLINE dimap #-}+  dimap f1 f2 (Query template encoder decoder preparable) =+    Query template (contramap f1 encoder) (fmap f2 decoder) preparable
library/Hasql/Session.hs view
@@ -1,15 +1,14 @@ module Hasql.Session (-  Session.Session,-  Session.sql,-  Session.query,+  Session,+  sql,+  query,   -- * Execution-  Session.Error(..),-  Session.ResultError(..),-  Session.RowError(..),-  Session.run,+  run,+  -- * Errors+  module Hasql.Private.Errors, ) where -import qualified Hasql.Private.Session as Session-+import Hasql.Private.Session+import Hasql.Private.Errors
profiling/Main.hs view
@@ -60,7 +60,7 @@  queryWithSingleRow :: C.Query () (Int64, Int64) queryWithSingleRow =-  C.statement template encoder decoder True+  C.Query template encoder decoder True   where     template =       "SELECT 1, 2"@@ -70,29 +70,29 @@       D.singleRow row       where         row =-          tuple <$> D.value D.int8 <*> D.value D.int8+          tuple <$> D.column D.int8 <*> D.column D.int8           where             tuple !a !b =               (a, b)  queryWithManyRows :: (D.Row (Int64, Int64) -> D.Result result) -> C.Query () result queryWithManyRows decoder =-  C.statement template encoder (decoder rowDecoder) True+  C.Query template encoder (decoder rowDecoder) True   where     template =       "SELECT generate_series(0,1000) as a, generate_series(1000,2000) as b"     encoder =       conquer     rowDecoder =-      tuple <$> D.value D.int8 <*> D.value D.int8+      tuple <$> D.column D.int8 <*> D.column D.int8       where         tuple !a !b =           (a, b)  queryWithManyRowsInVector :: C.Query () (Vector (Int64, Int64)) queryWithManyRowsInVector =-  queryWithManyRows D.rowsVector+  queryWithManyRows D.rowVector  queryWithManyRowsInList :: C.Query () (List (Int64, Int64)) queryWithManyRowsInList =-  queryWithManyRows D.rowsList+  queryWithManyRows D.rowList
tasty/Main.hs view
@@ -22,15 +22,34 @@   localOption (NumThreads 1) $   testGroup "All tests"   [+    testCase "Failed query" $+    let+      query =+        Query.Query "select true where 1 = any ($1) and $2" encoder decoder True+        where+          encoder =+            contrazip2+              (Encoders.param (Encoders.array (Encoders.dimension foldl' (Encoders.element Encoders.int8))))+              (Encoders.param Encoders.text)+          decoder =+            fmap (maybe False (const True)) (Decoders.rowMaybe (Decoders.column Decoders.bool))+      session =+        Session.query ([3, 7], "a") query+      in do+        x <- Connection.with (Session.run session)+        assertBool (show x) $ case x of+          Right (Left (Session.QueryError "select true where 1 = any ($1) and $2" ["[3, 7]", "\"a\""] _)) -> True+          _ -> False+    ,     testCase "IN simulation" $     let       query =-        Query.statement "select true where 1 = any ($1)" encoder decoder True+        Query.Query "select true where 1 = any ($1)" encoder decoder True         where           encoder =-            Encoders.value (Encoders.array (Encoders.arrayDimension foldl' (Encoders.arrayValue Encoders.int8)))+            Encoders.param (Encoders.array (Encoders.dimension foldl' (Encoders.element Encoders.int8)))           decoder =-            fmap (maybe False (const True)) (Decoders.maybeRow (Decoders.value Decoders.bool))+            fmap (maybe False (const True)) (Decoders.rowMaybe (Decoders.column Decoders.bool))       session =         do           result1 <- Session.query [1, 2] query@@ -43,12 +62,12 @@     testCase "NOT IN simulation" $     let       query =-        Query.statement "select true where 3 <> all ($1)" encoder decoder True+        Query.Query "select true where 3 <> all ($1)" encoder decoder True         where           encoder =-            Encoders.value (Encoders.array (Encoders.arrayDimension foldl' (Encoders.arrayValue Encoders.int8)))+            Encoders.param (Encoders.array (Encoders.dimension foldl' (Encoders.element Encoders.int8)))           decoder =-            fmap (maybe False (const True)) (Decoders.maybeRow (Decoders.value Decoders.bool))+            fmap (maybe False (const True)) (Decoders.rowMaybe (Decoders.column Decoders.bool))       session =         do           result1 <- Session.query [1, 2] query@@ -61,14 +80,14 @@     testCase "Composite decoding" $     let       query =-        Query.statement sql encoder decoder True+        Query.Query sql encoder decoder True         where           sql =             "select (1, true)"           encoder =              Encoders.unit           decoder =-            Decoders.singleRow (Decoders.value (Decoders.composite ((,) <$> Decoders.compositeValue Decoders.int8 <*> Decoders.compositeValue Decoders.bool)))+            Decoders.singleRow (Decoders.column (Decoders.composite ((,) <$> Decoders.field Decoders.int8 <*> Decoders.field Decoders.bool)))       session =         Session.query () query       in do@@ -78,7 +97,7 @@     testCase "Complex composite decoding" $     let       query =-        Query.statement sql encoder decoder True+        Query.Query sql encoder decoder True         where           sql =             "select (1, true) as entity1, ('hello', 3) as entity2"@@ -86,14 +105,14 @@             Encoders.unit           decoder =             Decoders.singleRow $-            (,) <$> Decoders.value entity1 <*> Decoders.value entity2+            (,) <$> Decoders.column entity1 <*> Decoders.column entity2             where               entity1 =                 Decoders.composite $-                (,) <$> Decoders.compositeValue Decoders.int8 <*> Decoders.compositeValue Decoders.bool+                (,) <$> Decoders.field Decoders.int8 <*> Decoders.field Decoders.bool               entity2 =                 Decoders.composite $-                (,) <$> Decoders.compositeValue Decoders.text <*> Decoders.compositeValue Decoders.int8+                (,) <$> Decoders.field Decoders.text <*> Decoders.field Decoders.int8       session =         Session.query () query       in do@@ -111,14 +130,14 @@             Session.query () query             where               query =-                Query.statement sql encoder decoder True+                Query.Query sql encoder decoder True                 where                   sql =                     "select array[]::int8[]"                   encoder =                     Encoders.unit                   decoder =-                    Decoders.singleRow (Decoders.value (Decoders.array (Decoders.arrayDimension replicateM (Decoders.arrayValue Decoders.int8))))+                    Decoders.singleRow (Decoders.column (Decoders.array (Decoders.dimension replicateM (Decoders.element Decoders.int8))))       in io     ,     testCase "Failing prepared statements" $@@ -129,7 +148,7 @@         where           resultTest =             \case-              Right (Left (Session.ResultError (Session.ServerError "26000" _ _ _))) -> False+              Right (Left (Session.QueryError _ _ (Session.ResultError (Session.ServerError "26000" _ _ _)))) -> False               _ -> True           session =             catchError session (const (pure ())) *> session@@ -138,7 +157,7 @@                 Session.query () query                 where                   query =-                    Query.statement sql encoder decoder True+                    Query.Query sql encoder decoder True                     where                       sql =                         "absurd"@@ -161,14 +180,14 @@                 Session.query 1 query                 where                   query =-                    Query.statement sql encoder decoder True+                    Query.Query sql encoder decoder True                     where                       sql =                         "select $1 :: int8"                       encoder =-                        Encoders.value Encoders.int8+                        Encoders.param Encoders.int8                       decoder =-                        Decoders.singleRow $ Decoders.value Decoders.int8+                        Decoders.singleRow $ Decoders.column Decoders.int8               fail =                 catchError (Session.sql "absurd") (const (pure ()))       in io@@ -177,15 +196,15 @@     let       sumQuery :: Query.Query (Int64, Int64) Int64       sumQuery =-        Query.statement sql encoder decoder True+        Query.Query sql encoder decoder True         where           sql =             "select ($1 + $2)"           encoder =-            contramap fst (Encoders.value Encoders.int8) <>-            contramap snd (Encoders.value Encoders.int8)+            contramap fst (Encoders.param Encoders.int8) <>+            contramap snd (Encoders.param Encoders.int8)           decoder =-            Decoders.singleRow (Decoders.value Decoders.int8)+            Decoders.singleRow (Decoders.column Decoders.int8)       sumSession :: Session.Session Int64       sumSession =         Session.sql "begin" *> Session.query (1, 1) sumQuery <* Session.sql "end"@@ -202,15 +221,15 @@     let       sumQuery :: Query.Query (Int64, Int64) Int64       sumQuery =-        Query.statement sql encoder decoder True+        Query.Query sql encoder decoder True         where           sql =             "select ($1 + $2)"           encoder =-            contramap fst (Encoders.value Encoders.int8) <>-            contramap snd (Encoders.value Encoders.int8)+            contramap fst (Encoders.param Encoders.int8) <>+            contramap snd (Encoders.param Encoders.int8)           decoder =-            Decoders.singleRow (Decoders.value Decoders.int8)+            Decoders.singleRow (Decoders.column Decoders.int8)       session :: Session.Session Int64       session =         do@@ -229,14 +248,14 @@         DSL.session $ do           let             query =-              Query.statement sql encoder decoder True+              Query.Query sql encoder decoder True               where                 sql =                   "select $1 = interval '10 seconds'"                 decoder =-                  (Decoders.singleRow (Decoders.value (Decoders.bool)))+                  (Decoders.singleRow (Decoders.column (Decoders.bool)))                 encoder =-                  Encoders.value (Encoders.interval)+                  Encoders.param (Encoders.interval)             in DSL.query (10 :: DiffTime) query       in actualIO >>= \x -> assertEqual (show x) (Right True) x     ,@@ -246,12 +265,12 @@         DSL.session $ do           let             query =-              Query.statement sql encoder decoder True+              Query.Query sql encoder decoder True               where                 sql =                   "select interval '10 seconds'"                 decoder =-                  (Decoders.singleRow (Decoders.value (Decoders.interval)))+                  (Decoders.singleRow (Decoders.column (Decoders.interval)))                 encoder =                   Encoders.unit             in DSL.query () query@@ -263,14 +282,14 @@         DSL.session $ do           let             query =-              Query.statement sql encoder decoder True+              Query.Query sql encoder decoder True               where                 sql =                   "select $1"                 decoder =-                  (Decoders.singleRow (Decoders.value (Decoders.interval)))+                  (Decoders.singleRow (Decoders.column (Decoders.interval)))                 encoder =-                  Encoders.value (Encoders.interval)+                  Encoders.param (Encoders.interval)             in DSL.query (10 :: DiffTime) query       in actualIO >>= \x -> assertEqual (show x) (Right (10 :: DiffTime)) x     ,@@ -280,28 +299,28 @@         DSL.session $ do           let             query =-              Query.statement sql mempty Decoders.unit True+              Query.Query sql mempty Decoders.unit True               where                 sql =                   "drop type if exists mood"             in DSL.query () query           let             query =-              Query.statement sql mempty Decoders.unit True+              Query.Query sql mempty Decoders.unit True               where                 sql =                   "create type mood as enum ('sad', 'ok', 'happy')"             in DSL.query () query           let             query =-              Query.statement sql encoder decoder True+              Query.Query sql encoder decoder True               where                 sql =                   "select $1 = ('ok' :: mood)"                 decoder =-                  (Decoders.singleRow (Decoders.value (Decoders.bool)))+                  (Decoders.singleRow (Decoders.column (Decoders.bool)))                 encoder =-                  Encoders.value (Encoders.unknown)+                  Encoders.param (Encoders.unknown)             in DSL.query "ok" query       in actualIO >>= assertEqual "" (Right True)     ,@@ -311,28 +330,28 @@         DSL.session $ do           let             query =-              Query.statement sql mempty Decoders.unit True+              Query.Query sql mempty Decoders.unit True               where                 sql =                   "create or replace function overloaded(a int, b int) returns int as $$ select a + b $$ language sql;"             in DSL.query () query           let             query =-              Query.statement sql mempty Decoders.unit True+              Query.Query sql mempty Decoders.unit True               where                 sql =                   "create or replace function overloaded(a text, b text, c text) returns text as $$ select a || b || c $$ language sql;"             in DSL.query () query           let             query =-              Query.statement sql encoder decoder True+              Query.Query sql encoder decoder True               where                 sql =                   "select overloaded($1, $2) || overloaded($3, $4, $5)"                 decoder =-                  (Decoders.singleRow (Decoders.value (Decoders.text)))+                  (Decoders.singleRow (Decoders.column (Decoders.text)))                 encoder =-                  contramany (Encoders.value Encoders.unknown)+                  contramany (Encoders.param Encoders.unknown)             in DSL.query ["1", "2", "4", "5", "6"] query       in actualIO >>= assertEqual "" (Right "3456")     ,@@ -342,28 +361,28 @@         DSL.session $ do           let             query =-              Query.statement sql mempty Decoders.unit True+              Query.Query sql mempty Decoders.unit True               where                 sql =                   "drop type if exists mood"             in DSL.query () query           let             query =-              Query.statement sql mempty Decoders.unit True+              Query.Query sql mempty Decoders.unit True               where                 sql =                   "create type mood as enum ('sad', 'ok', 'happy')"             in DSL.query () query           let             query =-              Query.statement sql encoder decoder True+              Query.Query sql encoder decoder True               where                 sql =                   "select ($1 :: mood)"                 decoder =-                  (Decoders.singleRow (Decoders.value (Decoders.enum (Just . id))))+                  (Decoders.singleRow (Decoders.column (Decoders.enum (Just . id))))                 encoder =-                  Encoders.value (Encoders.enum id)+                  Encoders.param (Encoders.enum id)             in DSL.query "ok" query       in actualIO >>= assertEqual "" (Right "ok")     ,@@ -376,26 +395,26 @@               DSL.query "ok" query               where                 query =-                  Query.statement sql encoder decoder True+                  Query.Query sql encoder decoder True                   where                     sql =                       "select $1"                     encoder =-                      Encoders.value Encoders.text+                      Encoders.param Encoders.text                     decoder =-                      (Decoders.singleRow (Decoders.value (Decoders.text)))+                      (Decoders.singleRow (Decoders.column (Decoders.text)))             effect2 =               DSL.query 1 query               where                 query =-                  Query.statement sql encoder decoder True+                  Query.Query sql encoder decoder True                   where                     sql =                       "select $1"                     encoder =-                      Encoders.value Encoders.int8+                      Encoders.param Encoders.int8                     decoder =-                      (Decoders.singleRow (Decoders.value Decoders.int8))+                      (Decoders.singleRow (Decoders.column Decoders.int8))             in (,) <$> effect1 <*> effect2       in actualIO >>= assertEqual "" (Right ("ok", 1))     ,@@ -419,7 +438,7 @@             DSL.query () $ Queries.plain $             "insert into a (name) values ('a')"             deleteRows =-            DSL.query () $ Query.statement sql def decoder False+            DSL.query () $ Query.Query sql def decoder False             where               sql =                 "delete from a"@@ -433,8 +452,8 @@         DSL.session $ do           DSL.query () $ Queries.plain $ "drop table if exists a"           DSL.query () $ Queries.plain $ "create table a (id serial not null, v char not null, primary key (id))"-          id1 <- DSL.query () $ Query.statement "insert into a (v) values ('a') returning id" def (Decoders.singleRow (Decoders.value Decoders.int4)) False-          id2 <- DSL.query () $ Query.statement "insert into a (v) values ('b') returning id" def (Decoders.singleRow (Decoders.value Decoders.int4)) False+          id1 <- DSL.query () $ Query.Query "insert into a (v) values ('a') returning id" def (Decoders.singleRow (Decoders.column Decoders.int4)) False+          id2 <- DSL.query () $ Query.Query "insert into a (v) values ('b') returning id" def (Decoders.singleRow (Decoders.column Decoders.int4)) False           DSL.query () $ Queries.plain $ "drop table if exists a"           pure (id1, id2)       in assertEqual "" (Right (1, 2)) =<< actualIO
tasty/Main/DSL.hs view
@@ -21,7 +21,7 @@  data SessionError =   ConnectionError (HC.ConnectionError) |-  SessionError (Hasql.Session.Error)+  SessionError (Hasql.Session.QueryError)   deriving (Show, Eq)  session :: Session a -> IO (Either SessionError a)
tasty/Main/Queries.hs view
@@ -9,11 +9,11 @@  def :: ByteString -> HQ.Query () () def sql =-  HQ.statement sql Prelude.def Prelude.def False+  HQ.Query sql Prelude.def Prelude.def False  plain :: ByteString -> HQ.Query () () plain sql =-  HQ.statement sql mempty HD.unit False+  HQ.Query sql mempty HD.unit False  dropType :: ByteString -> HQ.Query () () dropType name =@@ -28,9 +28,9 @@  selectList :: HQ.Query () ([] (Int64, Int64)) selectList =-  HQ.statement sql mempty decoder True+  HQ.Query sql mempty decoder True   where     sql =       "values (1,2), (3,4), (5,6)"     decoder =-      HD.rowsList ((,) <$> HD.value HD.int8 <*> HD.value HD.int8)+      HD.rowList ((,) <$> HD.column HD.int8 <*> HD.column HD.int8)
threads-test/Main/Queries.hs view
@@ -8,12 +8,12 @@  selectSleep :: Query Double () selectSleep =-  statement sql encoder decoder True+  Query sql encoder decoder True   where     sql =       "select pg_sleep($1)"     encoder =-      E.value E.float8+      E.param E.float8     decoder =       D.unit