forked from cartsnitch/cartsnitch
692f42fbbb
- Revert auth/dependencies.py, auth/routes.py, services/auth.py, schemas.py to Better-Auth session-cookie auth (removed JWT register/login/refresh) - Preserve GET /auth/me/email-in-address endpoint - Fix UUIDString TypeDecorator: process_result_value returns uuid.UUID (not str) so SQLAlchemy 2.0 sentinel tracking matches UUID-to-UUID - Fix seed_data fixture: look up real user_id from session token via sessions table; purchases now reference actual user FK - Update purchase_data fixture to use session-cookie auth - Update test_auth_endpoints, test_auth_validation to cookie-based tests - Remove TestRegistrationErrors and TestLoginErrors (no longer applicable) - Update test_openapi.py expected routes and count - Update test_error_handler.py to use PATCH /auth/me validation Co-Authored-By: Paperclip <noreply@paperclip.ing>
64 lines
1.9 KiB
Python
64 lines
1.9 KiB
Python
"""Base model and mixins for all CartSnitch ORM models."""
|
|
|
|
import uuid as uuid_lib
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import DateTime, String, TypeDecorator, func
|
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
|
|
|
|
class UUIDString(TypeDecorator):
|
|
"""Store UUIDs as VARCHAR(36) strings in all dialects.
|
|
|
|
This handles the fundamental mismatch between Python's uuid.UUID objects
|
|
(used everywhere in application code) and SQLite's lack of a native UUID type.
|
|
- On INSERT: converts uuid.UUID → str
|
|
- On SELECT: returns uuid.UUID (so SQLAlchemy 2.0 sentinel tracking matches correctly)
|
|
"""
|
|
|
|
impl = String(36)
|
|
cache_ok = True
|
|
|
|
def process_bind_param(self, value, dialect):
|
|
if value is None:
|
|
return value
|
|
if isinstance(value, uuid_lib.UUID):
|
|
return str(value)
|
|
return value # already a string
|
|
|
|
def process_result_value(self, value, dialect):
|
|
if value is None:
|
|
return value
|
|
if isinstance(value, uuid_lib.UUID):
|
|
return value
|
|
return uuid_lib.UUID(value) # convert str → UUID for correct sentinel tracking
|
|
|
|
|
|
class Base(DeclarativeBase):
|
|
"""Base class for all CartSnitch models."""
|
|
|
|
|
|
class TimestampMixin:
|
|
"""Mixin providing created_at / updated_at columns."""
|
|
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False
|
|
)
|
|
|
|
|
|
class UUIDPrimaryKeyMixin:
|
|
"""Mixin providing a UUID primary key.
|
|
|
|
Uses UUIDString so all DB dialects store the full 36-char UUID string
|
|
without truncation, while Python code always works with uuid.UUID objects.
|
|
"""
|
|
|
|
id: Mapped[uuid_lib.UUID] = mapped_column(
|
|
UUIDString(),
|
|
primary_key=True,
|
|
default=uuid_lib.uuid4,
|
|
)
|