database-wrapper 0.2.14__tar.gz → 0.2.16__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/PKG-INFO +8 -8
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/__init__.py +4 -4
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/abc.py +3 -3
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/config.py +3 -3
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/db_backend.py +3 -3
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/db_data_model.py +13 -15
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/db_introspector.py +20 -19
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/db_wrapper.py +6 -8
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/db_wrapper_async.py +6 -8
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/db_wrapper_mixin.py +20 -37
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/serialization.py +3 -4
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/utils/dataclass_addons.py +3 -2
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper.egg-info/PKG-INFO +8 -8
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper.egg-info/requires.txt +7 -7
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/pyproject.toml +27 -16
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/README.md +0 -0
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/common.py +0 -0
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/py.typed +0 -0
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/utils/__init__.py +0 -0
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper.egg-info/SOURCES.txt +0 -0
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper.egg-info/dependency_links.txt +0 -0
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper.egg-info/top_level.txt +0 -0
- {database_wrapper-0.2.14 → database_wrapper-0.2.16}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: database_wrapper
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: A Different Approach to Database Wrappers in Python
|
|
5
5
|
Author-email: Gints Murans <gm@gm.lv>
|
|
6
6
|
License: GNU General Public License v3.0 (GPL-3.0)
|
|
@@ -33,23 +33,23 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
33
33
|
Requires-Python: >=3.8
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
Provides-Extra: pgsql
|
|
36
|
-
Requires-Dist: database_wrapper_pgsql==0.2.
|
|
36
|
+
Requires-Dist: database_wrapper_pgsql==0.2.16; extra == "pgsql"
|
|
37
37
|
Provides-Extra: mysql
|
|
38
|
-
Requires-Dist: database_wrapper_mysql==0.2.
|
|
38
|
+
Requires-Dist: database_wrapper_mysql==0.2.16; extra == "mysql"
|
|
39
39
|
Provides-Extra: mssql
|
|
40
|
-
Requires-Dist: database_wrapper_mssql==0.2.
|
|
40
|
+
Requires-Dist: database_wrapper_mssql==0.2.16; extra == "mssql"
|
|
41
41
|
Provides-Extra: sqlite
|
|
42
|
-
Requires-Dist: database_wrapper_sqlite==0.2.
|
|
42
|
+
Requires-Dist: database_wrapper_sqlite==0.2.16; extra == "sqlite"
|
|
43
43
|
Provides-Extra: redis
|
|
44
|
-
Requires-Dist: database_wrapper_redis==0.2.
|
|
44
|
+
Requires-Dist: database_wrapper_redis==0.2.16; extra == "redis"
|
|
45
45
|
Provides-Extra: all
|
|
46
46
|
Requires-Dist: database_wrapper[mssql,mysql,pgsql,redis,sqlite]; extra == "all"
|
|
47
47
|
Provides-Extra: dev
|
|
48
48
|
Requires-Dist: ast-comments>=1.1.2; extra == "dev"
|
|
49
49
|
Requires-Dist: codespell>=2.2; extra == "dev"
|
|
50
50
|
Requires-Dist: build>=1.2.1; extra == "dev"
|
|
51
|
-
Requires-Dist:
|
|
52
|
-
Requires-Dist:
|
|
51
|
+
Requires-Dist: pyrefly; extra == "dev"
|
|
52
|
+
Requires-Dist: ruff; extra == "dev"
|
|
53
53
|
Requires-Dist: types-setuptools>=61.0.0; extra == "dev"
|
|
54
54
|
Requires-Dist: types-pymssql>=2.1.0; extra == "dev"
|
|
55
55
|
Requires-Dist: types-mysqlclient>=2.2.0; extra == "dev"
|
|
@@ -6,16 +6,16 @@ database_wrapper package - Base for database wrappers
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
|
|
9
|
-
from .abc import ConnectionABC, CursorABC, CursorAsyncABC, ConnectionAsyncABC
|
|
10
9
|
from . import utils
|
|
10
|
+
from .abc import ConnectionABC, ConnectionAsyncABC, CursorABC, CursorAsyncABC
|
|
11
|
+
from .common import DataModelType, NoParam, OrderByItem
|
|
11
12
|
from .db_backend import DatabaseBackend
|
|
12
|
-
from .db_data_model import
|
|
13
|
-
from .
|
|
13
|
+
from .db_data_model import DBDataModel, DBDefaultsDataModel, MetadataDict
|
|
14
|
+
from .db_introspector import ColumnMetaIntrospector, DBIntrospector
|
|
14
15
|
from .db_wrapper import DBWrapper
|
|
15
16
|
from .db_wrapper_async import DBWrapperAsync
|
|
16
17
|
from .serialization import SerializeType
|
|
17
18
|
from .utils.dataclass_addons import ignore_unknown_kwargs
|
|
18
|
-
from .db_introspector import ColumnMetaIntrospector, DBIntrospector
|
|
19
19
|
|
|
20
20
|
# Set the logger to a quiet default, can be enabled if needed
|
|
21
21
|
logger = logging.getLogger("database_wrapper")
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
from
|
|
2
|
-
from typing import Any,
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
from typing import Any, Literal, Protocol
|
|
3
3
|
|
|
4
4
|
from psycopg.sql import Composable
|
|
5
5
|
|
|
6
|
-
Row =
|
|
6
|
+
Row = dict[str, Any]
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class CursorABC(Protocol):
|
|
@@ -3,7 +3,7 @@ from typing import Any
|
|
|
3
3
|
CONFIG: dict[str, Any] = {
|
|
4
4
|
# These are supposed to be set automatically by a git pre-compile script
|
|
5
5
|
# They are one git commit hash behind, if used automatically
|
|
6
|
-
"git_commit_hash": "
|
|
7
|
-
"git_commit_date": "
|
|
8
|
-
"app_version": "0.2.
|
|
6
|
+
"git_commit_hash": "4baad61b81d9f178acd8de04c1a65f2053e06d89",
|
|
7
|
+
"git_commit_date": "09.01.2026 00:48",
|
|
8
|
+
"app_version": "0.2.16",
|
|
9
9
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import socket
|
|
3
|
-
|
|
4
|
-
from typing import Any, Coroutine
|
|
5
|
-
from threading import Event
|
|
3
|
+
from collections.abc import Coroutine
|
|
6
4
|
from contextvars import ContextVar
|
|
5
|
+
from threading import Event
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class DatabaseBackend:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import json
|
|
3
|
-
import datetime
|
|
4
1
|
import dataclasses
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import datetime
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from dataclasses import asdict, dataclass, field
|
|
7
7
|
from enum import Enum
|
|
8
|
-
from typing import Any,
|
|
8
|
+
from typing import Any, ClassVar, Literal, NotRequired, TypedDict, TypeVar, cast
|
|
9
9
|
|
|
10
10
|
from .serialization import (
|
|
11
11
|
SerializeType,
|
|
@@ -24,7 +24,7 @@ class MetadataDict(TypedDict):
|
|
|
24
24
|
exclude: NotRequired[bool]
|
|
25
25
|
serialize: NotRequired[Callable[[Any], Any] | SerializeType | None]
|
|
26
26
|
deserialize: NotRequired[Callable[[Any], Any] | None]
|
|
27
|
-
enum_class: NotRequired[
|
|
27
|
+
enum_class: NotRequired[type[Enum] | None]
|
|
28
28
|
timezone: NotRequired[str | datetime.tzinfo | None]
|
|
29
29
|
|
|
30
30
|
|
|
@@ -151,7 +151,7 @@ class DBDataModel:
|
|
|
151
151
|
|
|
152
152
|
# String - representation
|
|
153
153
|
def __repr__(self) -> str:
|
|
154
|
-
return "
|
|
154
|
+
return f"<{self.__class__.__name__} {self.__dict__}>"
|
|
155
155
|
|
|
156
156
|
def __str__(self) -> str:
|
|
157
157
|
return self.to_json_string()
|
|
@@ -186,9 +186,7 @@ class DBDataModel:
|
|
|
186
186
|
for field_name, field_obj in self.__dataclass_fields__.items():
|
|
187
187
|
metadata = cast(MetadataDict, field_obj.metadata)
|
|
188
188
|
assert (
|
|
189
|
-
"db_field" in metadata
|
|
190
|
-
and isinstance(metadata["db_field"], tuple)
|
|
191
|
-
and len(metadata["db_field"]) == 2
|
|
189
|
+
"db_field" in metadata and isinstance(metadata["db_field"], tuple) and len(metadata["db_field"]) == 2
|
|
192
190
|
), f"db_field metadata is not set for {field_name}"
|
|
193
191
|
field_type: str = metadata["db_field"][1]
|
|
194
192
|
schema["properties"][field_name] = {"type": field_type}
|
|
@@ -255,7 +253,7 @@ class DBDataModel:
|
|
|
255
253
|
|
|
256
254
|
def validate(self) -> Literal[True] | str:
|
|
257
255
|
"""
|
|
258
|
-
|
|
256
|
+
True if the instance is valid, otherwise an error message.
|
|
259
257
|
"""
|
|
260
258
|
raise NotImplementedError("`validate` is not implemented")
|
|
261
259
|
|
|
@@ -291,13 +289,13 @@ class DBDataModel:
|
|
|
291
289
|
|
|
292
290
|
def query_base(self) -> Any:
|
|
293
291
|
"""
|
|
294
|
-
|
|
292
|
+
Base query for all queries
|
|
295
293
|
"""
|
|
296
294
|
return None
|
|
297
295
|
|
|
298
296
|
def store_data(self) -> dict[str, Any] | None:
|
|
299
297
|
"""
|
|
300
|
-
|
|
298
|
+
Store data to database
|
|
301
299
|
"""
|
|
302
300
|
store_data: dict[str, Any] = {}
|
|
303
301
|
for field_name, field_obj in self.__dataclass_fields__.items():
|
|
@@ -321,7 +319,7 @@ class DBDataModel:
|
|
|
321
319
|
|
|
322
320
|
def update_data(self) -> dict[str, Any] | None:
|
|
323
321
|
"""
|
|
324
|
-
|
|
322
|
+
Update data to database
|
|
325
323
|
"""
|
|
326
324
|
|
|
327
325
|
update_data: dict[str, Any] = {}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
from dataclasses import MISSING, dataclass,
|
|
2
|
-
from
|
|
1
|
+
from dataclasses import MISSING, dataclass, field, make_dataclass
|
|
2
|
+
from dataclasses import fields as dc_fields
|
|
3
|
+
from datetime import date, datetime
|
|
3
4
|
from enum import Enum
|
|
4
5
|
from pathlib import Path
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Union, get_args, get_origin
|
|
6
7
|
|
|
7
8
|
from database_wrapper import DBDefaultsDataModel, MetadataDict, SerializeType
|
|
8
9
|
|
|
@@ -93,12 +94,12 @@ class DBIntrospector:
|
|
|
93
94
|
self,
|
|
94
95
|
table_name: str,
|
|
95
96
|
*,
|
|
96
|
-
class_name:
|
|
97
|
-
base:
|
|
98
|
-
enum_overrides: dict[str,
|
|
97
|
+
class_name: str | None = None,
|
|
98
|
+
base: type[DBDefaultsDataModel] = DBDefaultsDataModel,
|
|
99
|
+
enum_overrides: dict[str, type[Enum]] | None = None,
|
|
99
100
|
defaults_for_nullable: bool = True,
|
|
100
101
|
include_id_field: bool = True,
|
|
101
|
-
) ->
|
|
102
|
+
) -> type[DBDefaultsDataModel]:
|
|
102
103
|
(schema, table) = self.get_schema_table_name(table_name)
|
|
103
104
|
cols = self.get_table_columns(schema, table)
|
|
104
105
|
if not cols:
|
|
@@ -115,7 +116,7 @@ class DBIntrospector:
|
|
|
115
116
|
continue
|
|
116
117
|
|
|
117
118
|
# Enums
|
|
118
|
-
enum_class:
|
|
119
|
+
enum_class: type[Enum] | None = None
|
|
119
120
|
if c.enum_labels:
|
|
120
121
|
enum_class = enum_overrides.get(c.col_name)
|
|
121
122
|
if not enum_class:
|
|
@@ -127,14 +128,14 @@ class DBIntrospector:
|
|
|
127
128
|
|
|
128
129
|
# Optional typing if nullable
|
|
129
130
|
if c.is_nullable:
|
|
130
|
-
ann
|
|
131
|
+
ann: type[py_type] | None = py_type
|
|
131
132
|
else:
|
|
132
|
-
ann = py_type
|
|
133
|
+
ann = py_type
|
|
133
134
|
|
|
134
135
|
# Default value choice
|
|
135
136
|
default = None
|
|
136
137
|
default_factory = None
|
|
137
|
-
if c.is_nullable
|
|
138
|
+
if not c.is_nullable:
|
|
138
139
|
# give some sane defaults for common not-nullables that aren't id/serial
|
|
139
140
|
if py_type is bool:
|
|
140
141
|
default = False
|
|
@@ -156,7 +157,7 @@ class DBIntrospector:
|
|
|
156
157
|
elif py_type is set:
|
|
157
158
|
default_factory = set
|
|
158
159
|
elif py_type is bytes:
|
|
159
|
-
default =
|
|
160
|
+
default = b""
|
|
160
161
|
else:
|
|
161
162
|
# Leave unset so dataclass enforces passing it explicitly
|
|
162
163
|
default = None if defaults_for_nullable else None
|
|
@@ -202,15 +203,15 @@ class DBIntrospector:
|
|
|
202
203
|
def _tableName(self) -> str:
|
|
203
204
|
return table
|
|
204
205
|
|
|
205
|
-
|
|
206
|
-
|
|
206
|
+
cls.schemaName = property(_schemaName)
|
|
207
|
+
cls.tableName = property(_tableName)
|
|
207
208
|
|
|
208
209
|
return cls
|
|
209
210
|
|
|
210
211
|
# TODO: Need to improve handling of imports for external classes, including enums.
|
|
211
212
|
def render_dataclass_source(
|
|
212
213
|
self,
|
|
213
|
-
cls:
|
|
214
|
+
cls: type,
|
|
214
215
|
table_name: str,
|
|
215
216
|
*,
|
|
216
217
|
extra_imports: list[str] | None = None,
|
|
@@ -242,7 +243,7 @@ class DBIntrospector:
|
|
|
242
243
|
dynamic_enums: list[tuple[str, list[tuple[str, Any]]]] = []
|
|
243
244
|
external_enum_imports: set[tuple[str, str]] = set()
|
|
244
245
|
for f in dc_fields(cls):
|
|
245
|
-
md: MetadataDict = dict(f.metadata) if f.metadata else {}
|
|
246
|
+
md: MetadataDict = dict(f.metadata) if f.metadata else {}
|
|
246
247
|
enum_class = md.get("enum_class")
|
|
247
248
|
if enum_class:
|
|
248
249
|
mod = getattr(enum_class, "__module__", "")
|
|
@@ -250,7 +251,7 @@ class DBIntrospector:
|
|
|
250
251
|
# If it's the built-in Enum module (meaning we made it dynamically),
|
|
251
252
|
# embed it. Otherwise, import from its module.
|
|
252
253
|
if mod == "enum":
|
|
253
|
-
members = [(m.name, m.value) for m in enum_class]
|
|
254
|
+
members = [(m.name, m.value) for m in enum_class]
|
|
254
255
|
dynamic_enums.append((name, members))
|
|
255
256
|
else:
|
|
256
257
|
external_enum_imports.add((mod, name))
|
|
@@ -298,7 +299,7 @@ class DBIntrospector:
|
|
|
298
299
|
|
|
299
300
|
# Render fields (skip the inherited ones we know exist on base if they aren't present here)
|
|
300
301
|
for f in dc_fields(cls):
|
|
301
|
-
md: MetadataDict = dict(f.metadata) if f.metadata else {}
|
|
302
|
+
md: MetadataDict = dict(f.metadata) if f.metadata else {}
|
|
302
303
|
# We always render all fields that exist in this dataclass (your make_dataclass created them)
|
|
303
304
|
db_field = md.get("db_field", (f.name, "Any"))
|
|
304
305
|
if not (isinstance(db_field, tuple) and len(db_field) == 2):
|
|
@@ -357,7 +358,7 @@ class DBIntrospector:
|
|
|
357
358
|
lines.append(" out: dict[str, Any] = {}")
|
|
358
359
|
lines.append(" # Explicitly list each field (stable order)")
|
|
359
360
|
for f in dc_fields(cls):
|
|
360
|
-
md: MetadataDict = dict(f.metadata) if f.metadata else {}
|
|
361
|
+
md: MetadataDict = dict(f.metadata) if f.metadata else {}
|
|
361
362
|
serialize = md.get("serialize")
|
|
362
363
|
key = f.name
|
|
363
364
|
if serialize == SerializeType.DATETIME:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Generator
|
|
2
|
+
from typing import Any, overload
|
|
2
3
|
|
|
4
|
+
from .common import DataModelType, OrderByItem
|
|
3
5
|
from .db_data_model import DBDataModel
|
|
4
6
|
from .db_wrapper_mixin import DBWrapperMixin
|
|
5
|
-
from .common import OrderByItem, DataModelType
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class DBWrapper(DBWrapperMixin):
|
|
@@ -230,8 +231,7 @@ class DBWrapper(DBWrapperMixin):
|
|
|
230
231
|
)
|
|
231
232
|
|
|
232
233
|
@overload
|
|
233
|
-
def insert(self, records: DataModelType) -> tuple[int, int]:
|
|
234
|
-
...
|
|
234
|
+
def insert(self, records: DataModelType) -> tuple[int, int]: ...
|
|
235
235
|
|
|
236
236
|
@overload
|
|
237
237
|
def insert(self, records: list[DataModelType]) -> list[tuple[int, int]]: ...
|
|
@@ -335,8 +335,7 @@ class DBWrapper(DBWrapperMixin):
|
|
|
335
335
|
return affected_rows
|
|
336
336
|
|
|
337
337
|
@overload
|
|
338
|
-
def update(self, records: DataModelType) -> int:
|
|
339
|
-
...
|
|
338
|
+
def update(self, records: DataModelType) -> int: ...
|
|
340
339
|
|
|
341
340
|
@overload
|
|
342
341
|
def update(self, records: list[DataModelType]) -> list[int]: ...
|
|
@@ -441,8 +440,7 @@ class DBWrapper(DBWrapperMixin):
|
|
|
441
440
|
return affected_rows
|
|
442
441
|
|
|
443
442
|
@overload
|
|
444
|
-
def delete(self, records: DataModelType) -> int:
|
|
445
|
-
...
|
|
443
|
+
def delete(self, records: DataModelType) -> int: ...
|
|
446
444
|
|
|
447
445
|
@overload
|
|
448
446
|
def delete(self, records: list[DataModelType]) -> list[int]: ...
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import AsyncGenerator
|
|
2
|
+
from typing import Any, overload
|
|
2
3
|
|
|
3
|
-
from .common import
|
|
4
|
+
from .common import DataModelType, OrderByItem
|
|
4
5
|
from .db_data_model import DBDataModel
|
|
5
6
|
from .db_wrapper_mixin import DBWrapperMixin
|
|
6
7
|
|
|
@@ -232,8 +233,7 @@ class DBWrapperAsync(DBWrapperMixin):
|
|
|
232
233
|
)
|
|
233
234
|
|
|
234
235
|
@overload
|
|
235
|
-
async def insert(self, records: DataModelType) -> tuple[int, int]:
|
|
236
|
-
...
|
|
236
|
+
async def insert(self, records: DataModelType) -> tuple[int, int]: ...
|
|
237
237
|
|
|
238
238
|
@overload
|
|
239
239
|
async def insert(self, records: list[DataModelType]) -> list[tuple[int, int]]: ...
|
|
@@ -336,8 +336,7 @@ class DBWrapperAsync(DBWrapperMixin):
|
|
|
336
336
|
return affected_rows
|
|
337
337
|
|
|
338
338
|
@overload
|
|
339
|
-
async def update(self, records: DataModelType) -> int:
|
|
340
|
-
...
|
|
339
|
+
async def update(self, records: DataModelType) -> int: ...
|
|
341
340
|
|
|
342
341
|
@overload
|
|
343
342
|
async def update(self, records: list[DataModelType]) -> list[int]: ...
|
|
@@ -442,8 +441,7 @@ class DBWrapperAsync(DBWrapperMixin):
|
|
|
442
441
|
return affected_rows
|
|
443
442
|
|
|
444
443
|
@overload
|
|
445
|
-
async def delete(self, records: DataModelType) -> int:
|
|
446
|
-
...
|
|
444
|
+
async def delete(self, records: DataModelType) -> int: ...
|
|
447
445
|
|
|
448
446
|
@overload
|
|
449
447
|
async def delete(self, records: list[DataModelType]) -> list[int]: ...
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from typing import Any, cast
|
|
2
3
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from .common import OrderByItem, NoParam, DataModelType
|
|
4
|
+
from .common import DataModelType, NoParam, OrderByItem
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
class DBWrapperMixin:
|
|
@@ -113,7 +112,7 @@ class DBWrapperMixin:
|
|
|
113
112
|
|
|
114
113
|
def turn_data_into_model(
|
|
115
114
|
self,
|
|
116
|
-
empty_data_class:
|
|
115
|
+
empty_data_class: type[DataModelType],
|
|
117
116
|
db_data: dict[str, Any],
|
|
118
117
|
) -> DataModelType:
|
|
119
118
|
"""
|
|
@@ -170,11 +169,8 @@ class DBWrapperMixin:
|
|
|
170
169
|
if order_by is None:
|
|
171
170
|
return None
|
|
172
171
|
|
|
173
|
-
order_list = [
|
|
174
|
-
|
|
175
|
-
for item in order_by
|
|
176
|
-
]
|
|
177
|
-
return "ORDER BY %s" % ", ".join(order_list)
|
|
172
|
+
order_list = [f"{item[0]} {item[1] if len(item) > 1 and item[1] is not None else 'ASC'}" for item in order_by]
|
|
173
|
+
return "ORDER BY {}".format(", ".join(order_list))
|
|
178
174
|
|
|
179
175
|
def limit_query(self, offset: int = 0, limit: int = 100) -> Any | None:
|
|
180
176
|
"""
|
|
@@ -204,36 +200,32 @@ class DBWrapperMixin:
|
|
|
204
200
|
elif "$ends_with" in filter:
|
|
205
201
|
return (f"{key} LIKE %s", f"%{filter['$ends_with']}")
|
|
206
202
|
elif "$min" in filter and "$max" not in filter:
|
|
207
|
-
return (f"{key} >= %s", filter["$min"])
|
|
203
|
+
return (f"{key} >= %s", filter["$min"])
|
|
208
204
|
elif "$max" in filter and "$min" not in filter:
|
|
209
|
-
return (f"{key} <= %s", filter["$max"])
|
|
205
|
+
return (f"{key} <= %s", filter["$max"])
|
|
210
206
|
elif "$min" in filter and "$max" in filter:
|
|
211
|
-
return (f"{key} BETWEEN %s AND %s", filter["$min"], filter["$max"])
|
|
207
|
+
return (f"{key} BETWEEN %s AND %s", filter["$min"], filter["$max"])
|
|
212
208
|
elif "$in" in filter:
|
|
213
209
|
in_filter_1: list[Any] = cast(list[Any], filter["$in"])
|
|
214
|
-
return (
|
|
215
|
-
f"{key} IN (%s)" % ",".join(["%s"] * len(in_filter_1)),
|
|
216
|
-
) + tuple(in_filter_1)
|
|
210
|
+
return (f"{key} IN (%s)" % ",".join(["%s"] * len(in_filter_1)),) + tuple(in_filter_1)
|
|
217
211
|
elif "$not_in" in filter:
|
|
218
212
|
in_filter_2: list[Any] = cast(list[Any], filter["$in"])
|
|
219
|
-
return (
|
|
220
|
-
f"{key} NOT IN (%s)" % ",".join(["%s"] * len(in_filter_2)),
|
|
221
|
-
) + tuple(in_filter_2)
|
|
213
|
+
return (f"{key} NOT IN (%s)" % ",".join(["%s"] * len(in_filter_2)),) + tuple(in_filter_2)
|
|
222
214
|
elif "$not" in filter:
|
|
223
|
-
return (f"{key} != %s", filter["$not"])
|
|
215
|
+
return (f"{key} != %s", filter["$not"])
|
|
224
216
|
|
|
225
217
|
elif "$gt" in filter:
|
|
226
|
-
return (f"{key} > %s", filter["$gt"])
|
|
218
|
+
return (f"{key} > %s", filter["$gt"])
|
|
227
219
|
elif "$gte" in filter:
|
|
228
|
-
return (f"{key} >= %s", filter["$gte"])
|
|
220
|
+
return (f"{key} >= %s", filter["$gte"])
|
|
229
221
|
elif "$lt" in filter:
|
|
230
|
-
return (f"{key} < %s", filter["$lt"])
|
|
222
|
+
return (f"{key} < %s", filter["$lt"])
|
|
231
223
|
elif "$lte" in filter:
|
|
232
|
-
return (f"{key} <= %s", filter["$lte"])
|
|
224
|
+
return (f"{key} <= %s", filter["$lte"])
|
|
233
225
|
elif "$is_null" in filter:
|
|
234
|
-
return (f"{key} IS NULL",)
|
|
226
|
+
return (f"{key} IS NULL",)
|
|
235
227
|
elif "$is_not_null" in filter:
|
|
236
|
-
return (f"{key} IS NOT NULL",)
|
|
228
|
+
return (f"{key} IS NOT NULL",)
|
|
237
229
|
|
|
238
230
|
raise NotImplementedError("Filter type not supported")
|
|
239
231
|
elif type(filter) is str or type(filter) is int or type(filter) is float:
|
|
@@ -244,13 +236,9 @@ class DBWrapperMixin:
|
|
|
244
236
|
NoParam,
|
|
245
237
|
)
|
|
246
238
|
else:
|
|
247
|
-
raise NotImplementedError(
|
|
248
|
-
f"Filter type not supported: {key} = {type(filter)}"
|
|
249
|
-
)
|
|
239
|
+
raise NotImplementedError(f"Filter type not supported: {key} = {type(filter)}")
|
|
250
240
|
|
|
251
|
-
def create_filter(
|
|
252
|
-
self, filter: dict[str, Any] | None
|
|
253
|
-
) -> tuple[Any, tuple[Any, ...]]:
|
|
241
|
+
def create_filter(self, filter: dict[str, Any] | None) -> tuple[Any, tuple[Any, ...]]:
|
|
254
242
|
if filter is None or len(filter) == 0:
|
|
255
243
|
return ("", tuple())
|
|
256
244
|
|
|
@@ -287,12 +275,7 @@ class DBWrapperMixin:
|
|
|
287
275
|
|
|
288
276
|
columns = ", ".join(keys)
|
|
289
277
|
values_placeholder = ", ".join(["%s"] * len(values))
|
|
290
|
-
return (
|
|
291
|
-
f"INSERT INTO {table_identifier} "
|
|
292
|
-
f"({columns}) "
|
|
293
|
-
f"VALUES ({values_placeholder}) "
|
|
294
|
-
f"RETURNING {return_key}"
|
|
295
|
-
)
|
|
278
|
+
return f"INSERT INTO {table_identifier} ({columns}) VALUES ({values_placeholder}) RETURNING {return_key}"
|
|
296
279
|
|
|
297
280
|
def _format_update_query(
|
|
298
281
|
self,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import json
|
|
3
|
-
|
|
4
3
|
from decimal import Decimal
|
|
5
4
|
from enum import Enum
|
|
6
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
7
6
|
from zoneinfo import ZoneInfo
|
|
8
7
|
|
|
9
8
|
|
|
@@ -61,7 +60,7 @@ def serialize_value(value: Any, s_type: SerializeType) -> Any:
|
|
|
61
60
|
def deserialize_value(
|
|
62
61
|
value: Any,
|
|
63
62
|
s_type: SerializeType,
|
|
64
|
-
enum_class:
|
|
63
|
+
enum_class: type[Enum] | None = None,
|
|
65
64
|
timezone: str | datetime.tzinfo | None = None,
|
|
66
65
|
) -> Any:
|
|
67
66
|
if s_type == SerializeType.DATETIME:
|
|
@@ -95,7 +94,7 @@ def deserialize_value(
|
|
|
95
94
|
|
|
96
95
|
if s_type == SerializeType.JSON:
|
|
97
96
|
if isinstance(value, dict) or isinstance(value, list) or value is None:
|
|
98
|
-
return value
|
|
97
|
+
return value
|
|
99
98
|
|
|
100
99
|
return json.loads(value)
|
|
101
100
|
|
{database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper/utils/dataclass_addons.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import Any, TypeVar
|
|
2
3
|
|
|
3
|
-
AnyDataType = TypeVar("AnyDataType", bound=
|
|
4
|
+
AnyDataType = TypeVar("AnyDataType", bound=type[Any])
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def ignore_unknown_kwargs() -> Callable[[AnyDataType], AnyDataType]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: database_wrapper
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: A Different Approach to Database Wrappers in Python
|
|
5
5
|
Author-email: Gints Murans <gm@gm.lv>
|
|
6
6
|
License: GNU General Public License v3.0 (GPL-3.0)
|
|
@@ -33,23 +33,23 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
33
33
|
Requires-Python: >=3.8
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
Provides-Extra: pgsql
|
|
36
|
-
Requires-Dist: database_wrapper_pgsql==0.2.
|
|
36
|
+
Requires-Dist: database_wrapper_pgsql==0.2.16; extra == "pgsql"
|
|
37
37
|
Provides-Extra: mysql
|
|
38
|
-
Requires-Dist: database_wrapper_mysql==0.2.
|
|
38
|
+
Requires-Dist: database_wrapper_mysql==0.2.16; extra == "mysql"
|
|
39
39
|
Provides-Extra: mssql
|
|
40
|
-
Requires-Dist: database_wrapper_mssql==0.2.
|
|
40
|
+
Requires-Dist: database_wrapper_mssql==0.2.16; extra == "mssql"
|
|
41
41
|
Provides-Extra: sqlite
|
|
42
|
-
Requires-Dist: database_wrapper_sqlite==0.2.
|
|
42
|
+
Requires-Dist: database_wrapper_sqlite==0.2.16; extra == "sqlite"
|
|
43
43
|
Provides-Extra: redis
|
|
44
|
-
Requires-Dist: database_wrapper_redis==0.2.
|
|
44
|
+
Requires-Dist: database_wrapper_redis==0.2.16; extra == "redis"
|
|
45
45
|
Provides-Extra: all
|
|
46
46
|
Requires-Dist: database_wrapper[mssql,mysql,pgsql,redis,sqlite]; extra == "all"
|
|
47
47
|
Provides-Extra: dev
|
|
48
48
|
Requires-Dist: ast-comments>=1.1.2; extra == "dev"
|
|
49
49
|
Requires-Dist: codespell>=2.2; extra == "dev"
|
|
50
50
|
Requires-Dist: build>=1.2.1; extra == "dev"
|
|
51
|
-
Requires-Dist:
|
|
52
|
-
Requires-Dist:
|
|
51
|
+
Requires-Dist: pyrefly; extra == "dev"
|
|
52
|
+
Requires-Dist: ruff; extra == "dev"
|
|
53
53
|
Requires-Dist: types-setuptools>=61.0.0; extra == "dev"
|
|
54
54
|
Requires-Dist: types-pymssql>=2.1.0; extra == "dev"
|
|
55
55
|
Requires-Dist: types-mysqlclient>=2.2.0; extra == "dev"
|
|
@@ -6,8 +6,8 @@ database_wrapper[mssql,mysql,pgsql,redis,sqlite]
|
|
|
6
6
|
ast-comments>=1.1.2
|
|
7
7
|
codespell>=2.2
|
|
8
8
|
build>=1.2.1
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
pyrefly
|
|
10
|
+
ruff
|
|
11
11
|
types-setuptools>=61.0.0
|
|
12
12
|
types-pymssql>=2.1.0
|
|
13
13
|
types-mysqlclient>=2.2.0
|
|
@@ -17,16 +17,16 @@ mysqlclient>=2.2.2
|
|
|
17
17
|
pymssql>=2.2.10
|
|
18
18
|
|
|
19
19
|
[mssql]
|
|
20
|
-
database_wrapper_mssql==0.2.
|
|
20
|
+
database_wrapper_mssql==0.2.16
|
|
21
21
|
|
|
22
22
|
[mysql]
|
|
23
|
-
database_wrapper_mysql==0.2.
|
|
23
|
+
database_wrapper_mysql==0.2.16
|
|
24
24
|
|
|
25
25
|
[pgsql]
|
|
26
|
-
database_wrapper_pgsql==0.2.
|
|
26
|
+
database_wrapper_pgsql==0.2.16
|
|
27
27
|
|
|
28
28
|
[redis]
|
|
29
|
-
database_wrapper_redis==0.2.
|
|
29
|
+
database_wrapper_redis==0.2.16
|
|
30
30
|
|
|
31
31
|
[sqlite]
|
|
32
|
-
database_wrapper_sqlite==0.2.
|
|
32
|
+
database_wrapper_sqlite==0.2.16
|
|
@@ -4,14 +4,12 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "database_wrapper"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.16"
|
|
8
8
|
description = "A Different Approach to Database Wrappers in Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
11
|
-
license = {text = "GNU General Public License v3.0 (GPL-3.0)"}
|
|
12
|
-
authors = [
|
|
13
|
-
{name = "Gints Murans", email = "gm@gm.lv"}
|
|
14
|
-
]
|
|
11
|
+
license = { text = "GNU General Public License v3.0 (GPL-3.0)" }
|
|
12
|
+
authors = [{ name = "Gints Murans", email = "gm@gm.lv" }]
|
|
15
13
|
classifiers = [
|
|
16
14
|
"Development Status :: 4 - Beta",
|
|
17
15
|
"Intended Audience :: Developers",
|
|
@@ -31,9 +29,18 @@ classifiers = [
|
|
|
31
29
|
"Topic :: Database",
|
|
32
30
|
"Topic :: Database :: Front-Ends",
|
|
33
31
|
"Topic :: Software Development",
|
|
34
|
-
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
32
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
33
|
+
]
|
|
34
|
+
keywords = [
|
|
35
|
+
"database",
|
|
36
|
+
"wrapper",
|
|
37
|
+
"python",
|
|
38
|
+
"pgsql",
|
|
39
|
+
"mysql",
|
|
40
|
+
"mssql",
|
|
41
|
+
"sqlite",
|
|
42
|
+
"redis",
|
|
35
43
|
]
|
|
36
|
-
keywords = ["database", "wrapper", "python", "pgsql", "mysql", "mssql", "sqlite", "redis"]
|
|
37
44
|
dependencies = []
|
|
38
45
|
|
|
39
46
|
[project.urls]
|
|
@@ -45,28 +52,32 @@ Code = "https://github.com/gintsmurans/py_database_wrapper"
|
|
|
45
52
|
Download = "https://pypi.org/project/database_wrapper/"
|
|
46
53
|
|
|
47
54
|
[project.optional-dependencies]
|
|
48
|
-
pgsql = ["database_wrapper_pgsql == 0.2.
|
|
49
|
-
mysql = ["database_wrapper_mysql == 0.2.
|
|
50
|
-
mssql = ["database_wrapper_mssql == 0.2.
|
|
51
|
-
sqlite = ["database_wrapper_sqlite == 0.2.
|
|
52
|
-
redis = ["database_wrapper_redis == 0.2.
|
|
55
|
+
pgsql = ["database_wrapper_pgsql == 0.2.16"]
|
|
56
|
+
mysql = ["database_wrapper_mysql == 0.2.16"]
|
|
57
|
+
mssql = ["database_wrapper_mssql == 0.2.16"]
|
|
58
|
+
sqlite = ["database_wrapper_sqlite == 0.2.16"]
|
|
59
|
+
redis = ["database_wrapper_redis == 0.2.16"]
|
|
53
60
|
all = ["database_wrapper[pgsql,mysql,mssql,sqlite,redis]"]
|
|
54
61
|
dev = [
|
|
55
62
|
# Development
|
|
56
63
|
"ast-comments >= 1.1.2",
|
|
57
64
|
"codespell >= 2.2",
|
|
58
65
|
"build >= 1.2.1",
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
66
|
+
|
|
67
|
+
# Formatting
|
|
68
|
+
"pyrefly",
|
|
69
|
+
"ruff",
|
|
70
|
+
|
|
71
|
+
# Type hints
|
|
62
72
|
"types-setuptools >= 61.0.0",
|
|
63
73
|
"types-pymssql >= 2.1.0",
|
|
64
74
|
"types-mysqlclient >= 2.2.0",
|
|
75
|
+
|
|
65
76
|
# Database drivers
|
|
66
77
|
"psycopg[binary] >= 3.2.0",
|
|
67
78
|
"psycopg[pool] >= 3.2.0",
|
|
68
79
|
"mysqlclient >= 2.2.2",
|
|
69
|
-
"pymssql >= 2.2.10"
|
|
80
|
+
"pymssql >= 2.2.10",
|
|
70
81
|
]
|
|
71
82
|
|
|
72
83
|
# [tool.setuptools.packages.find]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{database_wrapper-0.2.14 → database_wrapper-0.2.16}/database_wrapper.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|