packages feed

pqi-conformance 0.0.1.2 → 0.1.0.0

raw patch · 111 files changed

+1333/−1241 lines, 111 filesdep ~pqiPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: pqi

API changes (from Hackage documentation)

- Pqi.Conformance: specs :: IsConnection c => Proxy c -> Spec
+ Pqi.Conformance: specs :: Adapter -> Spec

Files

CHANGELOG.md view
@@ -0,0 +1,10 @@+# v0.1.0.0++## Breaking++- Migrated to record-of-functions API structure++## Non-breaking++- Added parity specification for pipeline sync operations+- Added UnescapeBytea to the conformance test battery
pqi-conformance.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: pqi-conformance-version: 0.0.1.2+version: 0.1.0.0 category: Database, PostgreSQL, Testing synopsis: Differential conformance tests for pqi adapters description:@@ -164,6 +164,7 @@     Pqi.Conformance.Operation.Pass     Pqi.Conformance.Operation.PipelineStatus     Pqi.Conformance.Operation.PipelineSync+    Pqi.Conformance.Operation.PipelineSync.Parity     Pqi.Conformance.Operation.Port     Pqi.Conformance.Operation.Prepare     Pqi.Conformance.Operation.ProtocolVersion@@ -190,6 +191,7 @@     Pqi.Conformance.Operation.Socket     Pqi.Conformance.Operation.Status     Pqi.Conformance.Operation.TransactionStatus+    Pqi.Conformance.Operation.UnescapeBytea     Pqi.Conformance.Operation.UnsafeFreeResult     Pqi.Conformance.Operation.User     Pqi.Conformance.Prelude@@ -203,6 +205,6 @@     directory >=1.3 && <1.4,     hspec >=2.11 && <2.12,     postgresql-libpq >=0.11 && <0.12,-    pqi ^>=0.0,+    pqi ^>=0.1,     testcontainers-postgresql ^>=0.2,     text >=1.2 && <3,
src/library/Pqi/Conformance.hs view
@@ -1,11 +1,11 @@ -- | A reusable differential-testing toolkit for @pqi@ adapters. ----- An adapter's test suite calls 'specs' with a @'Proxy' \@MyConnection@. The+-- An adapter's test suite calls 'specs' with its 'Pqi.Adapter' value. The -- battery runs the same operation on the candidate and on the FFI reference -- and asserts that the protocol-derived observations match. -- -- The throwaway PostgreSQL container lifecycle is baked into 'specs', so--- adapter test suites only need @hspec (specs (Proxy \@MyConnection))@; they+-- adapter test suites only need @hspec (specs MyAdapter.adapter)@; they -- don't have to know about @testcontainers@ at all. The SCRAM-SHA-256 -- authentication spec is part of the @connectdb@ group and boots its own -- password-auth container.@@ -14,7 +14,7 @@   ) where -import Pqi (IsConnection)+import qualified Pqi import Pqi.Conformance.Harness import qualified Pqi.Conformance.Operation.BackendPID as BackendPID import qualified Pqi.Conformance.Operation.Cancel as Cancel@@ -113,6 +113,7 @@ import qualified Pqi.Conformance.Operation.Socket as Socket import qualified Pqi.Conformance.Operation.Status as Status import qualified Pqi.Conformance.Operation.TransactionStatus as TransactionStatus+import qualified Pqi.Conformance.Operation.UnescapeBytea as UnescapeBytea import qualified Pqi.Conformance.Operation.UnsafeFreeResult as UnsafeFreeResult import qualified Pqi.Conformance.Operation.User as User import Pqi.Conformance.Prelude@@ -122,117 +123,118 @@ -- trust-auth container, plus SCRAM-SHA-256 authentication (which boots its own -- password-auth container). Every operation spec is differential against the -- FFI reference.-specs :: (IsConnection c) => Proxy c -> Spec-specs proxy = parallel do+specs :: Pqi.Adapter -> Spec+specs adapter = parallel do   containerHook do     -- Connection lifecycle-    Connectdb.spec proxy-    ConnectStart.spec proxy-    ConnectPoll.spec proxy-    NewNullConnection.spec proxy-    IsNullConnection.spec proxy-    Finish.spec proxy-    Reset.spec proxy-    ResetStart.spec proxy-    ResetPoll.spec proxy+    Connectdb.spec adapter+    ConnectStart.spec adapter+    ConnectPoll.spec adapter+    NewNullConnection.spec adapter+    IsNullConnection.spec adapter+    Finish.spec adapter+    Reset.spec adapter+    ResetStart.spec adapter+    ResetPoll.spec adapter     -- Connection information accessors-    Db.spec proxy-    User.spec proxy-    Pass.spec proxy-    Host.spec proxy-    Port.spec proxy-    Options.spec proxy-    Status.spec proxy-    TransactionStatus.spec proxy-    ParameterStatus.spec proxy-    ProtocolVersion.spec proxy-    ServerVersion.spec proxy-    ErrorMessage.spec proxy-    Socket.spec proxy-    BackendPID.spec proxy-    ConnectionNeedsPassword.spec proxy-    ConnectionUsedPassword.spec proxy+    Db.spec adapter+    User.spec adapter+    Pass.spec adapter+    Host.spec adapter+    Port.spec adapter+    Options.spec adapter+    Status.spec adapter+    TransactionStatus.spec adapter+    ParameterStatus.spec adapter+    ProtocolVersion.spec adapter+    ServerVersion.spec adapter+    ErrorMessage.spec adapter+    Socket.spec adapter+    BackendPID.spec adapter+    ConnectionNeedsPassword.spec adapter+    ConnectionUsedPassword.spec adapter     -- Querying-    Exec.spec proxy-    ExecParams.spec proxy-    Prepare.spec proxy-    ExecPrepared.spec proxy-    DescribePrepared.spec proxy-    DescribePortal.spec proxy+    Exec.spec adapter+    ExecParams.spec adapter+    Prepare.spec adapter+    ExecPrepared.spec adapter+    DescribePrepared.spec adapter+    DescribePortal.spec adapter     -- Escaping-    EscapeStringConn.spec proxy-    EscapeByteaConn.spec proxy-    EscapeIdentifier.spec proxy+    EscapeStringConn.spec adapter+    EscapeByteaConn.spec adapter+    EscapeIdentifier.spec adapter+    UnescapeBytea.spec adapter     -- Asynchronous command processing-    SendQuery.spec proxy-    SendQueryParams.spec proxy-    SendPrepare.spec proxy-    SendQueryPrepared.spec proxy-    SendDescribePrepared.spec proxy-    SendDescribePortal.spec proxy-    GetResult.spec proxy-    ConsumeInput.spec proxy-    IsBusy.spec proxy-    Setnonblocking.spec proxy-    Isnonblocking.spec proxy-    SetSingleRowMode.spec proxy-    Flush.spec proxy+    SendQuery.spec adapter+    SendQueryParams.spec adapter+    SendPrepare.spec adapter+    SendQueryPrepared.spec adapter+    SendDescribePrepared.spec adapter+    SendDescribePortal.spec adapter+    GetResult.spec adapter+    ConsumeInput.spec adapter+    IsBusy.spec adapter+    Setnonblocking.spec adapter+    Isnonblocking.spec adapter+    SetSingleRowMode.spec adapter+    Flush.spec adapter     -- Pipelining-    PipelineStatus.spec proxy-    EnterPipelineMode.spec proxy-    ExitPipelineMode.spec proxy-    PipelineSync.spec proxy-    SendFlushRequest.spec proxy+    PipelineStatus.spec adapter+    EnterPipelineMode.spec adapter+    ExitPipelineMode.spec adapter+    PipelineSync.spec adapter+    SendFlushRequest.spec adapter     -- Cancellation-    GetCancel.spec proxy-    Cancel.spec proxy+    GetCancel.spec adapter+    Cancel.spec adapter     -- Notifications and notices-    Notifies.spec proxy-    DisableNoticeReporting.spec proxy-    EnableNoticeReporting.spec proxy-    GetNotice.spec proxy+    Notifies.spec adapter+    DisableNoticeReporting.spec adapter+    EnableNoticeReporting.spec adapter+    GetNotice.spec adapter     -- Copy sub-protocol-    PutCopyData.spec proxy-    PutCopyEnd.spec proxy-    GetCopyData.spec proxy+    PutCopyData.spec adapter+    PutCopyEnd.spec adapter+    GetCopyData.spec adapter     -- Large objects-    LoCreat.spec proxy-    LoCreate.spec proxy-    LoImport.spec proxy-    LoImportWithOid.spec proxy-    LoExport.spec proxy-    LoOpen.spec proxy-    LoWrite.spec proxy-    LoRead.spec proxy-    LoSeek.spec proxy-    LoTell.spec proxy-    LoTruncate.spec proxy-    LoClose.spec proxy-    LoUnlink.spec proxy+    LoCreat.spec adapter+    LoCreate.spec adapter+    LoImport.spec adapter+    LoImportWithOid.spec adapter+    LoExport.spec adapter+    LoOpen.spec adapter+    LoWrite.spec adapter+    LoRead.spec adapter+    LoSeek.spec adapter+    LoTell.spec adapter+    LoTruncate.spec adapter+    LoClose.spec adapter+    LoUnlink.spec adapter     -- Connection control-    ClientEncoding.spec proxy-    SetClientEncoding.spec proxy-    SetErrorVerbosity.spec proxy+    ClientEncoding.spec adapter+    SetClientEncoding.spec adapter+    SetErrorVerbosity.spec adapter     -- Result inspection-    ResultStatus.spec proxy-    ResultErrorMessage.spec proxy-    ResultErrorField.spec proxy-    UnsafeFreeResult.spec proxy-    Ntuples.spec proxy-    Nfields.spec proxy-    Fname.spec proxy-    Fnumber.spec proxy-    Ftable.spec proxy-    Ftablecol.spec proxy-    Fformat.spec proxy-    Ftype.spec proxy-    Fmod.spec proxy-    Fsize.spec proxy-    Getvalue.spec proxy-    GetvalueCopy.spec proxy-    Getisnull.spec proxy-    Getlength.spec proxy-    Nparams.spec proxy-    Paramtype.spec proxy-    CmdStatus.spec proxy-    CmdTuples.spec proxy+    ResultStatus.spec adapter+    ResultErrorMessage.spec adapter+    ResultErrorField.spec adapter+    UnsafeFreeResult.spec adapter+    Ntuples.spec adapter+    Nfields.spec adapter+    Fname.spec adapter+    Fnumber.spec adapter+    Ftable.spec adapter+    Ftablecol.spec adapter+    Fformat.spec adapter+    Ftype.spec adapter+    Fmod.spec adapter+    Fsize.spec adapter+    Getvalue.spec adapter+    GetvalueCopy.spec adapter+    Getisnull.spec adapter+    Getlength.spec adapter+    Nparams.spec adapter+    Paramtype.spec adapter+    CmdStatus.spec adapter+    CmdTuples.spec adapter
src/library/Pqi/Conformance/Harness.hs view
@@ -14,9 +14,9 @@ import qualified Data.ByteString.Char8 as ByteString.Char8 import qualified Data.Text as Text import Data.Unique (hashUnique, newUnique)-import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Prelude-import Pqi.Conformance.Reference (Reference)+import qualified Pqi.Conformance.Reference as Reference import Test.Hspec import qualified TestcontainersPostgresql as TcPg @@ -48,16 +48,15 @@ -- Each call creates a fresh database for the scenario and drops it afterwards, -- so tests are isolated even when the container is shared. differential ::-  forall c a.-  (Eq a, Show a, IsConnection c, HasCallStack) =>-  Proxy c ->+  (Eq a, Show a, HasCallStack) =>+  Pqi.Adapter ->   ByteString ->-  (forall c'. (IsConnection c') => c' -> IO a) ->+  (Pqi.Connection -> IO a) ->   Expectation-differential _ adminConninfo scenario =+differential adapter adminConninfo scenario =   withTestDb adminConninfo \testConninfo -> do-    candidate <- bracket (connectdb testConninfo :: IO c) finish scenario-    reference <- bracket (connectdb testConninfo :: IO Reference) finish scenario+    candidate <- bracket (adapter.connectdb testConninfo) (.finish) scenario+    reference <- bracket (Reference.adapter.connectdb testConninfo) (.finish) scenario     candidate `shouldBe` reference  -- Create a uniquely named database, run the action against it, and drop it on@@ -77,23 +76,22 @@  adminExec :: ByteString -> ByteString -> IO () adminExec conninfo sql = do-  conn <- connectdb conninfo :: IO Reference-  _ <- exec conn sql-  finish conn+  conn <- Reference.adapter.connectdb conninfo+  _ <- conn.exec sql+  conn.finish  -- | Like 'differential', but for scenarios that exercise connection -- establishment itself ('Pqi.connectdb' on a broken conninfo,--- 'Pqi.connectStart', 'Pqi.newNullConnection', ...): instead of an--- opened connection the scenario receives the conninfo and the candidate's--- connection type (via 'Proxy'), and manages any connections it opens itself.+-- 'Pqi.connectStart', 'Pqi.newNullConnection', ...): instead of an opened+-- connection the scenario receives the conninfo and the adapter to use, and+-- manages any connections it opens itself. differentialConnect ::-  forall c a.-  (Eq a, Show a, IsConnection c, HasCallStack) =>-  Proxy c ->+  (Eq a, Show a, HasCallStack) =>+  Pqi.Adapter ->   ByteString ->-  (forall c'. (IsConnection c', HasCallStack) => Proxy c' -> ByteString -> IO a) ->+  (Pqi.Adapter -> ByteString -> IO a) ->   Expectation-differentialConnect proxy conninfo scenario = do-  candidate <- scenario proxy conninfo-  reference <- scenario (Proxy :: Proxy Reference) conninfo+differentialConnect adapter conninfo scenario = do+  candidate <- scenario adapter conninfo+  reference <- scenario Reference.adapter conninfo   candidate `shouldBe` reference
src/library/Pqi/Conformance/Observation.hs view
@@ -1,16 +1,16 @@ -- | Plain, comparable snapshots of a connection or result. ----- The candidate adapter and the FFI reference produce values of /different/--- types (@'Pqi.ResultOf' candidate@ vs @'Pqi.ResultOf'--- 'Pqi.Ffi.Connection'@), so they cannot be compared directly. Instead we--- project each into one of these driver-independent records and compare those.+-- Every adapter produces the same concrete 'Pqi.Connection'\/'Pqi.Result'+-- record, so comparing candidate and reference values directly would also+-- compare the per-connection identity fields (@backendPID@, @socket@), which+-- are structurally incomparable across two independently-opened connections.+-- Projecting each into one of these driver-independent records first keeps+-- the comparison to protocol-derived information only. -- -- Only protocol-derived information is captured: both adapters parse the same--- wire bytes, so these fields genuinely agree. Per-connection identity values--- (@backendPID@, @socket@) are structurally incomparable across connections--- and are omitted. All result fields — including the flat error message text--- and all structured error fields — are captured in full and compared--- byte-identically.+-- wire bytes, so these fields genuinely agree. All result fields — including+-- the flat error message text and all structured error fields — are captured+-- in full and compared byte-identically. module Pqi.Conformance.Observation   ( ResultObservation (..),     FieldObservation (..),@@ -21,7 +21,6 @@   ) where -import Pqi (IsConnection (..), IsResult (..)) import qualified Pqi as Lq import Pqi.Conformance.Prelude @@ -67,40 +66,40 @@   deriving stock (Eq, Show)  -- | Project a result into a 'ResultObservation'.-observeResult :: (IsResult r) => r -> IO ResultObservation+observeResult :: Lq.Result -> IO ResultObservation observeResult result = do-  status <- Lq.resultStatus result+  status <- result.resultStatus   errorFields <-     traverse-      (\code -> (,) code <$> Lq.resultErrorField result code)+      (\code -> (,) code <$> result.resultErrorField code)       [minBound .. maxBound]-  errorMessage <- Lq.resultErrorMessage result-  ntuples <- Lq.ntuples result-  nfields <- Lq.nfields result-  nparams <- Lq.nparams result-  paramTypes <- traverse (Lq.paramtype result) [0 .. nparams - 1]+  errorMessage <- result.resultErrorMessage+  ntuples <- result.ntuples+  nfields <- result.nfields+  nparams <- result.nparams+  paramTypes <- traverse result.paramtype [0 .. nparams - 1]   fields <- traverse (observeField result) [0 .. nfields - 1]   rows <- traverse (\row -> traverse (observeCell result row) [0 .. nfields - 1]) [0 .. ntuples - 1]-  cmdStatus <- Lq.cmdStatus result-  cmdTuples <- Lq.cmdTuples result+  cmdStatus <- result.cmdStatus+  cmdTuples <- result.cmdTuples   pure ResultObservation {..} -observeField :: (IsResult r) => r -> Int32 -> IO FieldObservation+observeField :: Lq.Result -> Int32 -> IO FieldObservation observeField result column = do-  name <- Lq.fname result column-  typeOid <- Lq.ftype result column-  modifier <- Lq.fmod result column-  size <- Lq.fsize result column-  format <- Lq.fformat result column-  tableOid <- Lq.ftable result column-  tableColumn <- Lq.ftablecol result column+  name <- result.fname column+  typeOid <- result.ftype column+  modifier <- result.fmod column+  size <- result.fsize column+  format <- result.fformat column+  tableOid <- result.ftable column+  tableColumn <- result.ftablecol column   pure FieldObservation {..} -observeCell :: (IsResult r) => r -> Int32 -> Int32 -> IO CellObservation+observeCell :: Lq.Result -> Int32 -> Int32 -> IO CellObservation observeCell result row column = do-  value <- Lq.getvalue result row column-  isNull <- Lq.getisnull result row column-  length <- Lq.getlength result row column+  value <- result.getvalue row column+  isNull <- result.getisnull row column+  length <- result.getlength row column   pure CellObservation {..}  -- | A snapshot of the comparable portion of a connection's state. The@@ -125,20 +124,20 @@   deriving stock (Eq, Show)  -- | Project a connection into a 'ConnectionObservation'.-observeConnection :: (IsConnection c) => c -> IO ConnectionObservation+observeConnection :: Lq.Connection -> IO ConnectionObservation observeConnection connection = do-  status <- Lq.status connection-  transactionStatus <- Lq.transactionStatus connection-  serverVersion <- Lq.serverVersion connection-  serverVersionParam <- Lq.parameterStatus connection "server_version"-  protocolVersion <- Lq.protocolVersion connection-  db <- Lq.db connection-  user <- Lq.user connection-  pass <- Lq.pass connection-  host <- Lq.host connection-  port <- Lq.port connection-  options <- Lq.options connection-  connectionNeedsPassword <- Lq.connectionNeedsPassword connection-  connectionUsedPassword <- Lq.connectionUsedPassword connection-  let isNull = Lq.isNullConnection connection+  status <- connection.status+  transactionStatus <- connection.transactionStatus+  serverVersion <- connection.serverVersion+  serverVersionParam <- connection.parameterStatus "server_version"+  protocolVersion <- connection.protocolVersion+  db <- connection.db+  user <- connection.user+  pass <- connection.pass+  host <- connection.host+  port <- connection.port+  options <- connection.options+  connectionNeedsPassword <- connection.connectionNeedsPassword+  connectionUsedPassword <- connection.connectionUsedPassword+  let isNull = connection.isNullConnection   pure ConnectionObservation {..}
src/library/Pqi/Conformance/Operation/BackendPID.hs view
@@ -7,14 +7,14 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "backendPID" do     it "is positive on an open connection" \conninfo ->-      differential proxy conninfo \connection ->-        (> 0) <$> backendPID connection+      differential adapter conninfo \connection ->+        (> 0) <$> connection.backendPID
src/library/Pqi/Conformance/Operation/Cancel.hs view
@@ -9,7 +9,7 @@   ) where -import Pqi (IsCancel (..), IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import qualified Pqi.Conformance.Operation.Cancel.Cleanup as Cleanup import qualified Pqi.Conformance.Operation.Cancel.Stale as Stale@@ -17,35 +17,35 @@ import Pqi.Conformance.Scenario (drainResults, execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "cancel" do     it "succeeds on an idle connection" \conninfo ->-      differential proxy conninfo \connection -> do-        handle <- getCancel connection-        for handle cancel+      differential adapter conninfo \connection -> do+        handle <- connection.getCancel+        for handle (.cancel)      it "fails a running query with 57014" \conninfo ->-      differential proxy conninfo \connection -> do-        sent <- sendQuery connection "select pg_sleep(10)"+      differential adapter conninfo \connection -> do+        sent <- connection.sendQuery "select pg_sleep(10)"         threadDelay 100000-        handle <- getCancel connection-        cancelled <- for handle cancel+        handle <- connection.getCancel+        cancelled <- for handle (.cancel)         results <- drainResults connection         usable <- execScenario "select 1" connection         pure (sent, cancelled, results, usable)      it "leaves the connection usable after cancelling a short-running query" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         outcomes <- replicateM 3 do-          sent <- sendQuery connection "select pg_sleep(0.1)"+          sent <- connection.sendQuery "select pg_sleep(0.1)"           threadDelay 50000-          handle <- getCancel connection-          cancelled <- for handle cancel+          handle <- connection.getCancel+          cancelled <- for handle (.cancel)           results <- drainResults connection           usable <- execScenario "select 1" connection           pure (sent, cancelled, results, usable)         pure outcomes -    Cleanup.spec proxy-    Stale.spec proxy+    Cleanup.spec adapter+    Stale.spec adapter
src/library/Pqi/Conformance/Operation/Cancel/Cleanup.hs view
@@ -15,13 +15,13 @@ where  import Control.Exception (bracket)-import Pqi (ExecStatus (..), IsCancel (..), IsConnection (..), IsResult (..))+import qualified Pqi import qualified Pqi as Lq import Pqi.Conformance.Prelude import Test.Hspec -spec :: forall c. (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "cancel cleanup" do     -- Reproduces the state that hasql's cleanUpAfterInterruption reaches after     -- a timeout fires mid-pipeline:@@ -38,11 +38,11 @@     --   5. exec runs a follow-up command — it must NOT be cancelled by the     --      stale signal that arrived in step 2.     it "does not corrupt subsequent commands when cancel is called after pipeline results are drained" \conninfo ->-      bracket (connectdb conninfo :: IO c) finish \connection -> do+      bracket (adapter.connectdb conninfo) (.finish) \connection -> do         -- Enter pipeline mode and dispatch a fast query.-        _ <- enterPipelineMode connection-        _ <- sendQueryParams connection "select 1" [] Lq.Text-        _ <- pipelineSync connection+        _ <- connection.enterPipelineMode+        _ <- connection.sendQueryParams "select 1" [] Lq.Text+        _ <- connection.pipelineSync          -- Wait for the server to process the query so both messages         -- (CommandComplete + ReadyForQuery) are already in the socket by the@@ -53,7 +53,7 @@         -- After this loop exits, asyncPending=True in pqi-native because         -- ReadyForQuery has not been read yet.         let drainAll = do-              mr <- getResult connection+              mr <- connection.getResult               case mr of                 Nothing -> pure ()                 Just _ -> drainAll@@ -61,8 +61,8 @@          -- Send cancel.  Because asyncPending=True in pqi-native, a cancel         -- request is dispatched to the server despite the query being done.-        handle <- getCancel connection-        for_ handle cancel+        handle <- connection.getCancel+        for_ handle (.cancel)          -- Give the stale cancel enough time to reach the server and set         -- QueryCancelPending before the next command arrives.@@ -72,13 +72,13 @@         drainAll          -- Exit pipeline mode (sends an implicit Sync in the reference impl).-        _ <- exitPipelineMode connection+        _ <- connection.exitPipelineMode          -- A follow-up command must succeed; 57014 here means the stale cancel         -- corrupted the connection.-        mResult <- exec connection "select 1"+        mResult <- connection.exec "select 1"         case mResult of           Nothing -> expectationFailure "exec returned no result after pipeline cleanup"-          Just (result :: ResultOf c) -> do-            status <- resultStatus result-            status `shouldBe` TuplesOk+          Just result -> do+            status <- result.resultStatus+            status `shouldBe` Lq.TuplesOk
src/library/Pqi/Conformance/Operation/Cancel/Stale.hs view
@@ -32,7 +32,7 @@ where  import Control.Exception (bracket)-import Pqi (ExecStatus (..), FieldCode (..), IsCancel (..), IsConnection (..))+import qualified Pqi import qualified Pqi as Lq import Pqi.Conformance.Observation (ResultObservation (..)) import Pqi.Conformance.Prelude@@ -47,12 +47,12 @@ iterations :: Int iterations = 30 -spec :: forall c. (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "stale cancel" do     it "does not corrupt the next command when a cancel is sent during pipeline clean-up" \conninfo -> do       outcomes <- for [1 .. iterations] \i -> do-        outcome <- runScenario proxy conninfo+        outcome <- runScenario adapter conninfo         pure (i, outcome)       -- Every iteration's victim query must have succeeded.  Any iteration that       -- did not means a stale cancel corrupted the connection (57014).@@ -63,22 +63,20 @@ -- the victim query succeeded, or @Just (status, sqlstate)@ describing how it -- failed (e.g. @(FatalError, Just "57014")@). runScenario ::-  forall c.-  (IsConnection c) =>-  Proxy c ->+  Pqi.Adapter ->   ByteString ->-  IO (Maybe (ExecStatus, Maybe ByteString))-runScenario _ conninfo =-  bracket (connectdb conninfo :: IO c) finish \connection -> do+  IO (Maybe (Lq.ExecStatus, Maybe ByteString))+runScenario adapter conninfo =+  bracket (adapter.connectdb conninfo) (.finish) \connection -> do     -- Build a pipeline with a fast query followed by a slow one, mirroring the     -- sequence hasql issues.  Two prepared statements keep pendingParses in     -- play, matching the real-world reproduction.-    _ <- enterPipelineMode connection-    _ <- sendPrepare connection "s1" "select $1::int" Nothing-    _ <- sendQueryPrepared connection "s1" [Just ("42", Lq.Text)] Lq.Text-    _ <- sendPrepare connection "s2" "select pg_sleep($1)" (Just [float8Oid])-    _ <- sendQueryPrepared connection "s2" [Just ("0.1", Lq.Text)] Lq.Text-    _ <- pipelineSync connection+    _ <- connection.enterPipelineMode+    _ <- connection.sendPrepare "s1" "select $1::int" Nothing+    _ <- connection.sendQueryPrepared "s1" [Just ("42", Lq.Text)] Lq.Text+    _ <- connection.sendPrepare "s2" "select pg_sleep($1)" (Just [float8Oid])+    _ <- connection.sendQueryPrepared "s2" [Just ("0.1", Lq.Text)] Lq.Text+    _ <- connection.pipelineSync      -- Interrupt the read mid-pipeline, exactly as hasql's timeout does: the     -- slow pg_sleep is still running when the read is abandoned.@@ -87,27 +85,27 @@     -- cleanUpAfterInterruption: drain, cancel, drain.  The cancel is sent while     -- the pipeline is mid-flight; on buggy code its SIGINT can arrive late.     _ <- drainResults connection-    mHandle <- getCancel connection-    _ <- for mHandle cancel+    mHandle <- connection.getCancel+    _ <- for mHandle (.cancel)     _ <- drainResults connection      -- leavePipeline: the exact restore sequence hasql performs, including the     -- retry it falls back to.-    statusBefore <- pipelineStatus connection+    statusBefore <- connection.pipelineStatus     when (statusBefore == Lq.PipelineOn) do-      _ <- pipelineSync connection+      _ <- connection.pipelineSync       _ <- drainResults connection-      _ <- sendFlushRequest connection+      _ <- connection.sendFlushRequest       _ <- drainResults connection-      ok <- exitPipelineMode connection+      ok <- connection.exitPipelineMode       unless ok do         _ <- drainResults connection-        void (exitPipelineMode connection)+        void connection.exitPipelineMode      -- The victim.  It must not be cancelled by the stale signal.     execScenario "select 99" connection >>= \case-      Nothing -> pure (Just (FatalError, Just "no-result"))+      Nothing -> pure (Just (Lq.FatalError, Just "no-result"))       Just observation ->         case observation.status of-          TuplesOk -> pure Nothing-          status -> pure (Just (status, fromMaybe Nothing (lookup DiagSqlstate observation.errorFields)))+          Lq.TuplesOk -> pure Nothing+          status -> pure (Just (status, fromMaybe Nothing (lookup Lq.DiagSqlstate observation.errorFields)))
src/library/Pqi/Conformance/Operation/ClientEncoding.hs view
@@ -6,22 +6,22 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "clientEncoding" do     it "round-trips and governs result re-encoding" \conninfo ->-      differential proxy conninfo \connection -> do-        initial <- clientEncoding connection-        setOk <- setClientEncoding connection "LATIN1"-        switched <- clientEncoding connection-        reported <- parameterStatus connection "client_encoding"+      differential adapter conninfo \connection -> do+        initial <- connection.clientEncoding+        setOk <- connection.setClientEncoding "LATIN1"+        switched <- connection.clientEncoding+        reported <- connection.parameterStatus "client_encoding"         latinCell <- execScenario "select chr(233) as e" connection-        restoreOk <- setClientEncoding connection "UTF8"+        restoreOk <- connection.setClientEncoding "UTF8"         utfCell <- execScenario "select chr(233) as e" connection         pure (initial, setOk, switched, reported, latinCell, restoreOk, utfCell)
src/library/Pqi/Conformance/Operation/CmdStatus.hs view
@@ -5,18 +5,18 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "cmdStatus" do     it "reports the command tag for each command" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "create temporary table conformance_cmd_status (id int4, label text)"-        let tagOf sql = exec connection sql >>= traverse cmdStatus+      differential adapter conninfo \connection -> do+        _ <- connection.exec "create temporary table conformance_cmd_status (id int4, label text)"+        let tagOf sql = connection.exec sql >>= traverse (.cmdStatus)         insert <- tagOf "insert into conformance_cmd_status values (1, 'a'), (2, 'b')"         update <- tagOf "update conformance_cmd_status set label = 'c' where id = 1"         delete <- tagOf "delete from conformance_cmd_status where id = 2"
src/library/Pqi/Conformance/Operation/CmdTuples.hs view
@@ -5,18 +5,18 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "cmdTuples" do     it "reports the affected-row count for each command" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "create temporary table conformance_cmd_tuples (id int4, label text)"-        let countOf sql = exec connection sql >>= traverse cmdTuples+      differential adapter conninfo \connection -> do+        _ <- connection.exec "create temporary table conformance_cmd_tuples (id int4, label text)"+        let countOf sql = connection.exec sql >>= traverse (.cmdTuples)         insert <- countOf "insert into conformance_cmd_tuples values (1, 'a'), (2, 'b')"         update <- countOf "update conformance_cmd_tuples set label = 'c' where id = 1"         delete <- countOf "delete from conformance_cmd_tuples where id = 2"
src/library/Pqi/Conformance/Operation/ConnectPoll.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (pollUntilDone) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "connectPoll" do     it "reaches a terminal polling status and a ready connection" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy c) conninfo' -> do-        connection <- connectStart conninfo' :: IO c-        terminal <- pollUntilDone (connectPoll connection)-        connStatus <- status connection-        finish connection+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        connection <- adapter'.connectStart conninfo'+        terminal <- pollUntilDone connection.connectPoll+        connStatus <- connection.status+        connection.finish         pure (terminal, connStatus)
src/library/Pqi/Conformance/Operation/ConnectStart.hs view
@@ -5,20 +5,20 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Observation import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (pollUntilDone) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "connectStart" do     it "begins an asynchronous connection that polls to readiness" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy c) conninfo' -> do-        connection <- connectStart conninfo' :: IO c-        polled <- pollUntilDone (connectPoll connection)+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        connection <- adapter'.connectStart conninfo'+        polled <- pollUntilDone connection.connectPoll         observation <- observeConnection connection-        finish connection+        connection.finish         pure (polled, observation)
src/library/Pqi/Conformance/Operation/Connectdb.hs view
@@ -11,49 +11,49 @@ import qualified Data.ByteString.Char8 as ByteString.Char8 import qualified Data.Map.Strict as Map import qualified Data.Text as Text-import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Observation import Pqi.Conformance.Prelude-import Pqi.Conformance.Reference (Reference)+import qualified Pqi.Conformance.Reference as Reference import Test.Hspec import qualified TestcontainersPostgresql as TcPg -spec :: forall c. (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy = do+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter = do   describe "connectdb" do     it "opens a usable connection" \conninfo ->-      differential proxy conninfo observeConnection+      differential adapter conninfo observeConnection      it "accepts a URI-format conninfo" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy d) conninfo' -> do-        connection <- connectdb (kvToUri conninfo') :: IO d-        s <- status connection-        finish connection+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        connection <- adapter'.connectdb (kvToUri conninfo')+        s <- connection.status+        connection.finish         pure s      it "rejects an unknown database" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy d) conninfo' -> do-        connection <- connectdb (conninfo' <> " dbname=pqi_no_such_db") :: IO d-        observation <- status connection-        nullness <- pure (isNullConnection connection)-        finish connection+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        connection <- adapter'.connectdb (conninfo' <> " dbname=pqi_no_such_db")+        observation <- connection.status+        nullness <- pure connection.isNullConnection+        connection.finish         pure (observation, nullness)      it "rejects an unknown user" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy d) conninfo' -> do-        connection <- connectdb (conninfo' <> " user=pqi_no_such_user") :: IO d-        observation <- status connection-        finish connection+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        connection <- adapter'.connectdb (conninfo' <> " user=pqi_no_such_user")+        observation <- connection.status+        connection.finish         pure observation      it "defaults the user like the reference when user is omitted" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy d) conninfo' -> do-        connection <- connectdb (dropUser conninfo') :: IO d-        resolvedUser <- user connection-        observedStatus <- status connection-        observedError <- errorMessage connection-        finish connection+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        connection <- adapter'.connectdb (dropUser conninfo')+        resolvedUser <- connection.user+        observedStatus <- connection.status+        observedError <- connection.errorMessage+        connection.finish         pure (resolvedUser, observedStatus, observedError)    describe "SCRAM-SHA-256 authentication" do@@ -65,8 +65,8 @@                 TcPg.auth = TcPg.CredentialsAuth "scram" "secret"               } -          scramScenario :: forall c. (IsConnection c) => c -> IO (Maybe ResultObservation)-          scramScenario connection = exec connection "select 1 as scram_works" >>= traverse observeResult+          scramScenario :: Pqi.Connection -> IO (Maybe ResultObservation)+          scramScenario connection = connection.exec "select 1 as scram_works" >>= traverse observeResult        in TcPg.run scramConfig \(host, port) -> do             let conninfo =                   ByteString.Char8.pack@@ -76,9 +76,9 @@                         <> show port                         <> " user=scram password=secret dbname=scram"                     )-            native <- bracket (connectdb conninfo) finish (scramScenario @c)-            reference <- bracket (connectdb conninfo) finish (scramScenario @Reference)-            native `shouldBe` reference+            candidate <- bracket (adapter.connectdb conninfo) (.finish) scramScenario+            reference <- bracket (Reference.adapter.connectdb conninfo) (.finish) scramScenario+            candidate `shouldBe` reference  -- | Drop the @user=…@ token from a @key=value@ conninfo, leaving the user -- unspecified so the adapter must apply its own default. libpq derives the
src/library/Pqi/Conformance/Operation/ConnectionNeedsPassword.hs view
@@ -5,13 +5,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "connectionNeedsPassword" do     it "reports whether a password was needed" \conninfo ->-      differential proxy conninfo connectionNeedsPassword+      differential adapter conninfo (.connectionNeedsPassword)
src/library/Pqi/Conformance/Operation/ConnectionUsedPassword.hs view
@@ -5,13 +5,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "connectionUsedPassword" do     it "reports whether a password was used" \conninfo ->-      differential proxy conninfo connectionUsedPassword+      differential adapter conninfo (.connectionUsedPassword)
src/library/Pqi/Conformance/Operation/ConsumeInput.hs view
@@ -6,22 +6,22 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "consumeInput" do     it "drives result collection together with isBusy" \conninfo ->-      differential proxy conninfo \connection -> do-        sent <- sendQuery connection "select 42"+      differential adapter conninfo \connection -> do+        sent <- connection.sendQuery "select 42"         let settle (0 :: Int) = pure False             settle n = do-              consumed <- consumeInput connection-              busy <- isBusy connection+              consumed <- connection.consumeInput+              busy <- connection.isBusy               if busy then threadDelay 1000 >> settle (n - 1) else pure consumed         consumed <- settle 10000         results <- drainResults connection
src/library/Pqi/Conformance/Operation/Db.hs view
@@ -4,13 +4,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "db" do     it "reports the database name from the conninfo" \conninfo ->-      differential proxy conninfo db+      differential adapter conninfo (.db)
src/library/Pqi/Conformance/Operation/DescribePortal.hs view
@@ -5,24 +5,23 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Observation import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "describePortal" do     it "describes a declared cursor" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "begin"+      differential adapter conninfo \connection -> do+        _ <- connection.exec "begin"         _ <--          exec-            connection+          connection.exec             "declare conformance_cursor cursor for select 1 :: int4 as n, 'x' :: text as t"-        describePortal connection "conformance_cursor" >>= traverse observeResult+        connection.describePortal "conformance_cursor" >>= traverse observeResult      it "rejects an unknown portal" \conninfo ->-      differential proxy conninfo \connection ->-        describePortal connection "conformance_no_portal" >>= traverse observeResult+      differential adapter conninfo \connection ->+        connection.describePortal "conformance_no_portal" >>= traverse observeResult
src/library/Pqi/Conformance/Operation/DescribePrepared.hs view
@@ -6,26 +6,26 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Observation import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (int8Oid) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "describePrepared" do     it "reports parameter types" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_desc" "select $1 :: int4, $2 :: text" Nothing-        describePrepared connection "conformance_desc" >>= traverse observeResult+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_desc" "select $1 :: int4, $2 :: text" Nothing+        connection.describePrepared "conformance_desc" >>= traverse observeResult      it "reports explicit parameter types" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_typed" "select $1" (Just [int8Oid])-        describePrepared connection "conformance_typed" >>= traverse observeResult+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_typed" "select $1" (Just [int8Oid])+        connection.describePrepared "conformance_typed" >>= traverse observeResult      it "rejects an unknown statement" \conninfo ->-      differential proxy conninfo \connection ->-        describePrepared connection "conformance_missing" >>= traverse observeResult+      differential adapter conninfo \connection ->+        connection.describePrepared "conformance_missing" >>= traverse observeResult
src/library/Pqi/Conformance/Operation/DisableNoticeReporting.hs view
@@ -5,23 +5,23 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "disableNoticeReporting" do     it "stops retaining notices once disabled" \conninfo ->-      differential proxy conninfo \connection -> do-        enableNoticeReporting connection+      differential adapter conninfo \connection -> do+        connection.enableNoticeReporting         whileEnabled <- raiseNoticeAndCollect connection-        disableNoticeReporting connection+        connection.disableNoticeReporting         whileDisabled <- raiseNoticeAndCollect connection         pure (whileEnabled, whileDisabled) -raiseNoticeAndCollect :: (IsConnection c) => c -> IO Bool+raiseNoticeAndCollect :: Pqi.Connection -> IO Bool raiseNoticeAndCollect connection = do-  _ <- exec connection "do $$ begin raise notice 'conformance notice'; end $$"-  isJust <$> getNotice connection+  _ <- connection.exec "do $$ begin raise notice 'conformance notice'; end $$"+  isJust <$> connection.getNotice
src/library/Pqi/Conformance/Operation/EnableNoticeReporting.hs view
@@ -6,22 +6,22 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "enableNoticeReporting" do     it "makes a raised notice retrievable" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         beforeEnable <- raiseNoticeAndCollect connection-        enableNoticeReporting connection+        connection.enableNoticeReporting         afterEnable <- raiseNoticeAndCollect connection         pure (beforeEnable, afterEnable) -raiseNoticeAndCollect :: (IsConnection c) => c -> IO Bool+raiseNoticeAndCollect :: Pqi.Connection -> IO Bool raiseNoticeAndCollect connection = do-  _ <- exec connection "do $$ begin raise notice 'conformance notice'; end $$"-  isJust <$> getNotice connection+  _ <- connection.exec "do $$ begin raise notice 'conformance notice'; end $$"+  isJust <$> connection.getNotice
src/library/Pqi/Conformance/Operation/EnterPipelineMode.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "enterPipelineMode" do     it "enters pipeline mode and is idempotent" \conninfo ->-      differential proxy conninfo \connection -> do-        before <- pipelineStatus connection-        entered <- enterPipelineMode connection-        enteredAgain <- enterPipelineMode connection-        while <- pipelineStatus connection-        _ <- exitPipelineMode connection+      differential adapter conninfo \connection -> do+        before <- connection.pipelineStatus+        entered <- connection.enterPipelineMode+        enteredAgain <- connection.enterPipelineMode+        while <- connection.pipelineStatus+        _ <- connection.exitPipelineMode         pure (before, entered, enteredAgain, while)
src/library/Pqi/Conformance/Operation/ErrorMessage.hs view
@@ -15,48 +15,48 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "errorMessage" do     it "is empty on a healthy connection" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "select 1"-        errorMessage connection+      differential adapter conninfo \connection -> do+        _ <- connection.exec "select 1"+        connection.errorMessage      it "is populated after a failed exec and cleared by a subsequent success" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "do $$ begin raise exception 'conformance error'; end $$"-        afterFail <- errorMessage connection-        _ <- exec connection "select 1"-        afterSuccess <- errorMessage connection+      differential adapter conninfo \connection -> do+        _ <- connection.exec "do $$ begin raise exception 'conformance error'; end $$"+        afterFail <- connection.errorMessage+        _ <- connection.exec "select 1"+        afterSuccess <- connection.errorMessage         pure (afterFail, afterSuccess)      it "is populated after a failed getResult and cleared by a subsequent success" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- sendQuery connection "do $$ begin raise exception 'conformance error'; end $$"+      differential adapter conninfo \connection -> do+        _ <- connection.sendQuery "do $$ begin raise exception 'conformance error'; end $$"         _ <- drainResults connection-        afterFail <- errorMessage connection-        _ <- sendQuery connection "select 1"+        afterFail <- connection.errorMessage+        _ <- connection.sendQuery "select 1"         _ <- drainResults connection-        afterSuccess <- errorMessage connection+        afterSuccess <- connection.errorMessage         pure (afterFail, afterSuccess)      it "is populated after a connection failure" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy c) conninfo' -> do-        conn <- connectdb (conninfo' <> " user=pqi_no_such_user") :: IO c-        msg <- errorMessage conn-        finish conn+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        conn <- adapter'.connectdb (conninfo' <> " user=pqi_no_such_user")+        msg <- conn.errorMessage+        conn.finish         pure msg      it "is the null-connection sentinel on a null connection" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy c) _ -> do-        conn <- newNullConnection :: IO c-        msg <- errorMessage conn-        finish conn+      differentialConnect adapter conninfo \adapter' _ -> do+        conn <- adapter'.newNullConnection+        msg <- conn.errorMessage+        conn.finish         pure msg
src/library/Pqi/Conformance/Operation/EscapeByteaConn.hs view
@@ -6,17 +6,17 @@ where  import qualified Data.ByteString as ByteString-import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "escapeByteaConn" do     it "escapes a range of binary inputs" \conninfo ->-      differential proxy conninfo \connection ->-        traverse (escapeByteaConn connection) byteaCases+      differential adapter conninfo \connection ->+        traverse connection.escapeByteaConn byteaCases   where     byteaCases =       [ "",
src/library/Pqi/Conformance/Operation/EscapeIdentifier.hs view
@@ -5,22 +5,22 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "escapeIdentifier" do     it "escapes a range of identifiers" \conninfo ->-      differential proxy conninfo \connection ->-        traverse (escapeIdentifier connection) identifierCases+      differential adapter conninfo \connection ->+        traverse connection.escapeIdentifier identifierCases      it "produces identifiers that round-trip through a query" \conninfo ->-      differential proxy conninfo \connection -> do-        escaped <- escapeIdentifier connection "Wéird \"column\" name"+      differential adapter conninfo \connection -> do+        escaped <- connection.escapeIdentifier "Wéird \"column\" name"         for escaped \identifier ->           execScenario ("select 1 as " <> identifier) connection   where
src/library/Pqi/Conformance/Operation/EscapeStringConn.hs view
@@ -5,26 +5,26 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "escapeStringConn" do     it "escapes a range of strings" \conninfo ->-      differential proxy conninfo \connection ->-        traverse (escapeStringConn connection) stringCases+      differential adapter conninfo \connection ->+        traverse connection.escapeStringConn stringCases      it "rejects invalid encoding" \conninfo ->-      differential proxy conninfo \connection ->-        escapeStringConn connection "\255\254"+      differential adapter conninfo \connection ->+        connection.escapeStringConn "\255\254"      it "produces literals that round-trip through a query" \conninfo ->-      differential proxy conninfo \connection -> do-        escaped <- escapeStringConn connection "it's \\ tricky\nstuff"+      differential adapter conninfo \connection -> do+        escaped <- connection.escapeStringConn "it's \\ tricky\nstuff"         for escaped \literal ->           execScenario ("select '" <> literal <> "' :: text") connection   where
src/library/Pqi/Conformance/Operation/Exec.hs view
@@ -5,17 +5,17 @@   ) where -import Pqi (IsConnection)+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "exec" do     let forCase title sql =-          it title \conninfo -> differential proxy conninfo (execScenario sql)+          it title \conninfo -> differential adapter conninfo (execScenario sql)     forCase "select literal" "select 1"     forCase "multi-row, multi-column" "select i, i * 2 from generate_series (1, 3) as i"     forCase "nulls and text" "select null :: int4, 'hello' :: text, true"
src/library/Pqi/Conformance/Operation/ExecParams.hs view
@@ -6,7 +6,6 @@   ) where -import Pqi (IsConnection (..)) import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Observation@@ -14,31 +13,31 @@ import Pqi.Conformance.Scenario import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Lq.Adapter -> SpecWith ByteString+spec adapter =   describe "execParams" do     it "text result format" \conninfo ->-      differential proxy conninfo (paramsScenario Lq.Text)+      differential adapter conninfo (paramsScenario Lq.Text)     it "binary result format" \conninfo ->-      differential proxy conninfo (paramsScenario Lq.Binary)+      differential adapter conninfo (paramsScenario Lq.Binary)     it "null parameter" \conninfo ->-      differential proxy conninfo (observed "select $1 :: int4 as maybe_value" [Nothing] Lq.Text)+      differential adapter conninfo (observed "select $1 :: int4 as maybe_value" [Nothing] Lq.Text)     it "no parameters" \conninfo ->-      differential proxy conninfo (observed "select 'none' :: text" [] Lq.Text)+      differential adapter conninfo (observed "select 'none' :: text" [] Lq.Text)     it "binary parameter" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ observed "select $1 :: int4 * 2" [Just (int4Oid, "\NUL\NUL\NUL*", Lq.Binary)] Lq.Text     it "binary bytea round-trip" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ observed "select $1 :: bytea" [Just (byteaOid, "\NUL\1\2\255", Lq.Binary)] Lq.Binary     it "inferred parameter type" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ observed "select $1 :: int4 + 1" [Just (0, "41", Lq.Text)] Lq.Text     it "empty string is not null" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ observed "select $1 :: text, length ($1 :: text)" [Just (textOid, "", Lq.Text)] Lq.Text     it "many mixed parameters" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ observed           "select $1 :: int8, $2 :: float8, $3 :: bool, $4 :: text, $5 :: int4, $6 :: text"           [ Just (int8Oid, "9000000000000000000", Lq.Text),@@ -50,8 +49,8 @@           ]           Lq.Text     it "DML with parameters" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "create temporary table conformance_exec_params (id int4)"+      differential adapter conninfo \connection -> do+        _ <- connection.exec "create temporary table conformance_exec_params (id int4)"         insert <-           observed             "insert into conformance_exec_params values ($1), ($2)"@@ -66,15 +65,15 @@             connection         pure (insert, check)     it "too few parameters" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ observed "select $1 :: int4 + $2 :: int4" [Just (int4Oid, "1", Lq.Text)] Lq.Text     it "malformed parameter value" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ observed "select $1 :: int4" [Just (int4Oid, "not-a-number", Lq.Text)] Lq.Text     it "multiple statements are rejected" \conninfo ->-      differential proxy conninfo (observed "select 1; select 2" [] Lq.Text)+      differential adapter conninfo (observed "select 1; select 2" [] Lq.Text) -paramsScenario :: (IsConnection c) => Lq.Format -> c -> IO (Maybe ResultObservation)+paramsScenario :: Lq.Format -> Lq.Connection -> IO (Maybe ResultObservation) paramsScenario resultFormat =   observed     "select $1 :: int4 + $2 :: int4 as sum, $3 :: text as label"
src/library/Pqi/Conformance/Operation/ExecPrepared.hs view
@@ -6,41 +6,40 @@   ) where -import Pqi (IsConnection (..)) import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Observation import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Lq.Adapter -> SpecWith ByteString+spec adapter =   describe "execPrepared" do     it "executes a prepared statement" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_stmt" "select $1 :: text as a, $2 :: int4 as b" Nothing-        execPrepared connection "conformance_stmt" [Just ("hello", Lq.Text), Just ("7", Lq.Text)] Lq.Text+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_stmt" "select $1 :: text as a, $2 :: int4 as b" Nothing+        connection.execPrepared "conformance_stmt" [Just ("hello", Lq.Text), Just ("7", Lq.Text)] Lq.Text           >>= traverse observeResult      it "executes the unnamed prepared statement" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "" "select $1 :: int4 + 1" Nothing-        execPrepared connection "" [Just ("41", Lq.Text)] Lq.Text+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "" "select $1 :: int4 + 1" Nothing+        connection.execPrepared "" [Just ("41", Lq.Text)] Lq.Text           >>= traverse observeResult      it "executes a zero-parameter statement" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_no_params" "select 42" Nothing-        execPrepared connection "conformance_no_params" [] Lq.Text+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_no_params" "select 42" Nothing+        connection.execPrepared "conformance_no_params" [] Lq.Text           >>= traverse observeResult      it "binds null and binary parameters with a binary result" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_binary" "select $1 :: text, $2 :: bytea" Nothing-        execPrepared connection "conformance_binary" [Nothing, Just ("\NUL\1\255", Lq.Binary)] Lq.Binary+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_binary" "select $1 :: text, $2 :: bytea" Nothing+        connection.execPrepared "conformance_binary" [Nothing, Just ("\NUL\1\255", Lq.Binary)] Lq.Binary           >>= traverse observeResult      it "rejects an unknown statement" \conninfo ->-      differential proxy conninfo \connection ->-        execPrepared connection "conformance_missing" [] Lq.Text+      differential adapter conninfo \connection ->+        connection.execPrepared "conformance_missing" [] Lq.Text           >>= traverse observeResult
src/library/Pqi/Conformance/Operation/ExitPipelineMode.hs view
@@ -5,7 +5,6 @@   ) where -import Pqi (IsConnection (..)) import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Prelude@@ -13,25 +12,25 @@ import System.Timeout (timeout) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Lq.Adapter -> SpecWith ByteString+spec adapter =   describe "exitPipelineMode" do     it "returns the connection to its non-pipeline status" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- enterPipelineMode connection-        exited <- exitPipelineMode connection-        after <- pipelineStatus connection+      differential adapter conninfo \connection -> do+        _ <- connection.enterPipelineMode+        exited <- connection.exitPipelineMode+        after <- connection.pipelineStatus         pure (exited, after)      it "fails with work pending and succeeds once drained" \conninfo ->-      differential proxy conninfo \connection -> do-        entered <- enterPipelineMode connection-        sent <- sendQueryParams connection "select 1" [] Lq.Text-        prematureExit <- exitPipelineMode connection-        synced <- pipelineSync connection+      differential adapter conninfo \connection -> do+        entered <- connection.enterPipelineMode+        sent <- connection.sendQueryParams "select 1" [] Lq.Text+        prematureExit <- connection.exitPipelineMode+        synced <- connection.pipelineSync         results <- takeCommandResults connection         syncResult <- takeResult connection-        exited <- exitPipelineMode connection+        exited <- connection.exitPipelineMode         pure (entered, sent, prematureExit, synced, results, syncResult, exited)      -- Reproduces the cleanup sequence that hasql's cleanUpAfterInterruption +@@ -41,14 +40,14 @@     -- is consumed, then the connection is restored via the exact drain/sync     -- sequence that hasql uses.     it "recovers after mid-pipeline cancel (mirrors cleanUpAfterInterruption)" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- enterPipelineMode connection-        _ <- sendPrepare connection "s1" "select 1" Nothing-        _ <- sendQueryPrepared connection "s1" [] Lq.Text-        _ <- sendPrepare connection "s2" "select pg_sleep($1)" (Just [float8Oid])-        _ <- sendQueryPrepared connection "s2" [Just ("0.5", Lq.Text)] Lq.Text-        _ <- pipelineSync connection-        _ <- sendFlushRequest connection+      differential adapter conninfo \connection -> do+        _ <- connection.enterPipelineMode+        _ <- connection.sendPrepare "s1" "select 1" Nothing+        _ <- connection.sendQueryPrepared "s1" [] Lq.Text+        _ <- connection.sendPrepare "s2" "select pg_sleep($1)" (Just [float8Oid])+        _ <- connection.sendQueryPrepared "s2" [Just ("0.5", Lq.Text)] Lq.Text+        _ <- connection.pipelineSync+        _ <- connection.sendFlushRequest         -- Consume what toPipelineIO would have read before the timeout:         -- parse1 result + separator, exec1 result + separator, parse2 result + separator.         _ <- takeCommandResults connection@@ -56,17 +55,17 @@         _ <- takeCommandResults connection         -- exec2 (pg_sleep) is still running; cancel it to simulate the         -- timeout-triggered cancel in cleanUpAfterInterruption.-        mHandle <- getCancel connection-        _ <- for mHandle Lq.cancel+        mHandle <- connection.getCancel+        _ <- for mHandle (.cancel)         -- cleanUpAfterInterruption: drain1, then drain2 (after cancel)         _ <- drainResults connection         _ <- drainResults connection         -- leavePipeline: new Sync, drain, Flush, drain-        _ <- pipelineSync connection+        _ <- connection.pipelineSync         _ <- drainResults connection-        _ <- sendFlushRequest connection+        _ <- connection.sendFlushRequest         _ <- drainResults connection-        exited <- exitPipelineMode connection+        exited <- connection.exitPipelineMode         pure exited      -- Reproduces the failure seen in hasql's "Leaves the connection usable@@ -82,36 +81,36 @@     -- currently fails to leave pipeline mode, which is the bug this scenario     -- captures.     it "recovers after timeout interrupts mid-pipeline read" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- enterPipelineMode connection-        _ <- sendPrepare connection "s1" "select $1::int" Nothing-        _ <- sendQueryPrepared connection "s1" [Just ("42", Lq.Text)] Lq.Text-        _ <- sendPrepare connection "s2" "select pg_sleep($1)" (Just [float8Oid])-        _ <- sendQueryPrepared connection "s2" [Just ("0.1", Lq.Text)] Lq.Text-        _ <- pipelineSync connection+      differential adapter conninfo \connection -> do+        _ <- connection.enterPipelineMode+        _ <- connection.sendPrepare "s1" "select $1::int" Nothing+        _ <- connection.sendQueryPrepared "s1" [Just ("42", Lq.Text)] Lq.Text+        _ <- connection.sendPrepare "s2" "select pg_sleep($1)" (Just [float8Oid])+        _ <- connection.sendQueryPrepared "s2" [Just ("0.1", Lq.Text)] Lq.Text+        _ <- connection.pipelineSync         -- Interrupt the read just like hasql's Connection.use + timeout does.         _ <- timeout 50000 (drainResults connection)         -- cleanUpAfterInterruption         _ <- drainResults connection-        mHandle <- getCancel connection-        _ <- for mHandle Lq.cancel+        mHandle <- connection.getCancel+        _ <- for mHandle (.cancel)         _ <- drainResults connection         -- leavePipeline (including the retry that hasql performs)-        pipelineStatusBefore <- pipelineStatus connection+        pipelineStatusBefore <- connection.pipelineStatus         exited <-           if pipelineStatusBefore == Lq.PipelineOn             then do-              _ <- pipelineSync connection+              _ <- connection.pipelineSync               _ <- drainResults connection-              _ <- sendFlushRequest connection+              _ <- connection.sendFlushRequest               _ <- drainResults connection-              ok <- exitPipelineMode connection+              ok <- connection.exitPipelineMode               if ok                 then pure True                 else do                   _ <- drainResults connection-                  exitPipelineMode connection+                  connection.exitPipelineMode             else pure True-        afterStatus <- pipelineStatus connection+        afterStatus <- connection.pipelineStatus         usable <- execScenario "select 99" connection         pure (exited, afterStatus, usable)
src/library/Pqi/Conformance/Operation/Fformat.hs view
@@ -6,22 +6,21 @@   ) where -import Pqi (IsConnection (..), IsResult (..)) import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Lq.Adapter -> SpecWith ByteString+spec adapter =   describe "fformat" do     it "follows the requested result format" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         let formatsOf fmt =-              execParams connection "select 1 :: int4, 'x' :: text" [] fmt+              connection.execParams "select 1 :: int4, 'x' :: text" [] fmt                 >>= traverse \r -> do-                  n <- nfields r-                  traverse (fformat r) [0 .. n - 1]+                  n <- r.nfields+                  traverse r.fformat [0 .. n - 1]         textFormats <- formatsOf Lq.Text         binaryFormats <- formatsOf Lq.Binary         pure (textFormats, binaryFormats)
src/library/Pqi/Conformance/Operation/Finish.hs view
@@ -5,23 +5,23 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "finish" do     it "closes an open connection cleanly" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy c) conninfo' -> do-        connection <- connectdb conninfo' :: IO c-        before <- status connection-        finish connection+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        connection <- adapter'.connectdb conninfo'+        before <- connection.status+        connection.finish         pure before      it "closes the null sentinel cleanly" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy c) _ -> do-        connection <- newNullConnection :: IO c-        finish connection+      differentialConnect adapter conninfo \adapter' _ -> do+        connection <- adapter'.newNullConnection+        connection.finish         pure ()
src/library/Pqi/Conformance/Operation/Flush.hs view
@@ -5,20 +5,20 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults, flushUntilDone) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "flush" do     it "flushes queued output to completion in non-blocking mode" \conninfo ->-      differential proxy conninfo \connection -> do-        setOk <- setnonblocking connection True-        sent <- sendQuery connection "select 1"-        flushed <- flushUntilDone (flush connection)+      differential adapter conninfo \connection -> do+        setOk <- connection.setnonblocking True+        sent <- connection.sendQuery "select 1"+        flushed <- flushUntilDone connection.flush         results <- drainResults connection-        restoreOk <- setnonblocking connection False+        restoreOk <- connection.setnonblocking False         pure (setOk, sent, flushed, results, restoreOk)
src/library/Pqi/Conformance/Operation/Fmod.hs view
@@ -5,20 +5,20 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "fmod" do     it "reports type modifiers and degrades out of range" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         result <--          exec connection "select 1.5 :: numeric(10,2), 'pad' :: char(5), 'x' :: varchar(3), true, 1 :: int4"+          connection.exec "select 1.5 :: numeric(10,2), 'pad' :: char(5), 'x' :: varchar(3), true, 1 :: int4"         for result \r -> do-          n <- nfields r-          modifiers <- traverse (fmod r) [0 .. n - 1]-          outOfRange <- fmod r 9+          n <- r.nfields+          modifiers <- traverse r.fmod [0 .. n - 1]+          outOfRange <- r.fmod 9           pure (modifiers, outOfRange)
src/library/Pqi/Conformance/Operation/Fname.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "fname" do     it "names columns and degrades out of range" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 1 as foo, 2 as bar"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 1 as foo, 2 as bar"         for result \r -> do-          n <- nfields r-          names <- traverse (fname r) [0 .. n - 1]-          outOfRange <- fname r 5+          n <- r.nfields+          names <- traverse r.fname [0 .. n - 1]+          outOfRange <- r.fname 5           pure (names, outOfRange)
src/library/Pqi/Conformance/Operation/Fnumber.hs view
@@ -6,18 +6,18 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "fnumber" do     it "resolves names like an identifier" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 1 as foo, 2 as \"Bar\""+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 1 as foo, 2 as \"Bar\""         for result \r ->           traverse-            (fnumber r)+            r.fnumber             ["foo", "FOO", "Foo", "Bar", "bar", "\"Bar\"", "\"foo\"", "missing"]
src/library/Pqi/Conformance/Operation/Fsize.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "fsize" do     it "reports type sizes and degrades out of range" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 1 :: int2, 1 :: int4, 1 :: int8, 'x' :: text, true"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 1 :: int2, 1 :: int4, 1 :: int8, 'x' :: text, true"         for result \r -> do-          n <- nfields r-          sizes <- traverse (fsize r) [0 .. n - 1]-          outOfRange <- fsize r 9+          n <- r.nfields+          sizes <- traverse r.fsize [0 .. n - 1]+          outOfRange <- r.fsize 9           pure (sizes, outOfRange)
src/library/Pqi/Conformance/Operation/Ftable.hs view
@@ -8,17 +8,17 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "ftable" do     it "reports the source-table OID, or none for a computed column" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select relname, relkind, 1 as computed from pg_catalog.pg_class where false"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select relname, relkind, 1 as computed from pg_catalog.pg_class where false"         for result \r -> do-          n <- nfields r-          traverse (ftable r) [0 .. n - 1]+          n <- r.nfields+          traverse r.ftable [0 .. n - 1]
src/library/Pqi/Conformance/Operation/Ftablecol.hs view
@@ -8,17 +8,17 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "ftablecol" do     it "reports the source-column number, or zero for a computed column" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select relname, relkind, 1 as computed from pg_catalog.pg_class where false"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select relname, relkind, 1 as computed from pg_catalog.pg_class where false"         for result \r -> do-          n <- nfields r-          traverse (ftablecol r) [0 .. n - 1]+          n <- r.nfields+          traverse r.ftablecol [0 .. n - 1]
src/library/Pqi/Conformance/Operation/Ftype.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "ftype" do     it "reports type OIDs and degrades out of range" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 1 :: int4, 'x' :: text, true, 1.5 :: float8, 1 :: int2"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 1 :: int4, 'x' :: text, true, 1.5 :: float8, 1 :: int2"         for result \r -> do-          n <- nfields r-          types <- traverse (ftype r) [0 .. n - 1]-          outOfRange <- ftype r 9+          n <- r.nfields+          types <- traverse r.ftype [0 .. n - 1]+          outOfRange <- r.ftype 9           pure (types, outOfRange)
src/library/Pqi/Conformance/Operation/GetCancel.hs view
@@ -5,14 +5,14 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "getCancel" do     it "produces a handle for an open connection" \conninfo ->-      differential proxy conninfo \connection ->-        isJust <$> getCancel connection+      differential adapter conninfo \connection ->+        isJust <$> connection.getCancel
src/library/Pqi/Conformance/Operation/GetCopyData.hs view
@@ -5,17 +5,17 @@   ) where -import Pqi (IsConnection)+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (collectCopyOut, drainResults, execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "getCopyData" do     let copyOut sql conninfo =-          differential proxy conninfo \connection -> do+          differential adapter conninfo \connection -> do             started <- execScenario sql connection             rows <- collectCopyOut connection             outcome <- drainResults connection
src/library/Pqi/Conformance/Operation/GetNotice.hs view
@@ -10,18 +10,18 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "getNotice" do     it "yields the formatted notice while enabled and then drains" \conninfo ->-      differential proxy conninfo \connection -> do-        enableNoticeReporting connection-        _ <- exec connection "do $$ begin raise notice 'conformance notice'; end $$"-        firstNotice <- getNotice connection-        afterDrain <- getNotice connection+      differential adapter conninfo \connection -> do+        connection.enableNoticeReporting+        _ <- connection.exec "do $$ begin raise notice 'conformance notice'; end $$"+        firstNotice <- connection.getNotice+        afterDrain <- connection.getNotice         pure (firstNotice, afterDrain)
src/library/Pqi/Conformance/Operation/GetResult.hs view
@@ -5,18 +5,18 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (takeResult) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "getResult" do     it "yields each result then a Nothing terminator" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- sendQuery connection "select 1 :: int4"+      differential adapter conninfo \connection -> do+        _ <- connection.sendQuery "select 1 :: int4"         first <- takeResult connection         terminator <- takeResult connection         afterTerminator <- takeResult connection
src/library/Pqi/Conformance/Operation/Getisnull.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "getisnull" do     it "distinguishes null, empty, and non-empty cells" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 'x' :: text, '' :: text, null :: int4"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 'x' :: text, '' :: text, null :: int4"         for result \r -> do-          nonEmpty <- getisnull r 0 0-          empty <- getisnull r 0 1-          nullCell <- getisnull r 0 2+          nonEmpty <- r.getisnull 0 0+          empty <- r.getisnull 0 1+          nullCell <- r.getisnull 0 2           pure (nonEmpty, empty, nullCell)
src/library/Pqi/Conformance/Operation/Getlength.hs view
@@ -5,17 +5,17 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "getlength" do     it "reports byte lengths across cell shapes" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 'hello' :: text, 'héllo' :: text, '' :: text, null :: int4"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 'hello' :: text, 'héllo' :: text, '' :: text, null :: int4"         for result \r -> do-          n <- nfields r-          traverse (getlength r 0) [0 .. n - 1]+          n <- r.nfields+          traverse (r.getlength 0) [0 .. n - 1]
src/library/Pqi/Conformance/Operation/Getvalue.hs view
@@ -5,20 +5,20 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "getvalue" do     it "reads cells, nulls, and degrades out of range" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 'hello' :: text, null :: int4"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 'hello' :: text, null :: int4"         for result \r -> do-          present <- getvalue r 0 0-          nullCell <- getvalue r 0 1-          badRow <- getvalue r 1 0-          badColumn <- getvalue r 0 5+          present <- r.getvalue 0 0+          nullCell <- r.getvalue 0 1+          badRow <- r.getvalue 1 0+          badColumn <- r.getvalue 0 5           pure (present, nullCell, badRow, badColumn)
src/library/Pqi/Conformance/Operation/GetvalueCopy.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "getvalue'" do     it "copies cells that survive freeing the result" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 'copied' :: text, null :: int4"+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 'copied' :: text, null :: int4"         for result \r -> do-          first <- getvalue' r 0 0-          second <- getvalue' r 0 1-          unsafeFreeResult r+          first <- r.getvalue' 0 0+          second <- r.getvalue' 0 1+          r.unsafeFreeResult           pure (first, second)
src/library/Pqi/Conformance/Operation/Host.hs view
@@ -4,13 +4,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "host" do     it "reports the host from the conninfo" \conninfo ->-      differential proxy conninfo host+      differential adapter conninfo (.host)
src/library/Pqi/Conformance/Operation/IsBusy.hs view
@@ -5,22 +5,22 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "isBusy" do     it "settles to not-busy after the result arrives" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- sendQuery connection "select 42"-        let settle (0 :: Int) = isBusy connection+      differential adapter conninfo \connection -> do+        _ <- connection.sendQuery "select 42"+        let settle (0 :: Int) = connection.isBusy             settle n = do-              _ <- consumeInput connection-              busy <- isBusy connection+              _ <- connection.consumeInput+              busy <- connection.isBusy               if busy then threadDelay 1000 >> settle (n - 1) else pure busy         stillBusy <- settle 10000         _ <- drainResults connection
src/library/Pqi/Conformance/Operation/IsNullConnection.hs view
@@ -5,20 +5,20 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "isNullConnection" do     it "is True for the null sentinel and False for an open connection" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy c) conninfo' -> do-        nullConn <- newNullConnection :: IO c-        let nullIsNull = isNullConnection nullConn-        finish nullConn-        openConn <- connectdb conninfo' :: IO c-        let openIsNull = isNullConnection openConn-        finish openConn+      differentialConnect adapter conninfo \adapter' conninfo' -> do+        nullConn <- adapter'.newNullConnection+        let nullIsNull = nullConn.isNullConnection+        nullConn.finish+        openConn <- adapter'.connectdb conninfo'+        let openIsNull = openConn.isNullConnection+        openConn.finish         pure (nullIsNull, openIsNull)
src/library/Pqi/Conformance/Operation/Isnonblocking.hs view
@@ -5,17 +5,17 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "isnonblocking" do     it "is off initially and reflects a change" \conninfo ->-      differential proxy conninfo \connection -> do-        initially <- isnonblocking connection-        _ <- setnonblocking connection True-        afterEnable <- isnonblocking connection+      differential adapter conninfo \connection -> do+        initially <- connection.isnonblocking+        _ <- connection.setnonblocking True+        afterEnable <- connection.isnonblocking         pure (initially, afterEnable)
src/library/Pqi/Conformance/Operation/LoClose.hs view
@@ -5,24 +5,24 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import System.IO (IOMode (..)) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loClose" do     it "closes the descriptor and invalidates further reads" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection+          oid <- connection.loCreat           outcome <- for oid \o -> do-            fd <- loOpen connection o ReadMode-            closed <- for fd \f -> loClose connection f-            readAfterClose <- join <$> for fd \f -> loRead connection f 10+            fd <- connection.loOpen o ReadMode+            closed <- for fd (connection.loClose)+            readAfterClose <- join <$> for fd \f -> connection.loRead f 10             pure (closed, readAfterClose)-          traverse_ (loUnlink connection) oid+          traverse_ connection.loUnlink oid           pure outcome
src/library/Pqi/Conformance/Operation/LoCreat.hs view
@@ -8,18 +8,18 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loCreat" do     it "creates a large object" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection-          traverse_ (loUnlink connection) oid+          oid <- connection.loCreat+          traverse_ connection.loUnlink oid           pure (isJust oid)
src/library/Pqi/Conformance/Operation/LoCreate.hs view
@@ -8,23 +8,23 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loCreate" do     it "creates a large object with an explicit OID" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do           -- Best-effort cleanup of leftovers from an earlier crashed run; its           -- outcome legitimately differs between runs, so it is not observed.-          _ <- loUnlink connection explicitOid-          created <- loCreate connection explicitOid-          unlinked <- for created (loUnlink connection)+          _ <- connection.loUnlink explicitOid+          created <- connection.loCreate explicitOid+          unlinked <- for created connection.loUnlink           pure (created, unlinked)   where     explicitOid = 424242
src/library/Pqi/Conformance/Operation/LoExport.hs view
@@ -9,26 +9,26 @@ where  import qualified Data.ByteString as ByteString-import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import System.Directory (removeFile) import System.IO (hClose, openBinaryTempFile) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loExport" do     it "exports an imported object, round-tripping its bytes" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         (importPath, importHandle) <- openBinaryTempFile "/tmp" "pqi-conformance-export-in"         ByteString.hPut importHandle payload         hClose importHandle         (exportPath, exportHandle) <- openBinaryTempFile "/tmp" "pqi-conformance-export-out"         hClose exportHandle-        imported <- loImport connection importPath-        exported <- for imported \o -> loExport connection o exportPath-        traverse_ (loUnlink connection) imported+        imported <- connection.loImport importPath+        exported <- for imported \o -> connection.loExport o exportPath+        traverse_ connection.loUnlink imported         roundTripped <- ByteString.readFile exportPath         removeFile importPath         removeFile exportPath
src/library/Pqi/Conformance/Operation/LoImport.hs view
@@ -9,22 +9,22 @@ where  import qualified Data.ByteString as ByteString-import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import System.Directory (removeFile) import System.IO (hClose, openBinaryTempFile) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loImport" do     it "imports a file as a large object" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         (path, handle) <- openBinaryTempFile "/tmp" "pqi-conformance-import"         ByteString.hPut handle "pqi conformance payload"         hClose handle-        imported <- loImport connection path-        traverse_ (loUnlink connection) imported+        imported <- connection.loImport path+        traverse_ connection.loUnlink imported         removeFile path         pure (isJust imported)
src/library/Pqi/Conformance/Operation/LoImportWithOid.hs view
@@ -10,24 +10,24 @@ where  import qualified Data.ByteString as ByteString-import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import System.Directory (removeFile) import System.IO (hClose, openBinaryTempFile) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loImportWithOid" do     it "imports a file as a large object with an explicit OID" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         (path, handle) <- openBinaryTempFile "/tmp" "pqi-conformance-import-oid"         ByteString.hPut handle "pqi conformance payload"         hClose handle-        _ <- loUnlink connection explicitOid-        imported <- loImportWithOid connection path explicitOid-        unlinked <- for imported (loUnlink connection)+        _ <- connection.loUnlink explicitOid+        imported <- connection.loImportWithOid path explicitOid+        unlinked <- for imported connection.loUnlink         removeFile path         pure (imported, unlinked)   where
src/library/Pqi/Conformance/Operation/LoOpen.hs view
@@ -5,26 +5,26 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import System.IO (IOMode (..)) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loOpen" do     it "opens an existing object and rejects a missing one" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection+          oid <- connection.loCreat           opened <- for oid \o -> do-            fd <- loOpen connection o ReadWriteMode-            traverse_ (loClose connection) fd+            fd <- connection.loOpen o ReadWriteMode+            traverse_ connection.loClose fd             pure (isJust fd)           loUnlink' oid connection-          missing <- loOpen connection 4242424 ReadMode+          missing <- connection.loOpen 4242424 ReadMode           pure (opened, isJust missing)   where-    loUnlink' oid connection = traverse_ (loUnlink connection) oid+    loUnlink' oid connection = traverse_ connection.loUnlink oid
src/library/Pqi/Conformance/Operation/LoRead.hs view
@@ -5,27 +5,27 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import System.IO (IOMode (..), SeekMode (..)) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loRead" do     it "reads back what was written" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection+          oid <- connection.loCreat           outcome <- for oid \o -> do-            fd <- loOpen connection o ReadWriteMode+            fd <- connection.loOpen o ReadWriteMode             readBytes <- for fd \f -> do-              _ <- loWrite connection f "hello, large object"-              _ <- loSeek connection f AbsoluteSeek 0-              loRead connection f 5-            traverse_ (loClose connection) fd+              _ <- connection.loWrite f "hello, large object"+              _ <- connection.loSeek f AbsoluteSeek 0+              connection.loRead f 5+            traverse_ connection.loClose fd             pure readBytes-          traverse_ (loUnlink connection) oid+          traverse_ connection.loUnlink oid           pure outcome
src/library/Pqi/Conformance/Operation/LoSeek.hs view
@@ -5,29 +5,29 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import System.IO (IOMode (..), SeekMode (..)) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loSeek" do     it "seeks absolutely, relatively, and from the end" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection+          oid <- connection.loCreat           outcome <- for oid \o -> do-            fd <- loOpen connection o ReadWriteMode+            fd <- connection.loOpen o ReadWriteMode             seeks <- for fd \f -> do-              _ <- loWrite connection f "hello, large object"-              absolute <- loSeek connection f AbsoluteSeek 0-              relative <- loSeek connection f RelativeSeek 2-              fromEnd <- loSeek connection f SeekFromEnd (-6)+              _ <- connection.loWrite f "hello, large object"+              absolute <- connection.loSeek f AbsoluteSeek 0+              relative <- connection.loSeek f RelativeSeek 2+              fromEnd <- connection.loSeek f SeekFromEnd (-6)               pure (absolute, relative, fromEnd)-            traverse_ (loClose connection) fd+            traverse_ connection.loClose fd             pure seeks-          traverse_ (loUnlink connection) oid+          traverse_ connection.loUnlink oid           pure outcome
src/library/Pqi/Conformance/Operation/LoTell.hs view
@@ -5,29 +5,29 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import System.IO (IOMode (..), SeekMode (..)) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loTell" do     it "reports the position after a write and a seek" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection+          oid <- connection.loCreat           outcome <- for oid \o -> do-            fd <- loOpen connection o ReadWriteMode+            fd <- connection.loOpen o ReadWriteMode             positions <- for fd \f -> do-              _ <- loWrite connection f "hello, large object"-              afterWrite <- loTell connection f-              _ <- loSeek connection f AbsoluteSeek 3-              afterSeek <- loTell connection f+              _ <- connection.loWrite f "hello, large object"+              afterWrite <- connection.loTell f+              _ <- connection.loSeek f AbsoluteSeek 3+              afterSeek <- connection.loTell f               pure (afterWrite, afterSeek)-            traverse_ (loClose connection) fd+            traverse_ connection.loClose fd             pure positions-          traverse_ (loUnlink connection) oid+          traverse_ connection.loUnlink oid           pure outcome
src/library/Pqi/Conformance/Operation/LoTruncate.hs view
@@ -5,28 +5,28 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import System.IO (IOMode (..), SeekMode (..)) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loTruncate" do     it "truncates to a new size" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection+          oid <- connection.loCreat           outcome <- for oid \o -> do-            fd <- loOpen connection o ReadWriteMode+            fd <- connection.loOpen o ReadWriteMode             result <- for fd \f -> do-              _ <- loWrite connection f "hello, large object"-              truncated <- loTruncate connection f 5-              newEnd <- loSeek connection f SeekFromEnd 0+              _ <- connection.loWrite f "hello, large object"+              truncated <- connection.loTruncate f 5+              newEnd <- connection.loSeek f SeekFromEnd 0               pure (truncated, newEnd)-            traverse_ (loClose connection) fd+            traverse_ connection.loClose fd             pure result-          traverse_ (loUnlink connection) oid+          traverse_ connection.loUnlink oid           pure outcome
src/library/Pqi/Conformance/Operation/LoUnlink.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loUnlink" do     it "removes an existing object and rejects a missing one" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection-          removed <- for oid (loUnlink connection)-          missing <- loUnlink connection 4242424+          oid <- connection.loCreat+          removed <- for oid connection.loUnlink+          missing <- connection.loUnlink 4242424           pure (removed, missing)
src/library/Pqi/Conformance/Operation/LoWrite.hs view
@@ -4,24 +4,24 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (inTransaction) import System.IO (IOMode (..)) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "loWrite" do     it "reports the number of bytes written" \conninfo ->-      differential proxy conninfo \connection ->+      differential adapter conninfo \connection ->         inTransaction connection do-          oid <- loCreat connection+          oid <- connection.loCreat           outcome <- for oid \o -> do-            fd <- loOpen connection o ReadWriteMode-            written <- for fd \f -> loWrite connection f "hello, large object"-            traverse_ (loClose connection) fd+            fd <- connection.loOpen o ReadWriteMode+            written <- for fd \f -> connection.loWrite f "hello, large object"+            traverse_ connection.loClose fd             pure written-          traverse_ (loUnlink connection) oid+          traverse_ connection.loUnlink oid           pure outcome
src/library/Pqi/Conformance/Operation/NewNullConnection.hs view
@@ -5,18 +5,18 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "newNullConnection" do     it "produces a connection that is null and bad" \conninfo ->-      differentialConnect proxy conninfo \(_ :: Proxy c) _ -> do-        connection <- newNullConnection :: IO c-        nullness <- pure (isNullConnection connection)-        badness <- status connection-        finish connection+      differentialConnect adapter conninfo \adapter' _ -> do+        connection <- adapter'.newNullConnection+        nullness <- pure connection.isNullConnection+        badness <- connection.status+        connection.finish         pure (nullness, badness)
src/library/Pqi/Conformance/Operation/Nfields.hs view
@@ -5,17 +5,17 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "nfields" do     it "counts columns across result shapes" \conninfo ->-      differential proxy conninfo \connection -> do-        let countOf sql = exec connection sql >>= traverse nfields+      differential adapter conninfo \connection -> do+        let countOf sql = connection.exec sql >>= traverse (.nfields)         several <- countOf "select 1, 2, 3"         zero <- countOf "select"         command <- countOf "create temporary table conformance_nfields (id int4)"
src/library/Pqi/Conformance/Operation/Notifies.hs view
@@ -12,46 +12,47 @@   ) where -import Pqi (IsConnection (..), Notify (..))+import Pqi (Notify (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "notifies" do     it "is empty with no pending notifications" \conninfo ->-      differential proxy conninfo \connection ->-        fmap channelAndPayload <$> notifies connection+      differential adapter conninfo \connection ->+        fmap channelAndPayload <$> connection.notifies      it "delivers a listen/notify round-trip and then drains" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "listen conformance_channel"-        _ <- exec connection "notify conformance_channel, 'payload-1'"-        notification <- notifies connection-        pid <- backendPID connection+      differential adapter conninfo \connection -> do+        _ <- connection.exec "listen conformance_channel"+        _ <- connection.exec "notify conformance_channel, 'payload-1'"+        notification <- connection.notifies+        pid <- connection.backendPID         for_ notification \n -> n.bePid `shouldBe` pid-        drained <- fmap channelAndPayload <$> notifies connection+        drained <- fmap channelAndPayload <$> connection.notifies         pure (fmap channelAndPayload notification, drained)      it "queues notifications in order" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "listen conformance_channel"-        _ <- exec connection "notify conformance_channel, 'first'"-        _ <- exec connection "notify conformance_channel, 'second'"-        first <- notifies connection-        second <- notifies connection-        third <- notifies connection-        pid <- backendPID connection+      differential adapter conninfo \connection -> do+        _ <- connection.exec "listen conformance_channel"+        _ <- connection.exec "notify conformance_channel, 'first'"+        _ <- connection.exec "notify conformance_channel, 'second'"+        first <- connection.notifies+        second <- connection.notifies+        third <- connection.notifies+        pid <- connection.backendPID         for_ first \n -> n.bePid `shouldBe` pid         for_ second \n -> n.bePid `shouldBe` pid         pure (fmap channelAndPayload first, fmap channelAndPayload second, fmap channelAndPayload third)      it "stops delivery after unlisten" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "listen conformance_channel"-        _ <- exec connection "unlisten conformance_channel"-        _ <- exec connection "notify conformance_channel, 'lost'"-        fmap channelAndPayload <$> notifies connection+      differential adapter conninfo \connection -> do+        _ <- connection.exec "listen conformance_channel"+        _ <- connection.exec "unlisten conformance_channel"+        _ <- connection.exec "notify conformance_channel, 'lost'"+        fmap channelAndPayload <$> connection.notifies   where     channelAndPayload notification = (notification.relname, notification.extra)
src/library/Pqi/Conformance/Operation/Nparams.hs view
@@ -5,22 +5,22 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "nparams" do     it "counts the parameters of a prepared statement" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_nparams" "select $1 :: int4, $2 :: text" Nothing-        described <- describePrepared connection "conformance_nparams"-        for described nparams+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_nparams" "select $1 :: int4, $2 :: text" Nothing+        described <- connection.describePrepared "conformance_nparams"+        for described (.nparams)      it "is zero for a parameterless statement" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_nparams_zero" "select 42" Nothing-        described <- describePrepared connection "conformance_nparams_zero"-        for described nparams+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_nparams_zero" "select 42" Nothing+        described <- connection.describePrepared "conformance_nparams_zero"+        for described (.nparams)
src/library/Pqi/Conformance/Operation/Ntuples.hs view
@@ -5,17 +5,17 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "ntuples" do     it "counts rows across result shapes" \conninfo ->-      differential proxy conninfo \connection -> do-        let countOf sql = exec connection sql >>= traverse ntuples+      differential adapter conninfo \connection -> do+        let countOf sql = connection.exec sql >>= traverse (.ntuples)         many <- countOf "select i from generate_series (1, 3) as i"         none <- countOf "select 1 where false"         command <- countOf "create temporary table conformance_ntuples (id int4)"
src/library/Pqi/Conformance/Operation/Options.hs view
@@ -5,13 +5,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "options" do     it "reports the command-line options from the conninfo" \conninfo ->-      differential proxy conninfo options+      differential adapter conninfo (.options)
src/library/Pqi/Conformance/Operation/ParameterStatus.hs view
@@ -5,21 +5,21 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "parameterStatus" do     it "reports parameter statuses, including GUC_REPORT updates" \conninfo ->-      differential proxy conninfo \connection -> do-        before <- parameterStatus connection "application_name"-        _ <- exec connection "set application_name to 'pqi-conformance'"-        after <- parameterStatus connection "application_name"-        clientEncoding <- parameterStatus connection "client_encoding"-        standardConformingStrings <- parameterStatus connection "standard_conforming_strings"-        integerDatetimes <- parameterStatus connection "integer_datetimes"-        missing <- parameterStatus connection "no_such_parameter"+      differential adapter conninfo \connection -> do+        before <- connection.parameterStatus "application_name"+        _ <- connection.exec "set application_name to 'pqi-conformance'"+        after <- connection.parameterStatus "application_name"+        clientEncoding <- connection.parameterStatus "client_encoding"+        standardConformingStrings <- connection.parameterStatus "standard_conforming_strings"+        integerDatetimes <- connection.parameterStatus "integer_datetimes"+        missing <- connection.parameterStatus "no_such_parameter"         pure (before, after, clientEncoding, standardConformingStrings, integerDatetimes, missing)
src/library/Pqi/Conformance/Operation/Paramtype.hs view
@@ -5,27 +5,27 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (int8Oid) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "paramtype" do     it "reports inferred parameter types" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_paramtype" "select $1 :: int4, $2 :: text" Nothing-        described <- describePrepared connection "conformance_paramtype"+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_paramtype" "select $1 :: int4, $2 :: text" Nothing+        described <- connection.describePrepared "conformance_paramtype"         for described \r -> do-          n <- nparams r-          traverse (paramtype r) [0 .. n - 1]+          n <- r.nparams+          traverse r.paramtype [0 .. n - 1]      it "reports explicitly requested parameter types" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_paramtype_typed" "select $1" (Just [int8Oid])-        described <- describePrepared connection "conformance_paramtype_typed"+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_paramtype_typed" "select $1" (Just [int8Oid])+        described <- connection.describePrepared "conformance_paramtype_typed"         for described \r -> do-          n <- nparams r-          traverse (paramtype r) [0 .. n - 1]+          n <- r.nparams+          traverse r.paramtype [0 .. n - 1]
src/library/Pqi/Conformance/Operation/Pass.hs view
@@ -5,13 +5,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "pass" do     it "reports the password from the conninfo" \conninfo ->-      differential proxy conninfo pass+      differential adapter conninfo (.pass)
src/library/Pqi/Conformance/Operation/PipelineStatus.hs view
@@ -6,28 +6,28 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (takeCommandResults, takeResult) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "pipelineStatus" do     it "reports off, on, aborted, and recovery" \conninfo ->-      differential proxy conninfo \connection -> do-        off <- pipelineStatus connection-        _ <- enterPipelineMode connection-        on <- pipelineStatus connection-        _ <- traverse (\sql -> sendQueryParams connection sql [] Lq.Text) ["select 1", "select 1 / 0", "select 3"]-        _ <- pipelineSync connection+      differential adapter conninfo \connection -> do+        off <- connection.pipelineStatus+        _ <- connection.enterPipelineMode+        on <- connection.pipelineStatus+        _ <- traverse (\sql -> connection.sendQueryParams sql [] Lq.Text) ["select 1", "select 1 / 0", "select 3"]+        _ <- connection.pipelineSync         _ <- takeCommandResults connection         _ <- takeCommandResults connection-        aborted <- pipelineStatus connection+        aborted <- connection.pipelineStatus         _ <- takeCommandResults connection         _ <- takeResult connection-        recovered <- pipelineStatus connection-        _ <- exitPipelineMode connection+        recovered <- connection.pipelineStatus+        _ <- connection.exitPipelineMode         pure (off, on, aborted, recovered)
src/library/Pqi/Conformance/Operation/PipelineSync.hs view
@@ -5,52 +5,54 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import qualified Pqi as Lq import Pqi.Conformance.Harness+import qualified Pqi.Conformance.Operation.PipelineSync.Parity as Parity import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (takeCommandResults, takeResult) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "pipelineSync" do+    Parity.spec adapter     it "collects pipelined queries per sync" \conninfo ->-      differential proxy conninfo \connection -> do-        entered <- enterPipelineMode connection+      differential adapter conninfo \connection -> do+        entered <- connection.enterPipelineMode         sent <-           traverse-            (\sql -> sendQueryParams connection sql [] Lq.Text)+            (\sql -> connection.sendQueryParams sql [] Lq.Text)             ["select 1 :: int4", "select 'two' :: text", "select 3 :: int4, 'three' :: text"]-        synced <- pipelineSync connection+        synced <- connection.pipelineSync         first <- takeCommandResults connection         second <- takeCommandResults connection         third <- takeCommandResults connection         syncResult <- takeResult connection         idle <- takeResult connection-        exited <- exitPipelineMode connection+        exited <- connection.exitPipelineMode         pure (entered, sent, synced, first, second, third, syncResult, idle, exited)      it "aborts the rest of the pipeline after an error" \conninfo ->-      differential proxy conninfo \connection -> do-        entered <- enterPipelineMode connection+      differential adapter conninfo \connection -> do+        entered <- connection.enterPipelineMode         sent <-           traverse-            (\sql -> sendQueryParams connection sql [] Lq.Text)+            (\sql -> connection.sendQueryParams sql [] Lq.Text)             ["select 1", "select 1 / 0", "select 3"]-        synced <- pipelineSync connection+        synced <- connection.pipelineSync         first <- takeCommandResults connection         failed <- takeCommandResults connection         aborted <- takeCommandResults connection         syncResult <- takeResult connection-        exited <- exitPipelineMode connection+        exited <- connection.exitPipelineMode         pure (entered, sent, synced, first, failed, aborted, syncResult, exited)      it "returns a sync result when called without prior commands" \conninfo ->-      differential proxy conninfo \connection -> do-        entered <- enterPipelineMode connection-        synced <- pipelineSync connection+      differential adapter conninfo \connection -> do+        entered <- connection.enterPipelineMode+        synced <- connection.pipelineSync         syncResult <- takeResult connection         trailing <- takeResult connection-        exited <- exitPipelineMode connection+        exited <- connection.exitPipelineMode         pure (entered, synced, syncResult, trailing, exited)
+ src/library/Pqi/Conformance/Operation/PipelineSync/Parity.hs view
@@ -0,0 +1,52 @@+-- | Reproduces the @hasql@ pipeline parity benchmark scenarios at the @pqi@+-- level: the same sequence of queries is run both sequentially and inside a+-- pipeline, and the two ways of executing them must produce identical+-- observations.+--+-- This is a scenario test for 'Pqi.pipelineSync': it marks the sync point that+-- lets the pipelined batch complete.+module Pqi.Conformance.Operation.PipelineSync.Parity+  ( spec,+  )+where++import qualified Pqi+import qualified Pqi as Lq+import Pqi.Conformance.Harness+import Pqi.Conformance.Observation+import Pqi.Conformance.Prelude+import Pqi.Conformance.Scenario (observed, takeCommandResults, takeResult)+import Test.Hspec++spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =+  describe "parity" do+    it "manySmallResults matches sequential execution" \conninfo ->+      differential adapter conninfo \connection -> do+        let query = "SELECT 1, 2"+        sequential <- replicateM 100 (observed query [] Lq.Text connection)+        entered <- connection.enterPipelineMode+        sent <- replicateM 100 (connection.sendQueryParams query [] Lq.Text)+        synced <- connection.pipelineSync+        pipeline <- replicateM 100 (takeCommandResults connection)+        syncResult <- takeResult connection+        trailing <- takeResult connection+        exited <- connection.exitPipelineMode+        let pipelineResults = map fst pipeline+        sequential `shouldBe` pipelineResults+        pure (entered, sent, synced, pipeline, syncResult, trailing, exited, sequential)++    it "manyLargeResults matches sequential execution" \conninfo ->+      differential adapter conninfo \connection -> do+        let query = "SELECT generate_series(0,1000) as a, generate_series(1000,2000) as b"+        sequential <- replicateM 100 (observed query [] Lq.Text connection)+        entered <- connection.enterPipelineMode+        sent <- replicateM 100 (connection.sendQueryParams query [] Lq.Text)+        synced <- connection.pipelineSync+        pipeline <- replicateM 100 (takeCommandResults connection)+        syncResult <- takeResult connection+        trailing <- takeResult connection+        exited <- connection.exitPipelineMode+        let pipelineResults = map fst pipeline+        sequential `shouldBe` pipelineResults+        pure (entered, sent, synced, pipeline, syncResult, trailing, exited, sequential)
src/library/Pqi/Conformance/Operation/Port.hs view
@@ -4,13 +4,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "port" do     it "reports the port from the conninfo" \conninfo ->-      differential proxy conninfo port+      differential adapter conninfo (.port)
src/library/Pqi/Conformance/Operation/Prepare.hs view
@@ -5,24 +5,24 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Observation import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "prepare" do     it "reports its own result" \conninfo ->-      differential proxy conninfo \connection ->-        prepare connection "conformance_prep_result" "select $1 :: int4" Nothing+      differential adapter conninfo \connection ->+        connection.prepare "conformance_prep_result" "select $1 :: int4" Nothing           >>= traverse observeResult      it "rejects a duplicate statement name" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         first <--          prepare connection "conformance_dup" "select 1" Nothing >>= traverse observeResult+          connection.prepare "conformance_dup" "select 1" Nothing >>= traverse observeResult         second <--          prepare connection "conformance_dup" "select 2" Nothing >>= traverse observeResult+          connection.prepare "conformance_dup" "select 2" Nothing >>= traverse observeResult         pure (first, second)
src/library/Pqi/Conformance/Operation/ProtocolVersion.hs view
@@ -5,13 +5,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "protocolVersion" do     it "reports the protocol version" \conninfo ->-      differential proxy conninfo protocolVersion+      differential adapter conninfo (.protocolVersion)
src/library/Pqi/Conformance/Operation/PutCopyData.hs view
@@ -5,32 +5,32 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults, execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "putCopyData" do     it "streams rows into a COPY FROM STDIN" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "create temporary table conformance_copy (id int4, label text)"+      differential adapter conninfo \connection -> do+        _ <- connection.exec "create temporary table conformance_copy (id int4, label text)"         started <- execScenario "copy conformance_copy from stdin" connection-        firstRow <- putCopyData connection "1\thello\n"-        secondRow <- putCopyData connection "2\tworld\n"-        ended <- putCopyEnd connection Nothing+        firstRow <- connection.putCopyData "1\thello\n"+        secondRow <- connection.putCopyData "2\tworld\n"+        ended <- connection.putCopyEnd Nothing         outcome <- drainResults connection         check <-           execScenario "select count(*), min(label), max(label) from conformance_copy" connection         pure (started, firstRow, secondRow, ended, outcome, check)      it "feeds malformed data that the server rejects" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "create temporary table conformance_copy_bad (id int4)"+      differential adapter conninfo \connection -> do+        _ <- connection.exec "create temporary table conformance_copy_bad (id int4)"         started <- execScenario "copy conformance_copy_bad from stdin" connection-        row <- putCopyData connection "not-a-number\n"-        ended <- putCopyEnd connection Nothing+        row <- connection.putCopyData "not-a-number\n"+        ended <- connection.putCopyEnd Nothing         outcome <- drainResults connection         pure (started, row, ended, outcome)
src/library/Pqi/Conformance/Operation/PutCopyEnd.hs view
@@ -5,31 +5,31 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults, execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "putCopyEnd" do     it "commits the copied rows when ended without an error" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "create temporary table conformance_copy_end (id int4)"+      differential adapter conninfo \connection -> do+        _ <- connection.exec "create temporary table conformance_copy_end (id int4)"         started <- execScenario "copy conformance_copy_end from stdin" connection-        row <- putCopyData connection "1\n"-        ended <- putCopyEnd connection Nothing+        row <- connection.putCopyData "1\n"+        ended <- connection.putCopyEnd Nothing         outcome <- drainResults connection         check <- execScenario "select count(*) from conformance_copy_end" connection         pure (started, row, ended, outcome, check)      it "aborts the copy when ended with an error" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "create temporary table conformance_copy_abort (id int4)"+      differential adapter conninfo \connection -> do+        _ <- connection.exec "create temporary table conformance_copy_abort (id int4)"         started <- execScenario "copy conformance_copy_abort from stdin" connection-        row <- putCopyData connection "1\n"-        ended <- putCopyEnd connection (Just "conformance abort")+        row <- connection.putCopyData "1\n"+        ended <- connection.putCopyEnd (Just "conformance abort")         outcome <- drainResults connection         check <- execScenario "select count(*) from conformance_copy_abort" connection         pure (started, row, ended, outcome, check)
src/library/Pqi/Conformance/Operation/Reset.hs view
@@ -5,22 +5,22 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Observation import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "reset" do     it "restores a fresh session" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- prepare connection "conformance_reset" "select 1" Nothing-        _ <- exec connection "begin"-        inTransaction <- transactionStatus connection-        reset connection+      differential adapter conninfo \connection -> do+        _ <- connection.prepare "conformance_reset" "select 1" Nothing+        _ <- connection.exec "begin"+        inTransaction <- connection.transactionStatus+        connection.reset         afterReset <- observeConnection connection         -- The prepared statement must be gone in the fresh session.-        describeAfter <- describePrepared connection "conformance_reset" >>= traverse observeResult+        describeAfter <- connection.describePrepared "conformance_reset" >>= traverse observeResult         pure (inTransaction, afterReset, describeAfter)
src/library/Pqi/Conformance/Operation/ResetPoll.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (pollUntilDone) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "resetPoll" do     it "reaches a terminal polling status and a ready connection" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "begin"-        started <- resetStart connection-        terminal <- pollUntilDone (resetPoll connection)-        afterStatus <- transactionStatus connection+      differential adapter conninfo \connection -> do+        _ <- connection.exec "begin"+        started <- connection.resetStart+        terminal <- pollUntilDone connection.resetPoll+        afterStatus <- connection.transactionStatus         pure (started, terminal, afterStatus)
src/library/Pqi/Conformance/Operation/ResetStart.hs view
@@ -5,20 +5,20 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Observation import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (pollUntilDone) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "resetStart" do     it "begins an asynchronous reset that polls to a fresh session" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "begin"-        started <- resetStart connection-        polled <- pollUntilDone (resetPoll connection)+      differential adapter conninfo \connection -> do+        _ <- connection.exec "begin"+        started <- connection.resetStart+        polled <- pollUntilDone connection.resetPoll         afterReset <- observeConnection connection         pure (started, polled, afterReset)
src/library/Pqi/Conformance/Operation/ResultErrorField.hs view
@@ -10,17 +10,17 @@   ) where -import Pqi (IsConnection)+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (execAllScenario, execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "resultErrorField" do     let forCase title sql =-          it title \conninfo -> differential proxy conninfo (execScenario sql)+          it title \conninfo -> differential adapter conninfo (execScenario sql)     forCase "syntax error" "selct 1"     forCase "undefined table" "select * from pqi_no_such_table"     forCase "undefined column" "select no_such_column from (select 1) as t"@@ -33,7 +33,7 @@     forCase "value too long" "select 'abc' :: varchar(2)"      it "constraint violations" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ execAllScenario           [ "create temporary table conformance_errors (id int4 primary key, label text not null)",             "insert into conformance_errors values (1, 'a')",@@ -42,5 +42,5 @@           ]      it "a failed transaction block rejects further commands" \conninfo ->-      differential proxy conninfo+      differential adapter conninfo         $ execAllScenario ["begin", "select 1 / 0", "select 1", "rollback", "select 1"]
src/library/Pqi/Conformance/Operation/ResultErrorMessage.hs view
@@ -12,20 +12,20 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "resultErrorMessage" do     it "matches the full formatted libpq error string on failure and is empty on success" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         failed <--          exec connection "do $$ begin raise exception 'conformance error'; end $$"-            >>= traverse resultErrorMessage+          connection.exec "do $$ begin raise exception 'conformance error'; end $$"+            >>= traverse (.resultErrorMessage)         succeeded <--          exec connection "select 1"-            >>= traverse resultErrorMessage+          connection.exec "select 1"+            >>= traverse (.resultErrorMessage)         pure (failed, succeeded)
src/library/Pqi/Conformance/Operation/ResultStatus.hs view
@@ -5,17 +5,17 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "resultStatus" do     it "reports the status for each kind of result" \conninfo ->-      differential proxy conninfo \connection -> do-        let statusOf sql = exec connection sql >>= traverse resultStatus+      differential adapter conninfo \connection -> do+        let statusOf sql = connection.exec sql >>= traverse (.resultStatus)         tuples <- statusOf "select 1"         command <- statusOf "create temporary table conformance_status (id int4)"         empty <- statusOf ""
src/library/Pqi/Conformance/Operation/SendDescribePortal.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "sendDescribePortal" do     it "describes a declared cursor asynchronously" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- exec connection "begin"-        _ <- exec connection "declare conformance_async_cursor cursor for select 1 :: int4 as n"-        sent <- sendDescribePortal connection "conformance_async_cursor"+      differential adapter conninfo \connection -> do+        _ <- connection.exec "begin"+        _ <- connection.exec "declare conformance_async_cursor cursor for select 1 :: int4 as n"+        sent <- connection.sendDescribePortal "conformance_async_cursor"         results <- drainResults connection         pure (sent, results)
src/library/Pqi/Conformance/Operation/SendDescribePrepared.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "sendDescribePrepared" do     it "describes a prepared statement asynchronously" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- sendPrepare connection "conformance_send_desc" "select $1 :: int4 * 2" Nothing+      differential adapter conninfo \connection -> do+        _ <- connection.sendPrepare "conformance_send_desc" "select $1 :: int4 * 2" Nothing         _ <- drainResults connection-        sent <- sendDescribePrepared connection "conformance_send_desc"+        sent <- connection.sendDescribePrepared "conformance_send_desc"         results <- drainResults connection         pure (sent, results)
src/library/Pqi/Conformance/Operation/SendFlushRequest.hs view
@@ -5,23 +5,23 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (takeCommandResults, takeResult) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "sendFlushRequest" do     it "delivers results without a sync" \conninfo ->-      differential proxy conninfo \connection -> do-        entered <- enterPipelineMode connection-        sent <- sendQueryParams connection "select 42" [] Lq.Text-        flushRequested <- sendFlushRequest connection+      differential adapter conninfo \connection -> do+        entered <- connection.enterPipelineMode+        sent <- connection.sendQueryParams "select 42" [] Lq.Text+        flushRequested <- connection.sendFlushRequest         results <- takeCommandResults connection-        synced <- pipelineSync connection+        synced <- connection.pipelineSync         syncResult <- takeResult connection-        exited <- exitPipelineMode connection+        exited <- connection.exitPipelineMode         pure (entered, sent, flushRequested, results, synced, syncResult, exited)
src/library/Pqi/Conformance/Operation/SendPrepare.hs view
@@ -5,17 +5,17 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "sendPrepare" do     it "prepares a statement asynchronously" \conninfo ->-      differential proxy conninfo \connection -> do-        sent <- sendPrepare connection "conformance_send_prepare" "select $1 :: int4 * 2" Nothing+      differential adapter conninfo \connection -> do+        sent <- connection.sendPrepare "conformance_send_prepare" "select $1 :: int4 * 2" Nothing         results <- drainResults connection         pure (sent, results)
src/library/Pqi/Conformance/Operation/SendQuery.hs view
@@ -6,18 +6,18 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "sendQuery" do     let sendAndDrain sql conninfo =-          differential proxy conninfo \connection -> do-            sent <- sendQuery connection sql+          differential adapter conninfo \connection -> do+            sent <- connection.sendQuery sql             results <- drainResults connection             pure (sent, results)     it "sends a query and collects its result"
src/library/Pqi/Conformance/Operation/SendQueryParams.hs view
@@ -5,21 +5,20 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults, int4Oid) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "sendQueryParams" do     it "sends a parameterized query and collects its result" \conninfo ->-      differential proxy conninfo \connection -> do+      differential adapter conninfo \connection -> do         sent <--          sendQueryParams-            connection+          connection.sendQueryParams             "select $1 :: int4 + $2 :: int4, $3 :: text"             [Just (int4Oid, "40", Lq.Text), Just (int4Oid, "2", Lq.Text), Nothing]             Lq.Text
src/library/Pqi/Conformance/Operation/SendQueryPrepared.hs view
@@ -5,20 +5,20 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "sendQueryPrepared" do     it "executes a prepared statement asynchronously" \conninfo ->-      differential proxy conninfo \connection -> do-        _ <- sendPrepare connection "conformance_send_exec" "select $1 :: int4 * 2" Nothing+      differential adapter conninfo \connection -> do+        _ <- connection.sendPrepare "conformance_send_exec" "select $1 :: int4 * 2" Nothing         _ <- drainResults connection-        sent <- sendQueryPrepared connection "conformance_send_exec" [Just ("21", Lq.Text)] Lq.Text+        sent <- connection.sendQueryPrepared "conformance_send_exec" [Just ("21", Lq.Text)] Lq.Text         results <- drainResults connection         pure (sent, results)
src/library/Pqi/Conformance/Operation/ServerVersion.hs view
@@ -5,13 +5,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "serverVersion" do     it "reports the server version as an integer" \conninfo ->-      differential proxy conninfo serverVersion+      differential adapter conninfo (.serverVersion)
src/library/Pqi/Conformance/Operation/SetClientEncoding.hs view
@@ -5,19 +5,19 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "setClientEncoding" do     it "rejects an unknown encoding and leaves the session usable" \conninfo ->-      differential proxy conninfo \connection -> do-        rejected <- setClientEncoding connection "BOGUS_ENCODING"-        unchanged <- clientEncoding connection-        stillIdle <- transactionStatus connection+      differential adapter conninfo \connection -> do+        rejected <- connection.setClientEncoding "BOGUS_ENCODING"+        unchanged <- connection.clientEncoding+        stillIdle <- connection.transactionStatus         stillWorks <- execScenario "select 1" connection         pure (rejected, unchanged, stillIdle, stillWorks)
src/library/Pqi/Conformance/Operation/SetErrorVerbosity.hs view
@@ -5,18 +5,18 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import qualified Pqi as Lq import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "setErrorVerbosity" do     it "returns the previous setting" \conninfo ->-      differential proxy conninfo \connection -> do-        beforeTerse <- setErrorVerbosity connection Lq.ErrorsTerse-        beforeVerbose <- setErrorVerbosity connection Lq.ErrorsVerbose-        beforeDefault <- setErrorVerbosity connection Lq.ErrorsDefault+      differential adapter conninfo \connection -> do+        beforeTerse <- connection.setErrorVerbosity Lq.ErrorsTerse+        beforeVerbose <- connection.setErrorVerbosity Lq.ErrorsVerbose+        beforeDefault <- connection.setErrorVerbosity Lq.ErrorsDefault         pure (beforeTerse, beforeVerbose, beforeDefault)
src/library/Pqi/Conformance/Operation/SetSingleRowMode.hs view
@@ -5,25 +5,25 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (drainResults) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "setSingleRowMode" do     it "splits a multi-row result into single-row results" \conninfo ->-      differential proxy conninfo \connection -> do-        sent <- sendQuery connection "select i from generate_series (1, 3) as i"-        singleRow <- setSingleRowMode connection+      differential adapter conninfo \connection -> do+        sent <- connection.sendQuery "select i from generate_series (1, 3) as i"+        singleRow <- connection.setSingleRowMode         results <- drainResults connection         pure (sent, singleRow, results)      it "handles an empty result" \conninfo ->-      differential proxy conninfo \connection -> do-        sent <- sendQuery connection "select 1 where false"-        singleRow <- setSingleRowMode connection+      differential adapter conninfo \connection -> do+        sent <- connection.sendQuery "select 1 where false"+        singleRow <- connection.setSingleRowMode         results <- drainResults connection         pure (sent, singleRow, results)
src/library/Pqi/Conformance/Operation/Setnonblocking.hs view
@@ -5,18 +5,18 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "setnonblocking" do     it "turns the non-blocking flag on and off" \conninfo ->-      differential proxy conninfo \connection -> do-        setOn <- setnonblocking connection True-        nowOn <- isnonblocking connection-        setOff <- setnonblocking connection False-        nowOff <- isnonblocking connection+      differential adapter conninfo \connection -> do+        setOn <- connection.setnonblocking True+        nowOn <- connection.isnonblocking+        setOff <- connection.setnonblocking False+        nowOff <- connection.isnonblocking         pure (setOn, nowOn, setOff, nowOff)
src/library/Pqi/Conformance/Operation/Socket.hs view
@@ -7,14 +7,14 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "socket" do     it "is present on an open connection" \conninfo ->-      differential proxy conninfo \connection ->-        isJust <$> socket connection+      differential adapter conninfo \connection ->+        isJust <$> connection.socket
src/library/Pqi/Conformance/Operation/Status.hs view
@@ -4,13 +4,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "status" do     it "reports a ready connection as OK" \conninfo ->-      differential proxy conninfo status+      differential adapter conninfo (.status)
src/library/Pqi/Conformance/Operation/TransactionStatus.hs view
@@ -5,21 +5,21 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "transactionStatus" do     it "tracks status through a transaction" \conninfo ->-      differential proxy conninfo \connection -> do-        idle <- transactionStatus connection-        _ <- exec connection "begin"-        inTransaction <- transactionStatus connection-        _ <- exec connection "select 1 / 0"-        inError <- transactionStatus connection-        _ <- exec connection "rollback"-        afterRollback <- transactionStatus connection+      differential adapter conninfo \connection -> do+        idle <- connection.transactionStatus+        _ <- connection.exec "begin"+        inTransaction <- connection.transactionStatus+        _ <- connection.exec "select 1 / 0"+        inError <- connection.transactionStatus+        _ <- connection.exec "rollback"+        afterRollback <- connection.transactionStatus         pure (idle, inTransaction, inError, afterRollback)
+ src/library/Pqi/Conformance/Operation/UnescapeBytea.hs view
@@ -0,0 +1,49 @@+-- | Coverage for 'Pqi.unescapeBytea': decoding the textual representation of+-- a @bytea@ value, in both the hex and legacy escape formats, including+-- malformed input.+module Pqi.Conformance.Operation.UnescapeBytea+  ( spec,+  )+where++import qualified Pqi+import Pqi.Conformance.Prelude+import qualified Pqi.Conformance.Reference as Reference+import Test.Hspec++spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =+  describe "unescapeBytea" do+    for_ cases \input ->+      it (show input) \_ -> do+        candidate <- adapter.unescapeBytea input+        reference <- Reference.adapter.unescapeBytea input+        candidate `shouldBe` reference+  where+    cases =+      [ "",+        "\\x",+        "\\x00",+        "\\x00ff",+        "\\x48656c6c6f",+        "\\X48656C6C6F",+        "\\xAbCd",+        "Hello, world",+        "h\233llo bytes",+        "\\\\",+        "\\001\\002\\003",+        "a\\010b",+        "\\x4",+        "\\x4g",+        "\\xzz",+        "\\x61 62",+        "\\377",+        "\\400",+        "\\000",+        "\\1",+        "\\18",+        "\\8",+        "a\\b",+        "trailing\\",+        "mixed\\134text"+      ]
src/library/Pqi/Conformance/Operation/UnsafeFreeResult.hs view
@@ -10,17 +10,17 @@   ) where -import Pqi (IsConnection (..), IsResult (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Pqi.Conformance.Scenario (execScenario) import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "unsafeFreeResult" do     it "leaves the connection usable" \conninfo ->-      differential proxy conninfo \connection -> do-        result <- exec connection "select 1"-        traverse_ unsafeFreeResult result+      differential adapter conninfo \connection -> do+        result <- connection.exec "select 1"+        traverse_ (.unsafeFreeResult) result         execScenario "select 2" connection
src/library/Pqi/Conformance/Operation/User.hs view
@@ -4,13 +4,13 @@   ) where -import Pqi (IsConnection (..))+import qualified Pqi import Pqi.Conformance.Harness import Pqi.Conformance.Prelude import Test.Hspec -spec :: (IsConnection c) => Proxy c -> SpecWith ByteString-spec proxy =+spec :: Pqi.Adapter -> SpecWith ByteString+spec adapter =   describe "user" do     it "reports the user name from the conninfo" \conninfo ->-      differential proxy conninfo user+      differential adapter conninfo (.user)
src/library/Pqi/Conformance/Prelude.hs view
@@ -11,7 +11,6 @@ import Data.Foldable as Exports (for_, traverse_) import Data.Int as Exports import Data.Maybe as Exports-import Data.Proxy as Exports (Proxy (..)) import Data.Text as Exports (Text) import Data.Traversable as Exports (for) import Data.Word as Exports
src/library/Pqi/Conformance/Reference.hs view
@@ -1,159 +1,151 @@--- | The reference connection: a direct @postgresql-libpq@ wrapper used as the+-- | The reference adapter: a direct @postgresql-libpq@ wrapper used as the -- ground truth in differential tests. It is intentionally independent of the--- @pqi-ffi@ adapter so that adapter test suites can depend on--- @pqi-conformance@ without a circular dependency through @pqi-ffi@.+-- @pqi-ffi@ package (despite producing byte-identical output) so that+-- adapter test suites can depend on @pqi-conformance@ without a circular+-- dependency through @pqi-ffi@. module Pqi.Conformance.Reference-  ( Reference (..),-    RefResult (..),-    RefCancel (..),+  ( adapter,   ) where  import qualified Database.PostgreSQL.LibPQ as LibPQ-import Pqi-  ( IsCancel (..),-    IsConnection (..),-    IsResult (..),-  ) import qualified Pqi import Pqi.Conformance.Prelude --- | A direct wrapper over a @postgresql-libpq@ connection, used as the--- differential-testing reference.-newtype Reference = Reference LibPQ.Connection---- | A result backed by a C @PGresult@.-newtype RefResult = RefResult LibPQ.Result---- | A cancellation handle backed by a C @PGcancel@.-newtype RefCancel = RefCancel LibPQ.Cancel--instance IsResult RefResult where-  resultStatus (RefResult r) = fromExecStatus <$> LibPQ.resultStatus r-  resultErrorMessage (RefResult r) = LibPQ.resultErrorMessage r-  resultErrorField (RefResult r) field = LibPQ.resultErrorField r (toFieldCode field)-  unsafeFreeResult (RefResult r) = LibPQ.unsafeFreeResult r-  ntuples (RefResult r) = fromRow <$> LibPQ.ntuples r-  nfields (RefResult r) = fromColumn <$> LibPQ.nfields r-  fname (RefResult r) column = LibPQ.fname r (toColumn column)-  fnumber (RefResult r) name = fmap fromColumn <$> LibPQ.fnumber r name-  ftable (RefResult r) column = fromOid <$> LibPQ.ftable r (toColumn column)-  ftablecol (RefResult r) column = fromColumn <$> LibPQ.ftablecol r (toColumn column)-  fformat (RefResult r) column = fromFormat <$> LibPQ.fformat r (toColumn column)-  ftype (RefResult r) column = fromOid <$> LibPQ.ftype r (toColumn column)-  fmod (RefResult r) column = LibPQ.fmod r (toColumn column)-  fsize (RefResult r) column = LibPQ.fsize r (toColumn column)-  getvalue (RefResult r) row column = LibPQ.getvalue r (toRow row) (toColumn column)-  getvalue' (RefResult r) row column = LibPQ.getvalue' r (toRow row) (toColumn column)-  getisnull (RefResult r) row column = LibPQ.getisnull r (toRow row) (toColumn column)-  getlength (RefResult r) row column = LibPQ.getlength r (toRow row) (toColumn column)-  nparams (RefResult r) = fromIntegral <$> LibPQ.nparams r-  paramtype (RefResult r) index = fromOid <$> LibPQ.paramtype r (fromIntegral index)-  cmdStatus (RefResult r) = LibPQ.cmdStatus r-  cmdTuples (RefResult r) = LibPQ.cmdTuples r--instance IsCancel RefCancel where-  cancel (RefCancel handle) = LibPQ.cancel handle--instance IsConnection Reference where-  type ResultOf Reference = RefResult-  type CancelOf Reference = RefCancel--  connectdb conninfo = Reference <$> LibPQ.connectdb conninfo-  connectStart conninfo = Reference <$> LibPQ.connectStart conninfo-  connectPoll (Reference c) = fromPollingStatus <$> LibPQ.connectPoll c-  newNullConnection = Reference <$> LibPQ.newNullConnection-  isNullConnection (Reference c) = LibPQ.isNullConnection c-  finish (Reference c) = LibPQ.finish c-  reset (Reference c) = LibPQ.reset c-  resetStart (Reference c) = LibPQ.resetStart c-  resetPoll (Reference c) = fromPollingStatus <$> LibPQ.resetPoll c-  db (Reference c) = LibPQ.db c-  user (Reference c) = LibPQ.user c-  pass (Reference c) = LibPQ.pass c-  host (Reference c) = LibPQ.host c-  port (Reference c) = LibPQ.port c-  options (Reference c) = LibPQ.options c-  status (Reference c) = fromConnStatus <$> LibPQ.status c-  transactionStatus (Reference c) = fromTransactionStatus <$> LibPQ.transactionStatus c-  parameterStatus (Reference c) name = LibPQ.parameterStatus c name-  protocolVersion (Reference c) = LibPQ.protocolVersion c-  serverVersion (Reference c) = LibPQ.serverVersion c-  errorMessage (Reference c) = LibPQ.errorMessage c-  socket (Reference c) = LibPQ.socket c-  backendPID (Reference c) = fromIntegral <$> LibPQ.backendPID c-  connectionNeedsPassword (Reference c) = LibPQ.connectionNeedsPassword c-  connectionUsedPassword (Reference c) = LibPQ.connectionUsedPassword c--  exec (Reference c) sql =-    fmap RefResult <$> LibPQ.exec c sql-  execParams (Reference c) sql params resultFormat =-    fmap RefResult <$> LibPQ.execParams c sql (fmap (fmap toParam) params) (toFormat resultFormat)-  prepare (Reference c) name sql paramTypes =-    fmap RefResult <$> LibPQ.prepare c name sql (fmap (fmap toOid) paramTypes)-  execPrepared (Reference c) name params resultFormat =-    fmap RefResult <$> LibPQ.execPrepared c name (fmap (fmap toBoundParam) params) (toFormat resultFormat)-  describePrepared (Reference c) name =-    fmap RefResult <$> LibPQ.describePrepared c name-  describePortal (Reference c) name =-    fmap RefResult <$> LibPQ.describePortal c name--  escapeStringConn (Reference c) = LibPQ.escapeStringConn c-  escapeByteaConn (Reference c) = LibPQ.escapeByteaConn c-  escapeIdentifier (Reference c) = LibPQ.escapeIdentifier c--  sendQuery (Reference c) sql = LibPQ.sendQuery c sql-  sendQueryParams (Reference c) sql params resultFormat =-    LibPQ.sendQueryParams c sql (fmap (fmap toParam) params) (toFormat resultFormat)-  sendPrepare (Reference c) name sql paramTypes =-    LibPQ.sendPrepare c name sql (fmap (fmap toOid) paramTypes)-  sendQueryPrepared (Reference c) name params resultFormat =-    LibPQ.sendQueryPrepared c name (fmap (fmap toBoundParam) params) (toFormat resultFormat)-  sendDescribePrepared (Reference c) name = LibPQ.sendDescribePrepared c name-  sendDescribePortal (Reference c) name = LibPQ.sendDescribePortal c name-  getResult (Reference c) = fmap RefResult <$> LibPQ.getResult c-  consumeInput (Reference c) = LibPQ.consumeInput c-  isBusy (Reference c) = LibPQ.isBusy c-  setnonblocking (Reference c) nonBlocking = LibPQ.setnonblocking c nonBlocking-  isnonblocking (Reference c) = LibPQ.isnonblocking c-  setSingleRowMode (Reference c) = LibPQ.setSingleRowMode c-  flush (Reference c) = fromFlushStatus <$> LibPQ.flush c--  pipelineStatus (Reference c) = fromPipelineStatus <$> LibPQ.pipelineStatus c-  enterPipelineMode (Reference c) = LibPQ.enterPipelineMode c-  exitPipelineMode (Reference c) = LibPQ.exitPipelineMode c-  pipelineSync (Reference c) = LibPQ.pipelineSync c-  sendFlushRequest (Reference c) = LibPQ.sendFlushRequest c--  getCancel (Reference c) = fmap RefCancel <$> LibPQ.getCancel c--  notifies (Reference c) = fmap fromNotify <$> LibPQ.notifies c-  disableNoticeReporting (Reference c) = LibPQ.disableNoticeReporting c-  enableNoticeReporting (Reference c) = LibPQ.enableNoticeReporting c-  getNotice (Reference c) = LibPQ.getNotice c+-- | The reference adapter.+adapter :: Pqi.Adapter+adapter =+  Pqi.Adapter+    { Pqi.name = "postgresql-libpq (reference)",+      Pqi.connectdb = \conninfo -> mkConnection <$> LibPQ.connectdb conninfo,+      Pqi.connectStart = \conninfo -> mkConnection <$> LibPQ.connectStart conninfo,+      Pqi.newNullConnection = mkConnection <$> LibPQ.newNullConnection,+      Pqi.unescapeBytea = \input -> LibPQ.unescapeBytea input+    } -  putCopyData (Reference c) value = fromCopyInResult <$> LibPQ.putCopyData c value-  putCopyEnd (Reference c) reason = fromCopyInResult <$> LibPQ.putCopyEnd c reason-  getCopyData (Reference c) nonBlocking = fromCopyOutResult <$> LibPQ.getCopyData c nonBlocking+-- | Build a 'Pqi.Connection' whose fields close over the given+-- @postgresql-libpq@ connection handle.+mkConnection :: LibPQ.Connection -> Pqi.Connection+mkConnection c =+  Pqi.Connection+    { Pqi.connectPoll = fromPollingStatus <$> LibPQ.connectPoll c,+      Pqi.isNullConnection = LibPQ.isNullConnection c,+      Pqi.finish = LibPQ.finish c,+      Pqi.reset = LibPQ.reset c,+      Pqi.resetStart = LibPQ.resetStart c,+      Pqi.resetPoll = fromPollingStatus <$> LibPQ.resetPoll c,+      Pqi.db = LibPQ.db c,+      Pqi.user = LibPQ.user c,+      Pqi.pass = LibPQ.pass c,+      Pqi.host = LibPQ.host c,+      Pqi.port = LibPQ.port c,+      Pqi.options = LibPQ.options c,+      Pqi.status = fromConnStatus <$> LibPQ.status c,+      Pqi.transactionStatus = fromTransactionStatus <$> LibPQ.transactionStatus c,+      Pqi.parameterStatus = \name -> LibPQ.parameterStatus c name,+      Pqi.protocolVersion = LibPQ.protocolVersion c,+      Pqi.serverVersion = LibPQ.serverVersion c,+      Pqi.errorMessage = LibPQ.errorMessage c,+      Pqi.socket = LibPQ.socket c,+      Pqi.backendPID = fromIntegral <$> LibPQ.backendPID c,+      Pqi.connectionNeedsPassword = LibPQ.connectionNeedsPassword c,+      Pqi.connectionUsedPassword = LibPQ.connectionUsedPassword c,+      Pqi.exec = \sql -> fmap mkResult <$> LibPQ.exec c sql,+      Pqi.execParams = \sql params resultFormat ->+        fmap mkResult <$> LibPQ.execParams c sql (fmap (fmap toParam) params) (toFormat resultFormat),+      Pqi.prepare = \name sql paramTypes ->+        fmap mkResult <$> LibPQ.prepare c name sql (fmap (fmap toOid) paramTypes),+      Pqi.execPrepared = \name params resultFormat ->+        fmap mkResult <$> LibPQ.execPrepared c name (fmap (fmap toBoundParam) params) (toFormat resultFormat),+      Pqi.describePrepared = \name -> fmap mkResult <$> LibPQ.describePrepared c name,+      Pqi.describePortal = \name -> fmap mkResult <$> LibPQ.describePortal c name,+      Pqi.escapeStringConn = \s -> LibPQ.escapeStringConn c s,+      Pqi.escapeByteaConn = \s -> LibPQ.escapeByteaConn c s,+      Pqi.escapeIdentifier = \s -> LibPQ.escapeIdentifier c s,+      Pqi.sendQuery = \sql -> LibPQ.sendQuery c sql,+      Pqi.sendQueryParams = \sql params resultFormat ->+        LibPQ.sendQueryParams c sql (fmap (fmap toParam) params) (toFormat resultFormat),+      Pqi.sendPrepare = \name sql paramTypes ->+        LibPQ.sendPrepare c name sql (fmap (fmap toOid) paramTypes),+      Pqi.sendQueryPrepared = \name params resultFormat ->+        LibPQ.sendQueryPrepared c name (fmap (fmap toBoundParam) params) (toFormat resultFormat),+      Pqi.sendDescribePrepared = \name -> LibPQ.sendDescribePrepared c name,+      Pqi.sendDescribePortal = \name -> LibPQ.sendDescribePortal c name,+      Pqi.getResult = fmap mkResult <$> LibPQ.getResult c,+      Pqi.consumeInput = LibPQ.consumeInput c,+      Pqi.isBusy = LibPQ.isBusy c,+      Pqi.setnonblocking = \nonBlocking -> LibPQ.setnonblocking c nonBlocking,+      Pqi.isnonblocking = LibPQ.isnonblocking c,+      Pqi.setSingleRowMode = LibPQ.setSingleRowMode c,+      Pqi.flush = fromFlushStatus <$> LibPQ.flush c,+      Pqi.pipelineStatus = fromPipelineStatus <$> LibPQ.pipelineStatus c,+      Pqi.enterPipelineMode = LibPQ.enterPipelineMode c,+      Pqi.exitPipelineMode = LibPQ.exitPipelineMode c,+      Pqi.pipelineSync = LibPQ.pipelineSync c,+      Pqi.sendFlushRequest = LibPQ.sendFlushRequest c,+      Pqi.getCancel = fmap mkCancel <$> LibPQ.getCancel c,+      Pqi.notifies = fmap fromNotify <$> LibPQ.notifies c,+      Pqi.disableNoticeReporting = LibPQ.disableNoticeReporting c,+      Pqi.enableNoticeReporting = LibPQ.enableNoticeReporting c,+      Pqi.getNotice = LibPQ.getNotice c,+      Pqi.putCopyData = \value -> fromCopyInResult <$> LibPQ.putCopyData c value,+      Pqi.putCopyEnd = \reason -> fromCopyInResult <$> LibPQ.putCopyEnd c reason,+      Pqi.getCopyData = \nonBlocking -> fromCopyOutResult <$> LibPQ.getCopyData c nonBlocking,+      Pqi.loCreat = fmap fromOid <$> LibPQ.loCreat c,+      Pqi.loCreate = \oid -> fmap fromOid <$> LibPQ.loCreate c (toOid oid),+      Pqi.loImport = \path -> fmap fromOid <$> LibPQ.loImport c path,+      Pqi.loImportWithOid = \path oid -> fmap fromOid <$> LibPQ.loImportWithOid c path (toOid oid),+      Pqi.loExport = \oid path -> LibPQ.loExport c (toOid oid) path,+      Pqi.loOpen = \oid mode -> fmap fromLibPQLoFd <$> LibPQ.loOpen c (toOid oid) mode,+      Pqi.loWrite = \fd value -> LibPQ.loWrite c (toLibPQLoFd fd) value,+      Pqi.loRead = \fd len -> LibPQ.loRead c (toLibPQLoFd fd) len,+      Pqi.loSeek = \fd mode offset -> LibPQ.loSeek c (toLibPQLoFd fd) mode offset,+      Pqi.loTell = \fd -> LibPQ.loTell c (toLibPQLoFd fd),+      Pqi.loTruncate = \fd len -> LibPQ.loTruncate c (toLibPQLoFd fd) len,+      Pqi.loClose = \fd -> LibPQ.loClose c (toLibPQLoFd fd),+      Pqi.loUnlink = \oid -> LibPQ.loUnlink c (toOid oid),+      Pqi.clientEncoding = LibPQ.clientEncoding c,+      Pqi.setClientEncoding = \encoding -> LibPQ.setClientEncoding c encoding,+      Pqi.setErrorVerbosity = \verbosity ->+        fromVerbosity <$> LibPQ.setErrorVerbosity c (toVerbosity verbosity)+    } -  loCreat (Reference c) = fmap fromOid <$> LibPQ.loCreat c-  loCreate (Reference c) oid = fmap fromOid <$> LibPQ.loCreate c (toOid oid)-  loImport (Reference c) path = fmap fromOid <$> LibPQ.loImport c path-  loImportWithOid (Reference c) path oid = fmap fromOid <$> LibPQ.loImportWithOid c path (toOid oid)-  loExport (Reference c) oid path = LibPQ.loExport c (toOid oid) path-  loOpen (Reference c) oid mode = fmap fromLibPQLoFd <$> LibPQ.loOpen c (toOid oid) mode-  loWrite (Reference c) fd value = LibPQ.loWrite c (toLibPQLoFd fd) value-  loRead (Reference c) fd len = LibPQ.loRead c (toLibPQLoFd fd) len-  loSeek (Reference c) fd mode offset = LibPQ.loSeek c (toLibPQLoFd fd) mode offset-  loTell (Reference c) fd = LibPQ.loTell c (toLibPQLoFd fd)-  loTruncate (Reference c) fd len = LibPQ.loTruncate c (toLibPQLoFd fd) len-  loClose (Reference c) fd = LibPQ.loClose c (toLibPQLoFd fd)-  loUnlink (Reference c) oid = LibPQ.loUnlink c (toOid oid)+-- | Build a 'Pqi.Result' whose fields close over the given+-- @postgresql-libpq@ result handle.+mkResult :: LibPQ.Result -> Pqi.Result+mkResult r =+  Pqi.Result+    { Pqi.resultStatus = fromExecStatus <$> LibPQ.resultStatus r,+      Pqi.resultErrorMessage = LibPQ.resultErrorMessage r,+      Pqi.resultErrorField = \field -> LibPQ.resultErrorField r (toFieldCode field),+      Pqi.unsafeFreeResult = LibPQ.unsafeFreeResult r,+      Pqi.ntuples = fromRow <$> LibPQ.ntuples r,+      Pqi.nfields = fromColumn <$> LibPQ.nfields r,+      Pqi.fname = \column -> LibPQ.fname r (toColumn column),+      Pqi.fnumber = \name -> fmap fromColumn <$> LibPQ.fnumber r name,+      Pqi.ftable = \column -> fromOid <$> LibPQ.ftable r (toColumn column),+      Pqi.ftablecol = \column -> fromColumn <$> LibPQ.ftablecol r (toColumn column),+      Pqi.fformat = \column -> fromFormat <$> LibPQ.fformat r (toColumn column),+      Pqi.ftype = \column -> fromOid <$> LibPQ.ftype r (toColumn column),+      Pqi.fmod = \column -> LibPQ.fmod r (toColumn column),+      Pqi.fsize = \column -> LibPQ.fsize r (toColumn column),+      Pqi.getvalue = \row column -> LibPQ.getvalue' r (toRow row) (toColumn column),+      Pqi.getvalue' = \row column -> LibPQ.getvalue' r (toRow row) (toColumn column),+      Pqi.getisnull = \row column -> LibPQ.getisnull r (toRow row) (toColumn column),+      Pqi.getlength = \row column -> LibPQ.getlength r (toRow row) (toColumn column),+      Pqi.nparams = fromIntegral <$> LibPQ.nparams r,+      Pqi.paramtype = \index -> fromOid <$> LibPQ.paramtype r (fromIntegral index),+      Pqi.cmdStatus = LibPQ.cmdStatus r,+      Pqi.cmdTuples = LibPQ.cmdTuples r+    } -  clientEncoding (Reference c) = LibPQ.clientEncoding c-  setClientEncoding (Reference c) encoding = LibPQ.setClientEncoding c encoding-  setErrorVerbosity (Reference c) verbosity =-    fromVerbosity <$> LibPQ.setErrorVerbosity c (toVerbosity verbosity)+-- | Build a 'Pqi.Cancel' whose field closes over the given+-- @postgresql-libpq@ cancellation handle.+mkCancel :: LibPQ.Cancel -> Pqi.Cancel+mkCancel handle =+  Pqi.Cancel+    { Pqi.cancel = LibPQ.cancel handle+    }  -- * Type conversions 
src/library/Pqi/Conformance/Scenario.hs view
@@ -35,55 +35,49 @@   ) where -import Pqi-  ( CopyOutResult (..),-    FlushStatus (..),-    IsConnection (..),-    PollingStatus (..),-  )-import qualified Pqi as Lq+import Pqi (CopyOutResult (..), FlushStatus (..), PollingStatus (..))+import qualified Pqi import Pqi.Conformance.Observation import Pqi.Conformance.Prelude  -- | Run 'Pqi.exec' and observe its result (if any).-execScenario :: (IsConnection c) => ByteString -> c -> IO (Maybe ResultObservation)-execScenario sql connection = exec connection sql >>= traverse observeResult+execScenario :: ByteString -> Pqi.Connection -> IO (Maybe ResultObservation)+execScenario sql connection = connection.exec sql >>= traverse observeResult  -- | Run a sequence of statements with 'Pqi.exec', observing every result.-execAllScenario :: (IsConnection c) => [ByteString] -> c -> IO [Maybe ResultObservation]+execAllScenario :: [ByteString] -> Pqi.Connection -> IO [Maybe ResultObservation] execAllScenario sqls connection = traverse (`execScenario` connection) sqls  -- | Run 'Pqi.execParams' and observe its result (if any). observed ::-  (IsConnection c) =>   ByteString ->-  [Maybe (Word32, ByteString, Lq.Format)] ->-  Lq.Format ->-  c ->+  [Maybe (Word32, ByteString, Pqi.Format)] ->+  Pqi.Format ->+  Pqi.Connection ->   IO (Maybe ResultObservation) observed sql params resultFormat connection =-  execParams connection sql params resultFormat >>= traverse observeResult+  connection.execParams sql params resultFormat >>= traverse observeResult  -- | Collect and observe results with 'Pqi.getResult' until it reports -- completion with 'Nothing'.-drainResults :: (IsConnection c) => c -> IO [ResultObservation]+drainResults :: Pqi.Connection -> IO [ResultObservation] drainResults connection = go []   where     go acc =-      getResult connection >>= \case+      connection.getResult >>= \case         Nothing -> pure (reverse acc)         Just result -> do           observation <- observeResult result           go (observation : acc)  -- | One 'Pqi.getResult' step, observed.-takeResult :: (IsConnection c) => c -> IO (Maybe ResultObservation)-takeResult connection = getResult connection >>= traverse observeResult+takeResult :: Pqi.Connection -> IO (Maybe ResultObservation)+takeResult connection = connection.getResult >>= traverse observeResult  -- | The results of one pipelined command: its result and the 'Nothing' -- separator that ends it. takeCommandResults ::-  (IsConnection c) => c -> IO (Maybe ResultObservation, Maybe ResultObservation)+  Pqi.Connection -> IO (Maybe ResultObservation, Maybe ResultObservation) takeCommandResults connection = do   result <- takeResult connection   separator <- takeResult connection@@ -92,12 +86,12 @@ -- | Collect blocking 'Pqi.getCopyData' outcomes until the stream reports -- anything other than a row (normally 'CopyOutDone'), including that final -- outcome.-collectCopyOut :: (IsConnection c) => c -> IO [CopyOutResult]+collectCopyOut :: Pqi.Connection -> IO [CopyOutResult] collectCopyOut connection = go (1000 :: Int) []   where     go 0 acc = pure (reverse acc)     go n acc =-      getCopyData connection False >>= \case+      connection.getCopyData False >>= \case         CopyOutRow row -> go (n - 1) (CopyOutRow row : acc)         terminal -> pure (reverse (terminal : acc)) @@ -126,11 +120,11 @@  -- | Run an action between @begin@ and @commit@. Large-object operations must -- run inside a transaction block.-inTransaction :: (IsConnection c) => c -> IO a -> IO a+inTransaction :: Pqi.Connection -> IO a -> IO a inTransaction connection action = do-  _ <- exec connection "begin"+  _ <- connection.exec "begin"   result <- action-  _ <- exec connection "commit"+  _ <- connection.exec "commit"   pure result  boolOid :: Word32