Implement BaseModel class, TimestampMixin, TzDateTime type; cleanup Task model

This commit is contained in:
Lexi / Zoe 2022-04-15 21:45:10 +02:00
parent 7ce43a2bfe
commit 252c15acbd
Signed by: binaryDiv
GPG key ID: F8D4956E224DA232
15 changed files with 223 additions and 42 deletions

View file

@ -1 +1,3 @@
from .metadata import MetaData
from .sqlalchemy import SQLAlchemy
from .typing import Col, Rel

View file

@ -0,0 +1,25 @@
from sqlalchemy import MetaData as _MetaData
__all__ = [
'MetaData',
]
class MetaData(_MetaData):
"""
App specific subclass of the SQLAlchemy MetaData class.
"""
# Define naming convention for constraints
_naming_convention = {
"ix": 'ix_%(column_0_label)s',
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(constraint_name)s",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s"
}
def __init__(self, *args, naming_convention=None, **kwargs):
if not naming_convention:
naming_convention = self._naming_convention
super().__init__(*args, naming_convention=naming_convention, **kwargs)

View file

@ -0,0 +1,23 @@
from datetime import datetime
from sqlalchemy import Column, func
from sqlalchemy.orm import declarative_mixin
from tofu_api.common.database import Col
from tofu_api.common.database.types import TzDateTime
__all__ = [
'TimestampMixin'
]
@declarative_mixin
class TimestampMixin:
"""
Mixin for database models that provides the "created_at" and "modified_at" columns.
"""
# Created timestamp (automatically set to NOW() once on object creation)
created_at: Col[datetime] = Column(TzDateTime, nullable=False, server_default=func.now())
# Modified timestamp (automatically set to NOW() on each update)
modified_at: Col[datetime] = Column(TzDateTime, nullable=False, server_default=func.now(), onupdate=func.now())

View file

@ -0,0 +1 @@
from .tz_date_time import TzDateTime

View file

@ -0,0 +1,39 @@
from datetime import datetime, timezone
from sqlalchemy import DateTime, TypeDecorator
__all__ = [
'TzDateTime',
]
class TzDateTime(TypeDecorator):
"""
Custom SQLAlchemy data type for timezone aware datetimes.
"""
impl = DateTime
cache_ok = True
@property
def python_type(self):
return datetime
def process_bind_param(self, value: datetime, dialect):
"""
Convert a datetime object that is bound to a query parameter.
"""
if value is not None and value.tzinfo:
value = value.astimezone(timezone.utc).replace(tzinfo=None)
return value
def process_result_value(self, value: datetime, dialect):
"""
Convert a datetime object from a query result.
"""
return value.replace(tzinfo=timezone.utc) if value is not None else None
def process_literal_param(self, value: datetime, dialect):
"""
Convert a literal parameter value to be rendered inline within a statement.
"""
return self.process_bind_param(value, dialect)

View file

@ -0,0 +1,14 @@
from typing import TypeVar, Union
from sqlalchemy import Column
from sqlalchemy.orm import RelationshipProperty
__all__ = [
'Col',
'Rel',
]
# Define type aliases for SQLAlchemy columns and relationships in declarative models
_T = TypeVar('_T')
Col = Union[Column, _T]
Rel = Union[RelationshipProperty, _T]