Implement flexible entity relation system (Phases A–E)

Declarative relation registry via defrelation s-expressions with
cardinality enforcement (one-to-one, one-to-many, many-to-many),
registry-aware relate/unrelate/can-relate API endpoints, generic
container-nav fragment, and relation-driven UI components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 08:35:17 +00:00
parent 6f1d5bac3c
commit a0a0f5ebc2
17 changed files with 928 additions and 28 deletions

View File

@@ -148,9 +148,29 @@ class Component:
return f"<Component ~{self.name}({', '.join(self.params)})>"
# ---------------------------------------------------------------------------
# RelationDef
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class RelationDef:
"""A declared relation between two entity types.
Created by ``(defrelation :name ...)`` s-expressions.
"""
name: str # "page->market"
from_type: str # "page"
to_type: str # "market"
cardinality: str # "one-to-one" | "one-to-many" | "many-to-many"
inverse: str | None # "market->page"
nav: str # "submenu" | "tab" | "badge" | "inline" | "hidden"
nav_icon: str | None # "fa fa-shopping-bag"
nav_label: str | None # "markets"
# ---------------------------------------------------------------------------
# Type alias
# ---------------------------------------------------------------------------
# An s-expression value after evaluation
SExp = int | float | str | bool | Symbol | Keyword | Lambda | Component | list | dict | _Nil | None
SExp = int | float | str | bool | Symbol | Keyword | Lambda | Component | RelationDef | list | dict | _Nil | None