mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-17 13:08:19 -04:00
169 lines
4.9 KiB
Python
169 lines
4.9 KiB
Python
"""Contact database models."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from enum import StrEnum
|
|
|
|
from sqlalchemy import ForeignKey, String
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from python.orm.richie.base import RichieBase, TableBase
|
|
|
|
|
|
class RelationshipType(StrEnum):
|
|
"""Relationship types with default closeness weights.
|
|
|
|
Default weight is an integer 1-10 where 10 = closest relationship.
|
|
Users can override this per-relationship in the UI.
|
|
"""
|
|
|
|
SPOUSE = "spouse"
|
|
PARTNER = "partner"
|
|
PARENT = "parent"
|
|
CHILD = "child"
|
|
SIBLING = "sibling"
|
|
BEST_FRIEND = "best_friend"
|
|
GRANDPARENT = "grandparent"
|
|
GRANDCHILD = "grandchild"
|
|
AUNT_UNCLE = "aunt_uncle"
|
|
NIECE_NEPHEW = "niece_nephew"
|
|
COUSIN = "cousin"
|
|
IN_LAW = "in_law"
|
|
CLOSE_FRIEND = "close_friend"
|
|
FRIEND = "friend"
|
|
MENTOR = "mentor"
|
|
MENTEE = "mentee"
|
|
BUSINESS_PARTNER = "business_partner"
|
|
COLLEAGUE = "colleague"
|
|
MANAGER = "manager"
|
|
DIRECT_REPORT = "direct_report"
|
|
CLIENT = "client"
|
|
ACQUAINTANCE = "acquaintance"
|
|
NEIGHBOR = "neighbor"
|
|
EX = "ex"
|
|
OTHER = "other"
|
|
|
|
@property
|
|
def default_weight(self) -> int:
|
|
"""Return the default closeness weight (1-10) for this relationship type."""
|
|
weights = {
|
|
RelationshipType.SPOUSE: 10,
|
|
RelationshipType.PARTNER: 10,
|
|
RelationshipType.PARENT: 9,
|
|
RelationshipType.CHILD: 9,
|
|
RelationshipType.SIBLING: 9,
|
|
RelationshipType.BEST_FRIEND: 8,
|
|
RelationshipType.GRANDPARENT: 7,
|
|
RelationshipType.GRANDCHILD: 7,
|
|
RelationshipType.AUNT_UNCLE: 7,
|
|
RelationshipType.NIECE_NEPHEW: 7,
|
|
RelationshipType.COUSIN: 7,
|
|
RelationshipType.IN_LAW: 7,
|
|
RelationshipType.CLOSE_FRIEND: 6,
|
|
RelationshipType.FRIEND: 6,
|
|
RelationshipType.MENTOR: 5,
|
|
RelationshipType.MENTEE: 5,
|
|
RelationshipType.BUSINESS_PARTNER: 5,
|
|
RelationshipType.COLLEAGUE: 4,
|
|
RelationshipType.MANAGER: 4,
|
|
RelationshipType.DIRECT_REPORT: 4,
|
|
RelationshipType.CLIENT: 4,
|
|
RelationshipType.ACQUAINTANCE: 3,
|
|
RelationshipType.NEIGHBOR: 3,
|
|
RelationshipType.EX: 2,
|
|
RelationshipType.OTHER: 2,
|
|
}
|
|
return weights.get(self, 5)
|
|
|
|
@property
|
|
def display_name(self) -> str:
|
|
"""Return a human-readable display name."""
|
|
return self.value.replace("_", " ").title()
|
|
|
|
|
|
class ContactNeed(RichieBase):
|
|
"""Association table: Contact <-> Need."""
|
|
|
|
__tablename__ = "contact_need"
|
|
|
|
contact_id: Mapped[int] = mapped_column(
|
|
ForeignKey("main.contact.id", ondelete="CASCADE"),
|
|
primary_key=True,
|
|
)
|
|
need_id: Mapped[int] = mapped_column(
|
|
ForeignKey("main.need.id", ondelete="CASCADE"),
|
|
primary_key=True,
|
|
)
|
|
|
|
|
|
class ContactRelationship(RichieBase):
|
|
"""Association table: Contact <-> Contact with relationship type and weight."""
|
|
|
|
__tablename__ = "contact_relationship"
|
|
|
|
contact_id: Mapped[int] = mapped_column(
|
|
ForeignKey("main.contact.id", ondelete="CASCADE"),
|
|
primary_key=True,
|
|
)
|
|
related_contact_id: Mapped[int] = mapped_column(
|
|
ForeignKey("main.contact.id", ondelete="CASCADE"),
|
|
primary_key=True,
|
|
)
|
|
relationship_type: Mapped[str] = mapped_column(String(100))
|
|
closeness_weight: Mapped[int] = mapped_column(default=5)
|
|
|
|
|
|
class Contact(TableBase):
|
|
"""Contact model."""
|
|
|
|
__tablename__ = "contact"
|
|
|
|
name: Mapped[str]
|
|
|
|
age: Mapped[int | None]
|
|
bio: Mapped[str | None]
|
|
current_job: Mapped[str | None]
|
|
gender: Mapped[str | None]
|
|
goals: Mapped[str | None]
|
|
legal_name: Mapped[str | None]
|
|
profile_pic: Mapped[str | None]
|
|
safe_conversation_starters: Mapped[str | None]
|
|
self_sufficiency_score: Mapped[int | None]
|
|
social_structure_style: Mapped[str | None]
|
|
ssn: Mapped[str | None]
|
|
suffix: Mapped[str | None]
|
|
timezone: Mapped[str | None]
|
|
topics_to_avoid: Mapped[str | None]
|
|
|
|
needs: Mapped[list[Need]] = relationship(
|
|
"Need",
|
|
secondary=ContactNeed.__table__,
|
|
back_populates="contacts",
|
|
)
|
|
|
|
related_to: Mapped[list[ContactRelationship]] = relationship(
|
|
"ContactRelationship",
|
|
foreign_keys=[ContactRelationship.contact_id],
|
|
cascade="all, delete-orphan",
|
|
)
|
|
related_from: Mapped[list[ContactRelationship]] = relationship(
|
|
"ContactRelationship",
|
|
foreign_keys=[ContactRelationship.related_contact_id],
|
|
cascade="all, delete-orphan",
|
|
)
|
|
|
|
|
|
class Need(TableBase):
|
|
"""Need/accommodation model (e.g., light sensitive, ADHD)."""
|
|
|
|
__tablename__ = "need"
|
|
|
|
name: Mapped[str]
|
|
description: Mapped[str | None]
|
|
|
|
contacts: Mapped[list[Contact]] = relationship(
|
|
"Contact",
|
|
secondary=ContactNeed.__table__,
|
|
back_populates="needs",
|
|
)
|