Mache Charakterentwicklungsmigration wiederholbar
All checks were successful
Deploy to production / deploy (push) Successful in 2m26s
All checks were successful
Deploy to production / deploy (push) Successful in 2m26s
This commit is contained in:
@@ -11,6 +11,8 @@ Werte für bestehende Charaktere. Ein Datenbanktrigger initialisiert sie auch f
|
|||||||
neue Charaktere, einschließlich der direkten SQL-Inserts des Daemons für NPCs
|
neue Charaktere, einschließlich der direkten SQL-Inserts des Daemons für NPCs
|
||||||
und Neugeborene. Normale Updates, auch das Übergeben von NULL, würfeln bereits
|
und Neugeborene. Normale Updates, auch das Übergeben von NULL, würfeln bereits
|
||||||
gespeicherte Werte nicht neu aus. Explizite gültige Änderungen bleiben möglich.
|
gespeicherte Werte nicht neu aus. Explizite gültige Änderungen bleiben möglich.
|
||||||
|
Die Migration kann auch nach manueller Vorbereitung der Spalten erneut laufen:
|
||||||
|
Vorhandene Werte bleiben erhalten, fehlende Spalten und Werte werden ergänzt.
|
||||||
|
|
||||||
Das vereinfachte Spielmodell verwendet folgende Verteilung:
|
Das vereinfachte Spielmodell verwendet folgende Verteilung:
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ module.exports = {
|
|||||||
await queryInterface.sequelize.transaction(async (transaction) => {
|
await queryInterface.sequelize.transaction(async (transaction) => {
|
||||||
await queryInterface.sequelize.query(`
|
await queryInterface.sequelize.query(`
|
||||||
ALTER TABLE falukant_data.character
|
ALTER TABLE falukant_data.character
|
||||||
ADD COLUMN puberty_start_age SMALLINT,
|
ADD COLUMN IF NOT EXISTS puberty_start_age SMALLINT,
|
||||||
ADD COLUMN fertile_from_age SMALLINT;
|
ADD COLUMN IF NOT EXISTS fertile_from_age SMALLINT;
|
||||||
|
|
||||||
-- Shared by Sequelize and raw daemon INSERTs, including newborns and NPCs.
|
-- Shared by Sequelize and raw daemon INSERTs, including newborns and NPCs.
|
||||||
-- One real calendar day is one game year. These are game distributions,
|
-- One real calendar day is one game year. These are game distributions,
|
||||||
-- not medical predictions or reconstructed medieval population data.
|
-- not medical predictions or reconstructed medieval population data.
|
||||||
CREATE FUNCTION falukant_data.initialize_character_development()
|
CREATE OR REPLACE FUNCTION falukant_data.initialize_character_development()
|
||||||
RETURNS trigger LANGUAGE plpgsql AS $$
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF TG_OP = 'UPDATE' THEN
|
IF TG_OP = 'UPDATE' THEN
|
||||||
@@ -30,21 +30,35 @@ module.exports = {
|
|||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
DROP TRIGGER IF EXISTS initialize_character_development ON falukant_data.character;
|
||||||
CREATE TRIGGER initialize_character_development
|
CREATE TRIGGER initialize_character_development
|
||||||
BEFORE INSERT OR UPDATE ON falukant_data.character
|
BEFORE INSERT OR UPDATE ON falukant_data.character
|
||||||
FOR EACH ROW EXECUTE FUNCTION falukant_data.initialize_character_development();
|
FOR EACH ROW EXECUTE FUNCTION falukant_data.initialize_character_development();
|
||||||
|
|
||||||
-- Existing pregnancies and relationships are deliberately untouched.
|
-- Existing pregnancies and relationships are deliberately untouched.
|
||||||
UPDATE falukant_data.character SET puberty_start_age = puberty_start_age;
|
UPDATE falukant_data.character SET puberty_start_age = puberty_start_age
|
||||||
|
WHERE puberty_start_age IS NULL OR fertile_from_age IS NULL;
|
||||||
|
|
||||||
ALTER TABLE falukant_data.character
|
ALTER TABLE falukant_data.character
|
||||||
ALTER COLUMN puberty_start_age SET NOT NULL,
|
ALTER COLUMN puberty_start_age SET NOT NULL,
|
||||||
ALTER COLUMN fertile_from_age SET NOT NULL,
|
ALTER COLUMN fertile_from_age SET NOT NULL;
|
||||||
ADD CONSTRAINT character_development_ages_valid CHECK (
|
|
||||||
puberty_start_age BETWEEN 8 AND 18
|
DO $$
|
||||||
AND fertile_from_age > puberty_start_age
|
BEGIN
|
||||||
AND fertile_from_age <= 21
|
IF NOT EXISTS (
|
||||||
);
|
SELECT 1 FROM pg_constraint
|
||||||
|
WHERE conrelid = 'falukant_data.character'::regclass
|
||||||
|
AND conname = 'character_development_ages_valid'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE falukant_data.character
|
||||||
|
ADD CONSTRAINT character_development_ages_valid CHECK (
|
||||||
|
puberty_start_age BETWEEN 8 AND 18
|
||||||
|
AND fertile_from_age > puberty_start_age
|
||||||
|
AND fertile_from_age <= 21
|
||||||
|
);
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
`, { transaction });
|
`, { transaction });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -71,6 +71,31 @@ test('database migration, persistence and daemon conception paths', {
|
|||||||
await assert.rejects(db.query(`INSERT INTO falukant_data.character
|
await assert.rejects(db.query(`INSERT INTO falukant_data.character
|
||||||
(puberty_start_age, fertile_from_age) VALUES (12, 11)`));
|
(puberty_start_age, fertile_from_age) VALUES (12, 11)`));
|
||||||
|
|
||||||
|
await t.test('repeating the migration preserves all existing character data', async () => {
|
||||||
|
const [saved] = await db.query('SELECT * FROM falukant_data.character ORDER BY id');
|
||||||
|
await migration.up(qi);
|
||||||
|
const [repeated] = await db.query('SELECT * FROM falukant_data.character ORDER BY id');
|
||||||
|
assert.deepEqual(repeated, saved);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const bothColumns of [true, false]) {
|
||||||
|
await t.test(`manually prepared schema with ${bothColumns ? 'both columns' : 'one column'}`, async () => {
|
||||||
|
await migration.down(qi);
|
||||||
|
await db.query(`ALTER TABLE falukant_data.character ADD COLUMN puberty_start_age SMALLINT`);
|
||||||
|
if (bothColumns) {
|
||||||
|
await db.query(`ALTER TABLE falukant_data.character ADD COLUMN fertile_from_age SMALLINT;
|
||||||
|
UPDATE falukant_data.character SET fertile_from_age = 13 WHERE id = 1`);
|
||||||
|
}
|
||||||
|
await db.query(`UPDATE falukant_data.character SET puberty_start_age = 10 WHERE id = 1`);
|
||||||
|
await migration.up(qi);
|
||||||
|
const [characters] = await db.query('SELECT * FROM falukant_data.character ORDER BY id');
|
||||||
|
assert.equal(characters[0].puberty_start_age, 10);
|
||||||
|
if (bothColumns) assert.equal(characters[0].fertile_from_age, 13);
|
||||||
|
assert.deepEqual(characters[0].pregnancy_due_at, before[0].pregnancy_due_at);
|
||||||
|
assert.ok(characters.every(c => c.fertile_from_age > c.puberty_start_age));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await t.test('daemon checks both parents and preserves already scheduled births', {
|
await t.test('daemon checks both parents and preserves already scheduled births', {
|
||||||
skip: !process.env.DAEMON_SQL_PATH,
|
skip: !process.env.DAEMON_SQL_PATH,
|
||||||
}, async () => {
|
}, async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user