database-wrapper 0.1.33__py3-none-any.whl → 0.1.37__py3-none-any.whl
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/__init__.py +2 -3
- database_wrapper/common.py +14 -0
- database_wrapper/config.py +3 -3
- database_wrapper/db_data_model.py +50 -3
- database_wrapper/db_wrapper.py +71 -296
- database_wrapper/db_wrapper_async.py +69 -295
- database_wrapper/db_wrapper_mixin.py +308 -0
- database_wrapper/utils/dataclass_addons.py +3 -3
- {database_wrapper-0.1.33.dist-info → database_wrapper-0.1.37.dist-info}/METADATA +5 -5
- database_wrapper-0.1.37.dist-info/RECORD +16 -0
- {database_wrapper-0.1.33.dist-info → database_wrapper-0.1.37.dist-info}/WHEEL +1 -1
- database_wrapper/db_wrapper_interface.py +0 -434
- database_wrapper-0.1.33.dist-info/RECORD +0 -15
- {database_wrapper-0.1.33.dist-info → database_wrapper-0.1.37.dist-info}/top_level.txt +0 -0
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
from typing import AsyncGenerator, Any, overload
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from .db_backend import DatabaseBackend
|
|
3
|
+
from .common import OrderByItem, DataModelType
|
|
6
4
|
from .db_data_model import DBDataModel
|
|
7
|
-
from .
|
|
5
|
+
from .db_wrapper_mixin import DBWrapperMixin
|
|
8
6
|
|
|
9
7
|
|
|
10
|
-
class DBWrapperAsync(
|
|
8
|
+
class DBWrapperAsync(DBWrapperMixin):
|
|
11
9
|
"""
|
|
12
10
|
Async Database wrapper class.
|
|
13
11
|
|
|
@@ -15,66 +13,10 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
15
13
|
It means you will need to call close method manually from async context.
|
|
16
14
|
"""
|
|
17
15
|
|
|
18
|
-
###########################
|
|
19
|
-
### Instance properties ###
|
|
20
|
-
###########################
|
|
21
|
-
|
|
22
|
-
# Db backend
|
|
23
|
-
db: Any
|
|
24
|
-
"""Database backend object"""
|
|
25
|
-
|
|
26
|
-
dbConn: Any
|
|
27
|
-
"""
|
|
28
|
-
Database connection object.
|
|
29
|
-
|
|
30
|
-
Its not always set. Currently is used as a placeholder for async connections.
|
|
31
|
-
For sync connections db - DatabaseBackend.connection is used.
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
# logger
|
|
35
|
-
logger: Any
|
|
36
|
-
"""Logger object"""
|
|
37
|
-
|
|
38
16
|
#######################
|
|
39
17
|
### Class lifecycle ###
|
|
40
18
|
#######################
|
|
41
19
|
|
|
42
|
-
# Meta methods
|
|
43
|
-
def __init__(
|
|
44
|
-
self,
|
|
45
|
-
db: DatabaseBackend,
|
|
46
|
-
dbConn: Any = None,
|
|
47
|
-
logger: logging.Logger | None = None,
|
|
48
|
-
):
|
|
49
|
-
"""
|
|
50
|
-
Initializes a new instance of the DBWrapper class.
|
|
51
|
-
|
|
52
|
-
Args:
|
|
53
|
-
db (DatabaseBackend): The DatabaseBackend object.
|
|
54
|
-
logger (logging.Logger, optional): The logger object. Defaults to None.
|
|
55
|
-
"""
|
|
56
|
-
self.db = db
|
|
57
|
-
self.dbConn = dbConn
|
|
58
|
-
|
|
59
|
-
if logger is None:
|
|
60
|
-
loggerName = f"{__name__}.{self.__class__.__name__}"
|
|
61
|
-
self.logger = logging.getLogger(loggerName)
|
|
62
|
-
else:
|
|
63
|
-
self.logger = logger
|
|
64
|
-
|
|
65
|
-
def __del__(self):
|
|
66
|
-
"""
|
|
67
|
-
Deallocates the instance of the DBWrapper class.
|
|
68
|
-
"""
|
|
69
|
-
self.logger.debug("Dealloc")
|
|
70
|
-
|
|
71
|
-
# Force remove instances so that there are no circular references
|
|
72
|
-
if hasattr(self, "db") and self.db:
|
|
73
|
-
del self.db
|
|
74
|
-
|
|
75
|
-
if hasattr(self, "dbConn") and self.dbConn:
|
|
76
|
-
del self.dbConn
|
|
77
|
-
|
|
78
20
|
async def close(self) -> None:
|
|
79
21
|
"""
|
|
80
22
|
Async method for closing async resources.
|
|
@@ -85,22 +27,6 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
85
27
|
### Helper methods ###
|
|
86
28
|
######################
|
|
87
29
|
|
|
88
|
-
def makeIdentifier(self, schema: str | None, name: str) -> Any:
|
|
89
|
-
"""
|
|
90
|
-
Creates a SQL identifier object from the given name.
|
|
91
|
-
|
|
92
|
-
Args:
|
|
93
|
-
schema (str | None): The schema to create the identifier from.
|
|
94
|
-
name (str): The name to create the identifier from.
|
|
95
|
-
|
|
96
|
-
Returns:
|
|
97
|
-
str: The created SQL identifier object.
|
|
98
|
-
"""
|
|
99
|
-
if schema:
|
|
100
|
-
return f"{schema}.{name}"
|
|
101
|
-
|
|
102
|
-
return name
|
|
103
|
-
|
|
104
30
|
@overload
|
|
105
31
|
async def createCursor(self) -> Any: ...
|
|
106
32
|
|
|
@@ -115,93 +41,32 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
115
41
|
emptyDataClass (T | None, optional): The data model to use for the cursor. Defaults to None.
|
|
116
42
|
|
|
117
43
|
Returns:
|
|
118
|
-
|
|
44
|
+
The created cursor object.
|
|
119
45
|
"""
|
|
120
46
|
assert self.db is not None, "Database connection is not set"
|
|
121
47
|
return self.db.cursor
|
|
122
48
|
|
|
123
|
-
def logQuery(self, cursor: Any, query: Any, params: tuple[Any, ...]) -> None:
|
|
124
|
-
"""
|
|
125
|
-
Logs the given query and parameters.
|
|
126
|
-
|
|
127
|
-
Args:
|
|
128
|
-
cursor (Any): The database cursor.
|
|
129
|
-
query (Any): The query to log.
|
|
130
|
-
params (tuple[Any, ...]): The parameters to log.
|
|
131
|
-
"""
|
|
132
|
-
self.logger.debug(f"Query: {query} with params: {params}")
|
|
133
|
-
|
|
134
|
-
def turnDataIntoModel(
|
|
135
|
-
self,
|
|
136
|
-
emptyDataClass: T,
|
|
137
|
-
dbData: dict[str, Any],
|
|
138
|
-
) -> T:
|
|
139
|
-
"""
|
|
140
|
-
Turns the given data into a data model.
|
|
141
|
-
By default we are pretty sure that there is no factory in the cursor,
|
|
142
|
-
So we need to create a new instance of the data model and fill it with data
|
|
143
|
-
|
|
144
|
-
Args:
|
|
145
|
-
emptyDataClass (T): The data model to use.
|
|
146
|
-
dbData (dict[str, Any]): The data to turn into a model.
|
|
147
|
-
|
|
148
|
-
Returns:
|
|
149
|
-
T: The data model filled with data.
|
|
150
|
-
"""
|
|
151
|
-
|
|
152
|
-
result = emptyDataClass.__class__()
|
|
153
|
-
result.fillDataFromDict(dbData)
|
|
154
|
-
result.raw_data = dbData
|
|
155
|
-
return result
|
|
156
|
-
|
|
157
49
|
#####################
|
|
158
50
|
### Query methods ###
|
|
159
51
|
#####################
|
|
160
52
|
|
|
161
|
-
def filterQuery(self, schemaName: str | None, tableName: str) -> Any:
|
|
162
|
-
"""
|
|
163
|
-
Creates a SQL query to filter data from the given table.
|
|
164
|
-
|
|
165
|
-
Args:
|
|
166
|
-
schemaName (str | None): The name of the schema to filter data from.
|
|
167
|
-
tableName (str): The name of the table to filter data from.
|
|
168
|
-
|
|
169
|
-
Returns:
|
|
170
|
-
Any: The created SQL query object.
|
|
171
|
-
"""
|
|
172
|
-
fullTableName = self.makeIdentifier(schemaName, tableName)
|
|
173
|
-
return f"SELECT * FROM {fullTableName}"
|
|
174
|
-
|
|
175
|
-
def limitQuery(self, offset: int = 0, limit: int = 100) -> Any:
|
|
176
|
-
"""
|
|
177
|
-
Creates a SQL query to limit the number of results returned.
|
|
178
|
-
|
|
179
|
-
Args:
|
|
180
|
-
offset (int, optional): The number of results to skip. Defaults to 0.
|
|
181
|
-
limit (int, optional): The maximum number of results to return. Defaults to 100.
|
|
182
|
-
|
|
183
|
-
Returns:
|
|
184
|
-
Any: The created SQL query object.
|
|
185
|
-
"""
|
|
186
|
-
return f"LIMIT {limit} OFFSET {offset}"
|
|
187
|
-
|
|
188
53
|
# Action methods
|
|
189
54
|
async def getOne(
|
|
190
55
|
self,
|
|
191
|
-
emptyDataClass:
|
|
56
|
+
emptyDataClass: DataModelType,
|
|
192
57
|
customQuery: Any = None,
|
|
193
|
-
) ->
|
|
58
|
+
) -> DataModelType | None:
|
|
194
59
|
"""
|
|
195
|
-
Retrieves a single record from the database.
|
|
60
|
+
Retrieves a single record from the database by class defined id.
|
|
196
61
|
|
|
197
62
|
Args:
|
|
198
|
-
emptyDataClass (
|
|
63
|
+
emptyDataClass (DataModelType): The data model to use for the query.
|
|
199
64
|
customQuery (Any, optional): The custom query to use for the query. Defaults to None.
|
|
200
65
|
|
|
201
66
|
Returns:
|
|
202
|
-
|
|
67
|
+
DataModelType | None: The result of the query.
|
|
203
68
|
"""
|
|
204
|
-
# Query
|
|
69
|
+
# Query and filter
|
|
205
70
|
_query = (
|
|
206
71
|
customQuery
|
|
207
72
|
or emptyDataClass.queryBase()
|
|
@@ -214,18 +79,21 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
214
79
|
if not idValue:
|
|
215
80
|
raise ValueError("Id value is not set")
|
|
216
81
|
|
|
82
|
+
_filter = f"WHERE {self.makeIdentifier(emptyDataClass.tableAlias, idKey)} = %s"
|
|
83
|
+
_params = (idValue,)
|
|
84
|
+
|
|
217
85
|
# Create a SQL object for the query and format it
|
|
218
|
-
querySql =
|
|
86
|
+
querySql = self._formatFilterQuery(_query, _filter, None, None)
|
|
219
87
|
|
|
220
88
|
# Create a new cursor
|
|
221
89
|
newCursor = await self.createCursor(emptyDataClass)
|
|
222
90
|
|
|
223
91
|
# Log
|
|
224
|
-
self.logQuery(newCursor, querySql,
|
|
92
|
+
self.logQuery(newCursor, querySql, _params)
|
|
225
93
|
|
|
226
94
|
# Load data
|
|
227
95
|
try:
|
|
228
|
-
await newCursor.execute(querySql,
|
|
96
|
+
await newCursor.execute(querySql, _params)
|
|
229
97
|
|
|
230
98
|
# Fetch one row
|
|
231
99
|
row = await newCursor.fetchone()
|
|
@@ -240,42 +108,44 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
240
108
|
|
|
241
109
|
async def getByKey(
|
|
242
110
|
self,
|
|
243
|
-
emptyDataClass:
|
|
111
|
+
emptyDataClass: DataModelType,
|
|
244
112
|
idKey: str,
|
|
245
113
|
idValue: Any,
|
|
246
114
|
customQuery: Any = None,
|
|
247
|
-
) ->
|
|
115
|
+
) -> DataModelType | None:
|
|
248
116
|
"""
|
|
249
117
|
Retrieves a single record from the database using the given key.
|
|
250
118
|
|
|
251
119
|
Args:
|
|
252
|
-
emptyDataClass (
|
|
120
|
+
emptyDataClass (DataModelType): The data model to use for the query.
|
|
253
121
|
idKey (str): The name of the key to use for the query.
|
|
254
122
|
idValue (Any): The value of the key to use for the query.
|
|
255
123
|
customQuery (Any, optional): The custom query to use for the query. Defaults to None.
|
|
256
124
|
|
|
257
125
|
Returns:
|
|
258
|
-
|
|
126
|
+
DataModelType | None: The result of the query.
|
|
259
127
|
"""
|
|
260
|
-
# Query
|
|
128
|
+
# Query and filter
|
|
261
129
|
_query = (
|
|
262
130
|
customQuery
|
|
263
131
|
or emptyDataClass.queryBase()
|
|
264
132
|
or self.filterQuery(emptyDataClass.schemaName, emptyDataClass.tableName)
|
|
265
133
|
)
|
|
134
|
+
_filter = f"WHERE {self.makeIdentifier(emptyDataClass.tableAlias, idKey)} = %s"
|
|
135
|
+
_params = (idValue,)
|
|
266
136
|
|
|
267
137
|
# Create a SQL object for the query and format it
|
|
268
|
-
querySql =
|
|
138
|
+
querySql = self._formatFilterQuery(_query, _filter, None, None)
|
|
269
139
|
|
|
270
140
|
# Create a new cursor
|
|
271
141
|
newCursor = await self.createCursor(emptyDataClass)
|
|
272
142
|
|
|
273
143
|
# Log
|
|
274
|
-
self.logQuery(newCursor, querySql,
|
|
144
|
+
self.logQuery(newCursor, querySql, _params)
|
|
275
145
|
|
|
276
146
|
# Load data
|
|
277
147
|
try:
|
|
278
|
-
await newCursor.execute(querySql,
|
|
148
|
+
await newCursor.execute(querySql, _params)
|
|
279
149
|
|
|
280
150
|
# Fetch one row
|
|
281
151
|
row = await newCursor.fetchone()
|
|
@@ -291,19 +161,19 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
291
161
|
|
|
292
162
|
async def getAll(
|
|
293
163
|
self,
|
|
294
|
-
emptyDataClass:
|
|
164
|
+
emptyDataClass: DataModelType,
|
|
295
165
|
idKey: str | None = None,
|
|
296
166
|
idValue: Any | None = None,
|
|
297
167
|
orderBy: OrderByItem | None = None,
|
|
298
168
|
offset: int = 0,
|
|
299
169
|
limit: int = 100,
|
|
300
170
|
customQuery: Any = None,
|
|
301
|
-
) -> AsyncGenerator[
|
|
171
|
+
) -> AsyncGenerator[DataModelType, None]:
|
|
302
172
|
"""
|
|
303
173
|
Retrieves all records from the database.
|
|
304
174
|
|
|
305
175
|
Args:
|
|
306
|
-
emptyDataClass (
|
|
176
|
+
emptyDataClass (DataModelType): The data model to use for the query.
|
|
307
177
|
idKey (str | None, optional): The name of the key to use for filtering. Defaults to None.
|
|
308
178
|
idValue (Any | None, optional): The value of the key to use for filtering. Defaults to None.
|
|
309
179
|
orderBy (OrderByItem | None, optional): The order by item to use for sorting. Defaults to None.
|
|
@@ -312,36 +182,28 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
312
182
|
customQuery (Any, optional): The custom query to use for the query. Defaults to None.
|
|
313
183
|
|
|
314
184
|
Returns:
|
|
315
|
-
AsyncGenerator[
|
|
185
|
+
AsyncGenerator[DataModelType, None]: The result of the query.
|
|
316
186
|
"""
|
|
317
|
-
# Query
|
|
187
|
+
# Query and filter
|
|
318
188
|
_query = (
|
|
319
189
|
customQuery
|
|
320
190
|
or emptyDataClass.queryBase()
|
|
321
191
|
or self.filterQuery(emptyDataClass.schemaName, emptyDataClass.tableName)
|
|
322
192
|
)
|
|
323
193
|
_params: tuple[Any, ...] = ()
|
|
324
|
-
|
|
325
|
-
# Filter
|
|
194
|
+
_filter = None
|
|
326
195
|
if idKey and idValue:
|
|
327
|
-
|
|
196
|
+
_filter = (
|
|
197
|
+
f"WHERE {self.makeIdentifier(emptyDataClass.tableAlias, idKey)} = %s"
|
|
198
|
+
)
|
|
328
199
|
_params = (idValue,)
|
|
329
200
|
|
|
330
|
-
#
|
|
331
|
-
_order =
|
|
332
|
-
_limit =
|
|
333
|
-
|
|
334
|
-
if orderBy:
|
|
335
|
-
orderList = [
|
|
336
|
-
f"{item[0]} {item[1] if len(item) > 1 and item[1] != None else 'ASC'}"
|
|
337
|
-
for item in orderBy
|
|
338
|
-
]
|
|
339
|
-
_order = "ORDER BY %s" % ", ".join(orderList)
|
|
340
|
-
if offset or limit:
|
|
341
|
-
_limit = f"{self.limitQuery(offset, limit)}"
|
|
201
|
+
# Order and limit
|
|
202
|
+
_order = self.orderQuery(orderBy)
|
|
203
|
+
_limit = self.limitQuery(offset, limit)
|
|
342
204
|
|
|
343
205
|
# Create a SQL object for the query and format it
|
|
344
|
-
querySql =
|
|
206
|
+
querySql = self._formatFilterQuery(_query, _filter, _order, _limit)
|
|
345
207
|
|
|
346
208
|
# Create a new cursor
|
|
347
209
|
newCursor = await self.createCursor(emptyDataClass)
|
|
@@ -359,114 +221,36 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
359
221
|
row = await newCursor.fetchone()
|
|
360
222
|
if row is None:
|
|
361
223
|
break
|
|
224
|
+
|
|
362
225
|
yield self.turnDataIntoModel(emptyDataClass, row)
|
|
363
226
|
|
|
364
227
|
finally:
|
|
365
228
|
# Ensure the cursor is closed after the generator is exhausted or an error occurs
|
|
366
229
|
await newCursor.close()
|
|
367
230
|
|
|
368
|
-
def formatFilter(self, key: str, filter: Any) -> tuple[Any, ...]:
|
|
369
|
-
if type(filter) is dict:
|
|
370
|
-
if "$contains" in filter:
|
|
371
|
-
return (
|
|
372
|
-
f"{key} LIKE %s",
|
|
373
|
-
f"%{filter['$contains']}%",
|
|
374
|
-
)
|
|
375
|
-
elif "$starts_with" in filter:
|
|
376
|
-
return (f"{key} LIKE %s", f"{filter['$starts_with']}%")
|
|
377
|
-
elif "$ends_with" in filter:
|
|
378
|
-
return (f"{key} LIKE %s", f"%{filter['$ends_with']}")
|
|
379
|
-
elif "$min" in filter and "$max" not in filter:
|
|
380
|
-
return (f"{key} >= %s", filter["$min"]) # type: ignore
|
|
381
|
-
elif "$max" in filter and "$min" not in filter:
|
|
382
|
-
return (f"{key} <= %s", filter["$max"]) # type: ignore
|
|
383
|
-
elif "$min" in filter and "$max" in filter:
|
|
384
|
-
return (f"{key} BETWEEN %s AND %s", filter["$min"], filter["$max"]) # type: ignore
|
|
385
|
-
elif "$in" in filter:
|
|
386
|
-
inFilter1: list[Any] = cast(list[Any], filter["$in"])
|
|
387
|
-
return (f"{key} IN (%s)" % ",".join(["%s"] * len(inFilter1)),) + tuple(
|
|
388
|
-
inFilter1
|
|
389
|
-
)
|
|
390
|
-
elif "$not_in" in filter:
|
|
391
|
-
inFilter2: list[Any] = cast(list[Any], filter["$in"])
|
|
392
|
-
return (
|
|
393
|
-
f"{key} NOT IN (%s)" % ",".join(["%s"] * len(inFilter2)),
|
|
394
|
-
) + tuple(inFilter2)
|
|
395
|
-
elif "$not" in filter:
|
|
396
|
-
return (f"{key} != %s", filter["$not"]) # type: ignore
|
|
397
|
-
|
|
398
|
-
elif "$gt" in filter:
|
|
399
|
-
return (f"{key} > %s", filter["$gt"]) # type: ignore
|
|
400
|
-
elif "$gte" in filter:
|
|
401
|
-
return (f"{key} >= %s", filter["$gte"]) # type: ignore
|
|
402
|
-
elif "$lt" in filter:
|
|
403
|
-
return (f"{key} < %s", filter["$lt"]) # type: ignore
|
|
404
|
-
elif "$lte" in filter:
|
|
405
|
-
return (f"{key} <= %s", filter["$lte"]) # type: ignore
|
|
406
|
-
elif "$is_null" in filter:
|
|
407
|
-
return (f"{key} IS NULL",) # type: ignore
|
|
408
|
-
elif "$is_not_null" in filter:
|
|
409
|
-
return (f"{key} IS NOT NULL",) # type: ignore
|
|
410
|
-
|
|
411
|
-
raise NotImplementedError("Filter type not supported")
|
|
412
|
-
elif type(filter) is str or type(filter) is int or type(filter) is float:
|
|
413
|
-
return (f"{key} = %s", filter)
|
|
414
|
-
elif type(filter) is bool:
|
|
415
|
-
return (
|
|
416
|
-
f"{key} = TRUE" if filter else f"{key} = FALSE",
|
|
417
|
-
NoParam,
|
|
418
|
-
)
|
|
419
|
-
else:
|
|
420
|
-
raise NotImplementedError(
|
|
421
|
-
f"Filter type not supported: {key} = {type(filter)}"
|
|
422
|
-
)
|
|
423
|
-
|
|
424
|
-
def createFilter(
|
|
425
|
-
self, filter: dict[str, Any] | None
|
|
426
|
-
) -> tuple[str, tuple[Any, ...]]:
|
|
427
|
-
if filter is None or len(filter) == 0:
|
|
428
|
-
return ("", tuple())
|
|
429
|
-
|
|
430
|
-
raw = [self.formatFilter(key, filter[key]) for key in filter]
|
|
431
|
-
_query = " AND ".join([tup[0] for tup in raw])
|
|
432
|
-
_query = f"WHERE {_query}"
|
|
433
|
-
_params = tuple([val for tup in raw for val in tup[1:] if val is not NoParam])
|
|
434
|
-
|
|
435
|
-
return (_query, _params)
|
|
436
|
-
|
|
437
231
|
async def getFiltered(
|
|
438
232
|
self,
|
|
439
|
-
emptyDataClass:
|
|
233
|
+
emptyDataClass: DataModelType,
|
|
440
234
|
filter: dict[str, Any],
|
|
441
235
|
orderBy: OrderByItem | None = None,
|
|
442
236
|
offset: int = 0,
|
|
443
237
|
limit: int = 100,
|
|
444
238
|
customQuery: Any = None,
|
|
445
|
-
) -> AsyncGenerator[
|
|
446
|
-
#
|
|
239
|
+
) -> AsyncGenerator[DataModelType, None]:
|
|
240
|
+
# Query and filter
|
|
447
241
|
_query = (
|
|
448
242
|
customQuery
|
|
449
243
|
or emptyDataClass.queryBase()
|
|
450
244
|
or self.filterQuery(emptyDataClass.schemaName, emptyDataClass.tableName)
|
|
451
245
|
)
|
|
452
246
|
(_filter, _params) = self.createFilter(filter)
|
|
453
|
-
_filter = _filter
|
|
454
247
|
|
|
455
|
-
#
|
|
456
|
-
_order =
|
|
457
|
-
_limit =
|
|
248
|
+
# Order and limit
|
|
249
|
+
_order = self.orderQuery(orderBy)
|
|
250
|
+
_limit = self.limitQuery(offset, limit)
|
|
458
251
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
f"{item[0]} {item[1] if len(item) > 1 and item[1] != None else 'ASC'}"
|
|
462
|
-
for item in orderBy
|
|
463
|
-
]
|
|
464
|
-
_order = "ORDER BY %s" % ", ".join(orderList)
|
|
465
|
-
if offset or limit:
|
|
466
|
-
_limit = f"{self.limitQuery(offset, limit)}"
|
|
467
|
-
|
|
468
|
-
# Create a SQL object for the query and format it
|
|
469
|
-
querySql = f"{_query} {_filter} {_order} {_limit}"
|
|
252
|
+
# Create SQL query
|
|
253
|
+
querySql = self._formatFilterQuery(_query, _filter, _order, _limit)
|
|
470
254
|
|
|
471
255
|
# Create a new cursor
|
|
472
256
|
newCursor = await self.createCursor(emptyDataClass)
|
|
@@ -484,6 +268,7 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
484
268
|
row = await newCursor.fetchone()
|
|
485
269
|
if row is None:
|
|
486
270
|
break
|
|
271
|
+
|
|
487
272
|
yield self.turnDataIntoModel(emptyDataClass, row)
|
|
488
273
|
|
|
489
274
|
finally:
|
|
@@ -511,20 +296,10 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
511
296
|
Returns:
|
|
512
297
|
tuple[int, int]: The id of the record and the number of affected rows.
|
|
513
298
|
"""
|
|
514
|
-
keys = storeData.keys()
|
|
515
299
|
values = list(storeData.values())
|
|
516
|
-
|
|
517
300
|
tableIdentifier = self.makeIdentifier(schemaName, tableName)
|
|
518
301
|
returnKey = self.makeIdentifier(emptyDataClass.tableAlias, idKey)
|
|
519
|
-
|
|
520
|
-
columns = ", ".join(keys)
|
|
521
|
-
valuesPlaceholder = ", ".join(["%s"] * len(values))
|
|
522
|
-
insertQuery = (
|
|
523
|
-
f"INSERT INTO {tableIdentifier} "
|
|
524
|
-
f"({columns}) "
|
|
525
|
-
f"VALUES ({valuesPlaceholder}) "
|
|
526
|
-
f"RETURNING {returnKey}"
|
|
527
|
-
)
|
|
302
|
+
insertQuery = self._formatInsertQuery(tableIdentifier, storeData, returnKey)
|
|
528
303
|
|
|
529
304
|
# Create a new cursor
|
|
530
305
|
newCursor = await self.createCursor(emptyDataClass)
|
|
@@ -548,21 +323,21 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
548
323
|
await newCursor.close()
|
|
549
324
|
|
|
550
325
|
@overload
|
|
551
|
-
async def store(self, records:
|
|
326
|
+
async def store(self, records: DataModelType) -> tuple[int, int]: # type: ignore
|
|
552
327
|
...
|
|
553
328
|
|
|
554
329
|
@overload
|
|
555
|
-
async def store(self, records: list[
|
|
330
|
+
async def store(self, records: list[DataModelType]) -> list[tuple[int, int]]: ...
|
|
556
331
|
|
|
557
332
|
async def store(
|
|
558
333
|
self,
|
|
559
|
-
records:
|
|
334
|
+
records: DataModelType | list[DataModelType],
|
|
560
335
|
) -> tuple[int, int] | list[tuple[int, int]]:
|
|
561
336
|
"""
|
|
562
337
|
Stores a record or a list of records in the database.
|
|
563
338
|
|
|
564
339
|
Args:
|
|
565
|
-
records (
|
|
340
|
+
records (DataModelType | list[DataModelType]): The record or records to store.
|
|
566
341
|
|
|
567
342
|
Returns:
|
|
568
343
|
tuple[int, int] | list[tuple[int, int]]: The id of the record and
|
|
@@ -621,17 +396,12 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
621
396
|
int: The number of affected rows.
|
|
622
397
|
"""
|
|
623
398
|
(idKey, idValue) = updateId
|
|
624
|
-
keys = updateData.keys()
|
|
625
399
|
values = list(updateData.values())
|
|
626
400
|
values.append(idValue)
|
|
627
401
|
|
|
628
|
-
set_clause = ", ".join(f"{key} = %s" for key in keys)
|
|
629
|
-
|
|
630
402
|
tableIdentifier = self.makeIdentifier(schemaName, tableName)
|
|
631
403
|
updateKey = self.makeIdentifier(emptyDataClass.tableAlias, idKey)
|
|
632
|
-
updateQuery = (
|
|
633
|
-
f"UPDATE {tableIdentifier} SET {set_clause} WHERE {updateKey} = %s"
|
|
634
|
-
)
|
|
404
|
+
updateQuery = self._formatUpdateQuery(tableIdentifier, updateKey, updateData)
|
|
635
405
|
|
|
636
406
|
# Create a new cursor
|
|
637
407
|
newCursor = await self.createCursor(emptyDataClass)
|
|
@@ -651,18 +421,20 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
651
421
|
await newCursor.close()
|
|
652
422
|
|
|
653
423
|
@overload
|
|
654
|
-
async def update(self, records:
|
|
424
|
+
async def update(self, records: DataModelType) -> int: # type: ignore
|
|
655
425
|
...
|
|
656
426
|
|
|
657
427
|
@overload
|
|
658
|
-
async def update(self, records: list[
|
|
428
|
+
async def update(self, records: list[DataModelType]) -> list[int]: ...
|
|
659
429
|
|
|
660
|
-
async def update(
|
|
430
|
+
async def update(
|
|
431
|
+
self, records: DataModelType | list[DataModelType]
|
|
432
|
+
) -> int | list[int]:
|
|
661
433
|
"""
|
|
662
434
|
Updates a record or a list of records in the database.
|
|
663
435
|
|
|
664
436
|
Args:
|
|
665
|
-
records (
|
|
437
|
+
records (DataModelType | list[DataModelType]): The record or records to update.
|
|
666
438
|
|
|
667
439
|
Returns:
|
|
668
440
|
int | list[int]: The number of affected rows for a single record or a list of
|
|
@@ -745,7 +517,7 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
745
517
|
|
|
746
518
|
tableIdentifier = self.makeIdentifier(schemaName, tableName)
|
|
747
519
|
deleteKey = self.makeIdentifier(emptyDataClass.tableAlias, idKey)
|
|
748
|
-
delete_query =
|
|
520
|
+
delete_query = self._formatDeleteQuery(tableIdentifier, deleteKey)
|
|
749
521
|
|
|
750
522
|
# Create a new cursor
|
|
751
523
|
newCursor = await self.createCursor(emptyDataClass)
|
|
@@ -765,18 +537,20 @@ class DBWrapperAsync(DBWrapperInterface):
|
|
|
765
537
|
await newCursor.close()
|
|
766
538
|
|
|
767
539
|
@overload
|
|
768
|
-
async def delete(self, records:
|
|
540
|
+
async def delete(self, records: DataModelType) -> int: # type: ignore
|
|
769
541
|
...
|
|
770
542
|
|
|
771
543
|
@overload
|
|
772
|
-
async def delete(self, records: list[
|
|
544
|
+
async def delete(self, records: list[DataModelType]) -> list[int]: ...
|
|
773
545
|
|
|
774
|
-
async def delete(
|
|
546
|
+
async def delete(
|
|
547
|
+
self, records: DataModelType | list[DataModelType]
|
|
548
|
+
) -> int | list[int]:
|
|
775
549
|
"""
|
|
776
550
|
Deletes a record or a list of records from the database.
|
|
777
551
|
|
|
778
552
|
Args:
|
|
779
|
-
records (
|
|
553
|
+
records (DataModelType | list[DataModelType]): The record or records to delete.
|
|
780
554
|
|
|
781
555
|
Returns:
|
|
782
556
|
int | list[int]: The number of affected rows for a single record or a list of
|