64 lines
2.2 KiB
Python
64 lines
2.2 KiB
Python
"""
|
||
Modelli Label e MessageLabel – tagging messaggi con supporto tassonomia gerarchica.
|
||
|
||
Struttura ad albero (Feature N2 – Tassonomia di Classificazione Multi-livello):
|
||
parent_id = NULL → Livello 0: Ambito (Area Aziendale)
|
||
parent_id = ID ambito → Livello 1: Processo
|
||
parent_id = ID processo → Livello 2: Classificazione (foglia)
|
||
|
||
Le label senza parent_id sono label "piatte" classiche (comportamento pre-esistente).
|
||
"""
|
||
|
||
import uuid
|
||
|
||
from sqlalchemy import CHAR, ForeignKey, Index, String, Text
|
||
from sqlalchemy.dialects.postgresql import UUID
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from app.database import Base
|
||
|
||
|
||
class Label(Base):
|
||
__tablename__ = "labels"
|
||
|
||
id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
||
)
|
||
tenant_id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False
|
||
)
|
||
# Tassonomia: se parent_id è None è un nodo radice (Ambito) o label piatta
|
||
parent_id: Mapped[uuid.UUID | None] = mapped_column(
|
||
UUID(as_uuid=True),
|
||
ForeignKey("labels.id", ondelete="CASCADE"),
|
||
nullable=True,
|
||
)
|
||
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
||
color: Mapped[str | None] = mapped_column(CHAR(7), nullable=True) # hex #RRGGBB
|
||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
|
||
# Nota: i vincoli di unicità sono gestiti da indici parziali nel DB:
|
||
# uq_label_name_root – UNIQUE (tenant_id, name) WHERE parent_id IS NULL
|
||
# uq_label_name_parent – UNIQUE (tenant_id, name, parent_id) WHERE parent_id IS NOT NULL
|
||
__table_args__ = (
|
||
Index("idx_labels_parent", "parent_id"),
|
||
)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<Label {self.name!r} parent={self.parent_id}>"
|
||
|
||
|
||
class MessageLabel(Base):
|
||
__tablename__ = "message_labels"
|
||
|
||
message_id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True),
|
||
ForeignKey("messages.id", ondelete="CASCADE"),
|
||
primary_key=True,
|
||
)
|
||
label_id: Mapped[uuid.UUID] = mapped_column(
|
||
UUID(as_uuid=True),
|
||
ForeignKey("labels.id", ondelete="CASCADE"),
|
||
primary_key=True,
|
||
)
|