Files
boc/landvex-admin-backend/app/db/base.py
T
Bernt aee0f09db8 landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar
- Vision: Identify-modell, FAISS, OCR alla testade
- API: Alla 7 integrationstester passerade
- Upplösare: Entitetsupplösning verifierad
2026-07-05 06:41:32 +00:00

72 lines
2.4 KiB
Python

"""
LandveX Admin Backend — Database Base Model
SQLAlchemy declarative base and mixins
"""
from datetime import datetime, timezone
from typing import Any, Dict
from uuid import uuid4
from sqlalchemy import Column, DateTime, String, event
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import DeclarativeBase, declared_attr
class Base(DeclarativeBase):
"""Base class for all database models."""
# Generate tablename automatically from class name
@declared_attr.directive
def __tablename__(cls) -> str:
return cls.__name__.lower() + "s"
# Common columns for all tables
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
def to_dict(self) -> Dict[str, Any]:
"""Convert model instance to dictionary."""
result = {}
for column in self.__table__.columns:
value = getattr(self, column.name)
if value is not None:
if isinstance(value, datetime):
result[column.name] = value.isoformat()
else:
result[column.name] = value
return result
def __repr__(self) -> str:
return f"<{self.__class__.__name__}(id={self.id})>"
class AuditMixin:
"""Mixin to add audit fields to models."""
created_by = Column(String(255), nullable=True)
updated_by = Column(String(255), nullable=True)
deleted_at = Column(DateTime(timezone=True), nullable=True)
deleted_by = Column(String(255), nullable=True)
is_deleted = Column(String(1), default="N") # Soft delete flag
@property
def is_active(self) -> bool:
"""Check if record is active (not soft-deleted)."""
return self.is_deleted == "N" and self.deleted_at is None
class MetadataMixin:
"""Mixin to add JSON metadata field to models."""
metadata_json = Column("metadata", JSONB, default=dict)
def get_metadata(self) -> Dict[str, Any]:
"""Get metadata as dictionary."""
return self.metadata_json or {}
def set_metadata(self, key: str, value: Any) -> None:
"""Set a metadata value."""
if self.metadata_json is None:
self.metadata_json = {}
self.metadata_json[key] = value