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,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import re
|
|
2
3
|
from contextlib import asynccontextmanager, contextmanager
|
|
3
4
|
from typing import TYPE_CHECKING, Any, Optional, Union, cast, overload
|
|
4
5
|
|
|
@@ -6,143 +7,102 @@ from psycopg import AsyncConnection, Connection
|
|
|
6
7
|
from psycopg.rows import dict_row
|
|
7
8
|
|
|
8
9
|
from sqlspec.base import AsyncDriverAdapterProtocol, SyncDriverAdapterProtocol
|
|
9
|
-
from sqlspec.exceptions import
|
|
10
|
-
from sqlspec.mixins import SQLTranslatorMixin
|
|
11
|
-
from sqlspec.statement import
|
|
10
|
+
from sqlspec.exceptions import ParameterStyleMismatchError
|
|
11
|
+
from sqlspec.mixins import ResultConverter, SQLTranslatorMixin
|
|
12
|
+
from sqlspec.statement import SQLStatement
|
|
13
|
+
from sqlspec.typing import is_dict
|
|
12
14
|
|
|
13
15
|
if TYPE_CHECKING:
|
|
14
16
|
from collections.abc import AsyncGenerator, Generator, Sequence
|
|
15
17
|
|
|
18
|
+
from sqlspec.filters import StatementFilter
|
|
16
19
|
from sqlspec.typing import ModelDTOT, StatementParameterType, T
|
|
17
20
|
|
|
18
21
|
logger = logging.getLogger("sqlspec")
|
|
19
22
|
|
|
20
23
|
__all__ = ("PsycopgAsyncConnection", "PsycopgAsyncDriver", "PsycopgSyncConnection", "PsycopgSyncDriver")
|
|
21
24
|
|
|
25
|
+
|
|
26
|
+
NAMED_PARAMS_PATTERN = re.compile(r"(?<!:):([a-zA-Z0-9_]+)")
|
|
27
|
+
# Pattern matches %(name)s format while trying to avoid matches in string literals and comments
|
|
28
|
+
PSYCOPG_PARAMS_PATTERN = re.compile(r"(?<!'|\"|\w)%\(([a-zA-Z0-9_]+)\)s(?!'|\")")
|
|
29
|
+
|
|
22
30
|
PsycopgSyncConnection = Connection
|
|
23
31
|
PsycopgAsyncConnection = AsyncConnection
|
|
24
32
|
|
|
25
33
|
|
|
26
34
|
class PsycopgDriverBase:
|
|
27
|
-
dialect: str
|
|
35
|
+
dialect: str = "postgres"
|
|
28
36
|
|
|
29
37
|
def _process_sql_params(
|
|
30
38
|
self,
|
|
31
39
|
sql: str,
|
|
32
40
|
parameters: "Optional[StatementParameterType]" = None,
|
|
33
41
|
/,
|
|
42
|
+
*filters: "StatementFilter",
|
|
34
43
|
**kwargs: Any,
|
|
35
44
|
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
36
|
-
"""Process SQL and parameters
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
"""Process SQL and parameters using SQLStatement with dialect support.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
sql: The SQL statement to process.
|
|
49
|
+
parameters: The parameters to bind to the statement.
|
|
50
|
+
*filters: Statement filters to apply.
|
|
51
|
+
**kwargs: Additional keyword arguments.
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
ParameterStyleMismatchError: If the parameter style is mismatched.
|
|
39
55
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
Returns:
|
|
57
|
+
A tuple of (sql, parameters) ready for execution.
|
|
58
|
+
"""
|
|
59
|
+
statement = SQLStatement(sql, parameters, kwargs=kwargs, dialect=self.dialect)
|
|
60
|
+
|
|
61
|
+
# Apply all statement filters
|
|
62
|
+
for filter_obj in filters:
|
|
63
|
+
statement = statement.apply_filter(filter_obj)
|
|
45
64
|
|
|
46
|
-
|
|
47
|
-
if match.group("dquote") or match.group("squote") or match.group("comment"):
|
|
48
|
-
continue
|
|
65
|
+
processed_sql, processed_params, _ = statement.process()
|
|
49
66
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
found_params_regex.append(var_name)
|
|
53
|
-
start = match.start("var_name") - 1
|
|
54
|
-
end = match.end("var_name")
|
|
67
|
+
if is_dict(processed_params):
|
|
68
|
+
named_params = NAMED_PARAMS_PATTERN.findall(processed_sql)
|
|
55
69
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
f"Processed SQL: {processed_sql}"
|
|
60
|
-
)
|
|
61
|
-
raise SQLParsingError(msg)
|
|
70
|
+
if not named_params:
|
|
71
|
+
if PSYCOPG_PARAMS_PATTERN.search(processed_sql):
|
|
72
|
+
return processed_sql, processed_params
|
|
62
73
|
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
if processed_params:
|
|
75
|
+
msg = "psycopg: Dictionary parameters provided, but no named placeholders found in SQL."
|
|
76
|
+
raise ParameterStyleMismatchError(msg)
|
|
77
|
+
return processed_sql, None
|
|
65
78
|
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
# Convert named parameters to psycopg's preferred format
|
|
80
|
+
return NAMED_PARAMS_PATTERN.sub("%s", processed_sql), tuple(processed_params[name] for name in named_params)
|
|
68
81
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
list(parameter_dict.keys()),
|
|
73
|
-
processed_sql,
|
|
74
|
-
)
|
|
75
|
-
return processed_sql, parameter_dict
|
|
82
|
+
# For sequence parameters, ensure they're a tuple
|
|
83
|
+
if isinstance(processed_params, (list, tuple)):
|
|
84
|
+
return processed_sql, tuple(processed_params)
|
|
76
85
|
|
|
77
|
-
|
|
86
|
+
# For scalar parameter or None
|
|
87
|
+
if processed_params is not None:
|
|
88
|
+
return processed_sql, (processed_params,)
|
|
78
89
|
|
|
79
|
-
return processed_sql,
|
|
90
|
+
return processed_sql, None
|
|
80
91
|
|
|
81
92
|
|
|
82
93
|
class PsycopgSyncDriver(
|
|
83
94
|
PsycopgDriverBase,
|
|
84
95
|
SQLTranslatorMixin["PsycopgSyncConnection"],
|
|
85
96
|
SyncDriverAdapterProtocol["PsycopgSyncConnection"],
|
|
97
|
+
ResultConverter,
|
|
86
98
|
):
|
|
87
99
|
"""Psycopg Sync Driver Adapter."""
|
|
88
100
|
|
|
89
101
|
connection: "PsycopgSyncConnection"
|
|
90
|
-
dialect: str = "postgres"
|
|
91
102
|
|
|
92
103
|
def __init__(self, connection: "PsycopgSyncConnection") -> None:
|
|
93
104
|
self.connection = connection
|
|
94
105
|
|
|
95
|
-
def _process_sql_params(
|
|
96
|
-
self,
|
|
97
|
-
sql: str,
|
|
98
|
-
parameters: "Optional[StatementParameterType]" = None,
|
|
99
|
-
/,
|
|
100
|
-
**kwargs: Any,
|
|
101
|
-
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
102
|
-
stmt = SQLStatement(sql=sql, parameters=parameters, dialect=self.dialect, kwargs=kwargs or None)
|
|
103
|
-
processed_sql, processed_params = stmt.process()
|
|
104
|
-
|
|
105
|
-
if isinstance(processed_params, dict):
|
|
106
|
-
parameter_dict = processed_params
|
|
107
|
-
processed_sql_parts: list[str] = []
|
|
108
|
-
last_end = 0
|
|
109
|
-
found_params_regex: list[str] = []
|
|
110
|
-
|
|
111
|
-
for match in PARAM_REGEX.finditer(processed_sql):
|
|
112
|
-
if match.group("dquote") or match.group("squote") or match.group("comment"):
|
|
113
|
-
continue
|
|
114
|
-
|
|
115
|
-
if match.group("var_name"):
|
|
116
|
-
var_name = match.group("var_name")
|
|
117
|
-
found_params_regex.append(var_name)
|
|
118
|
-
start = match.start("var_name") - 1
|
|
119
|
-
end = match.end("var_name")
|
|
120
|
-
|
|
121
|
-
if var_name not in parameter_dict:
|
|
122
|
-
msg = (
|
|
123
|
-
f"Named parameter ':{var_name}' found in SQL but missing from processed parameters. "
|
|
124
|
-
f"Processed SQL: {processed_sql}"
|
|
125
|
-
)
|
|
126
|
-
raise SQLParsingError(msg)
|
|
127
|
-
|
|
128
|
-
processed_sql_parts.extend((processed_sql[last_end:start], f"%({var_name})s"))
|
|
129
|
-
last_end = end
|
|
130
|
-
|
|
131
|
-
processed_sql_parts.append(processed_sql[last_end:])
|
|
132
|
-
final_sql = "".join(processed_sql_parts)
|
|
133
|
-
|
|
134
|
-
if not found_params_regex and parameter_dict:
|
|
135
|
-
logger.warning(
|
|
136
|
-
"Dict params provided (%s), but no :name placeholders found. SQL: %s",
|
|
137
|
-
list(parameter_dict.keys()),
|
|
138
|
-
processed_sql,
|
|
139
|
-
)
|
|
140
|
-
return processed_sql, parameter_dict
|
|
141
|
-
|
|
142
|
-
return final_sql, parameter_dict
|
|
143
|
-
|
|
144
|
-
return processed_sql, processed_params
|
|
145
|
-
|
|
146
106
|
@staticmethod
|
|
147
107
|
@contextmanager
|
|
148
108
|
def _with_cursor(connection: "PsycopgSyncConnection") -> "Generator[Any, None, None]":
|
|
@@ -159,7 +119,7 @@ class PsycopgSyncDriver(
|
|
|
159
119
|
sql: str,
|
|
160
120
|
parameters: "Optional[StatementParameterType]" = None,
|
|
161
121
|
/,
|
|
162
|
-
|
|
122
|
+
*filters: "StatementFilter",
|
|
163
123
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
164
124
|
schema_type: None = None,
|
|
165
125
|
**kwargs: Any,
|
|
@@ -170,7 +130,7 @@ class PsycopgSyncDriver(
|
|
|
170
130
|
sql: str,
|
|
171
131
|
parameters: "Optional[StatementParameterType]" = None,
|
|
172
132
|
/,
|
|
173
|
-
|
|
133
|
+
*filters: "StatementFilter",
|
|
174
134
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
175
135
|
schema_type: "type[ModelDTOT]",
|
|
176
136
|
**kwargs: Any,
|
|
@@ -180,7 +140,7 @@ class PsycopgSyncDriver(
|
|
|
180
140
|
sql: str,
|
|
181
141
|
parameters: "Optional[StatementParameterType]" = None,
|
|
182
142
|
/,
|
|
183
|
-
|
|
143
|
+
*filters: "StatementFilter",
|
|
184
144
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
185
145
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
186
146
|
**kwargs: Any,
|
|
@@ -191,16 +151,14 @@ class PsycopgSyncDriver(
|
|
|
191
151
|
List of row data as either model instances or dictionaries.
|
|
192
152
|
"""
|
|
193
153
|
connection = self._connection(connection)
|
|
194
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
154
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
195
155
|
with self._with_cursor(connection) as cursor:
|
|
196
156
|
cursor.execute(sql, parameters)
|
|
197
157
|
results = cursor.fetchall()
|
|
198
158
|
if not results:
|
|
199
159
|
return []
|
|
200
160
|
|
|
201
|
-
|
|
202
|
-
return [cast("ModelDTOT", schema_type(**row)) for row in results] # pyright: ignore[reportUnknownArgumentType]
|
|
203
|
-
return [cast("dict[str,Any]", row) for row in results] # pyright: ignore[reportUnknownArgumentType]
|
|
161
|
+
return self.to_schema(cast("Sequence[dict[str, Any]]", results), schema_type=schema_type)
|
|
204
162
|
|
|
205
163
|
@overload
|
|
206
164
|
def select_one(
|
|
@@ -208,7 +166,7 @@ class PsycopgSyncDriver(
|
|
|
208
166
|
sql: str,
|
|
209
167
|
parameters: "Optional[StatementParameterType]" = None,
|
|
210
168
|
/,
|
|
211
|
-
|
|
169
|
+
*filters: "StatementFilter",
|
|
212
170
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
213
171
|
schema_type: None = None,
|
|
214
172
|
**kwargs: Any,
|
|
@@ -219,7 +177,7 @@ class PsycopgSyncDriver(
|
|
|
219
177
|
sql: str,
|
|
220
178
|
parameters: "Optional[StatementParameterType]" = None,
|
|
221
179
|
/,
|
|
222
|
-
|
|
180
|
+
*filters: "StatementFilter",
|
|
223
181
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
224
182
|
schema_type: "type[ModelDTOT]",
|
|
225
183
|
**kwargs: Any,
|
|
@@ -229,7 +187,7 @@ class PsycopgSyncDriver(
|
|
|
229
187
|
sql: str,
|
|
230
188
|
parameters: "Optional[StatementParameterType]" = None,
|
|
231
189
|
/,
|
|
232
|
-
|
|
190
|
+
*filters: "StatementFilter",
|
|
233
191
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
234
192
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
235
193
|
**kwargs: Any,
|
|
@@ -240,14 +198,13 @@ class PsycopgSyncDriver(
|
|
|
240
198
|
The first row of the query results.
|
|
241
199
|
"""
|
|
242
200
|
connection = self._connection(connection)
|
|
243
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
201
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
244
202
|
with self._with_cursor(connection) as cursor:
|
|
245
203
|
cursor.execute(sql, parameters)
|
|
246
204
|
row = cursor.fetchone()
|
|
247
205
|
row = self.check_not_found(row)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
return cast("dict[str,Any]", row)
|
|
206
|
+
|
|
207
|
+
return self.to_schema(cast("dict[str, Any]", row), schema_type=schema_type)
|
|
251
208
|
|
|
252
209
|
@overload
|
|
253
210
|
def select_one_or_none(
|
|
@@ -255,7 +212,7 @@ class PsycopgSyncDriver(
|
|
|
255
212
|
sql: str,
|
|
256
213
|
parameters: "Optional[StatementParameterType]" = None,
|
|
257
214
|
/,
|
|
258
|
-
|
|
215
|
+
*filters: "StatementFilter",
|
|
259
216
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
260
217
|
schema_type: None = None,
|
|
261
218
|
**kwargs: Any,
|
|
@@ -266,7 +223,7 @@ class PsycopgSyncDriver(
|
|
|
266
223
|
sql: str,
|
|
267
224
|
parameters: "Optional[StatementParameterType]" = None,
|
|
268
225
|
/,
|
|
269
|
-
|
|
226
|
+
*filters: "StatementFilter",
|
|
270
227
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
271
228
|
schema_type: "type[ModelDTOT]",
|
|
272
229
|
**kwargs: Any,
|
|
@@ -276,7 +233,7 @@ class PsycopgSyncDriver(
|
|
|
276
233
|
sql: str,
|
|
277
234
|
parameters: "Optional[StatementParameterType]" = None,
|
|
278
235
|
/,
|
|
279
|
-
|
|
236
|
+
*filters: "StatementFilter",
|
|
280
237
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
281
238
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
282
239
|
**kwargs: Any,
|
|
@@ -287,15 +244,13 @@ class PsycopgSyncDriver(
|
|
|
287
244
|
The first row of the query results.
|
|
288
245
|
"""
|
|
289
246
|
connection = self._connection(connection)
|
|
290
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
247
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
291
248
|
with self._with_cursor(connection) as cursor:
|
|
292
249
|
cursor.execute(sql, parameters)
|
|
293
250
|
row = cursor.fetchone()
|
|
294
251
|
if row is None:
|
|
295
252
|
return None
|
|
296
|
-
|
|
297
|
-
return cast("ModelDTOT", schema_type(**cast("dict[str,Any]", row)))
|
|
298
|
-
return cast("dict[str,Any]", row)
|
|
253
|
+
return self.to_schema(cast("dict[str, Any]", row), schema_type=schema_type)
|
|
299
254
|
|
|
300
255
|
@overload
|
|
301
256
|
def select_value(
|
|
@@ -303,7 +258,7 @@ class PsycopgSyncDriver(
|
|
|
303
258
|
sql: str,
|
|
304
259
|
parameters: "Optional[StatementParameterType]" = None,
|
|
305
260
|
/,
|
|
306
|
-
|
|
261
|
+
*filters: "StatementFilter",
|
|
307
262
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
308
263
|
schema_type: None = None,
|
|
309
264
|
**kwargs: Any,
|
|
@@ -314,7 +269,7 @@ class PsycopgSyncDriver(
|
|
|
314
269
|
sql: str,
|
|
315
270
|
parameters: "Optional[StatementParameterType]" = None,
|
|
316
271
|
/,
|
|
317
|
-
|
|
272
|
+
*filters: "StatementFilter",
|
|
318
273
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
319
274
|
schema_type: "type[T]",
|
|
320
275
|
**kwargs: Any,
|
|
@@ -324,7 +279,7 @@ class PsycopgSyncDriver(
|
|
|
324
279
|
sql: str,
|
|
325
280
|
parameters: "Optional[StatementParameterType]" = None,
|
|
326
281
|
/,
|
|
327
|
-
|
|
282
|
+
*filters: "StatementFilter",
|
|
328
283
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
329
284
|
schema_type: "Optional[type[T]]" = None,
|
|
330
285
|
**kwargs: Any,
|
|
@@ -335,7 +290,7 @@ class PsycopgSyncDriver(
|
|
|
335
290
|
The first value from the first row of results, or None if no results.
|
|
336
291
|
"""
|
|
337
292
|
connection = self._connection(connection)
|
|
338
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
293
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
339
294
|
with self._with_cursor(connection) as cursor:
|
|
340
295
|
cursor.execute(sql, parameters)
|
|
341
296
|
row = cursor.fetchone()
|
|
@@ -352,7 +307,7 @@ class PsycopgSyncDriver(
|
|
|
352
307
|
sql: str,
|
|
353
308
|
parameters: "Optional[StatementParameterType]" = None,
|
|
354
309
|
/,
|
|
355
|
-
|
|
310
|
+
*filters: "StatementFilter",
|
|
356
311
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
357
312
|
schema_type: None = None,
|
|
358
313
|
**kwargs: Any,
|
|
@@ -363,7 +318,7 @@ class PsycopgSyncDriver(
|
|
|
363
318
|
sql: str,
|
|
364
319
|
parameters: "Optional[StatementParameterType]" = None,
|
|
365
320
|
/,
|
|
366
|
-
|
|
321
|
+
*filters: "StatementFilter",
|
|
367
322
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
368
323
|
schema_type: "type[T]",
|
|
369
324
|
**kwargs: Any,
|
|
@@ -373,7 +328,7 @@ class PsycopgSyncDriver(
|
|
|
373
328
|
sql: str,
|
|
374
329
|
parameters: "Optional[StatementParameterType]" = None,
|
|
375
330
|
/,
|
|
376
|
-
|
|
331
|
+
*filters: "StatementFilter",
|
|
377
332
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
378
333
|
schema_type: "Optional[type[T]]" = None,
|
|
379
334
|
**kwargs: Any,
|
|
@@ -384,7 +339,7 @@ class PsycopgSyncDriver(
|
|
|
384
339
|
The first value from the first row of results, or None if no results.
|
|
385
340
|
"""
|
|
386
341
|
connection = self._connection(connection)
|
|
387
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
342
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
388
343
|
with self._with_cursor(connection) as cursor:
|
|
389
344
|
cursor.execute(sql, parameters)
|
|
390
345
|
row = cursor.fetchone()
|
|
@@ -402,7 +357,7 @@ class PsycopgSyncDriver(
|
|
|
402
357
|
sql: str,
|
|
403
358
|
parameters: "Optional[StatementParameterType]" = None,
|
|
404
359
|
/,
|
|
405
|
-
|
|
360
|
+
*filters: "StatementFilter",
|
|
406
361
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
407
362
|
**kwargs: Any,
|
|
408
363
|
) -> int:
|
|
@@ -412,7 +367,7 @@ class PsycopgSyncDriver(
|
|
|
412
367
|
The number of rows affected by the operation.
|
|
413
368
|
"""
|
|
414
369
|
connection = self._connection(connection)
|
|
415
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
370
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
416
371
|
with self._with_cursor(connection) as cursor:
|
|
417
372
|
cursor.execute(sql, parameters)
|
|
418
373
|
return getattr(cursor, "rowcount", -1) # pyright: ignore[reportUnknownMemberType]
|
|
@@ -423,7 +378,7 @@ class PsycopgSyncDriver(
|
|
|
423
378
|
sql: str,
|
|
424
379
|
parameters: "Optional[StatementParameterType]" = None,
|
|
425
380
|
/,
|
|
426
|
-
|
|
381
|
+
*filters: "StatementFilter",
|
|
427
382
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
428
383
|
schema_type: None = None,
|
|
429
384
|
**kwargs: Any,
|
|
@@ -434,7 +389,7 @@ class PsycopgSyncDriver(
|
|
|
434
389
|
sql: str,
|
|
435
390
|
parameters: "Optional[StatementParameterType]" = None,
|
|
436
391
|
/,
|
|
437
|
-
|
|
392
|
+
*filters: "StatementFilter",
|
|
438
393
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
439
394
|
schema_type: "type[ModelDTOT]",
|
|
440
395
|
**kwargs: Any,
|
|
@@ -444,7 +399,7 @@ class PsycopgSyncDriver(
|
|
|
444
399
|
sql: str,
|
|
445
400
|
parameters: "Optional[StatementParameterType]" = None,
|
|
446
401
|
/,
|
|
447
|
-
|
|
402
|
+
*filters: "StatementFilter",
|
|
448
403
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
449
404
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
450
405
|
**kwargs: Any,
|
|
@@ -455,7 +410,7 @@ class PsycopgSyncDriver(
|
|
|
455
410
|
The first row of results.
|
|
456
411
|
"""
|
|
457
412
|
connection = self._connection(connection)
|
|
458
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
413
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
459
414
|
with self._with_cursor(connection) as cursor:
|
|
460
415
|
cursor.execute(sql, parameters)
|
|
461
416
|
result = cursor.fetchone()
|
|
@@ -463,16 +418,13 @@ class PsycopgSyncDriver(
|
|
|
463
418
|
if result is None:
|
|
464
419
|
return None
|
|
465
420
|
|
|
466
|
-
|
|
467
|
-
return cast("ModelDTOT", schema_type(**result)) # pyright: ignore[reportUnknownArgumentType]
|
|
468
|
-
return cast("dict[str, Any]", result) # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
|
|
421
|
+
return self.to_schema(cast("dict[str, Any]", result), schema_type=schema_type)
|
|
469
422
|
|
|
470
423
|
def execute_script(
|
|
471
424
|
self,
|
|
472
425
|
sql: str,
|
|
473
426
|
parameters: "Optional[StatementParameterType]" = None,
|
|
474
427
|
/,
|
|
475
|
-
*,
|
|
476
428
|
connection: "Optional[PsycopgSyncConnection]" = None,
|
|
477
429
|
**kwargs: Any,
|
|
478
430
|
) -> str:
|
|
@@ -492,11 +444,11 @@ class PsycopgAsyncDriver(
|
|
|
492
444
|
PsycopgDriverBase,
|
|
493
445
|
SQLTranslatorMixin["PsycopgAsyncConnection"],
|
|
494
446
|
AsyncDriverAdapterProtocol["PsycopgAsyncConnection"],
|
|
447
|
+
ResultConverter,
|
|
495
448
|
):
|
|
496
449
|
"""Psycopg Async Driver Adapter."""
|
|
497
450
|
|
|
498
451
|
connection: "PsycopgAsyncConnection"
|
|
499
|
-
dialect: str = "postgres"
|
|
500
452
|
|
|
501
453
|
def __init__(self, connection: "PsycopgAsyncConnection") -> None:
|
|
502
454
|
self.connection = connection
|
|
@@ -517,7 +469,7 @@ class PsycopgAsyncDriver(
|
|
|
517
469
|
sql: str,
|
|
518
470
|
parameters: "Optional[StatementParameterType]" = None,
|
|
519
471
|
/,
|
|
520
|
-
|
|
472
|
+
*filters: "StatementFilter",
|
|
521
473
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
522
474
|
schema_type: None = None,
|
|
523
475
|
**kwargs: Any,
|
|
@@ -528,7 +480,7 @@ class PsycopgAsyncDriver(
|
|
|
528
480
|
sql: str,
|
|
529
481
|
parameters: "Optional[StatementParameterType]" = None,
|
|
530
482
|
/,
|
|
531
|
-
|
|
483
|
+
*filters: "StatementFilter",
|
|
532
484
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
533
485
|
schema_type: "type[ModelDTOT]",
|
|
534
486
|
**kwargs: Any,
|
|
@@ -538,9 +490,9 @@ class PsycopgAsyncDriver(
|
|
|
538
490
|
sql: str,
|
|
539
491
|
parameters: "Optional[StatementParameterType]" = None,
|
|
540
492
|
/,
|
|
541
|
-
|
|
542
|
-
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
493
|
+
*filters: "StatementFilter",
|
|
543
494
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
495
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
544
496
|
**kwargs: Any,
|
|
545
497
|
) -> "Sequence[Union[ModelDTOT, dict[str, Any]]]":
|
|
546
498
|
"""Fetch data from the database.
|
|
@@ -549,17 +501,13 @@ class PsycopgAsyncDriver(
|
|
|
549
501
|
List of row data as either model instances or dictionaries.
|
|
550
502
|
"""
|
|
551
503
|
connection = self._connection(connection)
|
|
552
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
553
|
-
results: list[Union[ModelDTOT, dict[str, Any]]] = []
|
|
554
|
-
|
|
504
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
555
505
|
async with self._with_cursor(connection) as cursor:
|
|
556
506
|
await cursor.execute(sql, parameters)
|
|
557
507
|
results = await cursor.fetchall()
|
|
558
508
|
if not results:
|
|
559
509
|
return []
|
|
560
|
-
|
|
561
|
-
return [cast("ModelDTOT", schema_type(**cast("dict[str,Any]", row))) for row in results] # pyright: ignore[reportUnknownArgumentType]
|
|
562
|
-
return [cast("dict[str,Any]", row) for row in results] # pyright: ignore[reportUnknownArgumentType]
|
|
510
|
+
return self.to_schema(cast("Sequence[dict[str, Any]]", results), schema_type=schema_type)
|
|
563
511
|
|
|
564
512
|
@overload
|
|
565
513
|
async def select_one(
|
|
@@ -567,7 +515,7 @@ class PsycopgAsyncDriver(
|
|
|
567
515
|
sql: str,
|
|
568
516
|
parameters: "Optional[StatementParameterType]" = None,
|
|
569
517
|
/,
|
|
570
|
-
|
|
518
|
+
*filters: "StatementFilter",
|
|
571
519
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
572
520
|
schema_type: None = None,
|
|
573
521
|
**kwargs: Any,
|
|
@@ -578,7 +526,7 @@ class PsycopgAsyncDriver(
|
|
|
578
526
|
sql: str,
|
|
579
527
|
parameters: "Optional[StatementParameterType]" = None,
|
|
580
528
|
/,
|
|
581
|
-
|
|
529
|
+
*filters: "StatementFilter",
|
|
582
530
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
583
531
|
schema_type: "type[ModelDTOT]",
|
|
584
532
|
**kwargs: Any,
|
|
@@ -588,7 +536,7 @@ class PsycopgAsyncDriver(
|
|
|
588
536
|
sql: str,
|
|
589
537
|
parameters: "Optional[StatementParameterType]" = None,
|
|
590
538
|
/,
|
|
591
|
-
|
|
539
|
+
*filters: "StatementFilter",
|
|
592
540
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
593
541
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
594
542
|
**kwargs: Any,
|
|
@@ -599,15 +547,13 @@ class PsycopgAsyncDriver(
|
|
|
599
547
|
The first row of the query results.
|
|
600
548
|
"""
|
|
601
549
|
connection = self._connection(connection)
|
|
602
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
603
|
-
|
|
550
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
604
551
|
async with self._with_cursor(connection) as cursor:
|
|
605
552
|
await cursor.execute(sql, parameters)
|
|
606
553
|
row = await cursor.fetchone()
|
|
607
554
|
row = self.check_not_found(row)
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
return cast("dict[str,Any]", row)
|
|
555
|
+
|
|
556
|
+
return self.to_schema(cast("dict[str, Any]", row), schema_type=schema_type)
|
|
611
557
|
|
|
612
558
|
@overload
|
|
613
559
|
async def select_one_or_none(
|
|
@@ -615,7 +561,7 @@ class PsycopgAsyncDriver(
|
|
|
615
561
|
sql: str,
|
|
616
562
|
parameters: "Optional[StatementParameterType]" = None,
|
|
617
563
|
/,
|
|
618
|
-
|
|
564
|
+
*filters: "StatementFilter",
|
|
619
565
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
620
566
|
schema_type: None = None,
|
|
621
567
|
**kwargs: Any,
|
|
@@ -626,7 +572,7 @@ class PsycopgAsyncDriver(
|
|
|
626
572
|
sql: str,
|
|
627
573
|
parameters: "Optional[StatementParameterType]" = None,
|
|
628
574
|
/,
|
|
629
|
-
|
|
575
|
+
*filters: "StatementFilter",
|
|
630
576
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
631
577
|
schema_type: "type[ModelDTOT]",
|
|
632
578
|
**kwargs: Any,
|
|
@@ -636,7 +582,7 @@ class PsycopgAsyncDriver(
|
|
|
636
582
|
sql: str,
|
|
637
583
|
parameters: "Optional[StatementParameterType]" = None,
|
|
638
584
|
/,
|
|
639
|
-
|
|
585
|
+
*filters: "StatementFilter",
|
|
640
586
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
641
587
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
642
588
|
**kwargs: Any,
|
|
@@ -647,16 +593,15 @@ class PsycopgAsyncDriver(
|
|
|
647
593
|
The first row of the query results.
|
|
648
594
|
"""
|
|
649
595
|
connection = self._connection(connection)
|
|
650
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
651
|
-
|
|
596
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
652
597
|
async with self._with_cursor(connection) as cursor:
|
|
653
598
|
await cursor.execute(sql, parameters)
|
|
654
599
|
row = await cursor.fetchone()
|
|
655
600
|
if row is None:
|
|
656
601
|
return None
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
return cast("dict[str,Any]", row)
|
|
602
|
+
|
|
603
|
+
# Use self.to_schema from ResultConverter mixin
|
|
604
|
+
return self.to_schema(cast("dict[str, Any]", row), schema_type=schema_type)
|
|
660
605
|
|
|
661
606
|
@overload
|
|
662
607
|
async def select_value(
|
|
@@ -664,7 +609,7 @@ class PsycopgAsyncDriver(
|
|
|
664
609
|
sql: str,
|
|
665
610
|
parameters: "Optional[StatementParameterType]" = None,
|
|
666
611
|
/,
|
|
667
|
-
|
|
612
|
+
*filters: "StatementFilter",
|
|
668
613
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
669
614
|
schema_type: None = None,
|
|
670
615
|
**kwargs: Any,
|
|
@@ -675,7 +620,7 @@ class PsycopgAsyncDriver(
|
|
|
675
620
|
sql: str,
|
|
676
621
|
parameters: "Optional[StatementParameterType]" = None,
|
|
677
622
|
/,
|
|
678
|
-
|
|
623
|
+
*filters: "StatementFilter",
|
|
679
624
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
680
625
|
schema_type: "type[T]",
|
|
681
626
|
**kwargs: Any,
|
|
@@ -685,7 +630,7 @@ class PsycopgAsyncDriver(
|
|
|
685
630
|
sql: str,
|
|
686
631
|
parameters: "Optional[StatementParameterType]" = None,
|
|
687
632
|
/,
|
|
688
|
-
|
|
633
|
+
*filters: "StatementFilter",
|
|
689
634
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
690
635
|
schema_type: "Optional[type[T]]" = None,
|
|
691
636
|
**kwargs: Any,
|
|
@@ -696,8 +641,7 @@ class PsycopgAsyncDriver(
|
|
|
696
641
|
The first value from the first row of results, or None if no results.
|
|
697
642
|
"""
|
|
698
643
|
connection = self._connection(connection)
|
|
699
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
700
|
-
|
|
644
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
701
645
|
async with self._with_cursor(connection) as cursor:
|
|
702
646
|
await cursor.execute(sql, parameters)
|
|
703
647
|
row = await cursor.fetchone()
|
|
@@ -708,12 +652,34 @@ class PsycopgAsyncDriver(
|
|
|
708
652
|
return schema_type(val) # type: ignore[call-arg]
|
|
709
653
|
return val
|
|
710
654
|
|
|
655
|
+
@overload
|
|
711
656
|
async def select_value_or_none(
|
|
712
657
|
self,
|
|
713
658
|
sql: str,
|
|
714
659
|
parameters: "Optional[StatementParameterType]" = None,
|
|
715
660
|
/,
|
|
716
|
-
|
|
661
|
+
*filters: "StatementFilter",
|
|
662
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
663
|
+
schema_type: None = None,
|
|
664
|
+
**kwargs: Any,
|
|
665
|
+
) -> "Optional[Any]": ...
|
|
666
|
+
@overload
|
|
667
|
+
async def select_value_or_none(
|
|
668
|
+
self,
|
|
669
|
+
sql: str,
|
|
670
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
671
|
+
/,
|
|
672
|
+
*filters: "StatementFilter",
|
|
673
|
+
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
674
|
+
schema_type: "type[T]",
|
|
675
|
+
**kwargs: Any,
|
|
676
|
+
) -> "Optional[T]": ...
|
|
677
|
+
async def select_value_or_none(
|
|
678
|
+
self,
|
|
679
|
+
sql: str,
|
|
680
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
681
|
+
/,
|
|
682
|
+
*filters: "StatementFilter",
|
|
717
683
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
718
684
|
schema_type: "Optional[type[T]]" = None,
|
|
719
685
|
**kwargs: Any,
|
|
@@ -724,8 +690,7 @@ class PsycopgAsyncDriver(
|
|
|
724
690
|
The first value from the first row of results, or None if no results.
|
|
725
691
|
"""
|
|
726
692
|
connection = self._connection(connection)
|
|
727
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
728
|
-
|
|
693
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
729
694
|
async with self._with_cursor(connection) as cursor:
|
|
730
695
|
await cursor.execute(sql, parameters)
|
|
731
696
|
row = await cursor.fetchone()
|
|
@@ -743,7 +708,7 @@ class PsycopgAsyncDriver(
|
|
|
743
708
|
sql: str,
|
|
744
709
|
parameters: "Optional[StatementParameterType]" = None,
|
|
745
710
|
/,
|
|
746
|
-
|
|
711
|
+
*filters: "StatementFilter",
|
|
747
712
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
748
713
|
**kwargs: Any,
|
|
749
714
|
) -> int:
|
|
@@ -753,15 +718,10 @@ class PsycopgAsyncDriver(
|
|
|
753
718
|
The number of rows affected by the operation.
|
|
754
719
|
"""
|
|
755
720
|
connection = self._connection(connection)
|
|
756
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
757
|
-
|
|
721
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
758
722
|
async with self._with_cursor(connection) as cursor:
|
|
759
723
|
await cursor.execute(sql, parameters)
|
|
760
|
-
|
|
761
|
-
rowcount = int(cursor.rowcount)
|
|
762
|
-
except (TypeError, ValueError):
|
|
763
|
-
rowcount = -1
|
|
764
|
-
return rowcount
|
|
724
|
+
return getattr(cursor, "rowcount", -1) # pyright: ignore[reportUnknownMemberType]
|
|
765
725
|
|
|
766
726
|
@overload
|
|
767
727
|
async def insert_update_delete_returning(
|
|
@@ -769,7 +729,7 @@ class PsycopgAsyncDriver(
|
|
|
769
729
|
sql: str,
|
|
770
730
|
parameters: "Optional[StatementParameterType]" = None,
|
|
771
731
|
/,
|
|
772
|
-
|
|
732
|
+
*filters: "StatementFilter",
|
|
773
733
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
774
734
|
schema_type: None = None,
|
|
775
735
|
**kwargs: Any,
|
|
@@ -780,7 +740,7 @@ class PsycopgAsyncDriver(
|
|
|
780
740
|
sql: str,
|
|
781
741
|
parameters: "Optional[StatementParameterType]" = None,
|
|
782
742
|
/,
|
|
783
|
-
|
|
743
|
+
*filters: "StatementFilter",
|
|
784
744
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
785
745
|
schema_type: "type[ModelDTOT]",
|
|
786
746
|
**kwargs: Any,
|
|
@@ -790,7 +750,7 @@ class PsycopgAsyncDriver(
|
|
|
790
750
|
sql: str,
|
|
791
751
|
parameters: "Optional[StatementParameterType]" = None,
|
|
792
752
|
/,
|
|
793
|
-
|
|
753
|
+
*filters: "StatementFilter",
|
|
794
754
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
795
755
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
796
756
|
**kwargs: Any,
|
|
@@ -801,25 +761,20 @@ class PsycopgAsyncDriver(
|
|
|
801
761
|
The first row of results.
|
|
802
762
|
"""
|
|
803
763
|
connection = self._connection(connection)
|
|
804
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
805
|
-
|
|
764
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
806
765
|
async with self._with_cursor(connection) as cursor:
|
|
807
766
|
await cursor.execute(sql, parameters)
|
|
808
767
|
result = await cursor.fetchone()
|
|
809
|
-
|
|
810
768
|
if result is None:
|
|
811
769
|
return None
|
|
812
770
|
|
|
813
|
-
|
|
814
|
-
return cast("ModelDTOT", schema_type(**result)) # pyright: ignore[reportUnknownArgumentType]
|
|
815
|
-
return cast("dict[str, Any]", result) # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
|
|
771
|
+
return self.to_schema(cast("dict[str, Any]", result), schema_type=schema_type)
|
|
816
772
|
|
|
817
773
|
async def execute_script(
|
|
818
774
|
self,
|
|
819
775
|
sql: str,
|
|
820
776
|
parameters: "Optional[StatementParameterType]" = None,
|
|
821
777
|
/,
|
|
822
|
-
*,
|
|
823
778
|
connection: "Optional[PsycopgAsyncConnection]" = None,
|
|
824
779
|
**kwargs: Any,
|
|
825
780
|
) -> str:
|
|
@@ -830,7 +785,6 @@ class PsycopgAsyncDriver(
|
|
|
830
785
|
"""
|
|
831
786
|
connection = self._connection(connection)
|
|
832
787
|
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
833
|
-
|
|
834
788
|
async with self._with_cursor(connection) as cursor:
|
|
835
789
|
await cursor.execute(sql, parameters)
|
|
836
790
|
return str(cursor.statusmessage) if cursor.statusmessage is not None else "DONE"
|