packages feed

kiroku-store 0.3.0.0 → 0.3.0.1

raw patch · 4 files changed

+61/−4 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -2,6 +2,19 @@  ## Unreleased +## 0.3.0.1 — 2026-07-14++### Bug Fixes++* A failure raised inside an opaque `runTransaction` body now preserves its+  SQLSTATE and server message. Anything that was not a `stream_events_pkey`+  duplicate previously went through the append-shaped mapper with a+  `<transaction>` sentinel stream, so e.g. a foreign-key violation surfaced as+  `StreamNotFound (StreamName "<transaction>")` and lost the real diagnostics.+  Such failures now map through the generic mapper — the foreign-key case above+  becomes `UnexpectedServerError "23503"` with the server's message intact.+  Duplicate-event mapping is unchanged.+ ## 0.3.0.0 — 2026-07-11  This release requires migrations `0003`–`0007` from `kiroku-store-migrations`.
kiroku-store.cabal view
@@ -1,6 +1,6 @@ cabal-version:   3.0 name:            kiroku-store-version:         0.3.0.0+version:         0.3.0.1 synopsis:        High-performance PostgreSQL event store description:   Kiroku is a PostgreSQL-backed event store for Haskell applications. It
src/Kiroku/Store/Error.hs view
@@ -183,8 +183,8 @@ {- | Map a hasql 'UsageError' raised inside an opaque transaction body.  The body has no stream context, so append duplicate violations are mapped-directly to 'DuplicateEvent' and all other failures fall back to the standard-append-shaped mapper with sentinel stream context.+directly to 'DuplicateEvent'. Every other failure uses the generic mapper so+its SQLSTATE and server message survive without inventing stream context. -} mapTransactionUsageError :: UsageError -> StoreError mapTransactionUsageError usageErr =@@ -195,7 +195,7 @@             | containsConstraint "stream_events_pkey" message detail ->                 DuplicateEvent (EventId <$> (detail >>= extractFirstUuidFromCompositeDetail))         _ ->-            mapUsageError "<transaction>" AnyVersion usageErr+            mapGenericUsageError usageErr   where     containsConstraint name message detail =         name `T.isInfixOf` message || maybe False (T.isInfixOf name) detail
test/Test/Transaction.hs view
@@ -38,6 +38,21 @@                 Right n -> n `shouldBe` (1 :: Int)                 Left err -> expectationFailure ("Expected Right 1, got: " <> show err) +        it "preserves SQLSTATE and message for an opaque foreign-key failure" $ \store -> do+            createForeignKeyTables (store ^. #pool)+            result <-+                runStoreIO store $+                    runTransaction $+                        Tx.statement () insertMissingForeignKeyStmt+            case result of+                Left (UnexpectedServerError code message) -> do+                    code `shouldBe` "23503"+                    T.toLower message `shouldSatisfy` T.isInfixOf "foreign key"+                Left (StreamNotFound (StreamName "<transaction>")) ->+                    expectationFailure "foreign-key failure was misclassified as a missing <transaction> stream"+                other ->+                    expectationFailure ("Expected UnexpectedServerError 23503, got: " <> show other)+     describe "appendToStreamTx (driven inside runTransaction)" $ do         it "appends events and a side-table row in one atomic transaction" $ \store -> do             createSideTable (store ^. #pool)@@ -326,6 +341,27 @@         E.noParams         D.noResult +createForeignKeyParentStmt :: Statement () ()+createForeignKeyParentStmt =+    unpreparable+        "CREATE TABLE IF NOT EXISTS test_tx_parent (id BIGINT PRIMARY KEY)"+        E.noParams+        D.noResult++createForeignKeyChildStmt :: Statement () ()+createForeignKeyChildStmt =+    unpreparable+        "CREATE TABLE IF NOT EXISTS test_tx_child (parent_id BIGINT NOT NULL REFERENCES test_tx_parent(id))"+        E.noParams+        D.noResult++insertMissingForeignKeyStmt :: Statement () ()+insertMissingForeignKeyStmt =+    preparable+        "INSERT INTO test_tx_child (parent_id) VALUES (999999)"+        E.noParams+        D.noResult+ {- | Insert a row into the side table. The @id@ doubles as the foreign key onto the stream the transaction appended to. -}@@ -353,6 +389,14 @@     case r of         Left err -> error ("createSideTable failed: " <> show err)         Right () -> pure ()++createForeignKeyTables :: Pool -> IO ()+createForeignKeyTables pool = do+    parent <- Pool.use pool (Session.statement () createForeignKeyParentStmt)+    child <- Pool.use pool (Session.statement () createForeignKeyChildStmt)+    case (parent, child) of+        (Right (), Right ()) -> pure ()+        other -> error ("createForeignKeyTables failed: " <> show other)  countSideTable :: Pool -> IO Int64 countSideTable pool = do