Skip to content

Add persistent-postgresql-ng package#2

Open
iand675 wants to merge 1 commit into02-19-add_direct_codec_interface_to_persistent_corefrom
02-19-add_persistent-postgresql-ng_package
Open

Add persistent-postgresql-ng package#2
iand675 wants to merge 1 commit into02-19-add_direct_codec_interface_to_persistent_corefrom
02-19-add_persistent-postgresql-ng_package

Conversation

@iand675
Copy link
Copy Markdown
Owner

@iand675 iand675 commented Feb 19, 2026

Summary

A PostgreSQL backend for persistent using the binary wire protocol and libpq pipeline mode.

  • Binary protocol via postgresql-binary (no text serialization)
  • Hedis-style automatic pipelining via lazy reply stream (unsafeInterleaveIO + atomicModifyIORef with head/tail)
  • UNNEST-based bulk inserts (fixed SQL template, single round-trip)
  • IN-clause collapse to = ANY($1)
  • Direct decode/encode path (zero PersistValue allocation)
  • PgDecode/PgEncode value-level codecs for compound types (arrays, composites)
  • FetchAll, FetchSingleRow, FetchChunked (PG17+) result fetch modes
  • DirectQueryCap wired into SqlBackend for the SqlBackend bridge
  • Pipelined get, insert, upsert, getBy, count, exists
  • 24-29x speedup on individual reads at 1ms network latency

Benchmarks (1ms latency per direction)

Operation persistent-postgresql persistent-postgresql-ng Speedup
get x100 310ms 11ms 28x
insert x100 314ms 13ms 24x
upsert x100 321ms 13ms 25x
delete x100 592ms 25ms 24x

A PostgreSQL backend for persistent using the binary wire protocol
and libpq pipeline mode. Features:

- Binary protocol via postgresql-binary (no text serialization)
- Hedis-style automatic pipelining via lazy reply stream
  (unsafeInterleaveIO + atomicModifyIORef with head/tail)
- UNNEST-based bulk inserts (fixed SQL template)
- IN-clause collapse to = ANY($1)
- Direct decode/encode path (zero PersistValue allocation)
- PgDecode/PgEncode value-level codecs for compound types
- FetchAll, FetchSingleRow, FetchChunked (PG17+) modes
- DirectQueryCap wired into SqlBackend for SqlBackend bridge
- Pipelined get, insert, upsert, getBy, count, exists
- 24-29x speedup on reads at 1ms network latency

Full test suite (363 tests across 3 fetch modes).
Benchmarks with TCP delay proxy for latency simulation.
license-file: LICENSE
author: Ian Duncan
maintainer: ian@ianduncan.me
synopsis: Pipelined PostgreSQL backend for persistent using binary protocol.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by cabal-fmt

Suggested change
synopsis: Pipelined PostgreSQL backend for persistent using binary protocol.
synopsis:
Pipelined PostgreSQL backend for persistent using binary protocol.

Database.Persist.Postgresql.Internal.PgType
Database.Persist.Postgresql.Internal.Placeholders
Database.Persist.Postgresql.JSON
Database.Persist.Postgresql.CustomType
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by cabal-fmt

Suggested change
Database.Persist.Postgresql.CustomType
Database.Persist.Postgresql.Pipeline
Database.Persist.Postgresql.Pipeline.FFI
Database.Persist.Postgresql.Pipeline.Internal

BinaryRoundTripSpec
DirectDecodeSpec
DirectEntityPOC
CustomConstraintTest
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by cabal-fmt

Suggested change
CustomConstraintTest

Comment on lines +48 to +49
| FetchChunked !Int
-- ^ Chunked mode (@PQsetChunkedRowsMode@, PG17+ libpq). Each
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
| FetchChunked !Int
-- ^ Chunked mode (@PQsetChunkedRowsMode@, PG17+ libpq). Each
FetchSingleRow
| -- | Chunked mode (@PQsetChunkedRowsMode@, PG17+ libpq). Each

Comment on lines +184 to +200
scalarCUInt PgBool = 16
scalarCUInt PgBytea = 17
scalarCUInt PgChar = 18
scalarCUInt PgName = 19
scalarCUInt PgInt2 = 21
scalarCUInt PgInt4 = 23
scalarCUInt PgInt8 = 20
scalarCUInt PgFloat4 = 700
scalarCUInt PgFloat8 = 701
scalarCUInt PgText = 25
scalarCUInt PgXml = 142
scalarCUInt PgMoney = 790
scalarCUInt PgBpchar = 1042
scalarCUInt PgVarchar = 1043
scalarCUInt PgDate = 1082
scalarCUInt PgTime = 1083
scalarCUInt PgTimestamp = 1114
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
scalarCUInt PgBool = 16
scalarCUInt PgBytea = 17
scalarCUInt PgChar = 18
scalarCUInt PgName = 19
scalarCUInt PgInt2 = 21
scalarCUInt PgInt4 = 23
scalarCUInt PgInt8 = 20
scalarCUInt PgFloat4 = 700
scalarCUInt PgFloat8 = 701
scalarCUInt PgText = 25
scalarCUInt PgXml = 142
scalarCUInt PgMoney = 790
scalarCUInt PgBpchar = 1042
scalarCUInt PgVarchar = 1043
scalarCUInt PgDate = 1082
scalarCUInt PgTime = 1083
scalarCUInt PgTimestamp = 1114
scalarCUInt PgBool = 16
scalarCUInt PgBytea = 17
scalarCUInt PgChar = 18
scalarCUInt PgName = 19
scalarCUInt PgInt2 = 21
scalarCUInt PgInt4 = 23
scalarCUInt PgInt8 = 20
scalarCUInt PgFloat4 = 700
scalarCUInt PgFloat8 = 701
scalarCUInt PgText = 25
scalarCUInt PgXml = 142
scalarCUInt PgMoney = 790
scalarCUInt PgBpchar = 1042
scalarCUInt PgVarchar = 1043
scalarCUInt PgDate = 1082
scalarCUInt PgTime = 1083
scalarCUInt PgTimestamp = 1114

Comment on lines +140 to +146
= QuestionMarkParams
-- ^ Traditional @?@ placeholders (persistent style). Each @?@ is a
-- distinct positional parameter.
| NumberedParams !Int
-- ^ PostgreSQL-native @$N@ placeholders. The 'Int' is the highest
-- @$N@ found. A single @$1@ can appear multiple times in the query,
-- referencing the same parameter value.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
= QuestionMarkParams
-- ^ Traditional @?@ placeholders (persistent style). Each @?@ is a
-- distinct positional parameter.
| NumberedParams !Int
-- ^ PostgreSQL-native @$N@ placeholders. The 'Int' is the highest
-- @$N@ found. A single @$1@ can appear multiple times in the query,
-- referencing the same parameter value.
= -- | Traditional @?@ placeholders (persistent style). Each @?@ is a
-- distinct positional parameter.
QuestionMarkParams
| -- | PostgreSQL-native @$N@ placeholders. The 'Int' is the highest
-- @$N@ found. A single @$1@ can appear multiple times in the query,
-- referencing the same parameter value.
NumberedParams !Int

(T.pack $ "Person " <> show i)
(20 + i `mod` 60)
(T.pack $ "person" <> show i <> "@test.com")
| i <- [1..n]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
| i <- [1..n]
| i <- [1 .. n]

Comment on lines +43 to +44
| FetchSingleRow
-- ^ Single-row mode (@PQsetSingleRowMode@). Each @PGresult@ contains
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
| FetchSingleRow
-- ^ Single-row mode (@PQsetSingleRowMode@). Each @PGresult@ contains
FetchAll
| -- | Single-row mode (@PQsetSingleRowMode@). Each @PGresult@ contains

Comment on lines +223 to +224
LibPQ.FlushOk -> return ()
LibPQ.FlushFailed -> throwIO $ PipelineExecError "flush failed"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
LibPQ.FlushOk -> return ()
LibPQ.FlushFailed -> throwIO $ PipelineExecError "flush failed"
LibPQ.FlushOk -> return ()
LibPQ.FlushFailed -> throwIO $ PipelineExecError "flush failed"

Database.Persist.Postgresql.Pipeline.FFI
Database.Persist.Postgresql.Internal
Database.Persist.Postgresql.Internal.Decoding
Database.Persist.Postgresql.Internal.Encoding
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by cabal-fmt

Suggested change
Database.Persist.Postgresql.Internal.Encoding

Comment on lines +21 to +28
aeson >=1.0
, base >=4.9 && <5
, bytestring >=0.10
, bytestring-strict-builder >=0.4
, conduit >=1.2.12
, containers >=0.5
, file-embed >=0.0.16
, monad-logger >=0.3.25
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by cabal-fmt

Suggested change
aeson >=1.0
, base >=4.9 && <5
, bytestring >=0.10
, bytestring-strict-builder >=0.4
, conduit >=1.2.12
, containers >=0.5
, file-embed >=0.0.16
, monad-logger >=0.3.25
aeson >=1.0
, base >=4.9 && <5
, bytestring >=0.10
, bytestring-strict-builder >=0.4
, conduit >=1.2.12
, containers >=0.5
, file-embed >=0.0.16
, monad-logger >=0.3.25

, bytestring
, containers
, fast-logger
, hspec >=2.4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by cabal-fmt

Suggested change
, hspec >=2.4
, hspec >=2.4

ghc-options: -Wall
build-depends:
aeson
, base >=4.9 && <5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by cabal-fmt

Suggested change
, base >=4.9 && <5
, base >=4.9 && <5

_ -> do
merr <- LibPQ.errorMessage conn
LibPQ.finish conn
let msg = maybe "Unknown connection error" B8.unpack merr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
let msg = maybe "Unknown connection error" B8.unpack merr
let
msg = maybe "Unknown connection error" B8.unpack merr

build-depends:
base >=4.9 && <5
, bytestring
, criterion >=1.5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by cabal-fmt

Suggested change
, criterion >=1.5
, criterion >=1.5

mapM_ delete delKeys
forM_ updKeys $ \k -> update k [BenchPersonAge =. 99]
forM_ (zip repKeys (people 100)) $ \(k, person) ->
replace k (person { benchPersonAge = 42 })
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
replace k (person { benchPersonAge = 42 })
replace k (person{benchPersonAge = 42})

-> ReaderT (PgPipeline.WriteBackend PgPipeline.PostgreSQLBackend) IO a -> IO a
pl pool action = runSqlPool action pool


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change

import Data.Pool (Pool)
import Data.Text (Text)
import qualified Data.Text as T
import Control.Monad.Trans.Reader (ReaderT, withReaderT)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
import Control.Monad.Trans.Reader (ReaderT, withReaderT)

Comment on lines +202 to +210
scalarCUInt PgInterval = 1186
scalarCUInt PgBit = 1560
scalarCUInt PgVarbit = 1562
scalarCUInt PgNumeric = 1700
scalarCUInt PgVoid = 2278
scalarCUInt PgJson = 114
scalarCUInt PgJsonb = 3802
scalarCUInt PgUnknown = 705
scalarCUInt PgUuid = 2950
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
scalarCUInt PgInterval = 1186
scalarCUInt PgBit = 1560
scalarCUInt PgVarbit = 1562
scalarCUInt PgNumeric = 1700
scalarCUInt PgVoid = 2278
scalarCUInt PgJson = 114
scalarCUInt PgJsonb = 3802
scalarCUInt PgUnknown = 705
scalarCUInt PgUuid = 2950
scalarCUInt PgInterval = 1186
scalarCUInt PgBit = 1560
scalarCUInt PgVarbit = 1562
scalarCUInt PgNumeric = 1700
scalarCUInt PgVoid = 2278
scalarCUInt PgJson = 114
scalarCUInt PgJsonb = 3802
scalarCUInt PgUnknown = 705
scalarCUInt PgUuid = 2950

drainToSyncClose conn = do
mret <- LibPQ.getResult conn
case mret of
Nothing -> drainToSyncClose conn -- NULL separator, keep reading
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
Nothing -> drainToSyncClose conn -- NULL separator, keep reading
Nothing -> drainToSyncClose conn -- NULL separator, keep reading

Comment on lines +68 to +70
| PgUnknown
-- ^ The PostgreSQL @unknown@ pseudotype (OID 705), used for untyped
-- string literals. Not to be confused with 'Unrecognized'.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
| PgUnknown
-- ^ The PostgreSQL @unknown@ pseudotype (OID 705), used for untyped
-- string literals. Not to be confused with 'Unrecognized'.
| -- | The PostgreSQL @unknown@ pseudotype (OID 705), used for untyped
-- string literals. Not to be confused with 'Unrecognized'.
PgUnknown

Comment on lines +150 to +157
let (_, pt) = pgCols env V.! col
in case pt of
Scalar PgText -> onOk (mkRunner col PD.text_strict)
Scalar PgVarchar -> onOk (mkRunner col PD.text_strict)
Scalar PgBpchar -> onOk (mkRunner col PD.text_strict)
Scalar PgChar -> onOk (mkRunner col PD.text_strict)
Scalar PgName -> onOk (mkRunner col PD.text_strict)
_ -> mismatch pt "Text" onErr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
let (_, pt) = pgCols env V.! col
in case pt of
Scalar PgText -> onOk (mkRunner col PD.text_strict)
Scalar PgVarchar -> onOk (mkRunner col PD.text_strict)
Scalar PgBpchar -> onOk (mkRunner col PD.text_strict)
Scalar PgChar -> onOk (mkRunner col PD.text_strict)
Scalar PgName -> onOk (mkRunner col PD.text_strict)
_ -> mismatch pt "Text" onErr
let
(_, pt) = pgCols env V.! col
in
case pt of
Scalar PgText -> onOk (mkRunner col PD.text_strict)
Scalar PgVarchar -> onOk (mkRunner col PD.text_strict)
Scalar PgBpchar -> onOk (mkRunner col PD.text_strict)
Scalar PgChar -> onOk (mkRunner col PD.text_strict)
Scalar PgName -> onOk (mkRunner col PD.text_strict)
_ -> mismatch pt "Text" onErr

Comment on lines +147 to +153
| otherwise = BS.pack $ concat
[ hexBytes 0 4, [0x2D]
, hexBytes 4 2, [0x2D]
, hexBytes 6 2, [0x2D]
, hexBytes 8 2, [0x2D]
, hexBytes 10 6
]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
| otherwise = BS.pack $ concat
[ hexBytes 0 4, [0x2D]
, hexBytes 4 2, [0x2D]
, hexBytes 6 2, [0x2D]
, hexBytes 8 2, [0x2D]
, hexBytes 10 6
]
| otherwise =
BS.pack $
concat
[ hexBytes 0 4
, [0x2D]
, hexBytes 4 2
, [0x2D]
, hexBytes 6 2
, [0x2D]
, hexBytes 8 2
, [0x2D]
, hexBytes 10 6
]

Comment on lines +245 to +247
:: PgDecode a
=> PgRowEnv -> FieldNameDB -> Int
-> (Text -> IO r) -> (FieldRunner PgRowEnv a -> IO r) -> IO r
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
:: PgDecode a
=> PgRowEnv -> FieldNameDB -> Int
-> (Text -> IO r) -> (FieldRunner PgRowEnv a -> IO r) -> IO r
:: (PgDecode a)
=> PgRowEnv
-> FieldNameDB
-> Int
-> (Text -> IO r)
-> (FieldRunner PgRowEnv a -> IO r)
-> IO r

decodeWith decoder bs onErr onOk =
case PD.valueParser decoder bs of
Left err -> onErr err
Right v -> onOk v
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
Right v -> onOk v
Right v -> onOk v

Comment on lines +18 to +19
import Control.Monad (replicateM)
import Data.Word (Word8)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
import Control.Monad (replicateM)
import Data.Word (Word8)

-- Generic array instance via PgDecode
---------------------------------------------------------------------------

instance {-# OVERLAPPABLE #-} PgDecode a => FieldDecode PgRowEnv [a] where
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
instance {-# OVERLAPPABLE #-} PgDecode a => FieldDecode PgRowEnv [a] where
instance {-# OVERLAPPABLE #-} (PgDecode a) => FieldDecode PgRowEnv [a] where

Comment on lines +166 to +172
pgTypeOid (Scalar s) = scalarOid s
pgTypeOid (Array s) = maybe (LibPQ.Oid 0) id (arrayOid s)
pgTypeOid (Composite _ _) = LibPQ.Oid 0
pgTypeOid (CompositeArray _) = LibPQ.Oid 0
pgTypeOid (Enum _ _) = LibPQ.Oid 0
pgTypeOid (EnumArray _) = LibPQ.Oid 0
pgTypeOid (Unrecognized n) = LibPQ.Oid (fromIntegral n)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
pgTypeOid (Scalar s) = scalarOid s
pgTypeOid (Array s) = maybe (LibPQ.Oid 0) id (arrayOid s)
pgTypeOid (Composite _ _) = LibPQ.Oid 0
pgTypeOid (CompositeArray _) = LibPQ.Oid 0
pgTypeOid (Enum _ _) = LibPQ.Oid 0
pgTypeOid (EnumArray _) = LibPQ.Oid 0
pgTypeOid (Unrecognized n) = LibPQ.Oid (fromIntegral n)
pgTypeOid (Scalar s) = scalarOid s
pgTypeOid (Array s) = maybe (LibPQ.Oid 0) id (arrayOid s)
pgTypeOid (Composite _ _) = LibPQ.Oid 0
pgTypeOid (CompositeArray _) = LibPQ.Oid 0
pgTypeOid (Enum _ _) = LibPQ.Oid 0
pgTypeOid (EnumArray _) = LibPQ.Oid 0
pgTypeOid (Unrecognized n) = LibPQ.Oid (fromIntegral n)

Comment on lines +217 to +220
in case pt of
Array _ -> onOk (mkRunner col decoder)
Unrecognized _ -> onOk (mkRunner col decoder)
_ -> mismatch pt "array" onErr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
in case pt of
Array _ -> onOk (mkRunner col decoder)
Unrecognized _ -> onOk (mkRunner col decoder)
_ -> mismatch pt "array" onErr
in
case pt of
Array _ -> onOk (mkRunner col decoder)
Unrecognized _ -> onOk (mkRunner col decoder)
_ -> mismatch pt "array" onErr

Comment on lines +161 to +170
let (_, pt) = pgCols env V.! col
in case pt of
Scalar PgBytea -> onOk (mkRunner col PD.bytea_strict)
Scalar PgXml -> onOk (mkRunner col PD.bytea_strict)
Scalar PgJson -> onOk (mkRunner col PD.bytea_strict)
Scalar PgJsonb -> onOk (mkRunner col (PD.jsonb_bytes Right))
Scalar PgBit -> onOk (mkRunner col PD.bytea_strict)
Scalar PgVarbit -> onOk (mkRunner col PD.bytea_strict)
Scalar PgUnknown -> onOk (mkRunner col PD.bytea_strict)
_ -> mismatch pt "ByteString" onErr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
let (_, pt) = pgCols env V.! col
in case pt of
Scalar PgBytea -> onOk (mkRunner col PD.bytea_strict)
Scalar PgXml -> onOk (mkRunner col PD.bytea_strict)
Scalar PgJson -> onOk (mkRunner col PD.bytea_strict)
Scalar PgJsonb -> onOk (mkRunner col (PD.jsonb_bytes Right))
Scalar PgBit -> onOk (mkRunner col PD.bytea_strict)
Scalar PgVarbit -> onOk (mkRunner col PD.bytea_strict)
Scalar PgUnknown -> onOk (mkRunner col PD.bytea_strict)
_ -> mismatch pt "ByteString" onErr
let
(_, pt) = pgCols env V.! col
in
case pt of
Scalar PgBytea -> onOk (mkRunner col PD.bytea_strict)
Scalar PgXml -> onOk (mkRunner col PD.bytea_strict)
Scalar PgJson -> onOk (mkRunner col PD.bytea_strict)
Scalar PgJsonb -> onOk (mkRunner col (PD.jsonb_bytes Right))
Scalar PgBit -> onOk (mkRunner col PD.bytea_strict)
Scalar PgVarbit -> onOk (mkRunner col PD.bytea_strict)
Scalar PgUnknown -> onOk (mkRunner col PD.bytea_strict)
_ -> mismatch pt "ByteString" onErr

Comment on lines +60 to +68
decodeByType (Scalar PgInterval) bs = PersistRational . toRational <$> run PD.interval_int bs
decodeByType (Scalar PgBit) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgVarbit) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgNumeric) bs = decodeNumeric bs
decodeByType (Scalar PgVoid) _ = Right PersistNull
decodeByType (Scalar PgJson) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgJsonb) bs = PersistByteString <$> decodeJsonb bs
decodeByType (Scalar PgUnknown) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgUuid) bs = do
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
decodeByType (Scalar PgInterval) bs = PersistRational . toRational <$> run PD.interval_int bs
decodeByType (Scalar PgBit) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgVarbit) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgNumeric) bs = decodeNumeric bs
decodeByType (Scalar PgVoid) _ = Right PersistNull
decodeByType (Scalar PgJson) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgJsonb) bs = PersistByteString <$> decodeJsonb bs
decodeByType (Scalar PgUnknown) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgUuid) bs = do
decodeByType (Scalar PgInterval) bs = PersistRational . toRational <$> run PD.interval_int bs
decodeByType (Scalar PgBit) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgVarbit) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgNumeric) bs = decodeNumeric bs
decodeByType (Scalar PgVoid) _ = Right PersistNull
decodeByType (Scalar PgJson) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgJsonb) bs = PersistByteString <$> decodeJsonb bs
decodeByType (Scalar PgUnknown) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgUuid) bs = do

import Data.Scientific (Scientific)
import Data.Text (Text)
import Data.Time (localTimeToUTC, utc)
import qualified Database.PostgreSQL.LibPQ as LibPQ
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
import qualified Database.PostgreSQL.LibPQ as LibPQ
import Data.Word (Word8)

Unrecognized _ -> onOk (mkRunner col decoder)
_ -> mismatch pt "array" onErr

instance {-# OVERLAPPING #-} PgDecode a => FieldDecode PgRowEnv [Maybe a] where
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
instance {-# OVERLAPPING #-} PgDecode a => FieldDecode PgRowEnv [Maybe a] where
instance {-# OVERLAPPING #-} (PgDecode a) => FieldDecode PgRowEnv [Maybe a] where

import qualified Data.Text
import qualified Data.Text.Encoding
import Data.Time (NominalDiffTime)
import Database.Persist.Sql
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
import Database.Persist.Sql

Comment on lines +142 to +146
let (_, pt) = pgCols env V.! col
in case pt of
Scalar PgNumeric -> onOk (mkRunnerWith col PD.numeric (toRational :: Scientific -> Rational))
Scalar PgMoney -> onOk (mkRunnerWith col (PD.int :: PD.Value Int64) fromIntegral)
_ -> mismatch pt "Rational" onErr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
let (_, pt) = pgCols env V.! col
in case pt of
Scalar PgNumeric -> onOk (mkRunnerWith col PD.numeric (toRational :: Scientific -> Rational))
Scalar PgMoney -> onOk (mkRunnerWith col (PD.int :: PD.Value Int64) fromIntegral)
_ -> mismatch pt "Rational" onErr
let
(_, pt) = pgCols env V.! col
in
case pt of
Scalar PgNumeric -> onOk (mkRunnerWith col PD.numeric (toRational :: Scientific -> Rational))
Scalar PgMoney -> onOk (mkRunnerWith col (PD.int :: PD.Value Int64) fromIntegral)
_ -> mismatch pt "Rational" onErr

Comment on lines +109 to +114
let (_, pt) = pgCols env V.! col
in case pt of
Scalar PgInt8 -> onOk (mkRunner col (PD.int :: PD.Value Int64))
Scalar PgInt4 -> onOk (mkRunnerWith col (PD.int :: PD.Value Int32) fromIntegral)
Scalar PgInt2 -> onOk (mkRunnerWith col (PD.int :: PD.Value Int16) fromIntegral)
_ -> mismatch pt "Int64" onErr
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
let (_, pt) = pgCols env V.! col
in case pt of
Scalar PgInt8 -> onOk (mkRunner col (PD.int :: PD.Value Int64))
Scalar PgInt4 -> onOk (mkRunnerWith col (PD.int :: PD.Value Int32) fromIntegral)
Scalar PgInt2 -> onOk (mkRunnerWith col (PD.int :: PD.Value Int16) fromIntegral)
_ -> mismatch pt "Int64" onErr
let
(_, pt) = pgCols env V.! col
in
case pt of
Scalar PgInt8 -> onOk (mkRunner col (PD.int :: PD.Value Int64))
Scalar PgInt4 -> onOk (mkRunnerWith col (PD.int :: PD.Value Int32) fromIntegral)
Scalar PgInt2 -> onOk (mkRunnerWith col (PD.int :: PD.Value Int16) fromIntegral)
_ -> mismatch pt "Int64" onErr

resolveOid :: OidCache -> LibPQ.Oid -> PgType
resolveOid cache oid = case fromOid oid of
Unrecognized n -> maybe (Unrecognized n) id (IntMap.lookup n cache)
known -> known
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
known -> known
known -> known

Comment on lines +235 to +243
arrayCUInt PgInterval = Just 1187
arrayCUInt PgBit = Just 1561
arrayCUInt PgVarbit = Just 1563
arrayCUInt PgNumeric = Just 1231
arrayCUInt PgJson = Just 199
arrayCUInt PgJsonb = Just 3807
arrayCUInt PgUuid = Just 2951
arrayCUInt PgVoid = Nothing
arrayCUInt PgUnknown = Nothing
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
arrayCUInt PgInterval = Just 1187
arrayCUInt PgBit = Just 1561
arrayCUInt PgVarbit = Just 1563
arrayCUInt PgNumeric = Just 1231
arrayCUInt PgJson = Just 199
arrayCUInt PgJsonb = Just 3807
arrayCUInt PgUuid = Just 2951
arrayCUInt PgVoid = Nothing
arrayCUInt PgUnknown = Nothing
arrayCUInt PgInterval = Just 1187
arrayCUInt PgBit = Just 1561
arrayCUInt PgVarbit = Just 1563
arrayCUInt PgNumeric = Just 1231
arrayCUInt PgJson = Just 199
arrayCUInt PgJsonb = Just 3807
arrayCUInt PgUuid = Just 2951
arrayCUInt PgVoid = Nothing
arrayCUInt PgUnknown = Nothing

Comment on lines +42 to +58
decodeByType (Scalar PgBool) bs = PersistBool <$> run PD.bool bs
decodeByType (Scalar PgBytea) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgChar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgName) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgInt8) bs = PersistInt64 <$> run (PD.int :: PD.Value Int64) bs
decodeByType (Scalar PgInt2) bs = PersistInt64 . fromIntegral <$> run (PD.int :: PD.Value Int16) bs
decodeByType (Scalar PgInt4) bs = PersistInt64 . fromIntegral <$> run (PD.int :: PD.Value Int32) bs
decodeByType (Scalar PgText) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgXml) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgFloat4) bs = PersistDouble . realToFrac <$> run PD.float4 bs
decodeByType (Scalar PgFloat8) bs = PersistDouble <$> run PD.float8 bs
decodeByType (Scalar PgMoney) bs = PersistRational . fromIntegral <$> run (PD.int :: PD.Value Int64) bs
decodeByType (Scalar PgBpchar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgVarchar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgDate) bs = PersistDay <$> run PD.date bs
decodeByType (Scalar PgTime) bs = PersistTimeOfDay <$> run PD.time_int bs
decodeByType (Scalar PgTimestamp) bs = PersistUTCTime . localTimeToUTC utc <$> run PD.timestamp_int bs
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
decodeByType (Scalar PgBool) bs = PersistBool <$> run PD.bool bs
decodeByType (Scalar PgBytea) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgChar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgName) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgInt8) bs = PersistInt64 <$> run (PD.int :: PD.Value Int64) bs
decodeByType (Scalar PgInt2) bs = PersistInt64 . fromIntegral <$> run (PD.int :: PD.Value Int16) bs
decodeByType (Scalar PgInt4) bs = PersistInt64 . fromIntegral <$> run (PD.int :: PD.Value Int32) bs
decodeByType (Scalar PgText) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgXml) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgFloat4) bs = PersistDouble . realToFrac <$> run PD.float4 bs
decodeByType (Scalar PgFloat8) bs = PersistDouble <$> run PD.float8 bs
decodeByType (Scalar PgMoney) bs = PersistRational . fromIntegral <$> run (PD.int :: PD.Value Int64) bs
decodeByType (Scalar PgBpchar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgVarchar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgDate) bs = PersistDay <$> run PD.date bs
decodeByType (Scalar PgTime) bs = PersistTimeOfDay <$> run PD.time_int bs
decodeByType (Scalar PgTimestamp) bs = PersistUTCTime . localTimeToUTC utc <$> run PD.timestamp_int bs
decodeByType (Scalar PgBool) bs = PersistBool <$> run PD.bool bs
decodeByType (Scalar PgBytea) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgChar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgName) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgInt8) bs = PersistInt64 <$> run (PD.int :: PD.Value Int64) bs
decodeByType (Scalar PgInt2) bs = PersistInt64 . fromIntegral <$> run (PD.int :: PD.Value Int16) bs
decodeByType (Scalar PgInt4) bs = PersistInt64 . fromIntegral <$> run (PD.int :: PD.Value Int32) bs
decodeByType (Scalar PgText) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgXml) bs = PersistByteString <$> run PD.bytea_strict bs
decodeByType (Scalar PgFloat4) bs = PersistDouble . realToFrac <$> run PD.float4 bs
decodeByType (Scalar PgFloat8) bs = PersistDouble <$> run PD.float8 bs
decodeByType (Scalar PgMoney) bs = PersistRational . fromIntegral <$> run (PD.int :: PD.Value Int64) bs
decodeByType (Scalar PgBpchar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgVarchar) bs = PersistText <$> run PD.text_strict bs
decodeByType (Scalar PgDate) bs = PersistDay <$> run PD.date bs
decodeByType (Scalar PgTime) bs = PersistTimeOfDay <$> run PD.time_int bs
decodeByType (Scalar PgTimestamp) bs = PersistUTCTime . localTimeToUTC utc <$> run PD.timestamp_int bs

Comment on lines +105 to +118
fromCUInt 16 = Scalar PgBool
fromCUInt 17 = Scalar PgBytea
fromCUInt 18 = Scalar PgChar
fromCUInt 19 = Scalar PgName
fromCUInt 20 = Scalar PgInt8
fromCUInt 21 = Scalar PgInt2
fromCUInt 23 = Scalar PgInt4
fromCUInt 25 = Scalar PgText
fromCUInt 114 = Scalar PgJson
fromCUInt 142 = Scalar PgXml
fromCUInt 700 = Scalar PgFloat4
fromCUInt 701 = Scalar PgFloat8
fromCUInt 705 = Scalar PgUnknown
fromCUInt 790 = Scalar PgMoney
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by fourmolu

Suggested change
fromCUInt 16 = Scalar PgBool
fromCUInt 17 = Scalar PgBytea
fromCUInt 18 = Scalar PgChar
fromCUInt 19 = Scalar PgName
fromCUInt 20 = Scalar PgInt8
fromCUInt 21 = Scalar PgInt2
fromCUInt 23 = Scalar PgInt4
fromCUInt 25 = Scalar PgText
fromCUInt 114 = Scalar PgJson
fromCUInt 142 = Scalar PgXml
fromCUInt 700 = Scalar PgFloat4
fromCUInt 701 = Scalar PgFloat8
fromCUInt 705 = Scalar PgUnknown
fromCUInt 790 = Scalar PgMoney
fromCUInt 16 = Scalar PgBool
fromCUInt 17 = Scalar PgBytea
fromCUInt 18 = Scalar PgChar
fromCUInt 19 = Scalar PgName
fromCUInt 20 = Scalar PgInt8
fromCUInt 21 = Scalar PgInt2
fromCUInt 23 = Scalar PgInt4
fromCUInt 25 = Scalar PgText
fromCUInt 114 = Scalar PgJson
fromCUInt 142 = Scalar PgXml
fromCUInt 700 = Scalar PgFloat4
fromCUInt 701 = Scalar PgFloat8
fromCUInt 705 = Scalar PgUnknown
fromCUInt 790 = Scalar PgMoney

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant