intermittent commit

This commit is contained in:
2026-07-14 13:22:09 +02:00
parent 420120af2f
commit f19350e65d
32 changed files with 11772 additions and 11 deletions
@@ -0,0 +1,2 @@
"""Address module database models."""
+330
View File
@@ -0,0 +1,330 @@
from __future__ import annotations
import uuid
from datetime import datetime
from typing import Any
from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, JSON, String, Text, text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from govoplan_core.db.base import Base, TimestampMixin
def new_uuid() -> str:
return str(uuid.uuid4())
class AddressBook(Base, TimestampMixin):
__tablename__ = "addresses_address_books"
__table_args__ = (
Index("ix_addresses_address_books_scope", "tenant_id", "scope_type", "scope_id"),
Index(
"uq_addresses_address_books_active_name",
"tenant_id",
"scope_type",
"scope_id",
"name",
unique=True,
sqlite_where=text("deleted_at IS NULL"),
postgresql_where=text("deleted_at IS NULL"),
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
scope_type: Mapped[str] = mapped_column(String(20), nullable=False, index=True)
scope_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
name: Mapped[str] = mapped_column(String(255), nullable=False)
description: Mapped[str | None] = mapped_column(Text)
source_kind: Mapped[str] = mapped_column(String(30), default="local", nullable=False, index=True)
source_ref: Mapped[str | None] = mapped_column(String(1000))
read_only: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
sync_status: Mapped[str | None] = mapped_column(String(30))
sync_error: Mapped[str | None] = mapped_column(Text)
created_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
updated_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True)
contacts: Mapped[list["Contact"]] = relationship(back_populates="address_book", cascade="all, delete-orphan")
address_lists: Mapped[list["AddressList"]] = relationship(back_populates="address_book", cascade="all, delete-orphan")
sync_sources: Mapped[list["AddressSyncSource"]] = relationship(back_populates="address_book", cascade="all, delete-orphan")
class Contact(Base, TimestampMixin):
__tablename__ = "addresses_contacts"
__table_args__ = (
Index("ix_addresses_contacts_book_name", "address_book_id", "display_name"),
Index("ix_addresses_contacts_tenant_name", "tenant_id", "display_name"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
address_book_id: Mapped[str] = mapped_column(
ForeignKey("addresses_address_books.id", ondelete="CASCADE"),
nullable=False,
index=True,
)
display_name: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
given_name: Mapped[str | None] = mapped_column(String(255))
family_name: Mapped[str | None] = mapped_column(String(255))
organization: Mapped[str | None] = mapped_column(String(255), index=True)
role_title: Mapped[str | None] = mapped_column(String(255))
note: Mapped[str | None] = mapped_column(Text)
tags: Mapped[list[str]] = mapped_column(JSON, default=list, nullable=False)
source_kind: Mapped[str] = mapped_column(String(30), default="local", nullable=False, index=True)
source_ref: Mapped[str | None] = mapped_column(String(1000))
source_payload_kind: Mapped[str | None] = mapped_column(String(40), nullable=True, index=True)
source_payload_raw: Mapped[str | None] = mapped_column(Text, nullable=True)
source_revision: Mapped[str | None] = mapped_column(String(255), nullable=True, index=True)
provenance: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, nullable=False)
created_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
updated_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True)
address_book: Mapped[AddressBook] = relationship(back_populates="contacts")
emails: Mapped[list["ContactEmail"]] = relationship(back_populates="contact", cascade="all, delete-orphan", order_by="ContactEmail.order_index")
phones: Mapped[list["ContactPhone"]] = relationship(back_populates="contact", cascade="all, delete-orphan", order_by="ContactPhone.order_index")
postal_addresses: Mapped[list["ContactPostalAddress"]] = relationship(
back_populates="contact",
cascade="all, delete-orphan",
order_by="ContactPostalAddress.order_index",
)
address_list_entries: Mapped[list["AddressListEntry"]] = relationship(back_populates="contact", cascade="all, delete-orphan")
class ContactEmail(Base, TimestampMixin):
__tablename__ = "addresses_contact_emails"
__table_args__ = (
Index("ix_addresses_contact_emails_lookup", "email"),
Index("ix_addresses_contact_emails_contact_primary", "contact_id", "is_primary"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
contact_id: Mapped[str] = mapped_column(ForeignKey("addresses_contacts.id", ondelete="CASCADE"), nullable=False, index=True)
label: Mapped[str | None] = mapped_column(String(80))
email: Mapped[str] = mapped_column(String(320), nullable=False, index=True)
is_primary: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
order_index: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
contact: Mapped[Contact] = relationship(back_populates="emails")
address_list_entries: Mapped[list["AddressListEntry"]] = relationship(back_populates="contact_email")
class ContactPhone(Base, TimestampMixin):
__tablename__ = "addresses_contact_phones"
__table_args__ = (Index("ix_addresses_contact_phones_contact_primary", "contact_id", "is_primary"),)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
contact_id: Mapped[str] = mapped_column(ForeignKey("addresses_contacts.id", ondelete="CASCADE"), nullable=False, index=True)
label: Mapped[str | None] = mapped_column(String(80))
phone: Mapped[str] = mapped_column(String(100), nullable=False)
is_primary: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
order_index: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
contact: Mapped[Contact] = relationship(back_populates="phones")
class ContactPostalAddress(Base, TimestampMixin):
__tablename__ = "addresses_contact_postal_addresses"
__table_args__ = (Index("ix_addresses_contact_postal_addresses_contact_primary", "contact_id", "is_primary"),)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
contact_id: Mapped[str] = mapped_column(ForeignKey("addresses_contacts.id", ondelete="CASCADE"), nullable=False, index=True)
label: Mapped[str | None] = mapped_column(String(80))
street: Mapped[str | None] = mapped_column(String(500))
postal_code: Mapped[str | None] = mapped_column(String(40))
locality: Mapped[str | None] = mapped_column(String(255))
region: Mapped[str | None] = mapped_column(String(255))
country: Mapped[str | None] = mapped_column(String(255))
is_primary: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
order_index: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
contact: Mapped[Contact] = relationship(back_populates="postal_addresses")
address_list_entries: Mapped[list["AddressListEntry"]] = relationship(back_populates="contact_postal_address")
class AddressList(Base, TimestampMixin):
__tablename__ = "addresses_address_lists"
__table_args__ = (
Index("ix_addresses_address_lists_book_name", "address_book_id", "name"),
Index(
"uq_addresses_address_lists_active_name",
"address_book_id",
"name",
unique=True,
sqlite_where=text("deleted_at IS NULL"),
postgresql_where=text("deleted_at IS NULL"),
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
address_book_id: Mapped[str] = mapped_column(ForeignKey("addresses_address_books.id", ondelete="CASCADE"), nullable=False, index=True)
name: Mapped[str] = mapped_column(String(255), nullable=False)
description: Mapped[str | None] = mapped_column(Text)
source_kind: Mapped[str] = mapped_column(String(30), default="local", nullable=False, index=True)
source_ref: Mapped[str | None] = mapped_column(String(1000))
read_only: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
created_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
updated_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True)
address_book: Mapped[AddressBook] = relationship(back_populates="address_lists")
entries: Mapped[list["AddressListEntry"]] = relationship(
back_populates="address_list",
cascade="all, delete-orphan",
order_by="AddressListEntry.order_index",
)
class AddressListEntry(Base, TimestampMixin):
__tablename__ = "addresses_address_list_entries"
__table_args__ = (
Index("ix_addresses_address_list_entries_list_order", "address_list_id", "order_index"),
Index("ix_addresses_address_list_entries_contact", "contact_id"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
address_list_id: Mapped[str] = mapped_column(ForeignKey("addresses_address_lists.id", ondelete="CASCADE"), nullable=False, index=True)
contact_id: Mapped[str] = mapped_column(ForeignKey("addresses_contacts.id", ondelete="CASCADE"), nullable=False, index=True)
contact_email_id: Mapped[str | None] = mapped_column(ForeignKey("addresses_contact_emails.id", ondelete="SET NULL"), nullable=True, index=True)
contact_postal_address_id: Mapped[str | None] = mapped_column(
ForeignKey("addresses_contact_postal_addresses.id", ondelete="SET NULL"),
nullable=True,
index=True,
)
target_kind: Mapped[str] = mapped_column(String(30), default="contact", nullable=False, index=True)
label: Mapped[str | None] = mapped_column(String(255))
order_index: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True)
address_list: Mapped[AddressList] = relationship(back_populates="entries")
contact: Mapped[Contact] = relationship(back_populates="address_list_entries")
contact_email: Mapped[ContactEmail | None] = relationship(back_populates="address_list_entries")
contact_postal_address: Mapped[ContactPostalAddress | None] = relationship(back_populates="address_list_entries")
class AddressSyncSource(Base, TimestampMixin):
__tablename__ = "addresses_sync_sources"
__table_args__ = (
Index("ix_addresses_sync_sources_book_status", "address_book_id", "status"),
Index("ix_addresses_sync_sources_connector", "tenant_id", "connector_type"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
address_book_id: Mapped[str] = mapped_column(ForeignKey("addresses_address_books.id", ondelete="CASCADE"), nullable=False, index=True)
connector_type: Mapped[str] = mapped_column(String(60), nullable=False, index=True)
display_name: Mapped[str] = mapped_column(String(255), nullable=False)
external_account_ref: Mapped[str | None] = mapped_column(String(1000), nullable=True)
external_address_book_ref: Mapped[str | None] = mapped_column(String(1000), nullable=True)
sync_direction: Mapped[str] = mapped_column(String(30), default="read_only", nullable=False, index=True)
read_only: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False, index=True)
status: Mapped[str] = mapped_column(String(30), default="idle", nullable=False, index=True)
sync_token: Mapped[str | None] = mapped_column(Text, nullable=True)
etag: Mapped[str | None] = mapped_column(String(1000), nullable=True)
remote_revision: Mapped[str | None] = mapped_column(String(1000), nullable=True)
last_attempted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
last_success_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
last_error: Mapped[str | None] = mapped_column(Text, nullable=True)
last_diagnostic: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
created_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
updated_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True)
address_book: Mapped[AddressBook] = relationship(back_populates="sync_sources")
tombstones: Mapped[list["AddressSyncTombstone"]] = relationship(back_populates="sync_source", cascade="all, delete-orphan")
conflicts: Mapped[list["AddressSyncConflict"]] = relationship(back_populates="sync_source", cascade="all, delete-orphan")
diagnostics: Mapped[list["AddressSyncDiagnostic"]] = relationship(back_populates="sync_source", cascade="all, delete-orphan")
class AddressSyncTombstone(Base, TimestampMixin):
__tablename__ = "addresses_sync_tombstones"
__table_args__ = (
Index("ix_addresses_sync_tombstones_source_remote", "sync_source_id", "remote_uid"),
Index("ix_addresses_sync_tombstones_source_href", "sync_source_id", "resource_href"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
sync_source_id: Mapped[str] = mapped_column(ForeignKey("addresses_sync_sources.id", ondelete="CASCADE"), nullable=False, index=True)
address_book_id: Mapped[str] = mapped_column(ForeignKey("addresses_address_books.id", ondelete="CASCADE"), nullable=False, index=True)
contact_id: Mapped[str | None] = mapped_column(ForeignKey("addresses_contacts.id", ondelete="SET NULL"), nullable=True, index=True)
remote_uid: Mapped[str | None] = mapped_column(String(1000), nullable=True)
resource_href: Mapped[str | None] = mapped_column(String(1000), nullable=True)
local_deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
remote_deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
synced_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True)
sync_source: Mapped[AddressSyncSource] = relationship(back_populates="tombstones")
address_book: Mapped[AddressBook] = relationship()
contact: Mapped[Contact | None] = relationship()
class AddressSyncConflict(Base, TimestampMixin):
__tablename__ = "addresses_sync_conflicts"
__table_args__ = (
Index("ix_addresses_sync_conflicts_source_status", "sync_source_id", "status"),
Index("ix_addresses_sync_conflicts_contact_status", "contact_id", "status"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
sync_source_id: Mapped[str] = mapped_column(ForeignKey("addresses_sync_sources.id", ondelete="CASCADE"), nullable=False, index=True)
address_book_id: Mapped[str] = mapped_column(ForeignKey("addresses_address_books.id", ondelete="CASCADE"), nullable=False, index=True)
contact_id: Mapped[str | None] = mapped_column(ForeignKey("addresses_contacts.id", ondelete="SET NULL"), nullable=True, index=True)
remote_uid: Mapped[str | None] = mapped_column(String(1000), nullable=True)
resource_href: Mapped[str | None] = mapped_column(String(1000), nullable=True)
field_path: Mapped[str] = mapped_column(String(500), nullable=False)
local_value: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
remote_value: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
local_updated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
remote_updated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
status: Mapped[str] = mapped_column(String(30), default="open", nullable=False, index=True)
resolution: Mapped[str | None] = mapped_column(String(60), nullable=True)
resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
resolved_by_account_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
metadata_: Mapped[dict[str, Any] | None] = mapped_column("metadata", JSON, nullable=True)
sync_source: Mapped[AddressSyncSource] = relationship(back_populates="conflicts")
address_book: Mapped[AddressBook] = relationship()
contact: Mapped[Contact | None] = relationship()
class AddressSyncDiagnostic(Base, TimestampMixin):
__tablename__ = "addresses_sync_diagnostics"
__table_args__ = (
Index("ix_addresses_sync_diagnostics_source_created", "sync_source_id", "created_at"),
Index("ix_addresses_sync_diagnostics_source_severity", "sync_source_id", "severity"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True)
sync_source_id: Mapped[str] = mapped_column(ForeignKey("addresses_sync_sources.id", ondelete="CASCADE"), nullable=False, index=True)
severity: Mapped[str] = mapped_column(String(30), default="info", nullable=False, index=True)
code: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
message: Mapped[str] = mapped_column(Text, nullable=False)
details: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
sync_source: Mapped[AddressSyncSource] = relationship(back_populates="diagnostics")
__all__ = [
"AddressBook",
"AddressList",
"AddressListEntry",
"AddressSyncConflict",
"AddressSyncDiagnostic",
"AddressSyncSource",
"AddressSyncTombstone",
"Contact",
"ContactEmail",
"ContactPhone",
"ContactPostalAddress",
"new_uuid",
]