aee0f09db8
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
72 lines
2.4 KiB
Python
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
|