-
Notifications
You must be signed in to change notification settings - Fork 1
/
base.py
77 lines (63 loc) · 2.43 KB
/
base.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from __future__ import annotations
import re
from sqlalchemy import not_
from sqlalchemy.exc import NoResultFound
from sqlalchemy.orm import Query, Session, as_declarative, declared_attr
from rating_api.exceptions import ObjectNotFound
@as_declarative()
class Base:
"""Base class for all database entities"""
@declared_attr
def __tablename__(cls) -> str: # pylint: disable=no-self-argument
"""Generate database table name automatically.
Convert CamelCase class name to snake_case db table name.
"""
return re.sub(r"(?<!^)(?=[A-Z])", "_", cls.__name__).lower()
def __repr__(self):
attrs = []
for c in self.__table__.columns:
attrs.append(f"{c.name}={getattr(self, c.name)}")
return "{}({})".format(c.__class__.__name__, ', '.join(attrs))
class BaseDbModel(Base):
__abstract__ = True
@classmethod
def create(cls, *, session: Session, **kwargs) -> BaseDbModel:
obj = cls(**kwargs)
session.add(obj)
session.flush()
return obj
@classmethod
def query(cls, *, with_deleted: bool = False, session: Session) -> Query:
"""Get all objects with soft deletes"""
objs = session.query(cls)
if not with_deleted and hasattr(cls, "is_deleted"):
objs = objs.filter(not_(cls.is_deleted))
return objs
@classmethod
def get(cls, id: int | str, *, with_deleted=False, session: Session) -> BaseDbModel:
"""Get object with soft deletes"""
objs = session.query(cls)
if not with_deleted and hasattr(cls, "is_deleted"):
objs = objs.filter(not_(cls.is_deleted))
try:
if hasattr(cls, "uuid"):
return objs.filter(cls.uuid == id).one()
return objs.filter(cls.id == id).one()
except NoResultFound:
raise ObjectNotFound(cls, id)
@classmethod
def update(cls, id: int | str, *, session: Session, **kwargs) -> BaseDbModel:
obj = cls.get(id, session=session)
for k, v in kwargs.items():
setattr(obj, k, v)
session.flush()
return obj
@classmethod
def delete(cls, id: int | str, *, session: Session) -> None:
"""Soft delete object if possible, else hard delete"""
obj = cls.get(id, session=session)
if hasattr(obj, "is_deleted"):
obj.is_deleted = True
else:
session.delete(obj)
session.flush()