mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-17 13:08:19 -04:00
setup multy db suport
This commit is contained in:
22
python/orm/richie/__init__.py
Normal file
22
python/orm/richie/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""Richie database ORM exports."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from python.orm.richie.base import RichieBase, TableBase
|
||||
from python.orm.richie.contact import (
|
||||
Contact,
|
||||
ContactNeed,
|
||||
ContactRelationship,
|
||||
Need,
|
||||
RelationshipType,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"Contact",
|
||||
"ContactNeed",
|
||||
"ContactRelationship",
|
||||
"Need",
|
||||
"RelationshipType",
|
||||
"RichieBase",
|
||||
"TableBase",
|
||||
]
|
||||
39
python/orm/richie/base.py
Normal file
39
python/orm/richie/base.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""Richie database ORM base."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, MetaData, func
|
||||
from sqlalchemy.ext.declarative import AbstractConcreteBase
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||
|
||||
from python.orm.common import NAMING_CONVENTION
|
||||
|
||||
|
||||
class RichieBase(DeclarativeBase):
|
||||
"""Base class for richie database ORM models."""
|
||||
|
||||
schema_name = "main"
|
||||
|
||||
metadata = MetaData(
|
||||
schema=schema_name,
|
||||
naming_convention=NAMING_CONVENTION,
|
||||
)
|
||||
|
||||
|
||||
class TableBase(AbstractConcreteBase, RichieBase):
|
||||
"""Abstract concrete base for richie tables with IDs and timestamps."""
|
||||
|
||||
__abstract__ = True
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
created: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now(),
|
||||
)
|
||||
updated: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
server_default=func.now(),
|
||||
onupdate=func.now(),
|
||||
)
|
||||
168
python/orm/richie/contact.py
Normal file
168
python/orm/richie/contact.py
Normal file
@@ -0,0 +1,168 @@
|
||||
"""Contact database models."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from sqlalchemy import ForeignKey, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from python.orm.richie.base import RichieBase, TableBase
|
||||
|
||||
|
||||
class RelationshipType(str, Enum):
|
||||
"""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",
|
||||
)
|
||||
Reference in New Issue
Block a user