sqlspec 0.9.0__py3-none-any.whl → 0.10.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/__init__.py +2 -1
- sqlspec/adapters/adbc/__init__.py +2 -1
- sqlspec/adapters/adbc/config.py +7 -13
- sqlspec/adapters/adbc/driver.py +160 -21
- sqlspec/adapters/aiosqlite/__init__.py +2 -1
- sqlspec/adapters/aiosqlite/config.py +10 -12
- sqlspec/adapters/aiosqlite/driver.py +160 -22
- sqlspec/adapters/asyncmy/__init__.py +2 -1
- sqlspec/adapters/asyncmy/driver.py +158 -22
- sqlspec/adapters/asyncpg/config.py +1 -3
- sqlspec/adapters/asyncpg/driver.py +143 -5
- sqlspec/adapters/bigquery/__init__.py +4 -0
- sqlspec/adapters/bigquery/config/__init__.py +3 -0
- sqlspec/adapters/bigquery/config/_common.py +40 -0
- sqlspec/adapters/bigquery/config/_sync.py +87 -0
- sqlspec/adapters/bigquery/driver.py +701 -0
- sqlspec/adapters/duckdb/__init__.py +2 -1
- sqlspec/adapters/duckdb/config.py +17 -18
- sqlspec/adapters/duckdb/driver.py +165 -27
- sqlspec/adapters/oracledb/__init__.py +8 -1
- sqlspec/adapters/oracledb/config/_asyncio.py +7 -8
- sqlspec/adapters/oracledb/config/_sync.py +6 -7
- sqlspec/adapters/oracledb/driver.py +311 -42
- sqlspec/adapters/psqlpy/__init__.py +9 -0
- sqlspec/adapters/psqlpy/config.py +11 -19
- sqlspec/adapters/psqlpy/driver.py +171 -19
- sqlspec/adapters/psycopg/__init__.py +8 -1
- sqlspec/adapters/psycopg/config/__init__.py +10 -0
- sqlspec/adapters/psycopg/config/_async.py +6 -7
- sqlspec/adapters/psycopg/config/_sync.py +7 -8
- sqlspec/adapters/psycopg/driver.py +344 -86
- sqlspec/adapters/sqlite/__init__.py +2 -1
- sqlspec/adapters/sqlite/config.py +12 -11
- sqlspec/adapters/sqlite/driver.py +160 -51
- sqlspec/base.py +402 -63
- sqlspec/exceptions.py +9 -0
- sqlspec/extensions/litestar/config.py +3 -11
- sqlspec/extensions/litestar/handlers.py +2 -1
- sqlspec/extensions/litestar/plugin.py +6 -2
- sqlspec/mixins.py +156 -0
- sqlspec/typing.py +19 -1
- {sqlspec-0.9.0.dist-info → sqlspec-0.10.0.dist-info}/METADATA +147 -3
- sqlspec-0.10.0.dist-info/RECORD +67 -0
- sqlspec-0.9.0.dist-info/RECORD +0 -61
- {sqlspec-0.9.0.dist-info → sqlspec-0.10.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.9.0.dist-info → sqlspec-0.10.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.9.0.dist-info → sqlspec-0.10.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,32 +1,95 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from contextlib import asynccontextmanager, contextmanager
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Optional, Union, cast, overload
|
|
4
4
|
|
|
5
|
+
from psycopg import AsyncConnection, Connection
|
|
5
6
|
from psycopg.rows import dict_row
|
|
6
7
|
|
|
7
|
-
from sqlspec.base import AsyncDriverAdapterProtocol, SyncDriverAdapterProtocol
|
|
8
|
+
from sqlspec.base import AsyncDriverAdapterProtocol, SyncDriverAdapterProtocol
|
|
8
9
|
from sqlspec.exceptions import SQLParsingError
|
|
10
|
+
from sqlspec.mixins import SQLTranslatorMixin
|
|
9
11
|
from sqlspec.statement import PARAM_REGEX, SQLStatement
|
|
10
12
|
|
|
11
13
|
if TYPE_CHECKING:
|
|
12
|
-
from collections.abc import AsyncGenerator, Generator
|
|
14
|
+
from collections.abc import AsyncGenerator, Generator, Sequence
|
|
13
15
|
|
|
14
|
-
from
|
|
15
|
-
|
|
16
|
-
from sqlspec.typing import ModelDTOT, StatementParameterType
|
|
16
|
+
from sqlspec.typing import ModelDTOT, StatementParameterType, T
|
|
17
17
|
|
|
18
18
|
logger = logging.getLogger("sqlspec")
|
|
19
19
|
|
|
20
|
-
__all__ = ("PsycopgAsyncDriver", "PsycopgSyncDriver")
|
|
20
|
+
__all__ = ("PsycopgAsyncConnection", "PsycopgAsyncDriver", "PsycopgSyncConnection", "PsycopgSyncDriver")
|
|
21
|
+
|
|
22
|
+
PsycopgSyncConnection = Connection
|
|
23
|
+
PsycopgAsyncConnection = AsyncConnection
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PsycopgDriverBase:
|
|
27
|
+
dialect: str
|
|
28
|
+
|
|
29
|
+
def _process_sql_params(
|
|
30
|
+
self,
|
|
31
|
+
sql: str,
|
|
32
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
33
|
+
/,
|
|
34
|
+
**kwargs: Any,
|
|
35
|
+
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
36
|
+
"""Process SQL and parameters, converting :name -> %(name)s if needed."""
|
|
37
|
+
stmt = SQLStatement(sql=sql, parameters=parameters, dialect=self.dialect, kwargs=kwargs or None)
|
|
38
|
+
processed_sql, processed_params = stmt.process()
|
|
39
|
+
|
|
40
|
+
if isinstance(processed_params, dict):
|
|
41
|
+
parameter_dict = processed_params
|
|
42
|
+
processed_sql_parts: list[str] = []
|
|
43
|
+
last_end = 0
|
|
44
|
+
found_params_regex: list[str] = []
|
|
45
|
+
|
|
46
|
+
for match in PARAM_REGEX.finditer(processed_sql):
|
|
47
|
+
if match.group("dquote") or match.group("squote") or match.group("comment"):
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
if match.group("var_name"):
|
|
51
|
+
var_name = match.group("var_name")
|
|
52
|
+
found_params_regex.append(var_name)
|
|
53
|
+
start = match.start("var_name") - 1
|
|
54
|
+
end = match.end("var_name")
|
|
55
|
+
|
|
56
|
+
if var_name not in parameter_dict:
|
|
57
|
+
msg = (
|
|
58
|
+
f"Named parameter ':{var_name}' found in SQL but missing from processed parameters. "
|
|
59
|
+
f"Processed SQL: {processed_sql}"
|
|
60
|
+
)
|
|
61
|
+
raise SQLParsingError(msg)
|
|
62
|
+
|
|
63
|
+
processed_sql_parts.extend((processed_sql[last_end:start], f"%({var_name})s"))
|
|
64
|
+
last_end = end
|
|
21
65
|
|
|
66
|
+
processed_sql_parts.append(processed_sql[last_end:])
|
|
67
|
+
final_sql = "".join(processed_sql_parts)
|
|
22
68
|
|
|
23
|
-
|
|
69
|
+
if not found_params_regex and parameter_dict:
|
|
70
|
+
logger.warning(
|
|
71
|
+
"Dict params provided (%s), but no :name placeholders found. SQL: %s",
|
|
72
|
+
list(parameter_dict.keys()),
|
|
73
|
+
processed_sql,
|
|
74
|
+
)
|
|
75
|
+
return processed_sql, parameter_dict
|
|
76
|
+
|
|
77
|
+
return final_sql, parameter_dict
|
|
78
|
+
|
|
79
|
+
return processed_sql, processed_params
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class PsycopgSyncDriver(
|
|
83
|
+
PsycopgDriverBase,
|
|
84
|
+
SQLTranslatorMixin["PsycopgSyncConnection"],
|
|
85
|
+
SyncDriverAdapterProtocol["PsycopgSyncConnection"],
|
|
86
|
+
):
|
|
24
87
|
"""Psycopg Sync Driver Adapter."""
|
|
25
88
|
|
|
26
|
-
connection: "
|
|
89
|
+
connection: "PsycopgSyncConnection"
|
|
27
90
|
dialect: str = "postgres"
|
|
28
91
|
|
|
29
|
-
def __init__(self, connection: "
|
|
92
|
+
def __init__(self, connection: "PsycopgSyncConnection") -> None:
|
|
30
93
|
self.connection = connection
|
|
31
94
|
|
|
32
95
|
def _process_sql_params(
|
|
@@ -36,7 +99,6 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
36
99
|
/,
|
|
37
100
|
**kwargs: Any,
|
|
38
101
|
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
39
|
-
"""Process SQL and parameters, converting :name -> %(name)s if needed."""
|
|
40
102
|
stmt = SQLStatement(sql=sql, parameters=parameters, dialect=self.dialect, kwargs=kwargs or None)
|
|
41
103
|
processed_sql, processed_params = stmt.process()
|
|
42
104
|
|
|
@@ -83,13 +145,36 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
83
145
|
|
|
84
146
|
@staticmethod
|
|
85
147
|
@contextmanager
|
|
86
|
-
def _with_cursor(connection: "
|
|
148
|
+
def _with_cursor(connection: "PsycopgSyncConnection") -> "Generator[Any, None, None]":
|
|
87
149
|
cursor = connection.cursor(row_factory=dict_row)
|
|
88
150
|
try:
|
|
89
151
|
yield cursor
|
|
90
152
|
finally:
|
|
91
153
|
cursor.close()
|
|
92
154
|
|
|
155
|
+
# --- Public API Methods --- #
|
|
156
|
+
@overload
|
|
157
|
+
def select(
|
|
158
|
+
self,
|
|
159
|
+
sql: str,
|
|
160
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
161
|
+
/,
|
|
162
|
+
*,
|
|
163
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
164
|
+
schema_type: None = None,
|
|
165
|
+
**kwargs: Any,
|
|
166
|
+
) -> "Sequence[dict[str, Any]]": ...
|
|
167
|
+
@overload
|
|
168
|
+
def select(
|
|
169
|
+
self,
|
|
170
|
+
sql: str,
|
|
171
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
172
|
+
/,
|
|
173
|
+
*,
|
|
174
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
175
|
+
schema_type: "type[ModelDTOT]",
|
|
176
|
+
**kwargs: Any,
|
|
177
|
+
) -> "Sequence[ModelDTOT]": ...
|
|
93
178
|
def select(
|
|
94
179
|
self,
|
|
95
180
|
sql: str,
|
|
@@ -97,9 +182,9 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
97
182
|
/,
|
|
98
183
|
*,
|
|
99
184
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
100
|
-
connection: "Optional[
|
|
185
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
101
186
|
**kwargs: Any,
|
|
102
|
-
) -> "
|
|
187
|
+
) -> "Sequence[Union[ModelDTOT, dict[str, Any]]]":
|
|
103
188
|
"""Fetch data from the database.
|
|
104
189
|
|
|
105
190
|
Returns:
|
|
@@ -117,13 +202,35 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
117
202
|
return [cast("ModelDTOT", schema_type(**row)) for row in results] # pyright: ignore[reportUnknownArgumentType]
|
|
118
203
|
return [cast("dict[str,Any]", row) for row in results] # pyright: ignore[reportUnknownArgumentType]
|
|
119
204
|
|
|
205
|
+
@overload
|
|
120
206
|
def select_one(
|
|
121
207
|
self,
|
|
122
208
|
sql: str,
|
|
123
209
|
parameters: "Optional[StatementParameterType]" = None,
|
|
124
210
|
/,
|
|
125
211
|
*,
|
|
126
|
-
connection: "Optional[
|
|
212
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
213
|
+
schema_type: None = None,
|
|
214
|
+
**kwargs: Any,
|
|
215
|
+
) -> "dict[str, Any]": ...
|
|
216
|
+
@overload
|
|
217
|
+
def select_one(
|
|
218
|
+
self,
|
|
219
|
+
sql: str,
|
|
220
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
221
|
+
/,
|
|
222
|
+
*,
|
|
223
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
224
|
+
schema_type: "type[ModelDTOT]",
|
|
225
|
+
**kwargs: Any,
|
|
226
|
+
) -> "ModelDTOT": ...
|
|
227
|
+
def select_one(
|
|
228
|
+
self,
|
|
229
|
+
sql: str,
|
|
230
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
231
|
+
/,
|
|
232
|
+
*,
|
|
233
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
127
234
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
128
235
|
**kwargs: Any,
|
|
129
236
|
) -> "Union[ModelDTOT, dict[str, Any]]":
|
|
@@ -142,13 +249,35 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
142
249
|
return cast("ModelDTOT", schema_type(**cast("dict[str,Any]", row)))
|
|
143
250
|
return cast("dict[str,Any]", row)
|
|
144
251
|
|
|
252
|
+
@overload
|
|
253
|
+
def select_one_or_none(
|
|
254
|
+
self,
|
|
255
|
+
sql: str,
|
|
256
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
257
|
+
/,
|
|
258
|
+
*,
|
|
259
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
260
|
+
schema_type: None = None,
|
|
261
|
+
**kwargs: Any,
|
|
262
|
+
) -> "Optional[dict[str, Any]]": ...
|
|
263
|
+
@overload
|
|
264
|
+
def select_one_or_none(
|
|
265
|
+
self,
|
|
266
|
+
sql: str,
|
|
267
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
268
|
+
/,
|
|
269
|
+
*,
|
|
270
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
271
|
+
schema_type: "type[ModelDTOT]",
|
|
272
|
+
**kwargs: Any,
|
|
273
|
+
) -> "Optional[ModelDTOT]": ...
|
|
145
274
|
def select_one_or_none(
|
|
146
275
|
self,
|
|
147
276
|
sql: str,
|
|
148
277
|
parameters: "Optional[StatementParameterType]" = None,
|
|
149
278
|
/,
|
|
150
279
|
*,
|
|
151
|
-
connection: "Optional[
|
|
280
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
152
281
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
153
282
|
**kwargs: Any,
|
|
154
283
|
) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
|
|
@@ -168,13 +297,35 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
168
297
|
return cast("ModelDTOT", schema_type(**cast("dict[str,Any]", row)))
|
|
169
298
|
return cast("dict[str,Any]", row)
|
|
170
299
|
|
|
300
|
+
@overload
|
|
171
301
|
def select_value(
|
|
172
302
|
self,
|
|
173
303
|
sql: str,
|
|
174
304
|
parameters: "Optional[StatementParameterType]" = None,
|
|
175
305
|
/,
|
|
176
306
|
*,
|
|
177
|
-
connection: "Optional[
|
|
307
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
308
|
+
schema_type: None = None,
|
|
309
|
+
**kwargs: Any,
|
|
310
|
+
) -> "Any": ...
|
|
311
|
+
@overload
|
|
312
|
+
def select_value(
|
|
313
|
+
self,
|
|
314
|
+
sql: str,
|
|
315
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
316
|
+
/,
|
|
317
|
+
*,
|
|
318
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
319
|
+
schema_type: "type[T]",
|
|
320
|
+
**kwargs: Any,
|
|
321
|
+
) -> "T": ...
|
|
322
|
+
def select_value(
|
|
323
|
+
self,
|
|
324
|
+
sql: str,
|
|
325
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
326
|
+
/,
|
|
327
|
+
*,
|
|
328
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
178
329
|
schema_type: "Optional[type[T]]" = None,
|
|
179
330
|
**kwargs: Any,
|
|
180
331
|
) -> "Union[T, Any]":
|
|
@@ -195,13 +346,35 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
195
346
|
return schema_type(val) # type: ignore[call-arg]
|
|
196
347
|
return val
|
|
197
348
|
|
|
349
|
+
@overload
|
|
198
350
|
def select_value_or_none(
|
|
199
351
|
self,
|
|
200
352
|
sql: str,
|
|
201
353
|
parameters: "Optional[StatementParameterType]" = None,
|
|
202
354
|
/,
|
|
203
355
|
*,
|
|
204
|
-
connection: "Optional[
|
|
356
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
357
|
+
schema_type: None = None,
|
|
358
|
+
**kwargs: Any,
|
|
359
|
+
) -> "Optional[Any]": ...
|
|
360
|
+
@overload
|
|
361
|
+
def select_value_or_none(
|
|
362
|
+
self,
|
|
363
|
+
sql: str,
|
|
364
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
365
|
+
/,
|
|
366
|
+
*,
|
|
367
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
368
|
+
schema_type: "type[T]",
|
|
369
|
+
**kwargs: Any,
|
|
370
|
+
) -> "Optional[T]": ...
|
|
371
|
+
def select_value_or_none(
|
|
372
|
+
self,
|
|
373
|
+
sql: str,
|
|
374
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
375
|
+
/,
|
|
376
|
+
*,
|
|
377
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
205
378
|
schema_type: "Optional[type[T]]" = None,
|
|
206
379
|
**kwargs: Any,
|
|
207
380
|
) -> "Optional[Union[T, Any]]":
|
|
@@ -230,7 +403,7 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
230
403
|
parameters: "Optional[StatementParameterType]" = None,
|
|
231
404
|
/,
|
|
232
405
|
*,
|
|
233
|
-
connection: "Optional[
|
|
406
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
234
407
|
**kwargs: Any,
|
|
235
408
|
) -> int:
|
|
236
409
|
"""Execute an INSERT, UPDATE, or DELETE query and return the number of affected rows.
|
|
@@ -244,13 +417,35 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
244
417
|
cursor.execute(sql, parameters)
|
|
245
418
|
return getattr(cursor, "rowcount", -1) # pyright: ignore[reportUnknownMemberType]
|
|
246
419
|
|
|
420
|
+
@overload
|
|
247
421
|
def insert_update_delete_returning(
|
|
248
422
|
self,
|
|
249
423
|
sql: str,
|
|
250
424
|
parameters: "Optional[StatementParameterType]" = None,
|
|
251
425
|
/,
|
|
252
426
|
*,
|
|
253
|
-
connection: "Optional[
|
|
427
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
428
|
+
schema_type: None = None,
|
|
429
|
+
**kwargs: Any,
|
|
430
|
+
) -> "dict[str, Any]": ...
|
|
431
|
+
@overload
|
|
432
|
+
def insert_update_delete_returning(
|
|
433
|
+
self,
|
|
434
|
+
sql: str,
|
|
435
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
436
|
+
/,
|
|
437
|
+
*,
|
|
438
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
439
|
+
schema_type: "type[ModelDTOT]",
|
|
440
|
+
**kwargs: Any,
|
|
441
|
+
) -> "ModelDTOT": ...
|
|
442
|
+
def insert_update_delete_returning(
|
|
443
|
+
self,
|
|
444
|
+
sql: str,
|
|
445
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
446
|
+
/,
|
|
447
|
+
*,
|
|
448
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
254
449
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
255
450
|
**kwargs: Any,
|
|
256
451
|
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
@@ -278,7 +473,7 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
278
473
|
parameters: "Optional[StatementParameterType]" = None,
|
|
279
474
|
/,
|
|
280
475
|
*,
|
|
281
|
-
connection: "Optional[
|
|
476
|
+
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
282
477
|
**kwargs: Any,
|
|
283
478
|
) -> str:
|
|
284
479
|
"""Execute a script.
|
|
@@ -293,86 +488,61 @@ class PsycopgSyncDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
293
488
|
return str(cursor.statusmessage) if cursor.statusmessage is not None else "DONE"
|
|
294
489
|
|
|
295
490
|
|
|
296
|
-
class PsycopgAsyncDriver(
|
|
491
|
+
class PsycopgAsyncDriver(
|
|
492
|
+
PsycopgDriverBase,
|
|
493
|
+
SQLTranslatorMixin["PsycopgAsyncConnection"],
|
|
494
|
+
AsyncDriverAdapterProtocol["PsycopgAsyncConnection"],
|
|
495
|
+
):
|
|
297
496
|
"""Psycopg Async Driver Adapter."""
|
|
298
497
|
|
|
299
|
-
connection: "
|
|
498
|
+
connection: "PsycopgAsyncConnection"
|
|
300
499
|
dialect: str = "postgres"
|
|
301
500
|
|
|
302
|
-
def __init__(self, connection: "
|
|
501
|
+
def __init__(self, connection: "PsycopgAsyncConnection") -> None:
|
|
303
502
|
self.connection = connection
|
|
304
503
|
|
|
305
|
-
def _process_sql_params(
|
|
306
|
-
self,
|
|
307
|
-
sql: str,
|
|
308
|
-
parameters: "Optional[StatementParameterType]" = None,
|
|
309
|
-
/,
|
|
310
|
-
**kwargs: Any,
|
|
311
|
-
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
312
|
-
"""Process SQL and parameters, converting :name -> %(name)s if needed."""
|
|
313
|
-
stmt = SQLStatement(sql=sql, parameters=parameters, dialect=self.dialect, kwargs=kwargs or None)
|
|
314
|
-
processed_sql, processed_params = stmt.process()
|
|
315
|
-
|
|
316
|
-
if isinstance(processed_params, dict):
|
|
317
|
-
parameter_dict = processed_params
|
|
318
|
-
processed_sql_parts: list[str] = []
|
|
319
|
-
last_end = 0
|
|
320
|
-
found_params_regex: list[str] = []
|
|
321
|
-
|
|
322
|
-
for match in PARAM_REGEX.finditer(processed_sql):
|
|
323
|
-
if match.group("dquote") or match.group("squote") or match.group("comment"):
|
|
324
|
-
continue
|
|
325
|
-
|
|
326
|
-
if match.group("var_name"):
|
|
327
|
-
var_name = match.group("var_name")
|
|
328
|
-
found_params_regex.append(var_name)
|
|
329
|
-
start = match.start("var_name") - 1
|
|
330
|
-
end = match.end("var_name")
|
|
331
|
-
|
|
332
|
-
if var_name not in parameter_dict:
|
|
333
|
-
msg = (
|
|
334
|
-
f"Named parameter ':{var_name}' found in SQL but missing from processed parameters. "
|
|
335
|
-
f"Processed SQL: {processed_sql}"
|
|
336
|
-
)
|
|
337
|
-
raise SQLParsingError(msg)
|
|
338
|
-
|
|
339
|
-
processed_sql_parts.extend((processed_sql[last_end:start], f"%({var_name})s"))
|
|
340
|
-
last_end = end
|
|
341
|
-
|
|
342
|
-
processed_sql_parts.append(processed_sql[last_end:])
|
|
343
|
-
final_sql = "".join(processed_sql_parts)
|
|
344
|
-
|
|
345
|
-
if not found_params_regex and parameter_dict:
|
|
346
|
-
logger.warning(
|
|
347
|
-
"Dict params provided (%s), but no :name placeholders found. SQL: %s",
|
|
348
|
-
list(parameter_dict.keys()),
|
|
349
|
-
processed_sql,
|
|
350
|
-
)
|
|
351
|
-
return processed_sql, parameter_dict
|
|
352
|
-
|
|
353
|
-
return final_sql, parameter_dict
|
|
354
|
-
|
|
355
|
-
return processed_sql, processed_params
|
|
356
|
-
|
|
357
504
|
@staticmethod
|
|
358
505
|
@asynccontextmanager
|
|
359
|
-
async def _with_cursor(connection: "
|
|
506
|
+
async def _with_cursor(connection: "PsycopgAsyncConnection") -> "AsyncGenerator[Any, None]":
|
|
360
507
|
cursor = connection.cursor(row_factory=dict_row)
|
|
361
508
|
try:
|
|
362
509
|
yield cursor
|
|
363
510
|
finally:
|
|
364
511
|
await cursor.close()
|
|
365
512
|
|
|
513
|
+
# --- Public API Methods --- #
|
|
514
|
+
@overload
|
|
366
515
|
async def select(
|
|
367
516
|
self,
|
|
368
517
|
sql: str,
|
|
369
518
|
parameters: "Optional[StatementParameterType]" = None,
|
|
370
519
|
/,
|
|
371
520
|
*,
|
|
372
|
-
connection: "Optional[
|
|
521
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
522
|
+
schema_type: None = None,
|
|
523
|
+
**kwargs: Any,
|
|
524
|
+
) -> "Sequence[dict[str, Any]]": ...
|
|
525
|
+
@overload
|
|
526
|
+
async def select(
|
|
527
|
+
self,
|
|
528
|
+
sql: str,
|
|
529
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
530
|
+
/,
|
|
531
|
+
*,
|
|
532
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
533
|
+
schema_type: "type[ModelDTOT]",
|
|
534
|
+
**kwargs: Any,
|
|
535
|
+
) -> "Sequence[ModelDTOT]": ...
|
|
536
|
+
async def select(
|
|
537
|
+
self,
|
|
538
|
+
sql: str,
|
|
539
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
540
|
+
/,
|
|
541
|
+
*,
|
|
542
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
373
543
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
374
544
|
**kwargs: Any,
|
|
375
|
-
) -> "
|
|
545
|
+
) -> "Sequence[Union[ModelDTOT, dict[str, Any]]]":
|
|
376
546
|
"""Fetch data from the database.
|
|
377
547
|
|
|
378
548
|
Returns:
|
|
@@ -391,13 +561,35 @@ class PsycopgAsyncDriver(AsyncDriverAdapterProtocol["AsyncConnection"]):
|
|
|
391
561
|
return [cast("ModelDTOT", schema_type(**cast("dict[str,Any]", row))) for row in results] # pyright: ignore[reportUnknownArgumentType]
|
|
392
562
|
return [cast("dict[str,Any]", row) for row in results] # pyright: ignore[reportUnknownArgumentType]
|
|
393
563
|
|
|
564
|
+
@overload
|
|
394
565
|
async def select_one(
|
|
395
566
|
self,
|
|
396
567
|
sql: str,
|
|
397
568
|
parameters: "Optional[StatementParameterType]" = None,
|
|
398
569
|
/,
|
|
399
570
|
*,
|
|
400
|
-
connection: "Optional[
|
|
571
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
572
|
+
schema_type: None = None,
|
|
573
|
+
**kwargs: Any,
|
|
574
|
+
) -> "dict[str, Any]": ...
|
|
575
|
+
@overload
|
|
576
|
+
async def select_one(
|
|
577
|
+
self,
|
|
578
|
+
sql: str,
|
|
579
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
580
|
+
/,
|
|
581
|
+
*,
|
|
582
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
583
|
+
schema_type: "type[ModelDTOT]",
|
|
584
|
+
**kwargs: Any,
|
|
585
|
+
) -> "ModelDTOT": ...
|
|
586
|
+
async def select_one(
|
|
587
|
+
self,
|
|
588
|
+
sql: str,
|
|
589
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
590
|
+
/,
|
|
591
|
+
*,
|
|
592
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
401
593
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
402
594
|
**kwargs: Any,
|
|
403
595
|
) -> "Union[ModelDTOT, dict[str, Any]]":
|
|
@@ -417,6 +609,28 @@ class PsycopgAsyncDriver(AsyncDriverAdapterProtocol["AsyncConnection"]):
|
|
|
417
609
|
return cast("ModelDTOT", schema_type(**cast("dict[str,Any]", row)))
|
|
418
610
|
return cast("dict[str,Any]", row)
|
|
419
611
|
|
|
612
|
+
@overload
|
|
613
|
+
async def select_one_or_none(
|
|
614
|
+
self,
|
|
615
|
+
sql: str,
|
|
616
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
617
|
+
/,
|
|
618
|
+
*,
|
|
619
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
620
|
+
schema_type: None = None,
|
|
621
|
+
**kwargs: Any,
|
|
622
|
+
) -> "Optional[dict[str, Any]]": ...
|
|
623
|
+
@overload
|
|
624
|
+
async def select_one_or_none(
|
|
625
|
+
self,
|
|
626
|
+
sql: str,
|
|
627
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
628
|
+
/,
|
|
629
|
+
*,
|
|
630
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
631
|
+
schema_type: "type[ModelDTOT]",
|
|
632
|
+
**kwargs: Any,
|
|
633
|
+
) -> "Optional[ModelDTOT]": ...
|
|
420
634
|
async def select_one_or_none(
|
|
421
635
|
self,
|
|
422
636
|
sql: str,
|
|
@@ -424,7 +638,7 @@ class PsycopgAsyncDriver(AsyncDriverAdapterProtocol["AsyncConnection"]):
|
|
|
424
638
|
/,
|
|
425
639
|
*,
|
|
426
640
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
427
|
-
connection: "Optional[
|
|
641
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
428
642
|
**kwargs: Any,
|
|
429
643
|
) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
|
|
430
644
|
"""Fetch one row from the database.
|
|
@@ -444,13 +658,35 @@ class PsycopgAsyncDriver(AsyncDriverAdapterProtocol["AsyncConnection"]):
|
|
|
444
658
|
return cast("ModelDTOT", schema_type(**cast("dict[str,Any]", row)))
|
|
445
659
|
return cast("dict[str,Any]", row)
|
|
446
660
|
|
|
661
|
+
@overload
|
|
662
|
+
async def select_value(
|
|
663
|
+
self,
|
|
664
|
+
sql: str,
|
|
665
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
666
|
+
/,
|
|
667
|
+
*,
|
|
668
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
669
|
+
schema_type: None = None,
|
|
670
|
+
**kwargs: Any,
|
|
671
|
+
) -> "Any": ...
|
|
672
|
+
@overload
|
|
673
|
+
async def select_value(
|
|
674
|
+
self,
|
|
675
|
+
sql: str,
|
|
676
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
677
|
+
/,
|
|
678
|
+
*,
|
|
679
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
680
|
+
schema_type: "type[T]",
|
|
681
|
+
**kwargs: Any,
|
|
682
|
+
) -> "T": ...
|
|
447
683
|
async def select_value(
|
|
448
684
|
self,
|
|
449
685
|
sql: str,
|
|
450
686
|
parameters: "Optional[StatementParameterType]" = None,
|
|
451
687
|
/,
|
|
452
688
|
*,
|
|
453
|
-
connection: "Optional[
|
|
689
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
454
690
|
schema_type: "Optional[type[T]]" = None,
|
|
455
691
|
**kwargs: Any,
|
|
456
692
|
) -> "Union[T, Any]":
|
|
@@ -478,7 +714,7 @@ class PsycopgAsyncDriver(AsyncDriverAdapterProtocol["AsyncConnection"]):
|
|
|
478
714
|
parameters: "Optional[StatementParameterType]" = None,
|
|
479
715
|
/,
|
|
480
716
|
*,
|
|
481
|
-
connection: "Optional[
|
|
717
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
482
718
|
schema_type: "Optional[type[T]]" = None,
|
|
483
719
|
**kwargs: Any,
|
|
484
720
|
) -> "Optional[Union[T, Any]]":
|
|
@@ -508,7 +744,7 @@ class PsycopgAsyncDriver(AsyncDriverAdapterProtocol["AsyncConnection"]):
|
|
|
508
744
|
parameters: "Optional[StatementParameterType]" = None,
|
|
509
745
|
/,
|
|
510
746
|
*,
|
|
511
|
-
connection: "Optional[
|
|
747
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
512
748
|
**kwargs: Any,
|
|
513
749
|
) -> int:
|
|
514
750
|
"""Execute an INSERT, UPDATE, or DELETE query and return the number of affected rows.
|
|
@@ -527,13 +763,35 @@ class PsycopgAsyncDriver(AsyncDriverAdapterProtocol["AsyncConnection"]):
|
|
|
527
763
|
rowcount = -1
|
|
528
764
|
return rowcount
|
|
529
765
|
|
|
766
|
+
@overload
|
|
767
|
+
async def insert_update_delete_returning(
|
|
768
|
+
self,
|
|
769
|
+
sql: str,
|
|
770
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
771
|
+
/,
|
|
772
|
+
*,
|
|
773
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
774
|
+
schema_type: None = None,
|
|
775
|
+
**kwargs: Any,
|
|
776
|
+
) -> "dict[str, Any]": ...
|
|
777
|
+
@overload
|
|
778
|
+
async def insert_update_delete_returning(
|
|
779
|
+
self,
|
|
780
|
+
sql: str,
|
|
781
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
782
|
+
/,
|
|
783
|
+
*,
|
|
784
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
785
|
+
schema_type: "type[ModelDTOT]",
|
|
786
|
+
**kwargs: Any,
|
|
787
|
+
) -> "ModelDTOT": ...
|
|
530
788
|
async def insert_update_delete_returning(
|
|
531
789
|
self,
|
|
532
790
|
sql: str,
|
|
533
791
|
parameters: "Optional[StatementParameterType]" = None,
|
|
534
792
|
/,
|
|
535
793
|
*,
|
|
536
|
-
connection: "Optional[
|
|
794
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
537
795
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
538
796
|
**kwargs: Any,
|
|
539
797
|
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
@@ -562,7 +820,7 @@ class PsycopgAsyncDriver(AsyncDriverAdapterProtocol["AsyncConnection"]):
|
|
|
562
820
|
parameters: "Optional[StatementParameterType]" = None,
|
|
563
821
|
/,
|
|
564
822
|
*,
|
|
565
|
-
connection: "Optional[
|
|
823
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
566
824
|
**kwargs: Any,
|
|
567
825
|
) -> str:
|
|
568
826
|
"""Execute a script.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from sqlspec.adapters.sqlite.config import SqliteConfig
|
|
2
|
-
from sqlspec.adapters.sqlite.driver import SqliteDriver
|
|
2
|
+
from sqlspec.adapters.sqlite.driver import SqliteConnection, SqliteDriver
|
|
3
3
|
|
|
4
4
|
__all__ = (
|
|
5
5
|
"SqliteConfig",
|
|
6
|
+
"SqliteConnection",
|
|
6
7
|
"SqliteDriver",
|
|
7
8
|
)
|