sqlspec 0.8.0__py3-none-any.whl → 0.9.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/_typing.py +39 -6
- sqlspec/adapters/adbc/__init__.py +2 -2
- sqlspec/adapters/adbc/config.py +34 -11
- sqlspec/adapters/adbc/driver.py +302 -111
- sqlspec/adapters/aiosqlite/__init__.py +2 -2
- sqlspec/adapters/aiosqlite/config.py +2 -2
- sqlspec/adapters/aiosqlite/driver.py +164 -42
- sqlspec/adapters/asyncmy/__init__.py +3 -3
- sqlspec/adapters/asyncmy/config.py +11 -12
- sqlspec/adapters/asyncmy/driver.py +161 -37
- sqlspec/adapters/asyncpg/__init__.py +5 -5
- sqlspec/adapters/asyncpg/config.py +17 -19
- sqlspec/adapters/asyncpg/driver.py +386 -96
- sqlspec/adapters/duckdb/__init__.py +2 -2
- sqlspec/adapters/duckdb/config.py +2 -2
- sqlspec/adapters/duckdb/driver.py +190 -60
- sqlspec/adapters/oracledb/__init__.py +8 -8
- sqlspec/adapters/oracledb/config/__init__.py +6 -6
- sqlspec/adapters/oracledb/config/_asyncio.py +9 -10
- sqlspec/adapters/oracledb/config/_sync.py +8 -9
- sqlspec/adapters/oracledb/driver.py +384 -45
- sqlspec/adapters/psqlpy/__init__.py +0 -0
- sqlspec/adapters/psqlpy/config.py +250 -0
- sqlspec/adapters/psqlpy/driver.py +481 -0
- sqlspec/adapters/psycopg/__init__.py +10 -5
- sqlspec/adapters/psycopg/config/__init__.py +6 -6
- sqlspec/adapters/psycopg/config/_async.py +12 -12
- sqlspec/adapters/psycopg/config/_sync.py +13 -13
- sqlspec/adapters/psycopg/driver.py +432 -222
- sqlspec/adapters/sqlite/__init__.py +2 -2
- sqlspec/adapters/sqlite/config.py +2 -2
- sqlspec/adapters/sqlite/driver.py +176 -72
- sqlspec/base.py +687 -161
- sqlspec/exceptions.py +30 -0
- sqlspec/extensions/litestar/config.py +6 -0
- sqlspec/extensions/litestar/handlers.py +25 -0
- sqlspec/extensions/litestar/plugin.py +8 -1
- sqlspec/statement.py +373 -0
- sqlspec/typing.py +10 -1
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.1.dist-info}/METADATA +144 -2
- sqlspec-0.9.1.dist-info/RECORD +61 -0
- sqlspec-0.8.0.dist-info/RECORD +0 -57
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.1.dist-info}/WHEEL +0 -0
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.1.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.1.dist-info}/licenses/NOTICE +0 -0
sqlspec/adapters/adbc/driver.py
CHANGED
|
@@ -1,41 +1,73 @@
|
|
|
1
1
|
import contextlib
|
|
2
|
+
import logging
|
|
2
3
|
import re
|
|
3
|
-
from collections.abc import Generator
|
|
4
|
+
from collections.abc import Generator, Sequence
|
|
4
5
|
from contextlib import contextmanager
|
|
5
|
-
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
|
6
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union, cast, overload
|
|
6
7
|
|
|
7
8
|
from adbc_driver_manager.dbapi import Connection, Cursor
|
|
8
9
|
|
|
9
|
-
from sqlspec.base import SyncDriverAdapterProtocol, T
|
|
10
|
+
from sqlspec.base import SyncArrowBulkOperationsMixin, SyncDriverAdapterProtocol, T
|
|
11
|
+
from sqlspec.exceptions import ParameterStyleMismatchError, SQLParsingError
|
|
12
|
+
from sqlspec.statement import SQLStatement
|
|
13
|
+
from sqlspec.typing import ArrowTable, StatementParameterType
|
|
10
14
|
|
|
11
15
|
if TYPE_CHECKING:
|
|
12
|
-
from sqlspec.typing import ModelDTOT, StatementParameterType
|
|
16
|
+
from sqlspec.typing import ArrowTable, ModelDTOT, StatementParameterType
|
|
13
17
|
|
|
14
18
|
__all__ = ("AdbcDriver",)
|
|
15
19
|
|
|
20
|
+
logger = logging.getLogger("sqlspec")
|
|
21
|
+
|
|
16
22
|
|
|
17
|
-
# Regex to find :param or %(param)s style placeholders, skipping those inside quotes
|
|
18
23
|
PARAM_REGEX = re.compile(
|
|
19
|
-
r"""
|
|
20
|
-
(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
r"""(?<![:\w\$]) # Avoid matching ::, \:, etc. and other vendor prefixes
|
|
25
|
+
(?:
|
|
26
|
+
(?P<dquote>"(?:[^"]|"")*") | # Double-quoted strings
|
|
27
|
+
(?P<squote>'(?:[^']|'')*') | # Single-quoted strings
|
|
28
|
+
(?P<comment>--.*?\n|\/\*.*?\*\/) | # SQL comments
|
|
29
|
+
(?P<lead>[:\$])(?P<var_name>[a-zA-Z_][a-zA-Z0-9_]*) # :name or $name identifier
|
|
30
|
+
)
|
|
24
31
|
""",
|
|
25
|
-
re.VERBOSE,
|
|
32
|
+
re.VERBOSE | re.DOTALL,
|
|
26
33
|
)
|
|
27
34
|
|
|
28
35
|
|
|
29
|
-
class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
36
|
+
class AdbcDriver(SyncArrowBulkOperationsMixin["Connection"], SyncDriverAdapterProtocol["Connection"]):
|
|
30
37
|
"""ADBC Sync Driver Adapter."""
|
|
31
38
|
|
|
32
39
|
connection: Connection
|
|
40
|
+
__supports_arrow__: ClassVar[bool] = True
|
|
33
41
|
|
|
34
42
|
def __init__(self, connection: "Connection") -> None:
|
|
35
43
|
"""Initialize the ADBC driver adapter."""
|
|
36
44
|
self.connection = connection
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
self.dialect = self._get_dialect(connection)
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def _get_dialect(connection: "Connection") -> str: # noqa: PLR0911
|
|
49
|
+
"""Get the database dialect based on the driver name.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
connection: The ADBC connection object.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The database dialect.
|
|
56
|
+
"""
|
|
57
|
+
driver_name = connection.adbc_get_info()["vendor_name"].lower()
|
|
58
|
+
if "postgres" in driver_name:
|
|
59
|
+
return "postgres"
|
|
60
|
+
if "bigquery" in driver_name:
|
|
61
|
+
return "bigquery"
|
|
62
|
+
if "sqlite" in driver_name:
|
|
63
|
+
return "sqlite"
|
|
64
|
+
if "duckdb" in driver_name:
|
|
65
|
+
return "duckdb"
|
|
66
|
+
if "mysql" in driver_name:
|
|
67
|
+
return "mysql"
|
|
68
|
+
if "snowflake" in driver_name:
|
|
69
|
+
return "snowflake"
|
|
70
|
+
return "postgres" # default to postgresql dialect
|
|
39
71
|
|
|
40
72
|
@staticmethod
|
|
41
73
|
def _cursor(connection: "Connection", *args: Any, **kwargs: Any) -> "Cursor":
|
|
@@ -51,87 +83,122 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
51
83
|
cursor.close() # type: ignore[no-untyped-call]
|
|
52
84
|
|
|
53
85
|
def _process_sql_params(
|
|
54
|
-
self,
|
|
86
|
+
self,
|
|
87
|
+
sql: str,
|
|
88
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
89
|
+
/,
|
|
90
|
+
**kwargs: Any,
|
|
55
91
|
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
92
|
+
# Determine effective parameter type *before* calling SQLStatement
|
|
93
|
+
merged_params_type = dict if kwargs else type(parameters)
|
|
94
|
+
|
|
95
|
+
# If ADBC + sqlite/duckdb + dictionary params, handle conversion manually
|
|
96
|
+
if self.dialect in {"sqlite", "duckdb"} and merged_params_type is dict:
|
|
97
|
+
logger.debug(
|
|
98
|
+
"ADBC/%s with dict params; bypassing SQLStatement conversion, manually converting to '?' positional.",
|
|
99
|
+
self.dialect,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Combine parameters and kwargs into the actual dictionary to use
|
|
103
|
+
parameter_dict = {} # type: ignore[var-annotated]
|
|
104
|
+
if isinstance(parameters, dict):
|
|
105
|
+
parameter_dict.update(parameters)
|
|
106
|
+
if kwargs:
|
|
107
|
+
parameter_dict.update(kwargs)
|
|
108
|
+
|
|
109
|
+
# Define regex locally to find :name or $name
|
|
110
|
+
|
|
111
|
+
processed_sql_parts: list[str] = []
|
|
112
|
+
ordered_params = []
|
|
113
|
+
last_end = 0
|
|
114
|
+
found_params_regex: list[str] = []
|
|
115
|
+
|
|
116
|
+
for match in PARAM_REGEX.finditer(sql): # Use original sql
|
|
117
|
+
if match.group("dquote") or match.group("squote") or match.group("comment"):
|
|
118
|
+
continue
|
|
119
|
+
|
|
120
|
+
if match.group("var_name"):
|
|
121
|
+
var_name = match.group("var_name")
|
|
122
|
+
leading_char = match.group("lead") # : or $
|
|
123
|
+
found_params_regex.append(var_name)
|
|
124
|
+
# Use match span directly for replacement
|
|
125
|
+
start = match.start()
|
|
126
|
+
end = match.end()
|
|
127
|
+
|
|
128
|
+
if var_name not in parameter_dict:
|
|
129
|
+
msg = f"Named parameter '{leading_char}{var_name}' found in SQL but not provided. SQL: {sql}"
|
|
130
|
+
raise SQLParsingError(msg)
|
|
131
|
+
|
|
132
|
+
processed_sql_parts.extend((sql[last_end:start], "?")) # Force ? style
|
|
133
|
+
ordered_params.append(parameter_dict[var_name])
|
|
134
|
+
last_end = end
|
|
135
|
+
|
|
136
|
+
processed_sql_parts.append(sql[last_end:])
|
|
137
|
+
|
|
138
|
+
if not found_params_regex and parameter_dict:
|
|
139
|
+
msg = f"ADBC/{self.dialect}: Dict params provided, but no :name or $name placeholders found. SQL: {sql}"
|
|
140
|
+
raise ParameterStyleMismatchError(msg)
|
|
141
|
+
|
|
142
|
+
# Key validation
|
|
143
|
+
provided_keys = set(parameter_dict.keys())
|
|
144
|
+
missing_keys = set(found_params_regex) - provided_keys
|
|
145
|
+
if missing_keys:
|
|
146
|
+
msg = (
|
|
147
|
+
f"Named parameters found in SQL ({found_params_regex}) but not provided: {missing_keys}. SQL: {sql}"
|
|
148
|
+
)
|
|
149
|
+
raise SQLParsingError(msg)
|
|
150
|
+
extra_keys = provided_keys - set(found_params_regex)
|
|
151
|
+
if extra_keys:
|
|
152
|
+
logger.debug("Extra parameters provided for ADBC/%s: %s", self.dialect, extra_keys)
|
|
153
|
+
# Allow extra keys
|
|
154
|
+
|
|
155
|
+
final_sql = "".join(processed_sql_parts)
|
|
156
|
+
final_params = tuple(ordered_params)
|
|
157
|
+
return final_sql, final_params
|
|
158
|
+
# For all other cases (other dialects, or non-dict params for sqlite/duckdb),
|
|
159
|
+
# use the standard SQLStatement processing.
|
|
160
|
+
stmt = SQLStatement(sql=sql, parameters=parameters, dialect=self.dialect, kwargs=kwargs or None)
|
|
161
|
+
return stmt.process()
|
|
162
|
+
|
|
163
|
+
@overload
|
|
164
|
+
def select(
|
|
165
|
+
self,
|
|
166
|
+
sql: str,
|
|
167
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
168
|
+
/,
|
|
169
|
+
*,
|
|
170
|
+
connection: "Optional[Connection]" = None,
|
|
171
|
+
schema_type: None = None,
|
|
172
|
+
**kwargs: Any,
|
|
173
|
+
) -> "Sequence[dict[str, Any]]": ...
|
|
174
|
+
@overload
|
|
175
|
+
def select(
|
|
176
|
+
self,
|
|
177
|
+
sql: str,
|
|
178
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
179
|
+
/,
|
|
180
|
+
*,
|
|
181
|
+
connection: "Optional[Connection]" = None,
|
|
182
|
+
schema_type: "type[ModelDTOT]",
|
|
183
|
+
**kwargs: Any,
|
|
184
|
+
) -> "Sequence[ModelDTOT]": ...
|
|
120
185
|
def select(
|
|
121
186
|
self,
|
|
122
187
|
sql: str,
|
|
123
188
|
parameters: Optional["StatementParameterType"] = None,
|
|
124
189
|
/,
|
|
190
|
+
*,
|
|
125
191
|
connection: Optional["Connection"] = None,
|
|
126
192
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
127
|
-
|
|
193
|
+
**kwargs: Any,
|
|
194
|
+
) -> "Sequence[Union[ModelDTOT, dict[str, Any]]]":
|
|
128
195
|
"""Fetch data from the database.
|
|
129
196
|
|
|
130
197
|
Returns:
|
|
131
198
|
List of row data as either model instances or dictionaries.
|
|
132
199
|
"""
|
|
133
200
|
connection = self._connection(connection)
|
|
134
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
201
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
135
202
|
with self._with_cursor(connection) as cursor:
|
|
136
203
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
137
204
|
results = cursor.fetchall() # pyright: ignore
|
|
@@ -144,13 +211,37 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
144
211
|
return [cast("ModelDTOT", schema_type(**dict(zip(column_names, row)))) for row in results] # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
|
|
145
212
|
return [dict(zip(column_names, row)) for row in results] # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
|
|
146
213
|
|
|
214
|
+
@overload
|
|
215
|
+
def select_one(
|
|
216
|
+
self,
|
|
217
|
+
sql: str,
|
|
218
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
219
|
+
/,
|
|
220
|
+
*,
|
|
221
|
+
connection: "Optional[Connection]" = None,
|
|
222
|
+
schema_type: None = None,
|
|
223
|
+
**kwargs: Any,
|
|
224
|
+
) -> "dict[str, Any]": ...
|
|
225
|
+
@overload
|
|
226
|
+
def select_one(
|
|
227
|
+
self,
|
|
228
|
+
sql: str,
|
|
229
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
230
|
+
/,
|
|
231
|
+
*,
|
|
232
|
+
connection: "Optional[Connection]" = None,
|
|
233
|
+
schema_type: "type[ModelDTOT]",
|
|
234
|
+
**kwargs: Any,
|
|
235
|
+
) -> "ModelDTOT": ...
|
|
147
236
|
def select_one(
|
|
148
237
|
self,
|
|
149
238
|
sql: str,
|
|
150
239
|
parameters: Optional["StatementParameterType"] = None,
|
|
151
240
|
/,
|
|
241
|
+
*,
|
|
152
242
|
connection: Optional["Connection"] = None,
|
|
153
243
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
244
|
+
**kwargs: Any,
|
|
154
245
|
) -> "Union[ModelDTOT, dict[str, Any]]":
|
|
155
246
|
"""Fetch one row from the database.
|
|
156
247
|
|
|
@@ -158,7 +249,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
158
249
|
The first row of the query results.
|
|
159
250
|
"""
|
|
160
251
|
connection = self._connection(connection)
|
|
161
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
252
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
162
253
|
with self._with_cursor(connection) as cursor:
|
|
163
254
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
164
255
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -168,13 +259,37 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
168
259
|
return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
|
|
169
260
|
return schema_type(**dict(zip(column_names, result))) # type: ignore[return-value]
|
|
170
261
|
|
|
262
|
+
@overload
|
|
263
|
+
def select_one_or_none(
|
|
264
|
+
self,
|
|
265
|
+
sql: str,
|
|
266
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
267
|
+
/,
|
|
268
|
+
*,
|
|
269
|
+
connection: "Optional[Connection]" = None,
|
|
270
|
+
schema_type: None = None,
|
|
271
|
+
**kwargs: Any,
|
|
272
|
+
) -> "Optional[dict[str, Any]]": ...
|
|
273
|
+
@overload
|
|
274
|
+
def select_one_or_none(
|
|
275
|
+
self,
|
|
276
|
+
sql: str,
|
|
277
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
278
|
+
/,
|
|
279
|
+
*,
|
|
280
|
+
connection: "Optional[Connection]" = None,
|
|
281
|
+
schema_type: "type[ModelDTOT]",
|
|
282
|
+
**kwargs: Any,
|
|
283
|
+
) -> "Optional[ModelDTOT]": ...
|
|
171
284
|
def select_one_or_none(
|
|
172
285
|
self,
|
|
173
286
|
sql: str,
|
|
174
287
|
parameters: Optional["StatementParameterType"] = None,
|
|
175
288
|
/,
|
|
289
|
+
*,
|
|
176
290
|
connection: Optional["Connection"] = None,
|
|
177
291
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
292
|
+
**kwargs: Any,
|
|
178
293
|
) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
|
|
179
294
|
"""Fetch one row from the database.
|
|
180
295
|
|
|
@@ -182,7 +297,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
182
297
|
The first row of the query results.
|
|
183
298
|
"""
|
|
184
299
|
connection = self._connection(connection)
|
|
185
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
300
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
186
301
|
with self._with_cursor(connection) as cursor:
|
|
187
302
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
188
303
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -193,13 +308,37 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
193
308
|
return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
|
|
194
309
|
return schema_type(**dict(zip(column_names, result))) # type: ignore[return-value]
|
|
195
310
|
|
|
311
|
+
@overload
|
|
312
|
+
def select_value(
|
|
313
|
+
self,
|
|
314
|
+
sql: str,
|
|
315
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
316
|
+
/,
|
|
317
|
+
*,
|
|
318
|
+
connection: "Optional[Connection]" = None,
|
|
319
|
+
schema_type: None = None,
|
|
320
|
+
**kwargs: Any,
|
|
321
|
+
) -> "Any": ...
|
|
322
|
+
@overload
|
|
323
|
+
def select_value(
|
|
324
|
+
self,
|
|
325
|
+
sql: str,
|
|
326
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
327
|
+
/,
|
|
328
|
+
*,
|
|
329
|
+
connection: "Optional[Connection]" = None,
|
|
330
|
+
schema_type: "type[T]",
|
|
331
|
+
**kwargs: Any,
|
|
332
|
+
) -> "T": ...
|
|
196
333
|
def select_value(
|
|
197
334
|
self,
|
|
198
335
|
sql: str,
|
|
199
336
|
parameters: Optional["StatementParameterType"] = None,
|
|
200
337
|
/,
|
|
338
|
+
*,
|
|
201
339
|
connection: Optional["Connection"] = None,
|
|
202
340
|
schema_type: "Optional[type[T]]" = None,
|
|
341
|
+
**kwargs: Any,
|
|
203
342
|
) -> "Union[T, Any]":
|
|
204
343
|
"""Fetch a single value from the database.
|
|
205
344
|
|
|
@@ -207,7 +346,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
207
346
|
The first value from the first row of results, or None if no results.
|
|
208
347
|
"""
|
|
209
348
|
connection = self._connection(connection)
|
|
210
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
349
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
211
350
|
with self._with_cursor(connection) as cursor:
|
|
212
351
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
213
352
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -216,13 +355,37 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
216
355
|
return result[0] # pyright: ignore[reportUnknownVariableType]
|
|
217
356
|
return schema_type(result[0]) # type: ignore[call-arg]
|
|
218
357
|
|
|
358
|
+
@overload
|
|
359
|
+
def select_value_or_none(
|
|
360
|
+
self,
|
|
361
|
+
sql: str,
|
|
362
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
363
|
+
/,
|
|
364
|
+
*,
|
|
365
|
+
connection: "Optional[Connection]" = None,
|
|
366
|
+
schema_type: None = None,
|
|
367
|
+
**kwargs: Any,
|
|
368
|
+
) -> "Optional[Any]": ...
|
|
369
|
+
@overload
|
|
370
|
+
def select_value_or_none(
|
|
371
|
+
self,
|
|
372
|
+
sql: str,
|
|
373
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
374
|
+
/,
|
|
375
|
+
*,
|
|
376
|
+
connection: "Optional[Connection]" = None,
|
|
377
|
+
schema_type: "type[T]",
|
|
378
|
+
**kwargs: Any,
|
|
379
|
+
) -> "Optional[T]": ...
|
|
219
380
|
def select_value_or_none(
|
|
220
381
|
self,
|
|
221
382
|
sql: str,
|
|
222
383
|
parameters: Optional["StatementParameterType"] = None,
|
|
223
384
|
/,
|
|
385
|
+
*,
|
|
224
386
|
connection: Optional["Connection"] = None,
|
|
225
387
|
schema_type: "Optional[type[T]]" = None,
|
|
388
|
+
**kwargs: Any,
|
|
226
389
|
) -> "Optional[Union[T, Any]]":
|
|
227
390
|
"""Fetch a single value from the database.
|
|
228
391
|
|
|
@@ -230,7 +393,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
230
393
|
The first value from the first row of results, or None if no results.
|
|
231
394
|
"""
|
|
232
395
|
connection = self._connection(connection)
|
|
233
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
396
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
234
397
|
with self._with_cursor(connection) as cursor:
|
|
235
398
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
236
399
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -245,7 +408,9 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
245
408
|
sql: str,
|
|
246
409
|
parameters: Optional["StatementParameterType"] = None,
|
|
247
410
|
/,
|
|
411
|
+
*,
|
|
248
412
|
connection: Optional["Connection"] = None,
|
|
413
|
+
**kwargs: Any,
|
|
249
414
|
) -> int:
|
|
250
415
|
"""Insert, update, or delete data from the database.
|
|
251
416
|
|
|
@@ -253,19 +418,43 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
253
418
|
Row count affected by the operation.
|
|
254
419
|
"""
|
|
255
420
|
connection = self._connection(connection)
|
|
256
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
421
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
257
422
|
|
|
258
423
|
with self._with_cursor(connection) as cursor:
|
|
259
424
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
260
425
|
return cursor.rowcount if hasattr(cursor, "rowcount") else -1
|
|
261
426
|
|
|
427
|
+
@overload
|
|
428
|
+
def insert_update_delete_returning(
|
|
429
|
+
self,
|
|
430
|
+
sql: str,
|
|
431
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
432
|
+
/,
|
|
433
|
+
*,
|
|
434
|
+
connection: "Optional[Connection]" = None,
|
|
435
|
+
schema_type: None = None,
|
|
436
|
+
**kwargs: Any,
|
|
437
|
+
) -> "dict[str, Any]": ...
|
|
438
|
+
@overload
|
|
439
|
+
def insert_update_delete_returning(
|
|
440
|
+
self,
|
|
441
|
+
sql: str,
|
|
442
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
443
|
+
/,
|
|
444
|
+
*,
|
|
445
|
+
connection: "Optional[Connection]" = None,
|
|
446
|
+
schema_type: "type[ModelDTOT]",
|
|
447
|
+
**kwargs: Any,
|
|
448
|
+
) -> "ModelDTOT": ...
|
|
262
449
|
def insert_update_delete_returning(
|
|
263
450
|
self,
|
|
264
451
|
sql: str,
|
|
265
452
|
parameters: Optional["StatementParameterType"] = None,
|
|
266
453
|
/,
|
|
454
|
+
*,
|
|
267
455
|
connection: Optional["Connection"] = None,
|
|
268
456
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
457
|
+
**kwargs: Any,
|
|
269
458
|
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
270
459
|
"""Insert, update, or delete data from the database and return result.
|
|
271
460
|
|
|
@@ -273,25 +462,31 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
273
462
|
The first row of results.
|
|
274
463
|
"""
|
|
275
464
|
connection = self._connection(connection)
|
|
276
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
277
|
-
column_names: list[str] = []
|
|
278
|
-
|
|
465
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
279
466
|
with self._with_cursor(connection) as cursor:
|
|
280
467
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
281
468
|
result = cursor.fetchall() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
282
|
-
if
|
|
469
|
+
if not result:
|
|
283
470
|
return None
|
|
471
|
+
|
|
472
|
+
first_row = result[0]
|
|
473
|
+
|
|
284
474
|
column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
475
|
+
|
|
476
|
+
result_dict = dict(zip(column_names, first_row))
|
|
477
|
+
|
|
478
|
+
if schema_type is None:
|
|
479
|
+
return result_dict
|
|
480
|
+
return cast("ModelDTOT", schema_type(**result_dict))
|
|
288
481
|
|
|
289
482
|
def execute_script(
|
|
290
483
|
self,
|
|
291
484
|
sql: str,
|
|
292
485
|
parameters: Optional["StatementParameterType"] = None,
|
|
293
486
|
/,
|
|
487
|
+
*,
|
|
294
488
|
connection: Optional["Connection"] = None,
|
|
489
|
+
**kwargs: Any,
|
|
295
490
|
) -> str:
|
|
296
491
|
"""Execute a script.
|
|
297
492
|
|
|
@@ -305,29 +500,25 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
305
500
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
306
501
|
return cast("str", cursor.statusmessage) if hasattr(cursor, "statusmessage") else "DONE" # pyright: ignore[reportUnknownMemberType,reportAttributeAccessIssue]
|
|
307
502
|
|
|
308
|
-
|
|
503
|
+
# --- Arrow Bulk Operations ---
|
|
504
|
+
|
|
505
|
+
def select_arrow( # pyright: ignore[reportUnknownParameterType]
|
|
309
506
|
self,
|
|
310
507
|
sql: str,
|
|
311
|
-
parameters: Optional[
|
|
508
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
312
509
|
/,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
510
|
+
*,
|
|
511
|
+
connection: "Optional[Connection]" = None,
|
|
512
|
+
**kwargs: Any,
|
|
513
|
+
) -> "ArrowTable":
|
|
514
|
+
"""Execute a SQL query and return results as an Apache Arrow Table.
|
|
317
515
|
|
|
318
516
|
Returns:
|
|
319
|
-
The
|
|
517
|
+
The results of the query as an Apache Arrow Table.
|
|
320
518
|
"""
|
|
321
|
-
|
|
322
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
323
|
-
column_names: list[str] = []
|
|
519
|
+
conn = self._connection(connection)
|
|
520
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
324
521
|
|
|
325
|
-
with self._with_cursor(
|
|
522
|
+
with self._with_cursor(conn) as cursor:
|
|
326
523
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
327
|
-
|
|
328
|
-
if len(result) == 0: # pyright: ignore[reportUnknownArgumentType]
|
|
329
|
-
return None
|
|
330
|
-
column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
331
|
-
if schema_type is not None:
|
|
332
|
-
return cast("ModelDTOT", schema_type(**dict(zip(column_names, result[0])))) # pyright: ignore[reportUnknownArgumentType]
|
|
333
|
-
return dict(zip(column_names, result[0])) # pyright: ignore[reportUnknownArgumentType, reportUnknownVariableType]
|
|
524
|
+
return cast("ArrowTable", cursor.fetch_arrow_table()) # pyright: ignore[reportUnknownMemberType]
|
|
@@ -15,11 +15,11 @@ if TYPE_CHECKING:
|
|
|
15
15
|
from typing import Literal
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
__all__ = ("
|
|
18
|
+
__all__ = ("AiosqliteConfig",)
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
@dataclass
|
|
22
|
-
class
|
|
22
|
+
class AiosqliteConfig(NoPoolAsyncConfig["Connection", "AiosqliteDriver"]):
|
|
23
23
|
"""Configuration for Aiosqlite database connections.
|
|
24
24
|
|
|
25
25
|
This class provides configuration options for Aiosqlite database connections, wrapping all parameters
|