sqlspec 0.10.0__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/_typing.py +24 -32
- 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.0.dist-info → sqlspec-0.11.0.dist-info}/METADATA +5 -1
- {sqlspec-0.10.0.dist-info → sqlspec-0.11.0.dist-info}/RECORD +32 -30
- {sqlspec-0.10.0.dist-info → sqlspec-0.11.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.10.0.dist-info → sqlspec-0.11.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.10.0.dist-info → sqlspec-0.11.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/adapters/adbc/driver.py
CHANGED
|
@@ -6,12 +6,14 @@ 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
12
|
from sqlspec.exceptions import ParameterStyleMismatchError, SQLParsingError
|
|
12
|
-
from sqlspec.
|
|
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,83 +87,197 @@ 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
|
/,
|
|
95
|
+
*filters: "StatementFilter",
|
|
97
96
|
**kwargs: Any,
|
|
98
|
-
) -> "tuple[str, Optional[
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
parameter_dict = {} # type: ignore[var-annotated]
|
|
111
|
-
if isinstance(parameters, dict):
|
|
112
|
-
parameter_dict.update(parameters)
|
|
113
|
-
if kwargs:
|
|
114
|
-
parameter_dict.update(kwargs)
|
|
115
|
-
|
|
116
|
-
# Define regex locally to find :name or $name
|
|
117
|
-
|
|
118
|
-
processed_sql_parts: list[str] = []
|
|
119
|
-
ordered_params = []
|
|
120
|
-
last_end = 0
|
|
121
|
-
found_params_regex: list[str] = []
|
|
122
|
-
|
|
123
|
-
for match in PARAM_REGEX.finditer(sql): # Use original sql
|
|
124
|
-
if match.group("dquote") or match.group("squote") or match.group("comment"):
|
|
125
|
-
continue
|
|
126
|
-
|
|
127
|
-
if match.group("var_name"):
|
|
128
|
-
var_name = match.group("var_name")
|
|
129
|
-
leading_char = match.group("lead") # : or $
|
|
130
|
-
found_params_regex.append(var_name)
|
|
131
|
-
# Use match span directly for replacement
|
|
132
|
-
start = match.start()
|
|
133
|
-
end = match.end()
|
|
134
|
-
|
|
135
|
-
if var_name not in parameter_dict:
|
|
136
|
-
msg = f"Named parameter '{leading_char}{var_name}' found in SQL but not provided. SQL: {sql}"
|
|
137
|
-
raise SQLParsingError(msg)
|
|
138
|
-
|
|
139
|
-
processed_sql_parts.extend((sql[last_end:start], "?")) # Force ? style
|
|
140
|
-
ordered_params.append(parameter_dict[var_name])
|
|
141
|
-
last_end = end
|
|
142
|
-
|
|
143
|
-
processed_sql_parts.append(sql[last_end:])
|
|
144
|
-
|
|
145
|
-
if not found_params_regex and parameter_dict:
|
|
146
|
-
msg = f"ADBC/{self.dialect}: Dict params provided, but no :name or $name placeholders found. SQL: {sql}"
|
|
147
|
-
raise ParameterStyleMismatchError(msg)
|
|
97
|
+
) -> "tuple[str, Optional[tuple[Any, ...]]]": # Always returns tuple or None for params
|
|
98
|
+
"""Process SQL and parameters for ADBC.
|
|
99
|
+
|
|
100
|
+
ADBC drivers generally use positional parameters with '?' placeholders.
|
|
101
|
+
This method processes the SQL statement and transforms parameters into the format
|
|
102
|
+
expected by ADBC drivers.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
sql: The SQL statement to process.
|
|
106
|
+
parameters: The parameters to bind to the statement.
|
|
107
|
+
*filters: Statement filters to apply.
|
|
108
|
+
**kwargs: Additional keyword arguments.
|
|
148
109
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
110
|
+
Raises:
|
|
111
|
+
ParameterStyleMismatchError: If positional parameters are mixed with keyword arguments.
|
|
112
|
+
SQLParsingError: If the SQL statement cannot be parsed.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
A tuple of (sql, parameters) ready for execution.
|
|
116
|
+
"""
|
|
117
|
+
# Special handling for SQLite with non-dict parameters and named placeholders
|
|
118
|
+
if self.dialect == "sqlite" and parameters is not None and not is_dict(parameters):
|
|
119
|
+
# First mask out comments and strings to avoid detecting parameters in those
|
|
120
|
+
comments = list(SQL_COMMENT_PATTERN.finditer(sql))
|
|
121
|
+
strings = list(SQL_STRING_PATTERN.finditer(sql))
|
|
122
|
+
|
|
123
|
+
all_matches = [(m.start(), m.end(), "comment") for m in comments] + [
|
|
124
|
+
(m.start(), m.end(), "string") for m in strings
|
|
125
|
+
]
|
|
126
|
+
all_matches.sort(reverse=True)
|
|
127
|
+
|
|
128
|
+
for start, end, _ in all_matches:
|
|
129
|
+
sql = sql[:start] + " " * (end - start) + sql[end:]
|
|
130
|
+
|
|
131
|
+
# Find named parameters in clean SQL
|
|
132
|
+
named_params = list(SQLITE_PARAM_PATTERN.finditer(sql))
|
|
133
|
+
|
|
134
|
+
if named_params:
|
|
135
|
+
param_positions = [(m.start(), m.end()) for m in named_params]
|
|
136
|
+
param_positions.sort(reverse=True)
|
|
137
|
+
for start, end in param_positions:
|
|
138
|
+
sql = sql[:start] + "?" + sql[end:]
|
|
139
|
+
if not isinstance(parameters, (list, tuple)):
|
|
140
|
+
return sql, (parameters,)
|
|
141
|
+
return sql, tuple(parameters)
|
|
142
|
+
|
|
143
|
+
# Standard processing for all other cases
|
|
144
|
+
merged_params = parameters
|
|
145
|
+
if kwargs:
|
|
146
|
+
if is_dict(parameters):
|
|
147
|
+
merged_params = {**parameters, **kwargs}
|
|
148
|
+
elif parameters is not None:
|
|
149
|
+
msg = "Cannot mix positional parameters with keyword arguments for adbc driver."
|
|
150
|
+
raise ParameterStyleMismatchError(msg)
|
|
151
|
+
else:
|
|
152
|
+
merged_params = kwargs
|
|
153
|
+
|
|
154
|
+
# 2. Create SQLStatement with dialect and process
|
|
155
|
+
statement = SQLStatement(sql, merged_params, dialect=self.dialect)
|
|
156
|
+
|
|
157
|
+
# Apply any filters
|
|
158
|
+
for filter_obj in filters:
|
|
159
|
+
statement = statement.apply_filter(filter_obj)
|
|
160
|
+
|
|
161
|
+
processed_sql, processed_params, parsed_expr = statement.process()
|
|
162
|
+
|
|
163
|
+
# Special handling for SQLite dialect with dict parameters
|
|
164
|
+
if self.dialect == "sqlite" and is_dict(processed_params):
|
|
165
|
+
# First, mask out comments and string literals with placeholders
|
|
166
|
+
masked_sql = processed_sql
|
|
167
|
+
|
|
168
|
+
# Replace comments and strings with placeholders
|
|
169
|
+
comments = list(SQL_COMMENT_PATTERN.finditer(masked_sql))
|
|
170
|
+
strings = list(SQL_STRING_PATTERN.finditer(masked_sql))
|
|
171
|
+
|
|
172
|
+
# Sort all matches by their start position (descending)
|
|
173
|
+
all_matches = [(m.start(), m.end(), "comment") for m in comments] + [
|
|
174
|
+
(m.start(), m.end(), "string") for m in strings
|
|
175
|
+
]
|
|
176
|
+
all_matches.sort(reverse=True)
|
|
177
|
+
|
|
178
|
+
# Replace each match with spaces to preserve positions
|
|
179
|
+
for start, end, _ in all_matches:
|
|
180
|
+
masked_sql = masked_sql[:start] + " " * (end - start) + masked_sql[end:]
|
|
181
|
+
|
|
182
|
+
# Now find parameters in the masked SQL
|
|
183
|
+
param_order = []
|
|
184
|
+
param_spans = [] # Store (start, end) of each parameter
|
|
185
|
+
|
|
186
|
+
for match in SQLITE_PARAM_PATTERN.finditer(masked_sql):
|
|
187
|
+
param_name = match.group(1)
|
|
188
|
+
if param_name in processed_params:
|
|
189
|
+
param_order.append(param_name)
|
|
190
|
+
param_spans.append((match.start(), match.end()))
|
|
191
|
+
|
|
192
|
+
if param_order:
|
|
193
|
+
# Replace parameters with ? placeholders in reverse order to preserve positions
|
|
194
|
+
result_sql = processed_sql
|
|
195
|
+
for i, (start, end) in enumerate(reversed(param_spans)): # noqa: B007
|
|
196
|
+
# Replace :param with ?
|
|
197
|
+
result_sql = result_sql[:start] + "?" + result_sql[start + 1 + len(param_order[-(i + 1)]) :]
|
|
198
|
+
|
|
199
|
+
return result_sql, tuple(processed_params[name] for name in param_order)
|
|
200
|
+
|
|
201
|
+
if processed_params is None:
|
|
202
|
+
return processed_sql, ()
|
|
203
|
+
if (
|
|
204
|
+
isinstance(processed_params, (tuple, list))
|
|
205
|
+
or (processed_params is not None and not isinstance(processed_params, dict))
|
|
206
|
+
) and parsed_expr is not None:
|
|
207
|
+
# Find all named placeholders
|
|
208
|
+
named_param_nodes = [
|
|
209
|
+
node
|
|
210
|
+
for node in parsed_expr.find_all(sqlglot_exp.Parameter, sqlglot_exp.Placeholder)
|
|
211
|
+
if (isinstance(node, sqlglot_exp.Parameter) and node.name and not node.name.isdigit())
|
|
212
|
+
or (
|
|
213
|
+
isinstance(node, sqlglot_exp.Placeholder)
|
|
214
|
+
and node.this
|
|
215
|
+
and not isinstance(node.this, (sqlglot_exp.Identifier, sqlglot_exp.Literal))
|
|
216
|
+
and not str(node.this).isdigit()
|
|
155
217
|
)
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
# If we found named parameters, transform to question marks
|
|
221
|
+
if named_param_nodes:
|
|
222
|
+
|
|
223
|
+
def convert_to_qmark(node: sqlglot_exp.Expression) -> sqlglot_exp.Expression:
|
|
224
|
+
if (isinstance(node, sqlglot_exp.Parameter) and node.name and not node.name.isdigit()) or (
|
|
225
|
+
isinstance(node, sqlglot_exp.Placeholder)
|
|
226
|
+
and node.this
|
|
227
|
+
and not isinstance(node.this, (sqlglot_exp.Identifier, sqlglot_exp.Literal))
|
|
228
|
+
and not str(node.this).isdigit()
|
|
229
|
+
):
|
|
230
|
+
return sqlglot_exp.Placeholder()
|
|
231
|
+
return node
|
|
232
|
+
|
|
233
|
+
# Transform the SQL
|
|
234
|
+
processed_sql = parsed_expr.transform(convert_to_qmark, copy=True).sql(dialect=self.dialect)
|
|
235
|
+
|
|
236
|
+
# If it's a scalar parameter, ensure it's wrapped in a tuple
|
|
237
|
+
if not isinstance(processed_params, (tuple, list)):
|
|
238
|
+
processed_params = (processed_params,) # type: ignore[unreachable]
|
|
239
|
+
|
|
240
|
+
# 6. Handle dictionary parameters
|
|
241
|
+
if is_dict(processed_params):
|
|
242
|
+
# Skip conversion if there's no parsed expression to work with
|
|
243
|
+
if parsed_expr is None:
|
|
244
|
+
msg = f"ADBC ({self.dialect}): Failed to parse SQL with dictionary parameters. Cannot determine parameter order."
|
|
156
245
|
raise SQLParsingError(msg)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
246
|
+
|
|
247
|
+
# Collect named parameters in the order they appear in the SQL
|
|
248
|
+
named_params = []
|
|
249
|
+
for node in parsed_expr.find_all(sqlglot_exp.Parameter, sqlglot_exp.Placeholder):
|
|
250
|
+
if isinstance(node, sqlglot_exp.Parameter) and node.name and node.name in processed_params:
|
|
251
|
+
named_params.append(node.name) # type: ignore[arg-type]
|
|
252
|
+
elif (
|
|
253
|
+
isinstance(node, sqlglot_exp.Placeholder)
|
|
254
|
+
and isinstance(node.this, str)
|
|
255
|
+
and node.this in processed_params
|
|
256
|
+
):
|
|
257
|
+
named_params.append(node.this) # type: ignore[arg-type]
|
|
258
|
+
|
|
259
|
+
# If we found named parameters, convert them to ? placeholders
|
|
260
|
+
if named_params:
|
|
261
|
+
# Transform SQL to use ? placeholders
|
|
262
|
+
def convert_to_qmark(node: sqlglot_exp.Expression) -> sqlglot_exp.Expression:
|
|
263
|
+
if isinstance(node, sqlglot_exp.Parameter) and node.name and node.name in processed_params:
|
|
264
|
+
return sqlglot_exp.Placeholder() # Anonymous ? placeholder
|
|
265
|
+
if (
|
|
266
|
+
isinstance(node, sqlglot_exp.Placeholder)
|
|
267
|
+
and isinstance(node.this, str)
|
|
268
|
+
and node.this in processed_params
|
|
269
|
+
):
|
|
270
|
+
return sqlglot_exp.Placeholder() # Anonymous ? placeholder
|
|
271
|
+
return node
|
|
272
|
+
|
|
273
|
+
return parsed_expr.transform(convert_to_qmark, copy=True).sql(dialect=self.dialect), tuple(
|
|
274
|
+
processed_params[name] # type: ignore[index]
|
|
275
|
+
for name in named_params
|
|
276
|
+
)
|
|
277
|
+
return processed_sql, tuple(processed_params.values())
|
|
278
|
+
if isinstance(processed_params, (list, tuple)):
|
|
279
|
+
return processed_sql, tuple(processed_params)
|
|
280
|
+
return processed_sql, (processed_params,)
|
|
169
281
|
|
|
170
282
|
@overload
|
|
171
283
|
def select(
|
|
@@ -173,7 +285,7 @@ class AdbcDriver(
|
|
|
173
285
|
sql: str,
|
|
174
286
|
parameters: "Optional[StatementParameterType]" = None,
|
|
175
287
|
/,
|
|
176
|
-
|
|
288
|
+
*filters: "StatementFilter",
|
|
177
289
|
connection: "Optional[AdbcConnection]" = None,
|
|
178
290
|
schema_type: None = None,
|
|
179
291
|
**kwargs: Any,
|
|
@@ -184,7 +296,7 @@ class AdbcDriver(
|
|
|
184
296
|
sql: str,
|
|
185
297
|
parameters: "Optional[StatementParameterType]" = None,
|
|
186
298
|
/,
|
|
187
|
-
|
|
299
|
+
*filters: "StatementFilter",
|
|
188
300
|
connection: "Optional[AdbcConnection]" = None,
|
|
189
301
|
schema_type: "type[ModelDTOT]",
|
|
190
302
|
**kwargs: Any,
|
|
@@ -194,29 +306,35 @@ class AdbcDriver(
|
|
|
194
306
|
sql: str,
|
|
195
307
|
parameters: Optional["StatementParameterType"] = None,
|
|
196
308
|
/,
|
|
197
|
-
|
|
309
|
+
*filters: "StatementFilter",
|
|
198
310
|
connection: Optional["AdbcConnection"] = None,
|
|
199
311
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
200
312
|
**kwargs: Any,
|
|
201
313
|
) -> "Sequence[Union[ModelDTOT, dict[str, Any]]]":
|
|
202
314
|
"""Fetch data from the database.
|
|
203
315
|
|
|
316
|
+
Args:
|
|
317
|
+
sql: The SQL query string.
|
|
318
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
319
|
+
*filters: Statement filters to apply.
|
|
320
|
+
connection: Optional connection override.
|
|
321
|
+
schema_type: Optional schema class for the result.
|
|
322
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
323
|
+
|
|
204
324
|
Returns:
|
|
205
325
|
List of row data as either model instances or dictionaries.
|
|
206
326
|
"""
|
|
207
327
|
connection = self._connection(connection)
|
|
208
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
328
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
329
|
+
|
|
209
330
|
with self._with_cursor(connection) as cursor:
|
|
210
331
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
211
332
|
results = cursor.fetchall() # pyright: ignore
|
|
212
333
|
if not results:
|
|
213
334
|
return []
|
|
335
|
+
column_names = [column[0] for column in cursor.description or []]
|
|
214
336
|
|
|
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]
|
|
337
|
+
return self.to_schema([dict(zip(column_names, row)) for row in results], schema_type=schema_type)
|
|
220
338
|
|
|
221
339
|
@overload
|
|
222
340
|
def select_one(
|
|
@@ -224,7 +342,7 @@ class AdbcDriver(
|
|
|
224
342
|
sql: str,
|
|
225
343
|
parameters: "Optional[StatementParameterType]" = None,
|
|
226
344
|
/,
|
|
227
|
-
|
|
345
|
+
*filters: "StatementFilter",
|
|
228
346
|
connection: "Optional[AdbcConnection]" = None,
|
|
229
347
|
schema_type: None = None,
|
|
230
348
|
**kwargs: Any,
|
|
@@ -235,7 +353,7 @@ class AdbcDriver(
|
|
|
235
353
|
sql: str,
|
|
236
354
|
parameters: "Optional[StatementParameterType]" = None,
|
|
237
355
|
/,
|
|
238
|
-
|
|
356
|
+
*filters: "StatementFilter",
|
|
239
357
|
connection: "Optional[AdbcConnection]" = None,
|
|
240
358
|
schema_type: "type[ModelDTOT]",
|
|
241
359
|
**kwargs: Any,
|
|
@@ -243,28 +361,35 @@ class AdbcDriver(
|
|
|
243
361
|
def select_one(
|
|
244
362
|
self,
|
|
245
363
|
sql: str,
|
|
246
|
-
parameters: Optional[
|
|
364
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
247
365
|
/,
|
|
248
|
-
|
|
249
|
-
connection: Optional[
|
|
366
|
+
*filters: "StatementFilter",
|
|
367
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
250
368
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
251
369
|
**kwargs: Any,
|
|
252
370
|
) -> "Union[ModelDTOT, dict[str, Any]]":
|
|
253
371
|
"""Fetch one row from the database.
|
|
254
372
|
|
|
373
|
+
Args:
|
|
374
|
+
sql: The SQL query string.
|
|
375
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
376
|
+
*filters: Statement filters to apply.
|
|
377
|
+
connection: Optional connection override.
|
|
378
|
+
schema_type: Optional schema class for the result.
|
|
379
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
380
|
+
|
|
255
381
|
Returns:
|
|
256
382
|
The first row of the query results.
|
|
257
383
|
"""
|
|
258
384
|
connection = self._connection(connection)
|
|
259
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
385
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
386
|
+
|
|
260
387
|
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]
|
|
388
|
+
cursor.execute(sql, parameters)
|
|
389
|
+
result = cursor.fetchone()
|
|
390
|
+
result = self.check_not_found(result)
|
|
391
|
+
column_names = [column[0] for column in cursor.description or []]
|
|
392
|
+
return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
|
|
268
393
|
|
|
269
394
|
@overload
|
|
270
395
|
def select_one_or_none(
|
|
@@ -272,7 +397,7 @@ class AdbcDriver(
|
|
|
272
397
|
sql: str,
|
|
273
398
|
parameters: "Optional[StatementParameterType]" = None,
|
|
274
399
|
/,
|
|
275
|
-
|
|
400
|
+
*filters: "StatementFilter",
|
|
276
401
|
connection: "Optional[AdbcConnection]" = None,
|
|
277
402
|
schema_type: None = None,
|
|
278
403
|
**kwargs: Any,
|
|
@@ -283,7 +408,7 @@ class AdbcDriver(
|
|
|
283
408
|
sql: str,
|
|
284
409
|
parameters: "Optional[StatementParameterType]" = None,
|
|
285
410
|
/,
|
|
286
|
-
|
|
411
|
+
*filters: "StatementFilter",
|
|
287
412
|
connection: "Optional[AdbcConnection]" = None,
|
|
288
413
|
schema_type: "type[ModelDTOT]",
|
|
289
414
|
**kwargs: Any,
|
|
@@ -293,27 +418,34 @@ class AdbcDriver(
|
|
|
293
418
|
sql: str,
|
|
294
419
|
parameters: Optional["StatementParameterType"] = None,
|
|
295
420
|
/,
|
|
296
|
-
|
|
421
|
+
*filters: "StatementFilter",
|
|
297
422
|
connection: Optional["AdbcConnection"] = None,
|
|
298
423
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
299
424
|
**kwargs: Any,
|
|
300
425
|
) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
|
|
301
|
-
"""Fetch one row from the database.
|
|
426
|
+
"""Fetch one row from the database or return None if no rows found.
|
|
427
|
+
|
|
428
|
+
Args:
|
|
429
|
+
sql: The SQL query string.
|
|
430
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
431
|
+
*filters: Statement filters to apply.
|
|
432
|
+
connection: Optional connection override.
|
|
433
|
+
schema_type: Optional schema class for the result.
|
|
434
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
302
435
|
|
|
303
436
|
Returns:
|
|
304
|
-
The first row of the query results.
|
|
437
|
+
The first row of the query results, or None if no results found.
|
|
305
438
|
"""
|
|
306
439
|
connection = self._connection(connection)
|
|
307
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
440
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
441
|
+
|
|
308
442
|
with self._with_cursor(connection) as cursor:
|
|
309
443
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
310
444
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
311
445
|
if result is None:
|
|
312
446
|
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]
|
|
447
|
+
column_names = [column[0] for column in cursor.description or []]
|
|
448
|
+
return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
|
|
317
449
|
|
|
318
450
|
@overload
|
|
319
451
|
def select_value(
|
|
@@ -321,7 +453,7 @@ class AdbcDriver(
|
|
|
321
453
|
sql: str,
|
|
322
454
|
parameters: "Optional[StatementParameterType]" = None,
|
|
323
455
|
/,
|
|
324
|
-
|
|
456
|
+
*filters: StatementFilter,
|
|
325
457
|
connection: "Optional[AdbcConnection]" = None,
|
|
326
458
|
schema_type: None = None,
|
|
327
459
|
**kwargs: Any,
|
|
@@ -332,7 +464,7 @@ class AdbcDriver(
|
|
|
332
464
|
sql: str,
|
|
333
465
|
parameters: "Optional[StatementParameterType]" = None,
|
|
334
466
|
/,
|
|
335
|
-
|
|
467
|
+
*filters: StatementFilter,
|
|
336
468
|
connection: "Optional[AdbcConnection]" = None,
|
|
337
469
|
schema_type: "type[T]",
|
|
338
470
|
**kwargs: Any,
|
|
@@ -340,20 +472,29 @@ class AdbcDriver(
|
|
|
340
472
|
def select_value(
|
|
341
473
|
self,
|
|
342
474
|
sql: str,
|
|
343
|
-
parameters: Optional[
|
|
475
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
344
476
|
/,
|
|
345
|
-
|
|
346
|
-
connection: Optional[
|
|
477
|
+
*filters: StatementFilter,
|
|
478
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
347
479
|
schema_type: "Optional[type[T]]" = None,
|
|
348
480
|
**kwargs: Any,
|
|
349
481
|
) -> "Union[T, Any]":
|
|
350
482
|
"""Fetch a single value from the database.
|
|
351
483
|
|
|
484
|
+
Args:
|
|
485
|
+
sql: The SQL query string.
|
|
486
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
487
|
+
*filters: Statement filters to apply.
|
|
488
|
+
connection: Optional connection override.
|
|
489
|
+
schema_type: Optional type to convert the result to.
|
|
490
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
491
|
+
|
|
352
492
|
Returns:
|
|
353
|
-
The first value
|
|
493
|
+
The first value of the first row of the query results.
|
|
354
494
|
"""
|
|
355
495
|
connection = self._connection(connection)
|
|
356
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
496
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
497
|
+
|
|
357
498
|
with self._with_cursor(connection) as cursor:
|
|
358
499
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
359
500
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -368,7 +509,7 @@ class AdbcDriver(
|
|
|
368
509
|
sql: str,
|
|
369
510
|
parameters: "Optional[StatementParameterType]" = None,
|
|
370
511
|
/,
|
|
371
|
-
|
|
512
|
+
*filters: StatementFilter,
|
|
372
513
|
connection: "Optional[AdbcConnection]" = None,
|
|
373
514
|
schema_type: None = None,
|
|
374
515
|
**kwargs: Any,
|
|
@@ -379,7 +520,7 @@ class AdbcDriver(
|
|
|
379
520
|
sql: str,
|
|
380
521
|
parameters: "Optional[StatementParameterType]" = None,
|
|
381
522
|
/,
|
|
382
|
-
|
|
523
|
+
*filters: StatementFilter,
|
|
383
524
|
connection: "Optional[AdbcConnection]" = None,
|
|
384
525
|
schema_type: "type[T]",
|
|
385
526
|
**kwargs: Any,
|
|
@@ -387,20 +528,29 @@ class AdbcDriver(
|
|
|
387
528
|
def select_value_or_none(
|
|
388
529
|
self,
|
|
389
530
|
sql: str,
|
|
390
|
-
parameters: Optional[
|
|
531
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
391
532
|
/,
|
|
392
|
-
|
|
393
|
-
connection: Optional[
|
|
533
|
+
*filters: StatementFilter,
|
|
534
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
394
535
|
schema_type: "Optional[type[T]]" = None,
|
|
395
536
|
**kwargs: Any,
|
|
396
537
|
) -> "Optional[Union[T, Any]]":
|
|
397
|
-
"""Fetch a single value
|
|
538
|
+
"""Fetch a single value or None if not found.
|
|
539
|
+
|
|
540
|
+
Args:
|
|
541
|
+
sql: The SQL query string.
|
|
542
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
543
|
+
*filters: Statement filters to apply.
|
|
544
|
+
connection: Optional connection override.
|
|
545
|
+
schema_type: Optional type to convert the result to.
|
|
546
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
398
547
|
|
|
399
548
|
Returns:
|
|
400
|
-
The first value
|
|
549
|
+
The first value of the first row of the query results, or None if no results found.
|
|
401
550
|
"""
|
|
402
551
|
connection = self._connection(connection)
|
|
403
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
552
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
553
|
+
|
|
404
554
|
with self._with_cursor(connection) as cursor:
|
|
405
555
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
406
556
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -413,19 +563,26 @@ class AdbcDriver(
|
|
|
413
563
|
def insert_update_delete(
|
|
414
564
|
self,
|
|
415
565
|
sql: str,
|
|
416
|
-
parameters: Optional[
|
|
566
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
417
567
|
/,
|
|
418
|
-
|
|
419
|
-
connection: Optional[
|
|
568
|
+
*filters: "StatementFilter",
|
|
569
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
420
570
|
**kwargs: Any,
|
|
421
571
|
) -> int:
|
|
422
|
-
"""
|
|
572
|
+
"""Execute an insert, update, or delete statement.
|
|
573
|
+
|
|
574
|
+
Args:
|
|
575
|
+
sql: The SQL statement to execute.
|
|
576
|
+
parameters: The parameters for the statement (dict, tuple, list, or None).
|
|
577
|
+
*filters: Statement filters to apply.
|
|
578
|
+
connection: Optional connection override.
|
|
579
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
423
580
|
|
|
424
581
|
Returns:
|
|
425
|
-
|
|
582
|
+
The number of rows affected by the statement.
|
|
426
583
|
"""
|
|
427
584
|
connection = self._connection(connection)
|
|
428
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
585
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
429
586
|
|
|
430
587
|
with self._with_cursor(connection) as cursor:
|
|
431
588
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
@@ -437,7 +594,7 @@ class AdbcDriver(
|
|
|
437
594
|
sql: str,
|
|
438
595
|
parameters: "Optional[StatementParameterType]" = None,
|
|
439
596
|
/,
|
|
440
|
-
|
|
597
|
+
*filters: StatementFilter,
|
|
441
598
|
connection: "Optional[AdbcConnection]" = None,
|
|
442
599
|
schema_type: None = None,
|
|
443
600
|
**kwargs: Any,
|
|
@@ -448,7 +605,7 @@ class AdbcDriver(
|
|
|
448
605
|
sql: str,
|
|
449
606
|
parameters: "Optional[StatementParameterType]" = None,
|
|
450
607
|
/,
|
|
451
|
-
|
|
608
|
+
*filters: StatementFilter,
|
|
452
609
|
connection: "Optional[AdbcConnection]" = None,
|
|
453
610
|
schema_type: "type[ModelDTOT]",
|
|
454
611
|
**kwargs: Any,
|
|
@@ -456,52 +613,59 @@ class AdbcDriver(
|
|
|
456
613
|
def insert_update_delete_returning(
|
|
457
614
|
self,
|
|
458
615
|
sql: str,
|
|
459
|
-
parameters: Optional[
|
|
616
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
460
617
|
/,
|
|
461
|
-
|
|
462
|
-
connection: Optional[
|
|
618
|
+
*filters: StatementFilter,
|
|
619
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
463
620
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
464
621
|
**kwargs: Any,
|
|
465
622
|
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
466
623
|
"""Insert, update, or delete data from the database and return result.
|
|
467
624
|
|
|
625
|
+
Args:
|
|
626
|
+
sql: The SQL statement to execute.
|
|
627
|
+
parameters: The parameters for the statement (dict, tuple, list, or None).
|
|
628
|
+
*filters: Statement filters to apply.
|
|
629
|
+
connection: Optional connection override.
|
|
630
|
+
schema_type: Optional schema class for the result.
|
|
631
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
632
|
+
|
|
468
633
|
Returns:
|
|
469
634
|
The first row of results.
|
|
470
635
|
"""
|
|
471
636
|
connection = self._connection(connection)
|
|
472
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
637
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
638
|
+
|
|
473
639
|
with self._with_cursor(connection) as cursor:
|
|
474
640
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
475
641
|
result = cursor.fetchall() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
476
642
|
if not result:
|
|
477
643
|
return None
|
|
478
|
-
|
|
479
|
-
first_row = result[0]
|
|
480
|
-
|
|
481
644
|
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))
|
|
645
|
+
return self.to_schema(dict(zip(column_names, result[0])), schema_type=schema_type)
|
|
488
646
|
|
|
489
647
|
def execute_script(
|
|
490
648
|
self,
|
|
491
649
|
sql: str,
|
|
492
|
-
parameters: Optional[
|
|
650
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
493
651
|
/,
|
|
494
|
-
|
|
495
|
-
connection: Optional["AdbcConnection"] = None,
|
|
652
|
+
connection: "Optional[AdbcConnection]" = None,
|
|
496
653
|
**kwargs: Any,
|
|
497
654
|
) -> str:
|
|
498
|
-
"""Execute a script.
|
|
655
|
+
"""Execute a SQL script.
|
|
656
|
+
|
|
657
|
+
Args:
|
|
658
|
+
sql: The SQL script to execute.
|
|
659
|
+
parameters: The parameters for the script (dict, tuple, list, or None).
|
|
660
|
+
*filters: Statement filters to apply.
|
|
661
|
+
connection: Optional connection override.
|
|
662
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
499
663
|
|
|
500
664
|
Returns:
|
|
501
|
-
|
|
665
|
+
A success message.
|
|
502
666
|
"""
|
|
503
667
|
connection = self._connection(connection)
|
|
504
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
668
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
505
669
|
|
|
506
670
|
with self._with_cursor(connection) as cursor:
|
|
507
671
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
@@ -514,18 +678,25 @@ class AdbcDriver(
|
|
|
514
678
|
sql: str,
|
|
515
679
|
parameters: "Optional[StatementParameterType]" = None,
|
|
516
680
|
/,
|
|
517
|
-
|
|
681
|
+
*filters: StatementFilter,
|
|
518
682
|
connection: "Optional[AdbcConnection]" = None,
|
|
519
683
|
**kwargs: Any,
|
|
520
|
-
) -> "ArrowTable":
|
|
684
|
+
) -> "ArrowTable": # pyright: ignore[reportUnknownVariableType]
|
|
521
685
|
"""Execute a SQL query and return results as an Apache Arrow Table.
|
|
522
686
|
|
|
687
|
+
Args:
|
|
688
|
+
sql: The SQL query string.
|
|
689
|
+
parameters: The parameters for the query (dict, tuple, list, or None).
|
|
690
|
+
*filters: Statement filters to apply.
|
|
691
|
+
connection: Optional connection override.
|
|
692
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
693
|
+
|
|
523
694
|
Returns:
|
|
524
|
-
|
|
695
|
+
An Apache Arrow Table containing the query results.
|
|
525
696
|
"""
|
|
526
|
-
|
|
527
|
-
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
697
|
+
connection = self._connection(connection)
|
|
698
|
+
sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
|
|
528
699
|
|
|
529
|
-
with self._with_cursor(
|
|
700
|
+
with self._with_cursor(connection) as cursor:
|
|
530
701
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
531
702
|
return cast("ArrowTable", cursor.fetch_arrow_table()) # pyright: ignore[reportUnknownMemberType]
|