store: run the names migrations after badges

This commit is contained in:
shum committed 2026-10-29 07:50:02 +00:00
1 parent 99ebbf0afe
commit ed5d41e7ed
5 files changed
+34 -16

No files matched your search

+5
View File
@@ -531,6 +531,11 @@ running beside the new one, on the same port and database. The database `badge_s
`BADGE_DB_CONN`, the `sx_badge_service_` tables and the chat database prefix
`simplex_badge_service` are unchanged.
A badge-service database upgrades in place: the store's own migrations run after every badge
migration, `20261012_badge_subscriptions` included. A store database created before the names
migration became `20261013_names` (it was `20261010_names`) does not start, as the service refuses
migrations applied out of the order it lists. Recreate such a database.
### Two sites
The image carries the badges build at `/srv/badges` and the names build at `/srv/names`, the
@@ -2,7 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module StoreService.Store.Postgres.Migrations (storeServiceSchemaMigrations, servicePrefix, withPrefix) where
module StoreService.Store.Postgres.Migrations (storeServiceSchemaMigrations, schemaMigrations, servicePrefix, withPrefix) where
import Data.List (sortOn)
import Data.Text (Text)
@@ -21,7 +21,7 @@ schemaMigrations =
("20260918_badge_group_ops", m20260918_badge_group_ops, Just down_m20260918_badge_group_ops),
("20260925_badge_store_receipts", m20260925_badge_store_receipts, Just down_m20260925_badge_store_receipts),
("20261012_badge_subscriptions", m20261012_badge_subscriptions, Just down_m20261012_badge_subscriptions),
("20261010_names", m20261010_names, Just down_m20261010_names),
("20261013_names", m20261013_names, Just down_m20261013_names),
("20261022_drop_taken_codes", m20261022_drop_taken_codes, Just down_m20261022_drop_taken_codes),
("20261022_name_balances", m20261022_name_balances, Just down_m20261022_name_balances),
("20261022_name_late_wait", m20261022_name_late_wait, Just down_m20261022_name_late_wait),
@@ -280,8 +280,8 @@ DROP TABLE @subscription_charges;
-- A registration is live as Names.Store's orderLive decides.
-- reserved_by is added after the registrations table, which references the codes table.
m20261010_names :: Text
m20261010_names =
m20261013_names :: Text
m20261013_names =
withPrefix
servicePrefix
[r|
@@ -417,8 +417,8 @@ CREATE INDEX @idx_name_transactions_status ON @name_transactions(status, registr
-- A table another table's foreign key references cannot be dropped, so reserved_by goes first.
-- The name orders' invoices go with them, except those with a payment, which stay for the accounts.
down_m20261010_names :: Text
down_m20261010_names =
down_m20261013_names :: Text
down_m20261013_names =
withPrefix
servicePrefix
[r|
@@ -2,7 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module StoreService.Store.SQLite.Migrations (storeServiceSchemaMigrations, servicePrefix, withPrefix) where
module StoreService.Store.SQLite.Migrations (storeServiceSchemaMigrations, schemaMigrations, servicePrefix, withPrefix) where
import Data.List (sortOn)
import Data.Text (Text)
@@ -22,7 +22,7 @@ schemaMigrations =
("20260918_badge_group_ops", m20260918_badge_group_ops, Just down_m20260918_badge_group_ops),
("20260925_badge_store_receipts", m20260925_badge_store_receipts, Just down_m20260925_badge_store_receipts),
("20261012_badge_subscriptions", m20261012_badge_subscriptions, Just down_m20261012_badge_subscriptions),
("20261010_names", m20261010_names, Just down_m20261010_names),
("20261013_names", m20261013_names, Just down_m20261013_names),
("20261022_drop_taken_codes", m20261022_drop_taken_codes, Just down_m20261022_drop_taken_codes),
("20261022_name_balances", m20261022_name_balances, Just down_m20261022_name_balances),
("20261022_name_late_wait", m20261022_name_late_wait, Just down_m20261022_name_late_wait),
@@ -281,8 +281,8 @@ DROP TABLE @subscription_charges;
-- A registration is live as Names.Store's orderLive decides.
-- reserved_by is added after the registrations table, which references the codes table.
m20261010_names :: Query
m20261010_names =
m20261013_names :: Query
m20261013_names =
withPrefix
servicePrefix
[sql|
@@ -419,8 +419,8 @@ CREATE INDEX @idx_name_transactions_status ON @name_transactions(status, registr
-- SQLite refuses to drop a column in a foreign key, and dropping a table deletes its rows first,
-- so the codes' references to registrations are cleared before the registrations go.
-- The name orders' invoices go with them, except those with a payment, which stay for the accounts.
down_m20261010_names :: Query
down_m20261010_names =
down_m20261013_names :: Query
down_m20261013_names =
withPrefix
servicePrefix
[sql|
+2 -2
View File
@@ -196,9 +196,9 @@ testNamesColumns = withServiceStore $ \st -> do
testNamesDownUp :: IO ()
testNamesDownUp = withServiceStore $ \st -> do
let names = dropWhile ((/= "20261010_names") . name) storeServiceSchemaMigrations
let names = dropWhile ((/= "20261013_names") . name) storeServiceSchemaMigrations
badgeColumns = mapM (fmap sort . columnsOf st) badgeTables
map name names `shouldBe` ["20261010_names", "20261022_drop_taken_codes", "20261022_name_balances", "20261022_name_late_wait", "20261023_name_terms", "20261027_name_invoiced_units"]
map name names `shouldBe` ["20261013_names", "20261022_drop_taken_codes", "20261022_name_balances", "20261022_name_late_wait", "20261023_name_terms", "20261027_name_invoiced_units"]
badgeBefore <- badgeColumns
code <- issue st 1 usable
placeCode st "r1" ownerA (order "alicebakery" 1) code `shouldReturn` Right ()
+15 -2
View File
@@ -116,12 +116,12 @@ import Text.Read (readMaybe)
import UnliftIO.Temporary (withTempDirectory)
#if defined(dbPostgres)
import StoreService.Store.Postgres.Migrations (storeServiceSchemaMigrations)
import StoreService.Store.Postgres.Migrations (schemaMigrations, storeServiceSchemaMigrations)
import ChatClient (testDBConnstr)
import Database.PostgreSQL.Simple (Only (..))
import qualified Simplex.Messaging.Agent.Store.Postgres.Migrations as Migrations
#else
import StoreService.Store.SQLite.Migrations (storeServiceSchemaMigrations)
import StoreService.Store.SQLite.Migrations (schemaMigrations, storeServiceSchemaMigrations)
import Data.String (fromString)
import Database.SQLite.Simple (Only (..))
import qualified Database.SQLite.Simple as SQL
@@ -182,6 +182,7 @@ badgeWebTests = do
it "refuses a duplicate provider_ref" testProviderRefUnique
it "M20260918 adds the multi-use columns and the group table" testGroupOpsColumns
it "M20260918 defaults a fresh code to one use with none spent" testGroupOpsRedeemCounts
it "declares its migrations in name order, master's badge migrations before the names ones" testMigrationOrder
it "migrates all the way down and up again" testSchemaDownUpCycle
it "rolls back only the group migration and re-applies it, keeping a code redeemed twice spent" testGroupOpsDownUp
it "rolls back only the subscription migration, restoring the columns it dropped, and re-applies it" testSubscriptionsDownUp
@@ -405,6 +406,18 @@ runMigrations st = Migrations.run st Nothing
runMigrations st = Migrations.run st Nothing True
#endif
-- | Applied migrations must be a prefix of this list by name, so a migration of ours dated
-- before one of master's breaks upgrading a badge-service database.
testMigrationOrder :: IO ()
testMigrationOrder = do
let declared = map (\(n, _, _) -> n) schemaMigrations
[(a, b) | (a, b) <- zip declared (drop 1 declared), a >= b] `shouldBe` []
let (badges, ours) = span (`elem` badgeMigrations) (map name storeServiceSchemaMigrations)
badges `shouldBe` badgeMigrations
ours `shouldBe` ["20261013_names", "20261022_drop_taken_codes", "20261022_name_balances", "20261022_name_late_wait", "20261023_name_terms", "20261027_name_invoiced_units"]
where
badgeMigrations = ["20260915_badge_service_schema", "20260918_badge_group_ops", "20260925_badge_store_receipts", "20261012_badge_subscriptions"]
testSchemaDownUpCycle :: IO ()
testSchemaDownUpCycle = withServiceStore $ \st -> do
let downMigrations = mapMaybe toDownMigration storeServiceSchemaMigrations