Rename all sexp directories, files, identifiers, and references to sx. artdag/ excluded (separate media processing DSL). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
102 lines
2.7 KiB
Python
102 lines
2.7 KiB
Python
"""
|
|
Relation registry — declarative entity relationship definitions.
|
|
|
|
Relations are defined as s-expressions using ``defrelation`` and stored
|
|
in a global registry. All services load the same definitions at startup
|
|
via ``load_relation_registry()``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from shared.sx.types import RelationDef
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Registry
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_RELATION_REGISTRY: dict[str, RelationDef] = {}
|
|
|
|
|
|
def register_relation(defn: RelationDef) -> None:
|
|
"""Add a RelationDef to the global registry."""
|
|
_RELATION_REGISTRY[defn.name] = defn
|
|
|
|
|
|
def get_relation(name: str) -> RelationDef | None:
|
|
"""Look up a relation by name (e.g. ``"page->market"``)."""
|
|
return _RELATION_REGISTRY.get(name)
|
|
|
|
|
|
def relations_from(entity_type: str) -> list[RelationDef]:
|
|
"""All relations where *entity_type* is the ``from`` side."""
|
|
return [d for d in _RELATION_REGISTRY.values() if d.from_type == entity_type]
|
|
|
|
|
|
def relations_to(entity_type: str) -> list[RelationDef]:
|
|
"""All relations where *entity_type* is the ``to`` side."""
|
|
return [d for d in _RELATION_REGISTRY.values() if d.to_type == entity_type]
|
|
|
|
|
|
def all_relations() -> list[RelationDef]:
|
|
"""Return all registered relations."""
|
|
return list(_RELATION_REGISTRY.values())
|
|
|
|
|
|
def clear_registry() -> None:
|
|
"""Clear all registered relations (for testing)."""
|
|
_RELATION_REGISTRY.clear()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Built-in relation definitions (s-expression source)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_BUILTIN_RELATIONS = '''
|
|
(begin
|
|
|
|
(defrelation :page->market
|
|
:from "page"
|
|
:to "market"
|
|
:cardinality :one-to-many
|
|
:inverse :market->page
|
|
:nav :submenu
|
|
:nav-icon "fa fa-shopping-bag"
|
|
:nav-label "markets")
|
|
|
|
(defrelation :page->calendar
|
|
:from "page"
|
|
:to "calendar"
|
|
:cardinality :one-to-many
|
|
:inverse :calendar->page
|
|
:nav :submenu
|
|
:nav-icon "fa fa-calendar"
|
|
:nav-label "calendars")
|
|
|
|
(defrelation :post->calendar_entry
|
|
:from "post"
|
|
:to "calendar_entry"
|
|
:cardinality :many-to-many
|
|
:inverse :calendar_entry->post
|
|
:nav :inline
|
|
:nav-icon "fa fa-file-alt"
|
|
:nav-label "events")
|
|
|
|
(defrelation :page->menu_node
|
|
:from "page"
|
|
:to "menu_node"
|
|
:cardinality :one-to-one
|
|
:nav :hidden)
|
|
|
|
)
|
|
'''
|
|
|
|
|
|
def load_relation_registry() -> None:
|
|
"""Parse built-in defrelation s-expressions and populate the registry."""
|
|
from shared.sx.evaluator import evaluate
|
|
from shared.sx.parser import parse
|
|
|
|
tree = parse(_BUILTIN_RELATIONS)
|
|
evaluate(tree)
|