Source code for loom.core.model.timestamped

"""Opt-in timestamped base model.

Provides :class:`TimestampedModel` for domain models that require audit
timestamps.  Timestamps are populated by the database server, not by
application code, avoiding clock-skew issues in distributed deployments.

Usage::

    from loom.core.model import TimestampedModel, ColumnField, DateTime

    class Order(TimestampedModel):
        __tablename__ = "orders"
        id: int = ColumnField(primary_key=True, autoincrement=True)
        total: float
"""

from __future__ import annotations

from datetime import datetime

from loom.core.model.base import BaseModel
from loom.core.model.enums import ServerDefault, ServerOnUpdate
from loom.core.model.field import ColumnField


[docs] class TimestampedModel(BaseModel): """Opt-in base for domain models that need audit timestamps. Adds ``created_at`` and ``updated_at`` as nullable server-default columns. Both fields are omitted from serialisation output when ``None`` (``omit_defaults=True`` is inherited from :class:`BaseModel`). **Design note:** ``trace_id`` is intentionally absent. Trace identifiers are an observability concern belonging to the transport layer, not to the domain model. Correlating a record with the request that created it is the responsibility of structured logs and SQL query comments — not of a model field. Attributes: created_at: UTC timestamp set by the database at INSERT time. ``None`` until the first flush/commit. updated_at: UTC timestamp updated by the database on every UPDATE. ``None`` until the first flush/commit. Example:: class Product(TimestampedModel): __tablename__ = "products" id: int = ColumnField(primary_key=True, autoincrement=True) name: str """ created_at: datetime | None = ColumnField( server_default=ServerDefault.NOW, nullable=True, ) updated_at: datetime | None = ColumnField( server_default=ServerDefault.NOW, server_onupdate=ServerOnUpdate.NOW, nullable=True, )