sqlspec 0.8.0__py3-none-any.whl → 0.9.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 +39 -6
- sqlspec/adapters/adbc/__init__.py +2 -2
- sqlspec/adapters/adbc/config.py +34 -11
- sqlspec/adapters/adbc/driver.py +167 -108
- sqlspec/adapters/aiosqlite/__init__.py +2 -2
- sqlspec/adapters/aiosqlite/config.py +2 -2
- sqlspec/adapters/aiosqlite/driver.py +28 -39
- sqlspec/adapters/asyncmy/__init__.py +3 -3
- sqlspec/adapters/asyncmy/config.py +11 -12
- sqlspec/adapters/asyncmy/driver.py +25 -34
- sqlspec/adapters/asyncpg/__init__.py +5 -5
- sqlspec/adapters/asyncpg/config.py +17 -19
- sqlspec/adapters/asyncpg/driver.py +249 -93
- sqlspec/adapters/duckdb/__init__.py +2 -2
- sqlspec/adapters/duckdb/config.py +2 -2
- sqlspec/adapters/duckdb/driver.py +49 -49
- 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 +114 -41
- sqlspec/adapters/psqlpy/__init__.py +0 -0
- sqlspec/adapters/psqlpy/config.py +258 -0
- sqlspec/adapters/psqlpy/driver.py +335 -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 +180 -218
- sqlspec/adapters/sqlite/__init__.py +2 -2
- sqlspec/adapters/sqlite/config.py +2 -2
- sqlspec/adapters/sqlite/driver.py +43 -41
- sqlspec/base.py +275 -153
- sqlspec/exceptions.py +30 -0
- sqlspec/extensions/litestar/config.py +6 -0
- sqlspec/extensions/litestar/handlers.py +25 -0
- sqlspec/extensions/litestar/plugin.py +6 -1
- sqlspec/statement.py +373 -0
- sqlspec/typing.py +10 -1
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/METADATA +4 -1
- sqlspec-0.9.0.dist-info/RECORD +61 -0
- sqlspec-0.8.0.dist-info/RECORD +0 -57
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/_typing.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# ruff: noqa: RUF100, PLR0913, A002, DOC201, PLR6301
|
|
1
2
|
"""This is a simple wrapper around a few important classes in each library.
|
|
2
3
|
|
|
3
4
|
This is used to ensure compatibility when one or more of the libraries are installed.
|
|
4
5
|
"""
|
|
5
6
|
|
|
7
|
+
from collections.abc import Iterable, Mapping
|
|
6
8
|
from enum import Enum
|
|
7
9
|
from typing import (
|
|
8
10
|
Any,
|
|
@@ -96,7 +98,7 @@ except ImportError:
|
|
|
96
98
|
|
|
97
99
|
def validate_python(
|
|
98
100
|
self,
|
|
99
|
-
object: Any,
|
|
101
|
+
object: Any,
|
|
100
102
|
/,
|
|
101
103
|
*,
|
|
102
104
|
strict: "Optional[bool]" = None,
|
|
@@ -127,10 +129,7 @@ try:
|
|
|
127
129
|
except ImportError:
|
|
128
130
|
import enum
|
|
129
131
|
from collections.abc import Iterable
|
|
130
|
-
from typing import
|
|
131
|
-
|
|
132
|
-
if TYPE_CHECKING:
|
|
133
|
-
from collections.abc import Iterable
|
|
132
|
+
from typing import Callable, Optional, Union
|
|
134
133
|
|
|
135
134
|
@dataclass_transform()
|
|
136
135
|
@runtime_checkable
|
|
@@ -174,7 +173,6 @@ except ImportError:
|
|
|
174
173
|
"""Placeholder init"""
|
|
175
174
|
|
|
176
175
|
def create_instance(self, **kwargs: Any) -> "T":
|
|
177
|
-
"""Placeholder implementation"""
|
|
178
176
|
return cast("T", kwargs)
|
|
179
177
|
|
|
180
178
|
def update_instance(self, instance: "T", **kwargs: Any) -> "T":
|
|
@@ -198,11 +196,46 @@ EmptyType = Union[Literal[EmptyEnum.EMPTY], UnsetType]
|
|
|
198
196
|
Empty: Final = EmptyEnum.EMPTY
|
|
199
197
|
|
|
200
198
|
|
|
199
|
+
try:
|
|
200
|
+
from pyarrow import Table as ArrowTable
|
|
201
|
+
|
|
202
|
+
PYARROW_INSTALLED = True
|
|
203
|
+
except ImportError:
|
|
204
|
+
|
|
205
|
+
@runtime_checkable
|
|
206
|
+
class ArrowTable(Protocol): # type: ignore[no-redef]
|
|
207
|
+
"""Placeholder Implementation"""
|
|
208
|
+
|
|
209
|
+
def to_batches(self, batch_size: int) -> Any: ...
|
|
210
|
+
def num_rows(self) -> int: ...
|
|
211
|
+
def num_columns(self) -> int: ...
|
|
212
|
+
def to_pydict(self) -> dict[str, Any]: ...
|
|
213
|
+
def to_string(self) -> str: ...
|
|
214
|
+
def from_arrays(
|
|
215
|
+
self,
|
|
216
|
+
arrays: list[Any],
|
|
217
|
+
names: "Optional[list[str]]" = None,
|
|
218
|
+
schema: "Optional[Any]" = None,
|
|
219
|
+
metadata: "Optional[Mapping[str, Any]]" = None,
|
|
220
|
+
) -> Any: ...
|
|
221
|
+
def from_pydict(
|
|
222
|
+
self,
|
|
223
|
+
mapping: dict[str, Any],
|
|
224
|
+
schema: "Optional[Any]" = None,
|
|
225
|
+
metadata: "Optional[Mapping[str, Any]]" = None,
|
|
226
|
+
) -> Any: ...
|
|
227
|
+
def from_batches(self, batches: Iterable[Any], schema: Optional[Any] = None) -> Any: ...
|
|
228
|
+
|
|
229
|
+
PYARROW_INSTALLED = False # pyright: ignore[reportConstantRedefinition]
|
|
230
|
+
|
|
231
|
+
|
|
201
232
|
__all__ = (
|
|
202
233
|
"LITESTAR_INSTALLED",
|
|
203
234
|
"MSGSPEC_INSTALLED",
|
|
235
|
+
"PYARROW_INSTALLED",
|
|
204
236
|
"PYDANTIC_INSTALLED",
|
|
205
237
|
"UNSET",
|
|
238
|
+
"ArrowTable",
|
|
206
239
|
"BaseModel",
|
|
207
240
|
"DTOData",
|
|
208
241
|
"DataclassProtocol",
|
sqlspec/adapters/adbc/config.py
CHANGED
|
@@ -14,11 +14,11 @@ if TYPE_CHECKING:
|
|
|
14
14
|
from collections.abc import Generator
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
__all__ = ("
|
|
17
|
+
__all__ = ("AdbcConfig",)
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
@dataclass
|
|
21
|
-
class
|
|
21
|
+
class AdbcConfig(NoPoolSyncConfig["Connection", "AdbcDriver"]):
|
|
22
22
|
"""Configuration for ADBC connections.
|
|
23
23
|
|
|
24
24
|
This class provides configuration options for ADBC database connections using the
|
|
@@ -55,17 +55,41 @@ class Adbc(NoPoolSyncConfig["Connection", "AdbcDriver"]):
|
|
|
55
55
|
"""
|
|
56
56
|
|
|
57
57
|
if isinstance(self.driver_name, str):
|
|
58
|
-
if self.driver_name != "adbc_driver_sqlite.dbapi.connect" and
|
|
58
|
+
if self.driver_name != "adbc_driver_sqlite.dbapi.connect" and self.driver_name in {
|
|
59
|
+
"sqlite",
|
|
60
|
+
"sqlite3",
|
|
61
|
+
"adbc_driver_sqlite",
|
|
62
|
+
}:
|
|
59
63
|
self.driver_name = "adbc_driver_sqlite.dbapi.connect"
|
|
60
|
-
elif self.driver_name != "adbc_driver_duckdb.dbapi.connect" and
|
|
64
|
+
elif self.driver_name != "adbc_driver_duckdb.dbapi.connect" and self.driver_name in {
|
|
65
|
+
"duckdb",
|
|
66
|
+
"adbc_driver_duckdb",
|
|
67
|
+
}:
|
|
61
68
|
self.driver_name = "adbc_driver_duckdb.dbapi.connect"
|
|
62
|
-
elif self.driver_name != "adbc_driver_postgresql.dbapi.connect" and
|
|
69
|
+
elif self.driver_name != "adbc_driver_postgresql.dbapi.connect" and self.driver_name in {
|
|
70
|
+
"postgres",
|
|
71
|
+
"adbc_driver_postgresql",
|
|
72
|
+
"postgresql",
|
|
73
|
+
"pg",
|
|
74
|
+
}:
|
|
63
75
|
self.driver_name = "adbc_driver_postgresql.dbapi.connect"
|
|
64
|
-
elif self.driver_name != "adbc_driver_snowflake.dbapi.connect" and
|
|
76
|
+
elif self.driver_name != "adbc_driver_snowflake.dbapi.connect" and self.driver_name in {
|
|
77
|
+
"snowflake",
|
|
78
|
+
"adbc_driver_snowflake",
|
|
79
|
+
"sf",
|
|
80
|
+
}:
|
|
65
81
|
self.driver_name = "adbc_driver_snowflake.dbapi.connect"
|
|
66
|
-
elif self.driver_name != "adbc_driver_bigquery.dbapi.connect" and
|
|
82
|
+
elif self.driver_name != "adbc_driver_bigquery.dbapi.connect" and self.driver_name in {
|
|
83
|
+
"bigquery",
|
|
84
|
+
"adbc_driver_bigquery",
|
|
85
|
+
"bq",
|
|
86
|
+
}:
|
|
67
87
|
self.driver_name = "adbc_driver_bigquery.dbapi.connect"
|
|
68
|
-
elif self.driver_name != "adbc_driver_flightsql.dbapi.connect" and
|
|
88
|
+
elif self.driver_name != "adbc_driver_flightsql.dbapi.connect" and self.driver_name in {
|
|
89
|
+
"flightsql",
|
|
90
|
+
"adbc_driver_flightsql",
|
|
91
|
+
"grpc",
|
|
92
|
+
}:
|
|
69
93
|
self.driver_name = "adbc_driver_flightsql.dbapi.connect"
|
|
70
94
|
return self.driver_name
|
|
71
95
|
|
|
@@ -153,11 +177,10 @@ class Adbc(NoPoolSyncConfig["Connection", "AdbcDriver"]):
|
|
|
153
177
|
"""
|
|
154
178
|
try:
|
|
155
179
|
connect_func = self._get_connect_func()
|
|
156
|
-
|
|
157
|
-
return connect_func(**_config)
|
|
180
|
+
return connect_func(**self.connection_config_dict)
|
|
158
181
|
except Exception as e:
|
|
159
182
|
# Include driver name in error message for better context
|
|
160
|
-
driver_name = self.driver_name if isinstance(self.driver_name, str) else "Unknown/
|
|
183
|
+
driver_name = self.driver_name if isinstance(self.driver_name, str) else "Unknown/Missing"
|
|
161
184
|
# Use the potentially modified driver_path from _get_connect_func if available,
|
|
162
185
|
# otherwise fallback to self.driver_name for the error message.
|
|
163
186
|
# This requires _get_connect_func to potentially return the used path or store it.
|
sqlspec/adapters/adbc/driver.py
CHANGED
|
@@ -1,41 +1,73 @@
|
|
|
1
1
|
import contextlib
|
|
2
|
+
import logging
|
|
2
3
|
import re
|
|
3
4
|
from collections.abc import Generator
|
|
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
|
|
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,79 +83,92 @@ 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
|
-
|
|
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()
|
|
119
162
|
|
|
120
163
|
def select(
|
|
121
164
|
self,
|
|
122
165
|
sql: str,
|
|
123
166
|
parameters: Optional["StatementParameterType"] = None,
|
|
124
167
|
/,
|
|
168
|
+
*,
|
|
125
169
|
connection: Optional["Connection"] = None,
|
|
126
170
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
171
|
+
**kwargs: Any,
|
|
127
172
|
) -> "list[Union[ModelDTOT, dict[str, Any]]]":
|
|
128
173
|
"""Fetch data from the database.
|
|
129
174
|
|
|
@@ -131,7 +176,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
131
176
|
List of row data as either model instances or dictionaries.
|
|
132
177
|
"""
|
|
133
178
|
connection = self._connection(connection)
|
|
134
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
179
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
135
180
|
with self._with_cursor(connection) as cursor:
|
|
136
181
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
137
182
|
results = cursor.fetchall() # pyright: ignore
|
|
@@ -149,8 +194,10 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
149
194
|
sql: str,
|
|
150
195
|
parameters: Optional["StatementParameterType"] = None,
|
|
151
196
|
/,
|
|
197
|
+
*,
|
|
152
198
|
connection: Optional["Connection"] = None,
|
|
153
199
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
200
|
+
**kwargs: Any,
|
|
154
201
|
) -> "Union[ModelDTOT, dict[str, Any]]":
|
|
155
202
|
"""Fetch one row from the database.
|
|
156
203
|
|
|
@@ -158,7 +205,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
158
205
|
The first row of the query results.
|
|
159
206
|
"""
|
|
160
207
|
connection = self._connection(connection)
|
|
161
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
208
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
162
209
|
with self._with_cursor(connection) as cursor:
|
|
163
210
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
164
211
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -173,8 +220,10 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
173
220
|
sql: str,
|
|
174
221
|
parameters: Optional["StatementParameterType"] = None,
|
|
175
222
|
/,
|
|
223
|
+
*,
|
|
176
224
|
connection: Optional["Connection"] = None,
|
|
177
225
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
226
|
+
**kwargs: Any,
|
|
178
227
|
) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
|
|
179
228
|
"""Fetch one row from the database.
|
|
180
229
|
|
|
@@ -182,7 +231,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
182
231
|
The first row of the query results.
|
|
183
232
|
"""
|
|
184
233
|
connection = self._connection(connection)
|
|
185
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
234
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
186
235
|
with self._with_cursor(connection) as cursor:
|
|
187
236
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
188
237
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -198,8 +247,10 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
198
247
|
sql: str,
|
|
199
248
|
parameters: Optional["StatementParameterType"] = None,
|
|
200
249
|
/,
|
|
250
|
+
*,
|
|
201
251
|
connection: Optional["Connection"] = None,
|
|
202
252
|
schema_type: "Optional[type[T]]" = None,
|
|
253
|
+
**kwargs: Any,
|
|
203
254
|
) -> "Union[T, Any]":
|
|
204
255
|
"""Fetch a single value from the database.
|
|
205
256
|
|
|
@@ -207,7 +258,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
207
258
|
The first value from the first row of results, or None if no results.
|
|
208
259
|
"""
|
|
209
260
|
connection = self._connection(connection)
|
|
210
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
261
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
211
262
|
with self._with_cursor(connection) as cursor:
|
|
212
263
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
213
264
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -221,8 +272,10 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
221
272
|
sql: str,
|
|
222
273
|
parameters: Optional["StatementParameterType"] = None,
|
|
223
274
|
/,
|
|
275
|
+
*,
|
|
224
276
|
connection: Optional["Connection"] = None,
|
|
225
277
|
schema_type: "Optional[type[T]]" = None,
|
|
278
|
+
**kwargs: Any,
|
|
226
279
|
) -> "Optional[Union[T, Any]]":
|
|
227
280
|
"""Fetch a single value from the database.
|
|
228
281
|
|
|
@@ -230,7 +283,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
230
283
|
The first value from the first row of results, or None if no results.
|
|
231
284
|
"""
|
|
232
285
|
connection = self._connection(connection)
|
|
233
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
286
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
234
287
|
with self._with_cursor(connection) as cursor:
|
|
235
288
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
236
289
|
result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
@@ -245,7 +298,9 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
245
298
|
sql: str,
|
|
246
299
|
parameters: Optional["StatementParameterType"] = None,
|
|
247
300
|
/,
|
|
301
|
+
*,
|
|
248
302
|
connection: Optional["Connection"] = None,
|
|
303
|
+
**kwargs: Any,
|
|
249
304
|
) -> int:
|
|
250
305
|
"""Insert, update, or delete data from the database.
|
|
251
306
|
|
|
@@ -253,7 +308,7 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
253
308
|
Row count affected by the operation.
|
|
254
309
|
"""
|
|
255
310
|
connection = self._connection(connection)
|
|
256
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
311
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
257
312
|
|
|
258
313
|
with self._with_cursor(connection) as cursor:
|
|
259
314
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
@@ -264,8 +319,10 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
264
319
|
sql: str,
|
|
265
320
|
parameters: Optional["StatementParameterType"] = None,
|
|
266
321
|
/,
|
|
322
|
+
*,
|
|
267
323
|
connection: Optional["Connection"] = None,
|
|
268
324
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
325
|
+
**kwargs: Any,
|
|
269
326
|
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
270
327
|
"""Insert, update, or delete data from the database and return result.
|
|
271
328
|
|
|
@@ -273,25 +330,31 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
273
330
|
The first row of results.
|
|
274
331
|
"""
|
|
275
332
|
connection = self._connection(connection)
|
|
276
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
277
|
-
column_names: list[str] = []
|
|
278
|
-
|
|
333
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
279
334
|
with self._with_cursor(connection) as cursor:
|
|
280
335
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
281
336
|
result = cursor.fetchall() # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
282
|
-
if
|
|
337
|
+
if not result:
|
|
283
338
|
return None
|
|
339
|
+
|
|
340
|
+
first_row = result[0]
|
|
341
|
+
|
|
284
342
|
column_names = [c[0] for c in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
343
|
+
|
|
344
|
+
result_dict = dict(zip(column_names, first_row))
|
|
345
|
+
|
|
346
|
+
if schema_type is None:
|
|
347
|
+
return result_dict
|
|
348
|
+
return cast("ModelDTOT", schema_type(**result_dict))
|
|
288
349
|
|
|
289
350
|
def execute_script(
|
|
290
351
|
self,
|
|
291
352
|
sql: str,
|
|
292
353
|
parameters: Optional["StatementParameterType"] = None,
|
|
293
354
|
/,
|
|
355
|
+
*,
|
|
294
356
|
connection: Optional["Connection"] = None,
|
|
357
|
+
**kwargs: Any,
|
|
295
358
|
) -> str:
|
|
296
359
|
"""Execute a script.
|
|
297
360
|
|
|
@@ -305,29 +368,25 @@ class AdbcDriver(SyncDriverAdapterProtocol["Connection"]):
|
|
|
305
368
|
cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
|
|
306
369
|
return cast("str", cursor.statusmessage) if hasattr(cursor, "statusmessage") else "DONE" # pyright: ignore[reportUnknownMemberType,reportAttributeAccessIssue]
|
|
307
370
|
|
|
308
|
-
|
|
371
|
+
# --- Arrow Bulk Operations ---
|
|
372
|
+
|
|
373
|
+
def select_arrow( # pyright: ignore[reportUnknownParameterType]
|
|
309
374
|
self,
|
|
310
375
|
sql: str,
|
|
311
|
-
parameters: Optional[
|
|
376
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
312
377
|
/,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
378
|
+
*,
|
|
379
|
+
connection: "Optional[Connection]" = None,
|
|
380
|
+
**kwargs: Any,
|
|
381
|
+
) -> "ArrowTable":
|
|
382
|
+
"""Execute a SQL query and return results as an Apache Arrow Table.
|
|
317
383
|
|
|
318
384
|
Returns:
|
|
319
|
-
The
|
|
385
|
+
The results of the query as an Apache Arrow Table.
|
|
320
386
|
"""
|
|
321
|
-
|
|
322
|
-
sql, parameters = self._process_sql_params(sql, parameters)
|
|
323
|
-
column_names: list[str] = []
|
|
387
|
+
conn = self._connection(connection)
|
|
388
|
+
sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
|
|
324
389
|
|
|
325
|
-
with self._with_cursor(
|
|
390
|
+
with self._with_cursor(conn) as cursor:
|
|
326
391
|
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]
|
|
392
|
+
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
|