// Exercises Migrations.applyWith against fixture steps and prints a verdict per // case. Run by tests/quickshell/migrations-contract.sh. // // Fixture steps rather than the real list: the real one is empty until the // first breaking schema change, and a mechanism that has never been run against // a failing step is not one to discover the behavior of during an upgrade. import Quickshell import QtQuick import qs.config ShellRoot { Component.onCompleted: { const steps = [ { version: 2, describe: "add b", migrate: v => { v.b = (v.a ?? 0) + 1; return v; } }, { version: 3, describe: "add c", migrate: v => { v.c = "three"; return v; } }, { version: 4, describe: "explode", migrate: v => { throw new Error("boom"); } } ]; const results = {}; // No version at all: a file written before versioning. Stamped, never // migrated. let r = Migrations.applyWith({ a: 1 }, steps, 3, 1); results.unversioned = { v: r.values.schemaVersion, migrated: r.migrated, changed: r.changed, untouched: r.values.b === undefined }; // Older file: every step above its version runs, in order. r = Migrations.applyWith({ a: 1, schemaVersion: 1 }, steps, 3, 1); results.upgrade = { v: r.values.schemaVersion, b: r.values.b, c: r.values.c, count: r.applied.length, migrated: r.migrated }; // Already current: nothing runs. r = Migrations.applyWith({ schemaVersion: 3, keep: "me" }, steps, 3, 1); results.current = { v: r.values.schemaVersion, migrated: r.migrated, kept: r.values.keep === "me", b: r.values.b === undefined }; // From the future: left completely alone, including its unknown keys. r = Migrations.applyWith({ schemaVersion: 9, futureKey: "x" }, steps, 3, 1); results.future = { v: r.values.schemaVersion, migrated: r.migrated, changed: r.changed, kept: r.values.futureKey === "x" }; // A failing step stops at the last good version rather than losing the // file or skipping past the failure forever. r = Migrations.applyWith({ schemaVersion: 1, a: 5 }, steps, 4, 1); results.failure = { v: r.values.schemaVersion, b: r.values.b, c: r.values.c, kept: r.values.a === 5, count: r.applied.length }; // Unknown keys survive a migration: rolling back to an older Panama // must not discard a newer version's settings. r = Migrations.applyWith({ schemaVersion: 1, unknownFromFuture: true }, steps, 3, 1); results.preserved = { kept: r.values.unknownFromFuture === true }; console.info("PANAMA-MIGRATIONS " + JSON.stringify(results)); Qt.callLater(() => Qt.quit()); } }