diff --git a/app/models/contact.py b/app/models/contact.py new file mode 100644 index 0000000..f3d081f --- /dev/null +++ b/app/models/contact.py @@ -0,0 +1,62 @@ +"""Contact model: people at accounts (or standalone contacts).""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Optional + +from sqlalchemy import ForeignKey, String +from sqlalchemy.orm import Mapped, mapped_column, relationship + +from app.models.base import Base, OrgScopedMixin, SoftDeleteMixin, TimestampMixin + +if TYPE_CHECKING: + from app.models.user import User + from app.models.account import Account + from app.models.activity import Activity + from app.models.note import Note + from app.models.tag_link import TagLink + + +class Contact(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin): + __tablename__ = "contacts" + + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + first_name: Mapped[str] = mapped_column(String(128), nullable=False) + last_name: Mapped[str] = mapped_column(String(128), nullable=False, index=True) + email: Mapped[Optional[str]] = mapped_column(String(255), nullable=True, index=True) + phone: Mapped[Optional[str]] = mapped_column(String(64), nullable=True) + account_id: Mapped[Optional[int]] = mapped_column( + ForeignKey("accounts.id"), nullable=True, index=True + ) + owner_id: Mapped[int] = mapped_column( + ForeignKey("users.id"), nullable=False, index=True + ) + + # Relationships + account: Mapped[Optional["Account"]] = relationship( + "Account", back_populates="contacts", lazy="selectin" + ) + owner: Mapped["User"] = relationship( + "User", foreign_keys=[owner_id], lazy="joined" + ) + activities: Mapped[list["Activity"]] = relationship( + "Activity", back_populates="contact", lazy="selectin" + ) + notes: Mapped[list["Note"]] = relationship( + "Note", + primaryjoin="and_(Contact.id==foreign(Note.parent_id), Note.parent_type=='contact')", + viewonly=True, + lazy="selectin", + ) + tags: Mapped[list["TagLink"]] = relationship( + "TagLink", + primaryjoin="and_(Contact.id==foreign(TagLink.parent_id), TagLink.parent_type=='contact')", + viewonly=True, + lazy="selectin", + ) + + def __repr__(self) -> str: + return f"" + + +__all__ = ["Contact"]