80 lines
3.5 KiB
Python
80 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Apply the versioned equipment companion artifact to a desktop database."""
|
|
import argparse
|
|
import json
|
|
import sqlite3
|
|
from pathlib import Path
|
|
|
|
FORMAT = "trainlog-equipment-associations"
|
|
VERSION = 2
|
|
|
|
|
|
def fail(message):
|
|
raise ValueError(message)
|
|
|
|
|
|
def load_catalog(path):
|
|
root = json.loads(path.read_text(encoding="utf-8"))
|
|
if root.get("format") != "trainlog-equipment-catalog" or root.get("version") != 1:
|
|
fail("catalogue équipement non supporté")
|
|
return {item["id"] for item in root["equipment"]}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("artifact", type=Path)
|
|
parser.add_argument("--database", type=Path, required=True)
|
|
parser.add_argument("--catalog", type=Path,
|
|
default=Path(__file__).resolve().parents[1] / "catalog/equipment-v1.json")
|
|
args = parser.parse_args()
|
|
payload = json.loads(args.artifact.read_text(encoding="utf-8"))
|
|
if payload.get("format") != FORMAT or payload.get("version") != VERSION:
|
|
fail("extension équipement non supportée")
|
|
if set(payload) != {"format", "version", "generated_at", "associations"}:
|
|
fail("clés extension équipement invalides")
|
|
known = load_catalog(args.catalog)
|
|
connection = sqlite3.connect(args.database)
|
|
try:
|
|
if connection.execute("PRAGMA user_version;").fetchone()[0] != 7:
|
|
fail("schema desktop v7 requis")
|
|
seen = set()
|
|
with connection:
|
|
for item in payload["associations"]:
|
|
if not isinstance(item, dict):
|
|
fail("association invalide")
|
|
session_id, entry_id, exercise_id, state = (item.get(k) for k in ("session_id", "entry_id", "exercise_id", "state"))
|
|
key = (session_id, entry_id)
|
|
if not isinstance(session_id, str) or not session_id or not isinstance(entry_id, str) or not entry_id or not isinstance(exercise_id, str) or not exercise_id or key in seen:
|
|
fail("identité association invalide ou dupliquée")
|
|
seen.add(key)
|
|
if state == "set":
|
|
if set(item) != {"session_id", "entry_id", "exercise_id", "state", "equipment_id"}:
|
|
fail("association set invalide")
|
|
equipment_id = item["equipment_id"]
|
|
if not isinstance(equipment_id, str) or equipment_id not in known:
|
|
fail(f"équipement inconnu: {equipment_id}")
|
|
elif state == "cleared":
|
|
if set(item) != {"session_id", "entry_id", "exercise_id", "state"}:
|
|
fail("association cleared invalide")
|
|
equipment_id = None
|
|
else:
|
|
fail("état association invalide")
|
|
cursor = connection.execute(
|
|
"UPDATE session_exercises SET equipment_id=? WHERE id=("
|
|
"SELECT se.id FROM session_exercises se JOIN sessions s ON s.id=se.session_row_id "
|
|
"WHERE s.session_id=? AND se.entry_id=?)",
|
|
(equipment_id, session_id, entry_id))
|
|
if cursor.rowcount != 1:
|
|
fail(f"entrée séance inconnue: {session_id}/{entry_id}")
|
|
print("EQUIPMENT_ASSOCIATIONS_IMPORT=PASS")
|
|
print(f"associations={len(seen)}")
|
|
finally:
|
|
connection.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except Exception as error:
|
|
print(f"EQUIPMENT_ASSOCIATIONS_IMPORT=FAIL {error}")
|
|
raise SystemExit(1)
|