from typing import List, Optional, TYPE_CHECKING if TYPE_CHECKING: from .rooms import Room from sqlalchemy import Identity, Integer, Unicode from sqlalchemy.orm import Mapped, mapped_column, relationship from . import db from ..temp import is_temp_id class Area(db.Model): __tablename__ = 'Areas' id: Mapped[int] = mapped_column("ID", Integer, Identity(start=1, increment=1), primary_key=True) name: Mapped[Optional[str]] = mapped_column("Area", Unicode(255), nullable=True) rooms: Mapped[List['Room']] = relationship('Room', back_populates='area') def __init__(self, name: Optional[str] = None): self.name = name def __repr__(self): return f"" def serialize(self): return { 'id': self.id, 'name': self.name } @classmethod def sync_from_state(cls, submitted_items: list[dict]) -> dict[str, int]: """ Syncs the Area table (aka 'sections') with the submitted list. Supports add, update, and delete. Also returns a mapping of temp IDs to real IDs for resolution. """ submitted_clean = [] seen_ids = set() temp_id_map = {} for item in submitted_items: if not isinstance(item, dict): continue name = str(item.get("name", "")).strip() raw_id = item.get("id") if not name: continue submitted_clean.append({"id": raw_id, "name": name}) # Record real (non-temp) IDs try: if raw_id is not None: parsed_id = int(raw_id) if parsed_id >= 0: seen_ids.add(parsed_id) except (ValueError, TypeError): pass existing_query = db.session.query(cls) existing_by_id = {area.id: area for area in existing_query.all()} existing_ids = set(existing_by_id.keys()) print(f"Existing area IDs: {existing_ids}") print(f"Submitted area IDs: {seen_ids}") for entry in submitted_clean: submitted_id_raw = entry.get("id") submitted_name = entry["name"] if is_temp_id(submitted_id_raw): new_area = cls(name=submitted_name) db.session.add(new_area) db.session.flush() # Get the real ID temp_id_map[submitted_id_raw] = new_area.id print(f"➕ Adding area: {submitted_name}") else: try: submitted_id = int(submitted_id_raw) except (ValueError, TypeError): continue # Skip malformed ID if submitted_id in existing_by_id: area = existing_by_id[submitted_id] if area.name != submitted_name: print(f"✏️ Updating area {area.id}: '{area.name}' → '{submitted_name}'") area.name = submitted_name for existing_id in existing_ids - seen_ids: area = existing_by_id[existing_id] db.session.delete(area) print(f"🗑️ Removing area: {area.name}") id_map = { **{str(i): i for i in seen_ids}, # "1" → 1 **{str(temp): real for temp, real in temp_id_map.items()} # "temp-1" → 5 } return id_map