Coverage for slidge/db/meta.py: 91%
35 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-11-07 05:11 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-11-07 05:11 +0000
1from __future__ import annotations
3import json
4from typing import Union
6import sqlalchemy as sa
7from slixmpp import JID
10class JIDType(sa.TypeDecorator[JID]):
11 """
12 Custom SQLAlchemy type for JIDs
13 """
15 impl = sa.types.TEXT
16 cache_ok = True
18 def process_bind_param(self, value: JID | None, dialect: sa.Dialect) -> str | None:
19 if value is None:
20 return value
21 return str(value)
23 def process_result_value(
24 self, value: str | None, dialect: sa.Dialect
25 ) -> JID | None:
26 if value is None:
27 return value
28 return JID(value)
31class JSONEncodedDict(sa.TypeDecorator):
32 """
33 Custom SQLAlchemy type for dictionaries stored as JSON
35 Note that mutations of the dictionary are not detected by SQLAlchemy,
36 which is why use ``attributes.flag_modified()`` in ``UserStore.update()``
37 """
39 impl = sa.VARCHAR
41 cache_ok = True
43 def process_bind_param(self, value, dialect):
44 if value is not None:
45 value = json.dumps(value)
47 return value
49 def process_result_value(self, value, dialect):
50 if value is not None:
51 value = json.loads(value)
52 return value
55JSONSerializableTypes = Union[str, float, None, "JSONSerializable"]
56JSONSerializable = dict[str, JSONSerializableTypes]
59class Base(sa.orm.DeclarativeBase):
60 type_annotation_map = {JSONSerializable: JSONEncodedDict, JID: JIDType}
61 naming_convention = {
62 "ix": "ix_%(column_0_label)s",
63 "uq": "uq_%(table_name)s_%(column_0_name)s",
64 "ck": "ck_%(table_name)s_`%(constraint_name)s`",
65 "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
66 "pk": "pk_%(table_name)s",
67 }
70def get_engine(path: str) -> sa.Engine:
71 engine = sa.create_engine(path)
72 return engine