neues skript sql_dump_diff.py zum Vergleich von 2 sql-dumps.

- leere, frisch initialisierte Datenbanken der Versionen verglichen
- datasetprogramme erkennen jetzt auch suche nach standardtabellen wie uom
This commit is contained in:
2026-08-22 17:45:46 +02:00
parent c0dd24b6c5
commit a55774eff2
19 changed files with 78583 additions and 269 deletions
+33 -4
View File
@@ -124,7 +124,7 @@ def load_spec(path):
return json.loads(text)
def resolve_value(value, created):
def resolve_value(value, created, search_cache):
"""
Löst Referenzen der Form {"$ref": "irgendein_key"} auf bereits in
diesem Lauf erzeugte Datensätze auf (z. B. um eine Adresse mit der
@@ -135,6 +135,21 @@ def resolve_value(value, created):
Werte, die kein einfacher JSON-Typ sind:
{"$decimal": "12.34"} -> decimal.Decimal("12.34")
{"$date": "2024-01-15"} -> datetime.date(2024, 1, 15)
{"$search": {"model": "product.uom",
"domain": [["name", "=", "Unit"]]}}
-> sucht den Record live auf dem
Zielserver (Model.find(domain)) -
für Stammdaten, die nicht Teil des
Testdatensatzes sind, sondern beim
Modul-Aktivieren per XML-Fixture
angelegt werden (Länder, Währungen,
Einheiten, Standard-Lagerorte, ...).
Wirft einen Fehler, wenn nichts
gefunden wird, statt einen neuen
Record anzulegen - ein fehlender
Treffer bedeutet meist, dass sich
die Fixture-Daten zwischen den
Versionen geändert haben.
{"$manual": "<ausdruck>"} -> Fehler mit Klartext, da diese
Stelle noch von Hand ausgefüllt
werden muss.
@@ -147,6 +162,19 @@ def resolve_value(value, created):
f"fehlgeschlagen."
)
return created[value["$ref"]]
if isinstance(value, dict) and "$search" in value:
spec = value["$search"]
cache_key = (spec["model"], json.dumps(spec["domain"], sort_keys=True))
if cache_key not in search_cache:
matches = Model.get(spec["model"]).find(spec["domain"])
if not matches:
raise ValueError(
f"$search fand keinen Treffer: model={spec['model']!r} "
f"domain={spec['domain']!r} - Stammdaten auf diesem "
f"Server geändert/entfernt?"
)
search_cache[cache_key] = matches[0].id
return search_cache[cache_key]
if isinstance(value, dict) and "$decimal" in value:
return decimal.Decimal(value["$decimal"])
if isinstance(value, dict) and "$date" in value:
@@ -158,9 +186,9 @@ def resolve_value(value, created):
f"dieser Datensatz angelegt wird."
)
if isinstance(value, list):
return [resolve_value(v, created) for v in value]
return [resolve_value(v, created, search_cache) for v in value]
if isinstance(value, dict):
return {k: resolve_value(v, created) for k, v in value.items()}
return {k: resolve_value(v, created, search_cache) for k, v in value.items()}
return value
@@ -187,6 +215,7 @@ def serialize(value):
def create_records(spec, created, results):
fields_cache = {} # model_name -> Set der auf DIESEM Server bekannten Felder
search_cache = {} # (model, domain-json) -> id, damit dieselbe Stammdaten-Suche nicht mehrfach läuft
for entry in spec["records"]:
key = entry["key"]
@@ -212,7 +241,7 @@ def create_records(spec, created, results):
for field_name, raw_value in fields.items():
actual_name = resolve_field_name(RecordModel, model_name, field_name, fields_cache)
actual_names[field_name] = actual_name
setattr(record, actual_name, resolve_value(raw_value, created))
setattr(record, actual_name, resolve_value(raw_value, created, search_cache))
record.save()
created[key] = record.id