packages feed

kiroku-store-migrations 0.4.0.0 → 0.5.0.0

raw patch · 4 files changed

+106/−30 lines, 4 filesdep ~ephemeral-pgdep ~pg-migratedep ~pg-migrate-cli

Dependency ranges changed: ephemeral-pg, pg-migrate, pg-migrate-cli, pg-migrate-embed, pg-migrate-import-codd, pg-migrate-test-support

Files

CHANGELOG.md view
@@ -1,5 +1,29 @@ # Changelog +## 0.5.0.0 — 2026-09-18++### Breaking Changes++* Requires the `pg-migrate` 1.2 series (`pg-migrate`, `pg-migrate-embed`,+  `pg-migrate-import-codd`, `pg-migrate-cli` `^>=1.2.0.0`, was `^>=1.1.0.0`).+  `Kiroku.Store.Migrations` re-exports `MigrationComponent`, `MigrationPlan`,+  `DefinitionError` and `PlanError` from `pg-migrate`, so this major bump+  follows the dependency's. pg-migrate 1.2 has no API or behavior changes+  relative to 1.1: consumers only need to move their own `pg-migrate` bounds+  to `^>=1.2`. The migration payloads, their checksums and the+  `kiroku-store-migrate` executable are unchanged.++### Other Changes++* The test-suite requires `ephemeral-pg >=0.3.1 && <0.4` and+  `pg-migrate-test-support ^>=1.2.0.0`, and builds on its+  `defaultEphemeralConfig` so orphaned clusters from killed runs are reaped.+* The UUIDv7 test now requires the PostgreSQL 18 builtin to exist exactly when+  the server major is 18, and reports which route supplied `kiroku.uuidv7()`.+  A run can no longer pass while exercising a different major than intended.+* The README documents running the suites against both PostgreSQL 17 and 18+  (`just test-matrix`, `just test-pg <major>`).+ ## 0.4.0.0 — 2026-08-16  ### Breaking Changes
README.md view
@@ -105,9 +105,37 @@ source-ledger preservation. The relation contract suite also proves the frozen `kiroku.subscription_checkpoints_v1` catalog, non-null value semantics, owner-rights privilege isolation, structural read-only behavior, downstream-view survival, and indexed query plan. `cabal test kiroku-store:kiroku-store-test`-consumes the same native plan through `kiroku-test-support` and proves the-complete store behavior, including append and read scenarios.+view survival, and indexed query plan. It also applies the plan's pending tail+in a session that never ran `0001` and cannot reach the Kiroku schema through+`search_path`, which is the upgrade shape BUG-1 lived in.+`cabal test kiroku-store:kiroku-store-test` consumes the same native plan+through `kiroku-test-support` and proves the complete store behavior, including+append and read scenarios.++### Both PostgreSQL majors++The suites reach PostgreSQL through `ephemeral-pg`, which runs whichever server+is on `PATH`, and the default dev shell carries only PostgreSQL 18. Migration+behavior differs by major -- `uuidv7()` is a builtin on 18 and comes from+`0001`'s fallback on 17 -- so a single-major run cannot cover this package.+Run both:++```bash+just test-matrix        # every suite, on PostgreSQL 17 and then 18+just test-pg 17         # one major+```++Each recipe enters the matching `nix develop .#postgresql<major>` shell and+refuses to run if that major is not the one on `PATH`. The suite reports the+route it exercised, so a run states which half of the matrix it covered:++```+PostgreSQL 17 UUIDv7 generator: kiroku.uuidv7() via 0001's fallback+PostgreSQL 18 UUIDv7 generator: kiroku.uuidv7() via 0010's alias for the builtin+```++Run the matrix before releasing this package, and after any migration change+that touches version-dependent behavior.  Migration `0010` adds replay-history retention leases, the per-schema coordinator, an indexed active-lease predicate, and statement-level
kiroku-store-migrations.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               kiroku-store-migrations-version:            0.4.0.0+version:            0.5.0.0 synopsis:           Schema migrations for kiroku-store description:   Native pg-migrate component, Codd history mapping, and migration executable@@ -52,9 +52,9 @@     , bytestring              >=0.11     && <0.13     , containers              >=0.6      && <0.8     , filepath                >=1.4      && <1.6-    , pg-migrate              ^>=1.1.0.0-    , pg-migrate-embed        ^>=1.1.0.0-    , pg-migrate-import-codd  ^>=1.1.0.0+    , pg-migrate              ^>=1.2.0.0+    , pg-migrate-embed        ^>=1.2.0.0+    , pg-migrate-import-codd  ^>=1.2.0.0     , template-haskell        >=2.20     && <2.24     , text                    >=2.0      && <2.2 @@ -70,8 +70,8 @@     , hasql                    >=1.10     && <1.11     , kiroku-store-migrations     , optparse-applicative     >=0.17     && <0.20-    , pg-migrate               ^>=1.1.0.0-    , pg-migrate-cli           ^>=1.1.0.0+    , pg-migrate               ^>=1.2.0.0+    , pg-migrate-cli           ^>=1.2.0.0     , text                     >=2.0      && <2.2  test-suite kiroku-store-migrations-test@@ -85,14 +85,14 @@     , base                     >=4.18     && <5     , bytestring               >=0.11     && <0.13     , directory                >=1.3-    , ephemeral-pg             >=0.2      && <0.3+    , ephemeral-pg             >=0.3.1    && <0.4     , filepath                 >=1.4      && <1.6     , hasql                    >=1.10     && <1.11     , hspec                    >=2.10     && <2.12     , kiroku-store-migrations-    , pg-migrate               ^>=1.1.0.0-    , pg-migrate-import-codd   ^>=1.1.0.0-    , pg-migrate-test-support  ^>=1.1.0.0+    , pg-migrate               ^>=1.2.0.0+    , pg-migrate-import-codd   ^>=1.2.0.0+    , pg-migrate-test-support  ^>=1.2.0.0     , temporary                >=1.3      && <1.4     , text                     >=2.0      && <2.2     , time                     >=1.12     && <1.15
test/Main.hs view
@@ -21,7 +21,7 @@ import Database.PostgreSQL.Migrate import Database.PostgreSQL.Migrate.History.Codd import Database.PostgreSQL.Migrate.Internal (migrationChecksumBytes)-import Database.PostgreSQL.Migrate.Test (withMigratedDatabase)+import Database.PostgreSQL.Migrate.Test (defaultEphemeralConfig, withMigratedDatabase) import EphemeralPg qualified as Pg import EphemeralPg.Config qualified as PgConfig import Hasql.Connection qualified as Connection@@ -315,16 +315,27 @@                         length applied `shouldBe` length nativeMigrationFiles                 withConnection settings assertSchema -        it "resolves the lease default through the qualified component generator" $ do+        -- kiroku.uuidv7() is the component's version-independent generator, but+        -- it arrives by a different route on each major: 0001's fallback on+        -- PostgreSQL 17, 0010's alias for the builtin on PostgreSQL 18. This+        -- case pins the route to the running server, so an acceptance run that+        -- believes it exercised one major and actually ran the other fails here+        -- instead of passing quietly. Both routes need a run to be covered --+        -- see `just test-matrix`.+        it "publishes the generator by the route its PostgreSQL major requires" $ do             plan <- requirePlan             result <- withMigratedDatabase plan $ \connection -> do-                -- kiroku.uuidv7() is the component's version-independent-                -- generator: PostgreSQL 17 gets 0001's fallback, PostgreSQL 18-                -- gets 0010's alias for the builtin. Either way the stored-                -- default names it, and no later migration needs search_path to-                -- reach a UUIDv7 generator.-                generator <- useSession connection (Session.statement () leaseDefaultStatement)-                generator `shouldBe` (True, Just "kiroku.uuidv7()")+                (major, builtinExists, generatorExists, leaseDefault) <-+                    useSession connection (Session.statement () leaseDefaultStatement)+                Text.IO.putStrLn+                    ( "PostgreSQL "+                        <> Text.pack (show major)+                        <> " UUIDv7 generator: kiroku.uuidv7() via "+                        <> (if builtinExists then "0010's alias for the builtin" else "0001's fallback")+                    )+                generatorExists `shouldBe` True+                builtinExists `shouldBe` (major >= 18)+                leaseDefault `shouldBe` Just "kiroku.uuidv7()"             either (expectationFailure . show) pure result          it "acquires a lease from a session whose search_path excludes kiroku" $ do@@ -512,12 +523,18 @@ importOutcomes :: HistoryImportReport -> [HistoryImportOutcome] importOutcomes HistoryImportReport{importResults} = importOutcome <$> toList importResults -kirokuPgConfig :: Pg.Config-kirokuPgConfig = Pg.defaultConfig{PgConfig.user = "kiroku"}+{- | Built on pg-migrate's stable per-user temporary root, which 'withMigratedDatabase'+also uses, so ephemeral-pg's startup sweep reclaims clusters left by killed runs.+-}+kirokuPgConfig :: IO Pg.Config+kirokuPgConfig = do+    base <- defaultEphemeralConfig+    pure base{PgConfig.user = "kiroku"}  withKirokuPg :: (Pg.Database -> IO ()) -> IO () withKirokuPg action = do-    started <- Pg.startCached kirokuPgConfig Pg.defaultCacheConfig+    config <- kirokuPgConfig+    started <- Pg.startCached config Pg.defaultCacheConfig     case started of         Left startError -> expectationFailure (show startError)         Right database -> action database `finally` Pg.stop database@@ -559,12 +576,17 @@         Encoders.noParams         (Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.bool))) --- | Whether @kiroku.uuidv7()@ exists, and the stored @lease_id@ default.-leaseDefaultStatement :: Statement () (Bool, Maybe Text)+{- | The server major, whether each UUIDv7 generator exists, and the stored+@lease_id@ default. Together these pin which route published+@kiroku.uuidv7()@ on the running server.+-}+leaseDefaultStatement :: Statement () (Int32, Bool, Bool, Maybe Text) leaseDefaultStatement =     Statement.preparable         """-        SELECT to_regprocedure('kiroku.uuidv7()') IS NOT NULL,+        SELECT pg_catalog.current_setting('server_version_num')::int / 10000,+               to_regprocedure('pg_catalog.uuidv7()') IS NOT NULL,+               to_regprocedure('kiroku.uuidv7()') IS NOT NULL,                (SELECT pg_catalog.pg_get_expr(stored.adbin, stored.adrelid)                   FROM pg_catalog.pg_attrdef AS stored                   JOIN pg_catalog.pg_attribute AS attribute@@ -575,8 +597,10 @@         """         Encoders.noParams         ( Decoders.singleRow-            ( (,)-                <$> Decoders.column (Decoders.nonNullable Decoders.bool)+            ( (,,,)+                <$> Decoders.column (Decoders.nonNullable Decoders.int4)+                <*> Decoders.column (Decoders.nonNullable Decoders.bool)+                <*> Decoders.column (Decoders.nonNullable Decoders.bool)                 <*> Decoders.column (Decoders.nullable Decoders.text)             )         )