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