sqlspec 0.10.1__py3-none-any.whl → 0.11.1__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.
Potentially problematic release.
This version of sqlspec might be problematic. Click here for more details.
- sqlspec/adapters/adbc/config.py +1 -1
- sqlspec/adapters/adbc/driver.py +340 -192
- sqlspec/adapters/aiosqlite/driver.py +183 -129
- sqlspec/adapters/asyncmy/driver.py +168 -88
- sqlspec/adapters/asyncpg/config.py +3 -1
- sqlspec/adapters/asyncpg/driver.py +208 -259
- sqlspec/adapters/bigquery/driver.py +184 -264
- sqlspec/adapters/duckdb/driver.py +172 -110
- sqlspec/adapters/oracledb/driver.py +274 -160
- sqlspec/adapters/psqlpy/driver.py +274 -211
- sqlspec/adapters/psycopg/driver.py +196 -283
- sqlspec/adapters/sqlite/driver.py +154 -142
- sqlspec/base.py +56 -85
- sqlspec/extensions/litestar/__init__.py +3 -12
- sqlspec/extensions/litestar/config.py +22 -7
- sqlspec/extensions/litestar/handlers.py +142 -85
- sqlspec/extensions/litestar/plugin.py +9 -8
- sqlspec/extensions/litestar/providers.py +521 -0
- sqlspec/filters.py +215 -11
- sqlspec/mixins.py +161 -12
- sqlspec/statement.py +276 -271
- sqlspec/typing.py +18 -1
- sqlspec/utils/__init__.py +2 -2
- sqlspec/utils/singleton.py +35 -0
- sqlspec/utils/sync_tools.py +90 -151
- sqlspec/utils/text.py +68 -5
- {sqlspec-0.10.1.dist-info → sqlspec-0.11.1.dist-info}/METADATA +8 -1
- {sqlspec-0.10.1.dist-info → sqlspec-0.11.1.dist-info}/RECORD +31 -29
- {sqlspec-0.10.1.dist-info → sqlspec-0.11.1.dist-info}/WHEEL +0 -0
- {sqlspec-0.10.1.dist-info → sqlspec-0.11.1.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.10.1.dist-info → sqlspec-0.11.1.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
# type: ignore
|
|
2
|
-
|
|
2
|
+
import logging
|
|
3
|
+
import re
|
|
4
|
+
from collections.abc import AsyncGenerator
|
|
3
5
|
from contextlib import asynccontextmanager
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Optional, Union,
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Optional, Union, overload
|
|
5
7
|
|
|
6
8
|
from asyncmy import Connection
|
|
7
9
|
|
|
8
10
|
from sqlspec.base import AsyncDriverAdapterProtocol
|
|
9
|
-
from sqlspec.
|
|
11
|
+
from sqlspec.exceptions import ParameterStyleMismatchError
|
|
12
|
+
from sqlspec.filters import StatementFilter
|
|
13
|
+
from sqlspec.mixins import ResultConverter, SQLTranslatorMixin
|
|
14
|
+
from sqlspec.statement import SQLStatement
|
|
15
|
+
from sqlspec.typing import is_dict
|
|
10
16
|
|
|
11
17
|
if TYPE_CHECKING:
|
|
18
|
+
from collections.abc import Mapping, Sequence
|
|
19
|
+
|
|
12
20
|
from asyncmy.cursors import Cursor
|
|
13
21
|
|
|
14
22
|
from sqlspec.typing import ModelDTOT, StatementParameterType, T
|
|
@@ -17,10 +25,16 @@ __all__ = ("AsyncmyDriver",)
|
|
|
17
25
|
|
|
18
26
|
AsyncmyConnection = Connection
|
|
19
27
|
|
|
28
|
+
logger = logging.getLogger("sqlspec")
|
|
29
|
+
|
|
30
|
+
# Pattern to identify MySQL-style placeholders (%s) for proper conversion
|
|
31
|
+
MYSQL_PLACEHOLDER_PATTERN = re.compile(r"(?<!%)%s")
|
|
32
|
+
|
|
20
33
|
|
|
21
34
|
class AsyncmyDriver(
|
|
22
35
|
SQLTranslatorMixin["AsyncmyConnection"],
|
|
23
36
|
AsyncDriverAdapterProtocol["AsyncmyConnection"],
|
|
37
|
+
ResultConverter,
|
|
24
38
|
):
|
|
25
39
|
"""Asyncmy MySQL/MariaDB Driver Adapter."""
|
|
26
40
|
|
|
@@ -39,14 +53,102 @@ class AsyncmyDriver(
|
|
|
39
53
|
finally:
|
|
40
54
|
await cursor.close()
|
|
41
55
|
|
|
56
|
+
def _process_sql_params(
|
|
57
|
+
self,
|
|
58
|
+
sql: str,
|
|
59
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
60
|
+
*filters: "StatementFilter",
|
|
61
|
+
**kwargs: Any,
|
|
62
|
+
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
63
|
+
"""Process SQL and parameters using SQLStatement with dialect support.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
sql: The SQL statement to process.
|
|
67
|
+
parameters: The parameters to bind to the statement. Can be data or a StatementFilter.
|
|
68
|
+
*filters: Statement filters to apply.
|
|
69
|
+
**kwargs: Additional keyword arguments.
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
ParameterStyleMismatchError: If the parameter style is not supported.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
A tuple of (sql, parameters) ready for execution.
|
|
76
|
+
"""
|
|
77
|
+
# Convert filters tuple to a list to allow modification
|
|
78
|
+
current_filters: list[StatementFilter] = list(filters)
|
|
79
|
+
actual_parameters: Optional[Union[Mapping[str, Any], Sequence[Any]]] = None
|
|
80
|
+
|
|
81
|
+
if parameters is not None:
|
|
82
|
+
if isinstance(parameters, StatementFilter):
|
|
83
|
+
current_filters.insert(0, parameters)
|
|
84
|
+
# actual_parameters remains None
|
|
85
|
+
else:
|
|
86
|
+
actual_parameters = parameters # type: ignore[assignment]
|
|
87
|
+
|
|
88
|
+
# Handle MySQL-specific placeholders (%s) which SQLGlot doesn't parse well
|
|
89
|
+
# If %s placeholders are present, handle them directly
|
|
90
|
+
mysql_placeholders_count = len(MYSQL_PLACEHOLDER_PATTERN.findall(sql))
|
|
91
|
+
|
|
92
|
+
if mysql_placeholders_count > 0:
|
|
93
|
+
# For MySQL format placeholders, minimal processing is needed
|
|
94
|
+
if actual_parameters is None:
|
|
95
|
+
if mysql_placeholders_count > 0:
|
|
96
|
+
msg = f"asyncmy: SQL statement contains {mysql_placeholders_count} format placeholders ('%s'), but no parameters were provided. SQL: {sql}"
|
|
97
|
+
raise ParameterStyleMismatchError(msg)
|
|
98
|
+
return sql, None
|
|
99
|
+
|
|
100
|
+
# Convert dict to tuple if needed
|
|
101
|
+
if is_dict(actual_parameters):
|
|
102
|
+
# MySQL's %s placeholders require positional params
|
|
103
|
+
msg = "asyncmy: Dictionary parameters provided with '%s' placeholders. MySQL format placeholders require tuple/list parameters."
|
|
104
|
+
raise ParameterStyleMismatchError(msg)
|
|
105
|
+
|
|
106
|
+
# Convert to tuple (handles both scalar and sequence cases)
|
|
107
|
+
if not isinstance(actual_parameters, (list, tuple)):
|
|
108
|
+
# Scalar parameter case
|
|
109
|
+
return sql, (actual_parameters,)
|
|
110
|
+
|
|
111
|
+
# Sequence parameter case - ensure appropriate length
|
|
112
|
+
if len(actual_parameters) != mysql_placeholders_count: # type: ignore[arg-type]
|
|
113
|
+
msg = f"asyncmy: Parameter count mismatch. SQL expects {mysql_placeholders_count} '%s' placeholders, but {len(actual_parameters)} parameters were provided. SQL: {sql}" # type: ignore[arg-type]
|
|
114
|
+
raise ParameterStyleMismatchError(msg)
|
|
115
|
+
|
|
116
|
+
return sql, tuple(actual_parameters) # type: ignore[arg-type]
|
|
117
|
+
|
|
118
|
+
# Create a SQLStatement with MySQL dialect
|
|
119
|
+
statement = SQLStatement(sql, actual_parameters, kwargs=kwargs, dialect=self.dialect)
|
|
120
|
+
|
|
121
|
+
# Apply any filters
|
|
122
|
+
for filter_obj in current_filters: # Use the modified list of filters
|
|
123
|
+
statement = statement.apply_filter(filter_obj)
|
|
124
|
+
|
|
125
|
+
# Process the statement for execution
|
|
126
|
+
processed_sql, processed_params, _ = statement.process()
|
|
127
|
+
|
|
128
|
+
# Convert parameters to the format expected by MySQL
|
|
129
|
+
if processed_params is None:
|
|
130
|
+
return processed_sql, None
|
|
131
|
+
|
|
132
|
+
# For MySQL, ensure parameters are in the right format
|
|
133
|
+
if is_dict(processed_params):
|
|
134
|
+
# Dictionary parameters are not well supported by asyncmy
|
|
135
|
+
msg = "asyncmy: Dictionary parameters are not supported for MySQL placeholders. Use sequence parameters."
|
|
136
|
+
raise ParameterStyleMismatchError(msg)
|
|
137
|
+
|
|
138
|
+
# For sequence parameters, ensure they're a tuple
|
|
139
|
+
if isinstance(processed_params, (list, tuple)):
|
|
140
|
+
return processed_sql, tuple(processed_params)
|
|
141
|
+
|
|
142
|
+
# For scalar parameter, wrap in a tuple
|
|
143
|
+
return processed_sql, (processed_params,)
|
|
144
|
+
|
|
42
145
|
# --- Public API Methods --- #
|
|
43
146
|
@overload
|
|
44
147
|
async def select(
|
|
45
148
|
self,
|
|
46
149
|
sql: str,
|
|
47
150
|
parameters: "Optional[StatementParameterType]" = None,
|
|
48
|
-
|
|
49
|
-
*,
|
|
151
|
+
*filters: "StatementFilter",
|
|
50
152
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
51
153
|
schema_type: None = None,
|
|
52
154
|
**kwargs: Any,
|
|
@@ -56,8 +158,7 @@ class AsyncmyDriver(
|
|
|
56
158
|
self,
|
|
57
159
|
sql: str,
|
|
58
160
|
parameters: "Optional[StatementParameterType]" = None,
|
|
59
|
-
|
|
60
|
-
*,
|
|
161
|
+
*filters: "StatementFilter",
|
|
61
162
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
62
163
|
schema_type: "type[ModelDTOT]",
|
|
63
164
|
**kwargs: Any,
|
|
@@ -65,37 +166,33 @@ class AsyncmyDriver(
|
|
|
65
166
|
async def select(
|
|
66
167
|
self,
|
|
67
168
|
sql: str,
|
|
68
|
-
parameters: Optional[
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
connection: Optional["AsyncmyConnection"] = None,
|
|
169
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
170
|
+
*filters: "StatementFilter",
|
|
171
|
+
connection: "Optional[AsyncmyConnection]" = None,
|
|
72
172
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
73
173
|
**kwargs: Any,
|
|
74
|
-
) -> "Sequence[Union[
|
|
174
|
+
) -> "Sequence[Union[dict[str, Any], ModelDTOT]]":
|
|
75
175
|
"""Fetch data from the database.
|
|
76
176
|
|
|
77
177
|
Returns:
|
|
78
178
|
List of row data as either model instances or dictionaries.
|
|
79
179
|
"""
|
|
80
180
|
connection = self._connection(connection)
|
|
81
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
181
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
82
182
|
async with self._with_cursor(connection) as cursor:
|
|
83
183
|
await cursor.execute(sql, parameters)
|
|
84
184
|
results = await cursor.fetchall()
|
|
85
185
|
if not results:
|
|
86
186
|
return []
|
|
87
187
|
column_names = [c[0] for c in cursor.description or []]
|
|
88
|
-
|
|
89
|
-
return [dict(zip(column_names, row)) for row in results]
|
|
90
|
-
return [schema_type(**dict(zip(column_names, row))) for row in results]
|
|
188
|
+
return self.to_schema([dict(zip(column_names, row)) for row in results], schema_type=schema_type)
|
|
91
189
|
|
|
92
190
|
@overload
|
|
93
191
|
async def select_one(
|
|
94
192
|
self,
|
|
95
193
|
sql: str,
|
|
96
194
|
parameters: "Optional[StatementParameterType]" = None,
|
|
97
|
-
|
|
98
|
-
*,
|
|
195
|
+
*filters: "StatementFilter",
|
|
99
196
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
100
197
|
schema_type: None = None,
|
|
101
198
|
**kwargs: Any,
|
|
@@ -105,8 +202,7 @@ class AsyncmyDriver(
|
|
|
105
202
|
self,
|
|
106
203
|
sql: str,
|
|
107
204
|
parameters: "Optional[StatementParameterType]" = None,
|
|
108
|
-
|
|
109
|
-
*,
|
|
205
|
+
*filters: "StatementFilter",
|
|
110
206
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
111
207
|
schema_type: "type[ModelDTOT]",
|
|
112
208
|
**kwargs: Any,
|
|
@@ -114,36 +210,32 @@ class AsyncmyDriver(
|
|
|
114
210
|
async def select_one(
|
|
115
211
|
self,
|
|
116
212
|
sql: str,
|
|
117
|
-
parameters: Optional[
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
connection: Optional["AsyncmyConnection"] = None,
|
|
213
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
214
|
+
*filters: "StatementFilter",
|
|
215
|
+
connection: "Optional[AsyncmyConnection]" = None,
|
|
121
216
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
122
217
|
**kwargs: Any,
|
|
123
|
-
) -> "Union[
|
|
218
|
+
) -> "Union[dict[str, Any], ModelDTOT]":
|
|
124
219
|
"""Fetch one row from the database.
|
|
125
220
|
|
|
126
221
|
Returns:
|
|
127
222
|
The first row of the query results.
|
|
128
223
|
"""
|
|
129
224
|
connection = self._connection(connection)
|
|
130
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
225
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
131
226
|
async with self._with_cursor(connection) as cursor:
|
|
132
227
|
await cursor.execute(sql, parameters)
|
|
133
228
|
result = await cursor.fetchone()
|
|
134
229
|
result = self.check_not_found(result)
|
|
135
230
|
column_names = [c[0] for c in cursor.description or []]
|
|
136
|
-
|
|
137
|
-
return dict(zip(column_names, result))
|
|
138
|
-
return cast("ModelDTOT", schema_type(**dict(zip(column_names, result))))
|
|
231
|
+
return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
|
|
139
232
|
|
|
140
233
|
@overload
|
|
141
234
|
async def select_one_or_none(
|
|
142
235
|
self,
|
|
143
236
|
sql: str,
|
|
144
237
|
parameters: "Optional[StatementParameterType]" = None,
|
|
145
|
-
|
|
146
|
-
*,
|
|
238
|
+
*filters: "StatementFilter",
|
|
147
239
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
148
240
|
schema_type: None = None,
|
|
149
241
|
**kwargs: Any,
|
|
@@ -153,8 +245,7 @@ class AsyncmyDriver(
|
|
|
153
245
|
self,
|
|
154
246
|
sql: str,
|
|
155
247
|
parameters: "Optional[StatementParameterType]" = None,
|
|
156
|
-
|
|
157
|
-
*,
|
|
248
|
+
*filters: "StatementFilter",
|
|
158
249
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
159
250
|
schema_type: "type[ModelDTOT]",
|
|
160
251
|
**kwargs: Any,
|
|
@@ -162,37 +253,33 @@ class AsyncmyDriver(
|
|
|
162
253
|
async def select_one_or_none(
|
|
163
254
|
self,
|
|
164
255
|
sql: str,
|
|
165
|
-
parameters: Optional[
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
connection: Optional["AsyncmyConnection"] = None,
|
|
256
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
257
|
+
*filters: "StatementFilter",
|
|
258
|
+
connection: "Optional[AsyncmyConnection]" = None,
|
|
169
259
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
170
260
|
**kwargs: Any,
|
|
171
|
-
) -> "Optional[Union[
|
|
261
|
+
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
172
262
|
"""Fetch one row from the database.
|
|
173
263
|
|
|
174
264
|
Returns:
|
|
175
265
|
The first row of the query results.
|
|
176
266
|
"""
|
|
177
267
|
connection = self._connection(connection)
|
|
178
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
268
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
179
269
|
async with self._with_cursor(connection) as cursor:
|
|
180
270
|
await cursor.execute(sql, parameters)
|
|
181
271
|
result = await cursor.fetchone()
|
|
182
272
|
if result is None:
|
|
183
273
|
return None
|
|
184
274
|
column_names = [c[0] for c in cursor.description or []]
|
|
185
|
-
|
|
186
|
-
return dict(zip(column_names, result))
|
|
187
|
-
return cast("ModelDTOT", schema_type(**dict(zip(column_names, result))))
|
|
275
|
+
return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
|
|
188
276
|
|
|
189
277
|
@overload
|
|
190
278
|
async def select_value(
|
|
191
279
|
self,
|
|
192
280
|
sql: str,
|
|
193
281
|
parameters: "Optional[StatementParameterType]" = None,
|
|
194
|
-
|
|
195
|
-
*,
|
|
282
|
+
*filters: "StatementFilter",
|
|
196
283
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
197
284
|
schema_type: None = None,
|
|
198
285
|
**kwargs: Any,
|
|
@@ -202,8 +289,7 @@ class AsyncmyDriver(
|
|
|
202
289
|
self,
|
|
203
290
|
sql: str,
|
|
204
291
|
parameters: "Optional[StatementParameterType]" = None,
|
|
205
|
-
|
|
206
|
-
*,
|
|
292
|
+
*filters: "StatementFilter",
|
|
207
293
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
208
294
|
schema_type: "type[T]",
|
|
209
295
|
**kwargs: Any,
|
|
@@ -212,8 +298,7 @@ class AsyncmyDriver(
|
|
|
212
298
|
self,
|
|
213
299
|
sql: str,
|
|
214
300
|
parameters: "Optional[StatementParameterType]" = None,
|
|
215
|
-
|
|
216
|
-
*,
|
|
301
|
+
*filters: "StatementFilter",
|
|
217
302
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
218
303
|
schema_type: "Optional[type[T]]" = None,
|
|
219
304
|
**kwargs: Any,
|
|
@@ -221,16 +306,14 @@ class AsyncmyDriver(
|
|
|
221
306
|
"""Fetch a single value from the database.
|
|
222
307
|
|
|
223
308
|
Returns:
|
|
224
|
-
The first value from the first row of results
|
|
309
|
+
The first value from the first row of results.
|
|
225
310
|
"""
|
|
226
311
|
connection = self._connection(connection)
|
|
227
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
228
|
-
|
|
312
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
229
313
|
async with self._with_cursor(connection) as cursor:
|
|
230
314
|
await cursor.execute(sql, parameters)
|
|
231
315
|
result = await cursor.fetchone()
|
|
232
316
|
result = self.check_not_found(result)
|
|
233
|
-
|
|
234
317
|
value = result[0]
|
|
235
318
|
if schema_type is not None:
|
|
236
319
|
return schema_type(value) # type: ignore[call-arg]
|
|
@@ -241,8 +324,7 @@ class AsyncmyDriver(
|
|
|
241
324
|
self,
|
|
242
325
|
sql: str,
|
|
243
326
|
parameters: "Optional[StatementParameterType]" = None,
|
|
244
|
-
|
|
245
|
-
*,
|
|
327
|
+
*filters: "StatementFilter",
|
|
246
328
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
247
329
|
schema_type: None = None,
|
|
248
330
|
**kwargs: Any,
|
|
@@ -252,8 +334,7 @@ class AsyncmyDriver(
|
|
|
252
334
|
self,
|
|
253
335
|
sql: str,
|
|
254
336
|
parameters: "Optional[StatementParameterType]" = None,
|
|
255
|
-
|
|
256
|
-
*,
|
|
337
|
+
*filters: "StatementFilter",
|
|
257
338
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
258
339
|
schema_type: "type[T]",
|
|
259
340
|
**kwargs: Any,
|
|
@@ -262,8 +343,7 @@ class AsyncmyDriver(
|
|
|
262
343
|
self,
|
|
263
344
|
sql: str,
|
|
264
345
|
parameters: "Optional[StatementParameterType]" = None,
|
|
265
|
-
|
|
266
|
-
*,
|
|
346
|
+
*filters: "StatementFilter",
|
|
267
347
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
268
348
|
schema_type: "Optional[type[T]]" = None,
|
|
269
349
|
**kwargs: Any,
|
|
@@ -274,15 +354,12 @@ class AsyncmyDriver(
|
|
|
274
354
|
The first value from the first row of results, or None if no results.
|
|
275
355
|
"""
|
|
276
356
|
connection = self._connection(connection)
|
|
277
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
278
|
-
|
|
357
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
279
358
|
async with self._with_cursor(connection) as cursor:
|
|
280
359
|
await cursor.execute(sql, parameters)
|
|
281
360
|
result = await cursor.fetchone()
|
|
282
|
-
|
|
283
361
|
if result is None:
|
|
284
362
|
return None
|
|
285
|
-
|
|
286
363
|
value = result[0]
|
|
287
364
|
if schema_type is not None:
|
|
288
365
|
return schema_type(value) # type: ignore[call-arg]
|
|
@@ -291,10 +368,9 @@ class AsyncmyDriver(
|
|
|
291
368
|
async def insert_update_delete(
|
|
292
369
|
self,
|
|
293
370
|
sql: str,
|
|
294
|
-
parameters: Optional[
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
connection: Optional["AsyncmyConnection"] = None,
|
|
371
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
372
|
+
*filters: "StatementFilter",
|
|
373
|
+
connection: "Optional[AsyncmyConnection]" = None,
|
|
298
374
|
**kwargs: Any,
|
|
299
375
|
) -> int:
|
|
300
376
|
"""Insert, update, or delete data from the database.
|
|
@@ -303,8 +379,7 @@ class AsyncmyDriver(
|
|
|
303
379
|
Row count affected by the operation.
|
|
304
380
|
"""
|
|
305
381
|
connection = self._connection(connection)
|
|
306
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
307
|
-
|
|
382
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
308
383
|
async with self._with_cursor(connection) as cursor:
|
|
309
384
|
await cursor.execute(sql, parameters)
|
|
310
385
|
return cursor.rowcount
|
|
@@ -314,8 +389,7 @@ class AsyncmyDriver(
|
|
|
314
389
|
self,
|
|
315
390
|
sql: str,
|
|
316
391
|
parameters: "Optional[StatementParameterType]" = None,
|
|
317
|
-
|
|
318
|
-
*,
|
|
392
|
+
*filters: "StatementFilter",
|
|
319
393
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
320
394
|
schema_type: None = None,
|
|
321
395
|
**kwargs: Any,
|
|
@@ -325,8 +399,7 @@ class AsyncmyDriver(
|
|
|
325
399
|
self,
|
|
326
400
|
sql: str,
|
|
327
401
|
parameters: "Optional[StatementParameterType]" = None,
|
|
328
|
-
|
|
329
|
-
*,
|
|
402
|
+
*filters: "StatementFilter",
|
|
330
403
|
connection: "Optional[AsyncmyConnection]" = None,
|
|
331
404
|
schema_type: "type[ModelDTOT]",
|
|
332
405
|
**kwargs: Any,
|
|
@@ -334,21 +407,19 @@ class AsyncmyDriver(
|
|
|
334
407
|
async def insert_update_delete_returning(
|
|
335
408
|
self,
|
|
336
409
|
sql: str,
|
|
337
|
-
parameters: Optional[
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
connection: Optional["AsyncmyConnection"] = None,
|
|
410
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
411
|
+
*filters: "StatementFilter",
|
|
412
|
+
connection: "Optional[AsyncmyConnection]" = None,
|
|
341
413
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
342
414
|
**kwargs: Any,
|
|
343
|
-
) -> "
|
|
415
|
+
) -> "Union[dict[str, Any], ModelDTOT]":
|
|
344
416
|
"""Insert, update, or delete data from the database and return result.
|
|
345
417
|
|
|
346
418
|
Returns:
|
|
347
419
|
The first row of results.
|
|
348
420
|
"""
|
|
349
421
|
connection = self._connection(connection)
|
|
350
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
351
|
-
column_names: list[str] = []
|
|
422
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
352
423
|
|
|
353
424
|
async with self._with_cursor(connection) as cursor:
|
|
354
425
|
await cursor.execute(sql, parameters)
|
|
@@ -356,17 +427,16 @@ class AsyncmyDriver(
|
|
|
356
427
|
if result is None:
|
|
357
428
|
return None
|
|
358
429
|
column_names = [c[0] for c in cursor.description or []]
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
430
|
+
|
|
431
|
+
# Convert to dict and use ResultConverter
|
|
432
|
+
dict_result = dict(zip(column_names, result))
|
|
433
|
+
return self.to_schema(dict_result, schema_type=schema_type)
|
|
362
434
|
|
|
363
435
|
async def execute_script(
|
|
364
436
|
self,
|
|
365
437
|
sql: str,
|
|
366
|
-
parameters: Optional[
|
|
367
|
-
|
|
368
|
-
*,
|
|
369
|
-
connection: Optional["AsyncmyConnection"] = None,
|
|
438
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
439
|
+
connection: "Optional[AsyncmyConnection]" = None,
|
|
370
440
|
**kwargs: Any,
|
|
371
441
|
) -> str:
|
|
372
442
|
"""Execute a script.
|
|
@@ -376,7 +446,17 @@ class AsyncmyDriver(
|
|
|
376
446
|
"""
|
|
377
447
|
connection = self._connection(connection)
|
|
378
448
|
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
379
|
-
|
|
380
449
|
async with self._with_cursor(connection) as cursor:
|
|
381
450
|
await cursor.execute(sql, parameters)
|
|
382
|
-
return "
|
|
451
|
+
return f"Script executed successfully. Rows affected: {cursor.rowcount}"
|
|
452
|
+
|
|
453
|
+
def _connection(self, connection: "Optional[AsyncmyConnection]" = None) -> "AsyncmyConnection":
|
|
454
|
+
"""Get the connection to use for the operation.
|
|
455
|
+
|
|
456
|
+
Args:
|
|
457
|
+
connection: Optional connection to use.
|
|
458
|
+
|
|
459
|
+
Returns:
|
|
460
|
+
The connection to use.
|
|
461
|
+
"""
|
|
462
|
+
return connection or self.connection
|
|
@@ -83,7 +83,9 @@ class AsyncpgConfig(AsyncDatabaseConfig["AsyncpgConnection", "Pool", "AsyncpgDri
|
|
|
83
83
|
"""For dialects that support the JSON datatype, this is a Python callable that will render a given object as JSON.
|
|
84
84
|
By default, SQLSpec's :attr:`encode_json() <sqlspec._serialization.encode_json>` is used."""
|
|
85
85
|
connection_type: "type[AsyncpgConnection]" = field(
|
|
86
|
-
hash=False,
|
|
86
|
+
hash=False,
|
|
87
|
+
init=False,
|
|
88
|
+
default_factory=lambda: PoolConnectionProxy, # type: ignore[assignment]
|
|
87
89
|
)
|
|
88
90
|
"""Type of the connection object"""
|
|
89
91
|
driver_type: "type[AsyncpgDriver]" = field(hash=False, init=False, default_factory=lambda: AsyncpgDriver) # type: ignore[type-abstract,unused-ignore]
|