engine/migrations/v1_to_v2.py: option sub_category->sub_categories[]; sub-category name slugify (whitespace/grammar chars->_, reserved suffixed, de-duped) cascaded to options + tag_groups; instance category_filter list->boolean-expr string + exclude_null flag; nested @{uuid:a,b,null} refs->@{uuid:a or b!null}. Idempotent. Two entry points share one core: envelope migrate_v1_to_v2 (import/export, registered in _CHAIN) + per-row migrate_module/bundle_v1_to_v2 (lazy/bulk DB path).
Register _CHAIN[1] + bump engine CURRENT_SCHEMA_VERSION 1->2. New SQL migration 016 marches stale DB rows 1->2 at boot via run_bulk_lazy + the per-row migrators (014's documented bump pattern). TS mirror (migrations.ts) + client CURRENT bump follow next (no cross-language version assertion couples them). Update version/entity-count assertions in payload-migration, migration-runner, and export-build tests.
98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
from engine.migrations import CURRENT_SCHEMA_VERSION, migrate_payload
|
|
|
|
EMPTY_7 = {
|
|
"bundles": [], "wildcards": [], "fixed_values": [],
|
|
"combines": [], "derivations": [], "constraints": [], "categories": [],
|
|
}
|
|
|
|
|
|
def test_returns_payload_as_is_at_current_version():
|
|
payload = {"schema_version": CURRENT_SCHEMA_VERSION, **EMPTY_7}
|
|
result = migrate_payload(payload)
|
|
assert result["ok"] is True
|
|
assert result["migrated"] == payload
|
|
assert result["migrated_entity_count"] == 0
|
|
|
|
|
|
def test_rejects_future_version():
|
|
payload = {"schema_version": CURRENT_SCHEMA_VERSION + 1, **EMPTY_7}
|
|
result = migrate_payload(payload)
|
|
assert result["ok"] is False
|
|
assert "future" in result["reason"].lower()
|
|
|
|
|
|
def test_rejects_missing_version():
|
|
result = migrate_payload({**EMPTY_7})
|
|
assert result["ok"] is False
|
|
assert "schema_version" in result["reason"]
|
|
|
|
|
|
def test_walks_chain_to_current():
|
|
v0_payload = {
|
|
"schema_version": 0,
|
|
**EMPTY_7,
|
|
"wildcards": [{"uuid": "u", "name": "old"}],
|
|
}
|
|
result = migrate_payload(v0_payload)
|
|
assert result["ok"] is True
|
|
assert result["migrated"]["schema_version"] == CURRENT_SCHEMA_VERSION
|
|
assert result["migrated"]["wildcards"][0]["migrated_from"] == 0
|
|
# 2 chain steps (v0->v1, v1->v2) each pass the 1 wildcard => count 2.
|
|
assert result["migrated_entity_count"] == 2
|
|
|
|
|
|
def test_walks_chain_on_empty_payload():
|
|
v0_empty = {"schema_version": 0, **EMPTY_7}
|
|
result = migrate_payload(v0_empty)
|
|
assert result["ok"] is True
|
|
assert result["migrated"]["schema_version"] == CURRENT_SCHEMA_VERSION
|
|
assert result["migrated_entity_count"] == 0
|
|
|
|
|
|
def test_tags_fixed_values_combines_derivations_categories():
|
|
v0_payload = {
|
|
"schema_version": 0,
|
|
"bundles": [],
|
|
"wildcards": [],
|
|
"fixed_values": [{"uuid": "fv1", "name": "fv"}],
|
|
"combines": [{"uuid": "cb1", "name": "cb"}],
|
|
"derivations": [{"uuid": "dr1", "name": "dr"}],
|
|
"constraints": [],
|
|
"categories": [{"uuid": "cat1", "name": "cat"}],
|
|
}
|
|
result = migrate_payload(v0_payload)
|
|
assert result["ok"] is True
|
|
assert result["migrated"]["fixed_values"][0]["migrated_from"] == 0
|
|
assert result["migrated"]["combines"][0]["migrated_from"] == 0
|
|
assert result["migrated"]["derivations"][0]["migrated_from"] == 0
|
|
assert result["migrated"]["categories"][0]["migrated_from"] == 0
|
|
|
|
|
|
def test_sums_all_7_arrays_for_migrated_entity_count():
|
|
v0_payload = {
|
|
"schema_version": 0,
|
|
"bundles": [{"uuid": "b1"}],
|
|
"wildcards": [{"uuid": "w1"}],
|
|
"fixed_values": [{"uuid": "fv1"}],
|
|
"combines": [{"uuid": "cb1"}],
|
|
"derivations": [{"uuid": "dr1"}],
|
|
"constraints": [{"uuid": "c1"}],
|
|
"categories": [{"uuid": "cat1"}],
|
|
}
|
|
result = migrate_payload(v0_payload)
|
|
assert result["ok"] is True
|
|
# 7 entities x 2 chain steps (v0->v1, v1->v2) = 14.
|
|
assert result["migrated_entity_count"] == 14
|
|
|
|
|
|
def test_defaults_missing_arrays_to_empty():
|
|
# A partial payload (missing new buckets) should still succeed —
|
|
# migrate_payload fills them in via .get("key", []).
|
|
partial = {"schema_version": CURRENT_SCHEMA_VERSION, "wildcards": [{"uuid": "w1"}]}
|
|
result = migrate_payload(partial)
|
|
assert result["ok"] is True
|
|
assert result["migrated"]["fixed_values"] == []
|
|
assert result["migrated"]["combines"] == []
|
|
assert result["migrated"]["derivations"] == []
|
|
assert result["migrated"]["categories"] == []
|