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
sqlspec/adapters/adbc/driver.py
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import contextlib
|
|
2
2
|
import logging
|
|
3
3
|
import re
|
|
4
|
-
from collections.abc import Generator, Sequence
|
|
4
|
+
from collections.abc import Generator, Mapping, Sequence
|
|
5
5
|
from contextlib import contextmanager
|
|
6
6
|
from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union, cast, overload
|
|
7
7
|
|
|
8
8
|
from adbc_driver_manager.dbapi import Connection, Cursor
|
|
9
|
+
from sqlglot import exp as sqlglot_exp
|
|
9
10
|
|
|
10
11
|
from sqlspec.base import SyncDriverAdapterProtocol
|
|
11
|
-
from sqlspec.exceptions import
|
|
12
|
-
from sqlspec.
|
|
12
|
+
from sqlspec.exceptions import SQLParsingError
|
|
13
|
+
from sqlspec.filters import StatementFilter
|
|
14
|
+
from sqlspec.mixins import ResultConverter, SQLTranslatorMixin, SyncArrowBulkOperationsMixin
|
|
13
15
|
from sqlspec.statement import SQLStatement
|
|
14
|
-
from sqlspec.typing import ArrowTable, StatementParameterType
|
|
16
|
+
from sqlspec.typing import ArrowTable, StatementParameterType, is_dict
|
|
15
17
|
|
|
16
18
|
if TYPE_CHECKING:
|
|
17
19
|
from sqlspec.typing import ArrowTable, ModelDTOT, StatementParameterType, T
|
|
@@ -20,39 +22,35 @@ __all__ = ("AdbcConnection", "AdbcDriver")
|
|
|
20
22
|
|
|
21
23
|
logger = logging.getLogger("sqlspec")
|
|
22
24
|
|
|
25
|
+
AdbcConnection = Connection
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
(?:
|
|
27
|
-
(?P<dquote>"(?:[^"]|"")*") | # Double-quoted strings
|
|
28
|
-
(?P<squote>'(?:[^']|'')*') | # Single-quoted strings
|
|
29
|
-
(?P<comment>--.*?\n|\/\*.*?\*\/) | # SQL comments
|
|
30
|
-
(?P<lead>[:\$])(?P<var_name>[a-zA-Z_][a-zA-Z0-9_]*) # :name or $name identifier
|
|
31
|
-
)
|
|
32
|
-
""",
|
|
33
|
-
re.VERBOSE | re.DOTALL,
|
|
34
|
-
)
|
|
27
|
+
# SQLite named parameter pattern - simple pattern to find parameter references
|
|
28
|
+
SQLITE_PARAM_PATTERN = re.compile(r"(?::|\$|@)([a-zA-Z0-9_]+)")
|
|
35
29
|
|
|
36
|
-
|
|
30
|
+
# Patterns to identify comments and string literals
|
|
31
|
+
SQL_COMMENT_PATTERN = re.compile(r"--[^\n]*|/\*.*?\*/", re.DOTALL)
|
|
32
|
+
SQL_STRING_PATTERN = re.compile(r"'[^']*'|\"[^\"]*\"")
|
|
37
33
|
|
|
38
34
|
|
|
39
35
|
class AdbcDriver(
|
|
40
36
|
SyncArrowBulkOperationsMixin["AdbcConnection"],
|
|
41
37
|
SQLTranslatorMixin["AdbcConnection"],
|
|
42
38
|
SyncDriverAdapterProtocol["AdbcConnection"],
|
|
39
|
+
ResultConverter,
|
|
43
40
|
):
|
|
44
41
|
"""ADBC Sync Driver Adapter."""
|
|
45
42
|
|
|
46
43
|
connection: AdbcConnection
|
|
47
44
|
__supports_arrow__: ClassVar[bool] = True
|
|
45
|
+
dialect: str = "adbc"
|
|
48
46
|
|
|
49
47
|
def __init__(self, connection: "AdbcConnection") -> None:
|
|
50
48
|
"""Initialize the ADBC driver adapter."""
|
|
51
49
|
self.connection = connection
|
|
52
|
-
self.dialect = self._get_dialect(connection)
|
|
50
|
+
self.dialect = self._get_dialect(connection) # Store detected dialect
|
|
53
51
|
|
|
54
52
|
@staticmethod
|
|
55
|
-
def _get_dialect(connection: "AdbcConnection") -> str:
|
|
53
|
+
def _get_dialect(connection: "AdbcConnection") -> str:
|
|
56
54
|
"""Get the database dialect based on the driver name.
|
|
57
55
|
|
|
58
56
|
Args:
|
|
@@ -89,91 +87,202 @@ class AdbcDriver(
|
|
|
89
87
|
with contextlib.suppress(Exception):
|
|
90
88
|
cursor.close() # type: ignore[no-untyped-call]
|
|
91
89
|
|
|
92
|
-
def _process_sql_params(
|
|
90
|
+
def _process_sql_params( # noqa: C901, PLR0912, PLR0915
|
|
93
91
|
self,
|
|
94
92
|
sql: str,
|
|
95
93
|
parameters: "Optional[StatementParameterType]" = None,
|
|
96
|
-
|
|
94
|
+
*filters: "StatementFilter",
|
|
97
95
|
**kwargs: Any,
|
|
98
|
-
) -> "tuple[str, Optional[
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
96
|
+
) -> "tuple[str, Optional[tuple[Any, ...]]]": # Always returns tuple or None for params
|
|
97
|
+
"""Process SQL and parameters for ADBC.
|
|
98
|
+
|
|
99
|
+
ADBC drivers generally use positional parameters with '?' placeholders.
|
|
100
|
+
This method processes the SQL statement and transforms parameters into the format
|
|
101
|
+
expected by ADBC drivers.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
sql: The SQL statement to process.
|
|
105
|
+
parameters: The parameters to bind to the statement.
|
|
106
|
+
*filters: Statement filters to apply.
|
|
107
|
+
**kwargs: Additional keyword arguments.
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
SQLParsingError: If the SQL statement cannot be parsed.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
A tuple of (sql, parameters) ready for execution.
|
|
114
|
+
"""
|
|
115
|
+
passed_parameters: Optional[Union[Mapping[str, Any], Sequence[Any]]] = None
|
|
116
|
+
combined_filters_list: list[StatementFilter] = list(filters)
|
|
117
|
+
|
|
118
|
+
if parameters is not None:
|
|
119
|
+
if isinstance(parameters, StatementFilter):
|
|
120
|
+
combined_filters_list.insert(0, parameters)
|
|
121
|
+
# passed_parameters remains None
|
|
122
|
+
else:
|
|
123
|
+
# If parameters is not a StatementFilter, it's actual data parameters.
|
|
124
|
+
passed_parameters = parameters
|
|
125
|
+
|
|
126
|
+
# Special handling for SQLite with non-dict parameters and named placeholders
|
|
127
|
+
if self.dialect == "sqlite" and passed_parameters is not None and not is_dict(passed_parameters):
|
|
128
|
+
# First mask out comments and strings to avoid detecting parameters in those
|
|
129
|
+
comments = list(SQL_COMMENT_PATTERN.finditer(sql))
|
|
130
|
+
strings = list(SQL_STRING_PATTERN.finditer(sql))
|
|
131
|
+
|
|
132
|
+
all_matches = [(m.start(), m.end(), "comment") for m in comments] + [
|
|
133
|
+
(m.start(), m.end(), "string") for m in strings
|
|
134
|
+
]
|
|
135
|
+
all_matches.sort(reverse=True)
|
|
136
|
+
|
|
137
|
+
for start, end, _ in all_matches:
|
|
138
|
+
sql = sql[:start] + " " * (end - start) + sql[end:]
|
|
139
|
+
|
|
140
|
+
# Find named parameters in clean SQL
|
|
141
|
+
named_params = list(SQLITE_PARAM_PATTERN.finditer(sql))
|
|
142
|
+
|
|
143
|
+
if named_params:
|
|
144
|
+
param_positions = [(m.start(), m.end()) for m in named_params]
|
|
145
|
+
param_positions.sort(reverse=True)
|
|
146
|
+
for start, end in param_positions:
|
|
147
|
+
sql = sql[:start] + "?" + sql[end:]
|
|
148
|
+
if not isinstance(passed_parameters, (list, tuple)):
|
|
149
|
+
passed_parameters = (passed_parameters,)
|
|
150
|
+
passed_parameters = tuple(passed_parameters)
|
|
151
|
+
|
|
152
|
+
# Standard processing for all other cases
|
|
153
|
+
statement = SQLStatement(sql, passed_parameters, kwargs=kwargs, dialect=self.dialect)
|
|
154
|
+
|
|
155
|
+
# Apply any filters from combined_filters_list
|
|
156
|
+
for filter_obj in combined_filters_list:
|
|
157
|
+
statement = statement.apply_filter(filter_obj)
|
|
158
|
+
|
|
159
|
+
processed_sql, processed_params, parsed_expr = statement.process()
|
|
160
|
+
|
|
161
|
+
# Special handling for SQLite dialect with dict parameters
|
|
162
|
+
if self.dialect == "sqlite" and is_dict(processed_params):
|
|
163
|
+
# First, mask out comments and string literals with placeholders
|
|
164
|
+
masked_sql = processed_sql
|
|
165
|
+
|
|
166
|
+
# Replace comments and strings with placeholders
|
|
167
|
+
comments = list(SQL_COMMENT_PATTERN.finditer(masked_sql))
|
|
168
|
+
strings = list(SQL_STRING_PATTERN.finditer(masked_sql))
|
|
169
|
+
|
|
170
|
+
# Sort all matches by their start position (descending)
|
|
171
|
+
all_matches = [(m.start(), m.end(), "comment") for m in comments] + [
|
|
172
|
+
(m.start(), m.end(), "string") for m in strings
|
|
173
|
+
]
|
|
174
|
+
all_matches.sort(reverse=True)
|
|
175
|
+
|
|
176
|
+
# Replace each match with spaces to preserve positions
|
|
177
|
+
for start, end, _ in all_matches:
|
|
178
|
+
masked_sql = masked_sql[:start] + " " * (end - start) + masked_sql[end:]
|
|
179
|
+
|
|
180
|
+
# Now find parameters in the masked SQL
|
|
181
|
+
param_order = []
|
|
182
|
+
param_spans = [] # Store (start, end) of each parameter
|
|
183
|
+
|
|
184
|
+
for match in SQLITE_PARAM_PATTERN.finditer(masked_sql):
|
|
185
|
+
param_name = match.group(1)
|
|
186
|
+
if param_name in processed_params:
|
|
187
|
+
param_order.append(param_name)
|
|
188
|
+
param_spans.append((match.start(), match.end()))
|
|
189
|
+
|
|
190
|
+
if param_order:
|
|
191
|
+
# Replace parameters with ? placeholders in reverse order to preserve positions
|
|
192
|
+
result_sql = processed_sql
|
|
193
|
+
for i, (start, end) in enumerate(reversed(param_spans)): # noqa: B007
|
|
194
|
+
# Replace :param with ?
|
|
195
|
+
result_sql = result_sql[:start] + "?" + result_sql[start + 1 + len(param_order[-(i + 1)]) :]
|
|
196
|
+
|
|
197
|
+
return result_sql, tuple(processed_params[name] for name in param_order)
|
|
198
|
+
|
|
199
|
+
if processed_params is None:
|
|
200
|
+
return processed_sql, ()
|
|
201
|
+
if (
|
|
202
|
+
isinstance(processed_params, (tuple, list))
|
|
203
|
+
or (processed_params is not None and not isinstance(processed_params, dict))
|
|
204
|
+
) and parsed_expr is not None:
|
|
205
|
+
# Find all named placeholders
|
|
206
|
+
named_param_nodes = [
|
|
207
|
+
node
|
|
208
|
+
for node in parsed_expr.find_all(sqlglot_exp.Parameter, sqlglot_exp.Placeholder)
|
|
209
|
+
if (isinstance(node, sqlglot_exp.Parameter) and node.name and not node.name.isdigit())
|
|
210
|
+
or (
|
|
211
|
+
isinstance(node, sqlglot_exp.Placeholder)
|
|
212
|
+
and node.this
|
|
213
|
+
and not isinstance(node.this, (sqlglot_exp.Identifier, sqlglot_exp.Literal))
|
|
214
|
+
and not str(node.this).isdigit()
|
|
155
215
|
)
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
# If we found named parameters, transform to question marks
|
|
219
|
+
if named_param_nodes:
|
|
220
|
+
|
|
221
|
+
def convert_to_qmark(node: sqlglot_exp.Expression) -> sqlglot_exp.Expression:
|
|
222
|
+
if (isinstance(node, sqlglot_exp.Parameter) and node.name and not node.name.isdigit()) or (
|
|
223
|
+
isinstance(node, sqlglot_exp.Placeholder)
|
|
224
|
+
and node.this
|
|
225
|
+
and not isinstance(node.this, (sqlglot_exp.Identifier, sqlglot_exp.Literal))
|
|
226
|
+
and not str(node.this).isdigit()
|
|
227
|
+
):
|
|
228
|
+
return sqlglot_exp.Placeholder()
|
|
229
|
+
return node
|
|
230
|
+
|
|
231
|
+
# Transform the SQL
|
|
232
|
+
processed_sql = parsed_expr.transform(convert_to_qmark, copy=True).sql(dialect=self.dialect)
|
|
233
|
+
|
|
234
|
+
# If it's a scalar parameter, ensure it's wrapped in a tuple
|
|
235
|
+
if not isinstance(processed_params, (tuple, list)):
|
|
236
|
+
processed_params = (processed_params,) # type: ignore[unreachable]
|
|
237
|
+
|
|
238
|
+
# 6. Handle dictionary parameters
|
|
239
|
+
if is_dict(processed_params):
|
|
240
|
+
# Skip conversion if there's no parsed expression to work with
|
|
241
|
+
if parsed_expr is None:
|
|
242
|
+
msg = f"ADBC ({self.dialect}): Failed to parse SQL with dictionary parameters. Cannot determine parameter order."
|
|
156
243
|
raise SQLParsingError(msg)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
244
|
+
|
|
245
|
+
# Collect named parameters in the order they appear in the SQL
|
|
246
|
+
named_params = []
|
|
247
|
+
for node in parsed_expr.find_all(sqlglot_exp.Parameter, sqlglot_exp.Placeholder):
|
|
248
|
+
if isinstance(node, sqlglot_exp.Parameter) and node.name and node.name in processed_params:
|
|
249
|
+
named_params.append(node.name) # type: ignore[arg-type]
|
|
250
|
+
elif (
|
|
251
|
+
isinstance(node, sqlglot_exp.Placeholder)
|
|
252
|
+
and isinstance(node.this, str)
|
|
253
|
+
and node.this in processed_params
|
|
254
|
+
):
|
|
255
|
+
named_params.append(node.this) # type: ignore[arg-type]
|
|
256
|
+
|
|
257
|
+
# If we found named parameters, convert them to ? placeholders
|
|
258
|
+
if named_params:
|
|
259
|
+
# Transform SQL to use ? placeholders
|
|
260
|
+
def convert_to_qmark(node: sqlglot_exp.Expression) -> sqlglot_exp.Expression:
|
|
261
|
+
if isinstance(node, sqlglot_exp.Parameter) and node.name and node.name in processed_params:
|
|
262
|
+
return sqlglot_exp.Placeholder() # Anonymous ? placeholder
|
|
263
|
+
if (
|
|
264
|
+
isinstance(node, sqlglot_exp.Placeholder)
|
|
265
|
+
and isinstance(node.this, str)
|
|
266
|
+
and node.this in processed_params
|
|
267
|
+
):
|
|
268
|
+
return sqlglot_exp.Placeholder() # Anonymous ? placeholder
|
|
269
|
+
return node
|
|
270
|
+
|
|
271
|
+
return parsed_expr.transform(convert_to_qmark, copy=True).sql(dialect=self.dialect), tuple(
|
|
272
|
+
processed_params[name] # type: ignore[index]
|
|
273
|
+
for name in named_params
|
|
274
|
+
)
|
|
275
|
+
return processed_sql, tuple(processed_params.values())
|
|
276
|
+
if isinstance(processed_params, (list, tuple)):
|
|
277
|
+
return processed_sql, tuple(processed_params)
|
|
278
|
+
return processed_sql, (processed_params,)
|
|
169
279
|
|
|
170
280
|
@overload
|
|
171
281
|
def select(
|
|
172
282
|
self,
|
|
173
283
|
sql: str,
|
|
174
284
|
parameters: "Optional[StatementParameterType]" = None,
|
|
175
|
-
|
|
176
|
-
*,
|
|
285
|
+
*filters: "StatementFilter",
|
|
177
286
|
connection: "Optional[AdbcConnection]" = None,
|
|
178
287
|
schema_type: None = None,
|
|
179
288
|
**kwargs: Any,
|
|
@@ -183,8 +292,7 @@ class AdbcDriver(
|
|
|
183
292
|
self,
|
|
184
293
|
sql: str,
|
|
185
294
|
parameters: "Optional[StatementParameterType]" = None,
|
|
186
|
-
|
|
187
|
-
*,
|
|
295
|
+
*filters: "StatementFilter",
|
|
188
296
|
connection: "Optional[AdbcConnection]" = None,
|
|
189
297
|
schema_type: "type[ModelDTOT]",
|
|
190
298
|
**kwargs: Any,
|
|
@@ -193,38 +301,42 @@ class AdbcDriver(
|
|
|
193
301
|
self,
|
|
194
302
|
sql: str,
|
|
195
303
|
parameters: Optional["StatementParameterType"] = None,
|
|
196
|
-
|
|
197
|
-
*,
|
|
304
|
+
*filters: "StatementFilter",
|
|
198
305
|
connection: Optional["AdbcConnection"] = None,
|
|
199
306
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
200
307
|
**kwargs: Any,
|
|
201
308
|
) -> "Sequence[Union[ModelDTOT, dict[str, Any]]]":
|
|
202
309
|
"""Fetch data from the database.
|
|
203
310
|
|
|
311
|
+
Args:
|
|
312
|
+
sql: The SQL query string.
|
|
313
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
314
|
+
*filters: Statement filters to apply.
|
|
315
|
+
connection: Optional connection override.
|
|
316
|
+
schema_type: Optional schema class for the result.
|
|
317
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
318
|
+
|
|
204
319
|
Returns:
|
|
205
320
|
List of row data as either model instances or dictionaries.
|
|
206
321
|
"""
|
|
207
322
|
connection = self._connection(connection)
|
|
208
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
323
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
324
|
+
|
|
209
325
|
with self._with_cursor(connection) as cursor:
|
|
210
326
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
211
327
|
results = cursor.fetchall() # pyright: ignore
|
|
212
328
|
if not results:
|
|
213
329
|
return []
|
|
330
|
+
column_names = [column[0] for column in cursor.description or []]
|
|
214
331
|
|
|
215
|
-
column_names
|
|
216
|
-
|
|
217
|
-
if schema_type is not None:
|
|
218
|
-
return [cast("ModelDTOT", schema_type(**dict(zip(column_names, row)))) for row in results] # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
|
|
219
|
-
return [dict(zip(column_names, row)) for row in results] # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
|
|
332
|
+
return self.to_schema([dict(zip(column_names, row)) for row in results], schema_type=schema_type)
|
|
220
333
|
|
|
221
334
|
@overload
|
|
222
335
|
def select_one(
|
|
223
336
|
self,
|
|
224
337
|
sql: str,
|
|
225
338
|
parameters: "Optional[StatementParameterType]" = None,
|
|
226
|
-
|
|
227
|
-
*,
|
|
339
|
+
*filters: "StatementFilter",
|
|
228
340
|
connection: "Optional[AdbcConnection]" = None,
|
|
229
341
|
schema_type: None = None,
|
|
230
342
|
**kwargs: Any,
|
|
@@ -234,8 +346,7 @@ class AdbcDriver(
|
|
|
234
346
|
self,
|
|
235
347
|
sql: str,
|
|
236
348
|
parameters: "Optional[StatementParameterType]" = None,
|
|
237
|
-
|
|
238
|
-
*,
|
|
349
|
+
*filters: "StatementFilter",
|
|
239
350
|
connection: "Optional[AdbcConnection]" = None,
|
|
240
351
|
schema_type: "type[ModelDTOT]",
|
|
241
352
|
**kwargs: Any,
|
|
@@ -243,36 +354,41 @@ class AdbcDriver(
|
|
|
243
354
|
def select_one(
|
|
244
355
|
self,
|
|
245
356
|
sql: str,
|
|
246
|
-
parameters: Optional[
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
connection: Optional["AdbcConnection"] = None,
|
|
357
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
358
|
+
*filters: "StatementFilter",
|
|
359
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
250
360
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
251
361
|
**kwargs: Any,
|
|
252
362
|
) -> "Union[ModelDTOT, dict[str, Any]]":
|
|
253
363
|
"""Fetch one row from the database.
|
|
254
364
|
|
|
365
|
+
Args:
|
|
366
|
+
sql: The SQL query string.
|
|
367
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
368
|
+
*filters: Statement filters to apply.
|
|
369
|
+
connection: Optional connection override.
|
|
370
|
+
schema_type: Optional schema class for the result.
|
|
371
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
372
|
+
|
|
255
373
|
Returns:
|
|
256
374
|
The first row of the query results.
|
|
257
375
|
"""
|
|
258
376
|
connection = self._connection(connection)
|
|
259
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
377
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
378
|
+
|
|
260
379
|
with self._with_cursor(connection) as cursor:
|
|
261
|
-
cursor.execute(sql, parameters)
|
|
262
|
-
result = cursor.fetchone()
|
|
263
|
-
result = self.check_not_found(result)
|
|
264
|
-
column_names = [
|
|
265
|
-
|
|
266
|
-
return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
|
|
267
|
-
return schema_type(**dict(zip(column_names, result))) # type: ignore[return-value]
|
|
380
|
+
cursor.execute(sql, parameters)
|
|
381
|
+
result = cursor.fetchone()
|
|
382
|
+
result = self.check_not_found(result)
|
|
383
|
+
column_names = [column[0] for column in cursor.description or []]
|
|
384
|
+
return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
|
|
268
385
|
|
|
269
386
|
@overload
|
|
270
387
|
def select_one_or_none(
|
|
271
388
|
self,
|
|
272
389
|
sql: str,
|
|
273
390
|
parameters: "Optional[StatementParameterType]" = None,
|
|
274
|
-
|
|
275
|
-
*,
|
|
391
|
+
*filters: "StatementFilter",
|
|
276
392
|
connection: "Optional[AdbcConnection]" = None,
|
|
277
393
|
schema_type: None = None,
|
|
278
394
|
**kwargs: Any,
|
|
@@ -282,8 +398,7 @@ class AdbcDriver(
|
|
|
282
398
|
self,
|
|
283
399
|
sql: str,
|
|
284
400
|
parameters: "Optional[StatementParameterType]" = None,
|
|
285
|
-
|
|
286
|
-
*,
|
|
401
|
+
*filters: "StatementFilter",
|
|
287
402
|
connection: "Optional[AdbcConnection]" = None,
|
|
288
403
|
schema_type: "type[ModelDTOT]",
|
|
289
404
|
**kwargs: Any,
|
|
@@ -292,36 +407,41 @@ class AdbcDriver(
|
|
|
292
407
|
self,
|
|
293
408
|
sql: str,
|
|
294
409
|
parameters: Optional["StatementParameterType"] = None,
|
|
295
|
-
|
|
296
|
-
*,
|
|
410
|
+
*filters: "StatementFilter",
|
|
297
411
|
connection: Optional["AdbcConnection"] = None,
|
|
298
412
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
299
413
|
**kwargs: Any,
|
|
300
414
|
) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
|
|
301
|
-
"""Fetch one row from the database.
|
|
415
|
+
"""Fetch one row from the database or return None if no rows found.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
sql: The SQL query string.
|
|
419
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
420
|
+
*filters: Statement filters to apply.
|
|
421
|
+
connection: Optional connection override.
|
|
422
|
+
schema_type: Optional schema class for the result.
|
|
423
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
302
424
|
|
|
303
425
|
Returns:
|
|
304
|
-
The first row of the query results.
|
|
426
|
+
The first row of the query results, or None if no results found.
|
|
305
427
|
"""
|
|
306
428
|
connection = self._connection(connection)
|
|
307
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
429
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
430
|
+
|
|
308
431
|
with self._with_cursor(connection) as cursor:
|
|
309
432
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
310
433
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
311
434
|
if result is None:
|
|
312
435
|
return None
|
|
313
|
-
column_names = [
|
|
314
|
-
|
|
315
|
-
return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
|
|
316
|
-
return schema_type(**dict(zip(column_names, result))) # type: ignore[return-value]
|
|
436
|
+
column_names = [column[0] for column in cursor.description or []]
|
|
437
|
+
return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
|
|
317
438
|
|
|
318
439
|
@overload
|
|
319
440
|
def select_value(
|
|
320
441
|
self,
|
|
321
442
|
sql: str,
|
|
322
443
|
parameters: "Optional[StatementParameterType]" = None,
|
|
323
|
-
|
|
324
|
-
*,
|
|
444
|
+
*filters: "StatementFilter",
|
|
325
445
|
connection: "Optional[AdbcConnection]" = None,
|
|
326
446
|
schema_type: None = None,
|
|
327
447
|
**kwargs: Any,
|
|
@@ -331,8 +451,7 @@ class AdbcDriver(
|
|
|
331
451
|
self,
|
|
332
452
|
sql: str,
|
|
333
453
|
parameters: "Optional[StatementParameterType]" = None,
|
|
334
|
-
|
|
335
|
-
*,
|
|
454
|
+
*filters: "StatementFilter",
|
|
336
455
|
connection: "Optional[AdbcConnection]" = None,
|
|
337
456
|
schema_type: "type[T]",
|
|
338
457
|
**kwargs: Any,
|
|
@@ -340,20 +459,28 @@ class AdbcDriver(
|
|
|
340
459
|
def select_value(
|
|
341
460
|
self,
|
|
342
461
|
sql: str,
|
|
343
|
-
parameters: Optional[
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
connection: Optional["AdbcConnection"] = None,
|
|
462
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
463
|
+
*filters: "StatementFilter",
|
|
464
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
347
465
|
schema_type: "Optional[type[T]]" = None,
|
|
348
466
|
**kwargs: Any,
|
|
349
467
|
) -> "Union[T, Any]":
|
|
350
468
|
"""Fetch a single value from the database.
|
|
351
469
|
|
|
470
|
+
Args:
|
|
471
|
+
sql: The SQL query string.
|
|
472
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
473
|
+
*filters: Statement filters to apply.
|
|
474
|
+
connection: Optional connection override.
|
|
475
|
+
schema_type: Optional type to convert the result to.
|
|
476
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
477
|
+
|
|
352
478
|
Returns:
|
|
353
|
-
The first value
|
|
479
|
+
The first value of the first row of the query results.
|
|
354
480
|
"""
|
|
355
481
|
connection = self._connection(connection)
|
|
356
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
482
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
483
|
+
|
|
357
484
|
with self._with_cursor(connection) as cursor:
|
|
358
485
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
359
486
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -367,8 +494,7 @@ class AdbcDriver(
|
|
|
367
494
|
self,
|
|
368
495
|
sql: str,
|
|
369
496
|
parameters: "Optional[StatementParameterType]" = None,
|
|
370
|
-
|
|
371
|
-
*,
|
|
497
|
+
*filters: "StatementFilter",
|
|
372
498
|
connection: "Optional[AdbcConnection]" = None,
|
|
373
499
|
schema_type: None = None,
|
|
374
500
|
**kwargs: Any,
|
|
@@ -378,8 +504,7 @@ class AdbcDriver(
|
|
|
378
504
|
self,
|
|
379
505
|
sql: str,
|
|
380
506
|
parameters: "Optional[StatementParameterType]" = None,
|
|
381
|
-
|
|
382
|
-
*,
|
|
507
|
+
*filters: "StatementFilter",
|
|
383
508
|
connection: "Optional[AdbcConnection]" = None,
|
|
384
509
|
schema_type: "type[T]",
|
|
385
510
|
**kwargs: Any,
|
|
@@ -387,20 +512,28 @@ class AdbcDriver(
|
|
|
387
512
|
def select_value_or_none(
|
|
388
513
|
self,
|
|
389
514
|
sql: str,
|
|
390
|
-
parameters: Optional[
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
connection: Optional["AdbcConnection"] = None,
|
|
515
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
516
|
+
*filters: "StatementFilter",
|
|
517
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
394
518
|
schema_type: "Optional[type[T]]" = None,
|
|
395
519
|
**kwargs: Any,
|
|
396
520
|
) -> "Optional[Union[T, Any]]":
|
|
397
|
-
"""Fetch a single value
|
|
521
|
+
"""Fetch a single value or None if not found.
|
|
522
|
+
|
|
523
|
+
Args:
|
|
524
|
+
sql: The SQL query string.
|
|
525
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
526
|
+
*filters: Statement filters to apply.
|
|
527
|
+
connection: Optional connection override.
|
|
528
|
+
schema_type: Optional type to convert the result to.
|
|
529
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
398
530
|
|
|
399
531
|
Returns:
|
|
400
|
-
The first value
|
|
532
|
+
The first value of the first row of the query results, or None if no results found.
|
|
401
533
|
"""
|
|
402
534
|
connection = self._connection(connection)
|
|
403
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
535
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
536
|
+
|
|
404
537
|
with self._with_cursor(connection) as cursor:
|
|
405
538
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
406
539
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -413,19 +546,25 @@ class AdbcDriver(
|
|
|
413
546
|
def insert_update_delete(
|
|
414
547
|
self,
|
|
415
548
|
sql: str,
|
|
416
|
-
parameters: Optional[
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
connection: Optional["AdbcConnection"] = None,
|
|
549
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
550
|
+
*filters: "StatementFilter",
|
|
551
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
420
552
|
**kwargs: Any,
|
|
421
553
|
) -> int:
|
|
422
|
-
"""
|
|
554
|
+
"""Execute an insert, update, or delete statement.
|
|
555
|
+
|
|
556
|
+
Args:
|
|
557
|
+
sql: The SQL statement string.
|
|
558
|
+
parameters: The parameters for the statement (dict, tuple, list, or None).
|
|
559
|
+
*filters: Statement filters to apply.
|
|
560
|
+
connection: Optional connection override.
|
|
561
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
423
562
|
|
|
424
563
|
Returns:
|
|
425
564
|
Row count affected by the operation.
|
|
426
565
|
"""
|
|
427
566
|
connection = self._connection(connection)
|
|
428
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
567
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
429
568
|
|
|
430
569
|
with self._with_cursor(connection) as cursor:
|
|
431
570
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
@@ -436,8 +575,7 @@ class AdbcDriver(
|
|
|
436
575
|
self,
|
|
437
576
|
sql: str,
|
|
438
577
|
parameters: "Optional[StatementParameterType]" = None,
|
|
439
|
-
|
|
440
|
-
*,
|
|
578
|
+
*filters: "StatementFilter",
|
|
441
579
|
connection: "Optional[AdbcConnection]" = None,
|
|
442
580
|
schema_type: None = None,
|
|
443
581
|
**kwargs: Any,
|
|
@@ -447,8 +585,7 @@ class AdbcDriver(
|
|
|
447
585
|
self,
|
|
448
586
|
sql: str,
|
|
449
587
|
parameters: "Optional[StatementParameterType]" = None,
|
|
450
|
-
|
|
451
|
-
*,
|
|
588
|
+
*filters: "StatementFilter",
|
|
452
589
|
connection: "Optional[AdbcConnection]" = None,
|
|
453
590
|
schema_type: "type[ModelDTOT]",
|
|
454
591
|
**kwargs: Any,
|
|
@@ -456,52 +593,57 @@ class AdbcDriver(
|
|
|
456
593
|
def insert_update_delete_returning(
|
|
457
594
|
self,
|
|
458
595
|
sql: str,
|
|
459
|
-
parameters: Optional[
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
connection: Optional["AdbcConnection"] = None,
|
|
596
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
597
|
+
*filters: "StatementFilter",
|
|
598
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
463
599
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
464
600
|
**kwargs: Any,
|
|
465
601
|
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
466
|
-
"""Insert, update, or delete data
|
|
602
|
+
"""Insert, update, or delete data with RETURNING clause.
|
|
603
|
+
|
|
604
|
+
Args:
|
|
605
|
+
sql: The SQL statement string.
|
|
606
|
+
parameters: The parameters for the statement (dict, tuple, list, or None).
|
|
607
|
+
*filters: Statement filters to apply.
|
|
608
|
+
connection: Optional connection override.
|
|
609
|
+
schema_type: Optional schema class for the result.
|
|
610
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
467
611
|
|
|
468
612
|
Returns:
|
|
469
|
-
The
|
|
613
|
+
The returned row data, or None if no row returned.
|
|
470
614
|
"""
|
|
471
615
|
connection = self._connection(connection)
|
|
472
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
616
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
617
|
+
|
|
473
618
|
with self._with_cursor(connection) as cursor:
|
|
474
619
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
475
620
|
result = cursor.fetchall() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
476
621
|
if not result:
|
|
477
622
|
return None
|
|
478
|
-
|
|
479
|
-
first_row = result[0]
|
|
480
|
-
|
|
481
623
|
column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
482
|
-
|
|
483
|
-
result_dict = dict(zip(column_names, first_row))
|
|
484
|
-
|
|
485
|
-
if schema_type is None:
|
|
486
|
-
return result_dict
|
|
487
|
-
return cast("ModelDTOT", schema_type(**result_dict))
|
|
624
|
+
return self.to_schema(dict(zip(column_names, result[0])), schema_type=schema_type)
|
|
488
625
|
|
|
489
626
|
def execute_script(
|
|
490
627
|
self,
|
|
491
628
|
sql: str,
|
|
492
|
-
parameters: Optional[
|
|
493
|
-
|
|
494
|
-
*,
|
|
495
|
-
connection: Optional["AdbcConnection"] = None,
|
|
629
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
630
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
496
631
|
**kwargs: Any,
|
|
497
632
|
) -> str:
|
|
498
|
-
"""Execute a script.
|
|
633
|
+
"""Execute a SQL script.
|
|
634
|
+
|
|
635
|
+
Args:
|
|
636
|
+
sql: The SQL script to execute.
|
|
637
|
+
parameters: The parameters for the script (dict, tuple, list, or None).
|
|
638
|
+
*filters: Statement filters to apply.
|
|
639
|
+
connection: Optional connection override.
|
|
640
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
499
641
|
|
|
500
642
|
Returns:
|
|
501
|
-
|
|
643
|
+
A success message.
|
|
502
644
|
"""
|
|
503
645
|
connection = self._connection(connection)
|
|
504
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
646
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
505
647
|
|
|
506
648
|
with self._with_cursor(connection) as cursor:
|
|
507
649
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
@@ -509,23 +651,29 @@ class AdbcDriver(
|
|
|
509
651
|
|
|
510
652
|
# --- Arrow Bulk Operations ---
|
|
511
653
|
|
|
512
|
-
def select_arrow(
|
|
654
|
+
def select_arrow(
|
|
513
655
|
self,
|
|
514
656
|
sql: str,
|
|
515
657
|
parameters: "Optional[StatementParameterType]" = None,
|
|
516
|
-
|
|
517
|
-
*,
|
|
658
|
+
*filters: "StatementFilter",
|
|
518
659
|
connection: "Optional[AdbcConnection]" = None,
|
|
519
660
|
**kwargs: Any,
|
|
520
|
-
) -> "ArrowTable":
|
|
661
|
+
) -> "ArrowTable": # pyright: ignore[reportUnknownVariableType]
|
|
521
662
|
"""Execute a SQL query and return results as an Apache Arrow Table.
|
|
522
663
|
|
|
664
|
+
Args:
|
|
665
|
+
sql: The SQL query string.
|
|
666
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
667
|
+
*filters: Statement filters to apply.
|
|
668
|
+
connection: Optional connection override.
|
|
669
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
670
|
+
|
|
523
671
|
Returns:
|
|
524
|
-
|
|
672
|
+
An Arrow Table containing the query results.
|
|
525
673
|
"""
|
|
526
|
-
|
|
527
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
674
|
+
connection = self._connection(connection)
|
|
675
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
528
676
|
|
|
529
|
-
with self._with_cursor(
|
|
677
|
+
with self._with_cursor(connection) as cursor:
|
|
530
678
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
531
679
|
return cast("ArrowTable", cursor.fetch_arrow_table()) # pyright: ignore[reportUnknownMemberType]
|