From 81407c3038ee0b4a26649d984d38af2505263dc2 Mon Sep 17 00:00:00 2001 From: d3vyce <44915747+d3vyce@users.noreply.github.com> Date: Sat, 14 Mar 2026 17:30:11 +0100 Subject: [PATCH] fix: use clock_timestamp() instead of now() for Mixin to ensure unique values (#138) --- docs/module/models.md | 6 +++--- docs_src/examples/pagination_search/models.py | 10 ++++------ src/fastapi_toolsets/models.py | 8 ++++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/docs/module/models.md b/docs/module/models.md index d470258..bf07232 100644 --- a/docs/module/models.md +++ b/docs/module/models.md @@ -18,7 +18,7 @@ class Article(Base, UUIDMixin, TimestampMixin): content: Mapped[str] ``` -All timestamp columns are timezone-aware (`TIMESTAMPTZ`). All defaults are server-side, so they are also applied when inserting rows via raw SQL outside the ORM. +All timestamp columns are timezone-aware (`TIMESTAMPTZ`). All defaults are server-side (`clock_timestamp()`), so they are also applied when inserting rows via raw SQL outside the ORM. ## Mixins @@ -42,7 +42,7 @@ print(user.id) # UUID('...') ### [`CreatedAtMixin`](../reference/models.md#fastapi_toolsets.models.CreatedAtMixin) -Adds a `created_at: datetime` column set to `NOW()` on insert. The column has no `onupdate` hook — it is intentionally immutable after the row is created. +Adds a `created_at: datetime` column set to `clock_timestamp()` on insert. The column has no `onupdate` hook — it is intentionally immutable after the row is created. ```python from fastapi_toolsets.models import UUIDMixin, CreatedAtMixin @@ -55,7 +55,7 @@ class Order(Base, UUIDMixin, CreatedAtMixin): ### [`UpdatedAtMixin`](../reference/models.md#fastapi_toolsets.models.UpdatedAtMixin) -Adds an `updated_at: datetime` column set to `NOW()` on insert and automatically updated to `NOW()` on every ORM-level update (via SQLAlchemy's `onupdate` hook). +Adds an `updated_at: datetime` column set to `clock_timestamp()` on insert and automatically updated to `clock_timestamp()` on every ORM-level update (via SQLAlchemy's `onupdate` hook). ```python from fastapi_toolsets.models import UUIDMixin, UpdatedAtMixin diff --git a/docs_src/examples/pagination_search/models.py b/docs_src/examples/pagination_search/models.py index 83df37b..f3969fd 100644 --- a/docs_src/examples/pagination_search/models.py +++ b/docs_src/examples/pagination_search/models.py @@ -1,9 +1,10 @@ -import datetime import uuid -from sqlalchemy import Boolean, DateTime, ForeignKey, String, Text, func +from sqlalchemy import Boolean, ForeignKey, String, Text from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship +from fastapi_toolsets.models import CreatedAtMixin + class Base(DeclarativeBase): pass @@ -18,13 +19,10 @@ class Category(Base): articles: Mapped[list["Article"]] = relationship(back_populates="category") -class Article(Base): +class Article(Base, CreatedAtMixin): __tablename__ = "articles" id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4) - created_at: Mapped[datetime.datetime] = mapped_column( - DateTime(timezone=True), server_default=func.now() - ) title: Mapped[str] = mapped_column(String(256)) body: Mapped[str] = mapped_column(Text) status: Mapped[str] = mapped_column(String(32)) diff --git a/src/fastapi_toolsets/models.py b/src/fastapi_toolsets/models.py index bbc269b..72a8127 100644 --- a/src/fastapi_toolsets/models.py +++ b/src/fastapi_toolsets/models.py @@ -3,7 +3,7 @@ import uuid from datetime import datetime -from sqlalchemy import DateTime, Uuid, func, text +from sqlalchemy import DateTime, Uuid, text from sqlalchemy.orm import Mapped, mapped_column __all__ = [ @@ -29,7 +29,7 @@ class CreatedAtMixin: created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), - server_default=func.now(), + server_default=text("clock_timestamp()"), ) @@ -38,8 +38,8 @@ class UpdatedAtMixin: updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), - server_default=func.now(), - onupdate=func.now(), + server_default=text("clock_timestamp()"), + onupdate=text("clock_timestamp()"), )