Files
svg-backend/backend/app/services/structure_diff.py

199 lines
7.3 KiB
Python

from __future__ import annotations
from app.repositories.scheme_groups import list_scheme_version_groups
from app.repositories.scheme_seats import list_scheme_version_seats
from app.repositories.scheme_sectors import list_scheme_version_sectors
from app.services.baseline_selector import select_baseline_scheme_version
def _sector_compare_value(row) -> dict:
return {
"element_id": row.element_id,
"sector_id": row.sector_id,
"name": row.name,
"classes_raw": row.classes_raw,
}
def _sector_response_value(row) -> dict:
payload = _sector_compare_value(row)
payload["sector_record_id"] = row.sector_record_id
return payload
def _group_compare_value(row) -> dict:
return {
"element_id": row.element_id,
"group_id": row.group_id,
"name": row.name,
"classes_raw": row.classes_raw,
}
def _group_response_value(row) -> dict:
payload = _group_compare_value(row)
payload["group_record_id"] = row.group_record_id
return payload
def _seat_compare_value(row) -> dict:
return {
"element_id": row.element_id,
"seat_id": row.seat_id,
"sector_id": row.sector_id,
"group_id": row.group_id,
"row_label": row.row_label,
"seat_number": row.seat_number,
}
def _seat_response_value(row) -> dict:
payload = _seat_compare_value(row)
payload["seat_record_id"] = row.seat_record_id
return payload
def _build_diff(
*,
before_compare_map: dict,
after_compare_map: dict,
before_payload_map: dict,
after_payload_map: dict,
) -> list[dict]:
keys = sorted(set(before_payload_map.keys()) | set(after_payload_map.keys()))
result: list[dict] = []
for key in keys:
before_compare = before_compare_map.get(key)
after_compare = after_compare_map.get(key)
before_payload = before_payload_map.get(key)
after_payload = after_payload_map.get(key)
if before_compare is None and after_compare is not None:
status = "added"
elif before_compare is not None and after_compare is None:
status = "removed"
elif before_compare != after_compare:
status = "changed"
else:
status = "unchanged"
result.append(
{
"key": key,
"status": status,
"before": before_payload,
"after": after_payload,
}
)
return result
def _sector_key(row) -> str:
return row.sector_id if row.sector_id else (row.element_id if row.element_id else row.sector_record_id)
def _group_key(row) -> str:
return row.group_id if row.group_id else (row.element_id if row.element_id else row.group_record_id)
def _seat_key(row) -> str:
return row.seat_id if row.seat_id else (row.element_id if row.element_id else row.seat_record_id)
async def build_structure_diff(
*,
scheme_id: str,
draft_scheme_version_id: str,
baseline_override_scheme_version_id: str | None = None,
) -> dict:
baseline, baseline_strategy = await select_baseline_scheme_version(
scheme_id=scheme_id,
draft_scheme_version_id=draft_scheme_version_id,
override_scheme_version_id=baseline_override_scheme_version_id,
)
draft_sectors = await list_scheme_version_sectors(draft_scheme_version_id)
draft_groups = await list_scheme_version_groups(draft_scheme_version_id)
draft_seats = await list_scheme_version_seats(draft_scheme_version_id)
if baseline is None:
baseline_sector_compare_map = {}
baseline_group_compare_map = {}
baseline_seat_compare_map = {}
baseline_sector_payload_map = {}
baseline_group_payload_map = {}
baseline_seat_payload_map = {}
baseline_scheme_version_id = None
else:
baseline_scheme_version_id = baseline.scheme_version_id
baseline_sectors = await list_scheme_version_sectors(baseline.scheme_version_id)
baseline_groups = await list_scheme_version_groups(baseline.scheme_version_id)
baseline_seats = await list_scheme_version_seats(baseline.scheme_version_id)
baseline_sector_compare_map = {
_sector_key(row): _sector_compare_value(row)
for row in baseline_sectors
}
baseline_sector_payload_map = {
_sector_key(row): _sector_response_value(row)
for row in baseline_sectors
}
baseline_group_compare_map = {
_group_key(row): _group_compare_value(row)
for row in baseline_groups
}
baseline_group_payload_map = {
_group_key(row): _group_response_value(row)
for row in baseline_groups
}
baseline_seat_compare_map = {
_seat_key(row): _seat_compare_value(row)
for row in baseline_seats
}
baseline_seat_payload_map = {
_seat_key(row): _seat_response_value(row)
for row in baseline_seats
}
draft_sector_compare_map = {_sector_key(row): _sector_compare_value(row) for row in draft_sectors}
draft_sector_payload_map = {_sector_key(row): _sector_response_value(row) for row in draft_sectors}
draft_group_compare_map = {_group_key(row): _group_compare_value(row) for row in draft_groups}
draft_group_payload_map = {_group_key(row): _group_response_value(row) for row in draft_groups}
draft_seat_compare_map = {_seat_key(row): _seat_compare_value(row) for row in draft_seats}
draft_seat_payload_map = {_seat_key(row): _seat_response_value(row) for row in draft_seats}
sector_diff = _build_diff(
before_compare_map=baseline_sector_compare_map,
after_compare_map=draft_sector_compare_map,
before_payload_map=baseline_sector_payload_map,
after_payload_map=draft_sector_payload_map,
)
group_diff = _build_diff(
before_compare_map=baseline_group_compare_map,
after_compare_map=draft_group_compare_map,
before_payload_map=baseline_group_payload_map,
after_payload_map=draft_group_payload_map,
)
seat_diff = _build_diff(
before_compare_map=baseline_seat_compare_map,
after_compare_map=draft_seat_compare_map,
before_payload_map=baseline_seat_payload_map,
after_payload_map=draft_seat_payload_map,
)
return {
"baseline_scheme_version_id": baseline_scheme_version_id,
"baseline_strategy": baseline_strategy,
"summary": {
"sectors_added": sum(1 for item in sector_diff if item["status"] == "added"),
"sectors_removed": sum(1 for item in sector_diff if item["status"] == "removed"),
"sectors_changed": sum(1 for item in sector_diff if item["status"] == "changed"),
"groups_added": sum(1 for item in group_diff if item["status"] == "added"),
"groups_removed": sum(1 for item in group_diff if item["status"] == "removed"),
"groups_changed": sum(1 for item in group_diff if item["status"] == "changed"),
"seats_added": sum(1 for item in seat_diff if item["status"] == "added"),
"seats_removed": sum(1 for item in seat_diff if item["status"] == "removed"),
"seats_changed": sum(1 for item in seat_diff if item["status"] == "changed"),
},
"sectors": sector_diff,
"groups": group_diff,
"seats": seat_diff,
}