sqlspec 0.7.1__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/__init__.py +15 -0
- sqlspec/_serialization.py +16 -2
- sqlspec/_typing.py +40 -7
- sqlspec/adapters/adbc/__init__.py +7 -0
- sqlspec/adapters/adbc/config.py +183 -17
- sqlspec/adapters/adbc/driver.py +392 -0
- sqlspec/adapters/aiosqlite/__init__.py +5 -1
- sqlspec/adapters/aiosqlite/config.py +24 -6
- sqlspec/adapters/aiosqlite/driver.py +264 -0
- sqlspec/adapters/asyncmy/__init__.py +7 -2
- sqlspec/adapters/asyncmy/config.py +71 -11
- sqlspec/adapters/asyncmy/driver.py +246 -0
- sqlspec/adapters/asyncpg/__init__.py +9 -0
- sqlspec/adapters/asyncpg/config.py +102 -25
- sqlspec/adapters/asyncpg/driver.py +444 -0
- sqlspec/adapters/duckdb/__init__.py +5 -1
- sqlspec/adapters/duckdb/config.py +194 -12
- sqlspec/adapters/duckdb/driver.py +225 -0
- sqlspec/adapters/oracledb/__init__.py +7 -4
- sqlspec/adapters/oracledb/config/__init__.py +4 -4
- sqlspec/adapters/oracledb/config/_asyncio.py +96 -12
- sqlspec/adapters/oracledb/config/_common.py +1 -1
- sqlspec/adapters/oracledb/config/_sync.py +96 -12
- sqlspec/adapters/oracledb/driver.py +571 -0
- 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 +16 -0
- sqlspec/adapters/psycopg/config/__init__.py +6 -6
- sqlspec/adapters/psycopg/config/_async.py +107 -15
- sqlspec/adapters/psycopg/config/_common.py +2 -2
- sqlspec/adapters/psycopg/config/_sync.py +107 -15
- sqlspec/adapters/psycopg/driver.py +578 -0
- sqlspec/adapters/sqlite/__init__.py +7 -0
- sqlspec/adapters/sqlite/config.py +24 -6
- sqlspec/adapters/sqlite/driver.py +305 -0
- sqlspec/base.py +565 -63
- sqlspec/exceptions.py +30 -0
- sqlspec/extensions/litestar/__init__.py +19 -0
- sqlspec/extensions/litestar/_utils.py +56 -0
- sqlspec/extensions/litestar/config.py +87 -0
- sqlspec/extensions/litestar/handlers.py +213 -0
- sqlspec/extensions/litestar/plugin.py +105 -11
- sqlspec/statement.py +373 -0
- sqlspec/typing.py +81 -17
- sqlspec/utils/__init__.py +3 -0
- sqlspec/utils/fixtures.py +4 -5
- sqlspec/utils/sync_tools.py +335 -0
- {sqlspec-0.7.1.dist-info → sqlspec-0.9.0.dist-info}/METADATA +4 -1
- sqlspec-0.9.0.dist-info/RECORD +61 -0
- sqlspec-0.7.1.dist-info/RECORD +0 -46
- {sqlspec-0.7.1.dist-info → sqlspec-0.9.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.7.1.dist-info → sqlspec-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.7.1.dist-info → sqlspec-0.9.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/__init__.py
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from sqlspec import adapters, base, exceptions, extensions, filters, typing, utils
|
|
2
|
+
from sqlspec.__metadata__ import __version__
|
|
3
|
+
from sqlspec.base import SQLSpec
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"SQLSpec",
|
|
7
|
+
"__version__",
|
|
8
|
+
"adapters",
|
|
9
|
+
"base",
|
|
10
|
+
"exceptions",
|
|
11
|
+
"extensions",
|
|
12
|
+
"filters",
|
|
13
|
+
"typing",
|
|
14
|
+
"utils",
|
|
15
|
+
)
|
sqlspec/_serialization.py
CHANGED
|
@@ -60,12 +60,26 @@ __all__ = (
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
def convert_datetime_to_gmt_iso(dt: datetime.datetime) -> str: # pragma: no cover
|
|
63
|
-
"""Handle datetime serialization for nested timestamps.
|
|
63
|
+
"""Handle datetime serialization for nested timestamps.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
dt: The datetime to convert.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
The ISO formatted datetime string.
|
|
70
|
+
"""
|
|
64
71
|
if not dt.tzinfo:
|
|
65
72
|
dt = dt.replace(tzinfo=datetime.timezone.utc)
|
|
66
73
|
return dt.isoformat().replace("+00:00", "Z")
|
|
67
74
|
|
|
68
75
|
|
|
69
76
|
def convert_date_to_iso(dt: datetime.date) -> str: # pragma: no cover
|
|
70
|
-
"""Handle datetime serialization for nested timestamps.
|
|
77
|
+
"""Handle datetime serialization for nested timestamps.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
dt: The date to convert.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
The ISO formatted date string.
|
|
84
|
+
"""
|
|
71
85
|
return dt.isoformat()
|
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,
|
|
@@ -29,7 +31,7 @@ T_co = TypeVar("T_co", covariant=True)
|
|
|
29
31
|
|
|
30
32
|
try:
|
|
31
33
|
from pydantic import (
|
|
32
|
-
BaseModel,
|
|
34
|
+
BaseModel, # pyright: ignore[reportAssignmentType]
|
|
33
35
|
FailFast, # pyright: ignore[reportGeneralTypeIssues,reportAssignmentType]
|
|
34
36
|
TypeAdapter,
|
|
35
37
|
)
|
|
@@ -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
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
from contextlib import contextmanager
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional, Union, cast
|
|
4
4
|
|
|
5
|
+
from adbc_driver_manager.dbapi import Connection
|
|
6
|
+
|
|
7
|
+
from sqlspec.adapters.adbc.driver import AdbcDriver
|
|
5
8
|
from sqlspec.base import NoPoolSyncConfig
|
|
9
|
+
from sqlspec.exceptions import ImproperConfigurationError
|
|
6
10
|
from sqlspec.typing import Empty, EmptyType
|
|
11
|
+
from sqlspec.utils.module_loader import import_string
|
|
7
12
|
|
|
8
13
|
if TYPE_CHECKING:
|
|
9
14
|
from collections.abc import Generator
|
|
10
|
-
from typing import Any
|
|
11
15
|
|
|
12
|
-
from adbc_driver_manager.dbapi import Connection
|
|
13
16
|
|
|
14
|
-
__all__ = ("
|
|
17
|
+
__all__ = ("AdbcConfig",)
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
@dataclass
|
|
18
|
-
class
|
|
21
|
+
class AdbcConfig(NoPoolSyncConfig["Connection", "AdbcDriver"]):
|
|
19
22
|
"""Configuration for ADBC connections.
|
|
20
23
|
|
|
21
24
|
This class provides configuration options for ADBC database connections using the
|
|
@@ -25,23 +28,186 @@ class AdbcDatabaseConfig(NoPoolSyncConfig["Connection"]):
|
|
|
25
28
|
uri: "Union[str, EmptyType]" = Empty
|
|
26
29
|
"""Database URI"""
|
|
27
30
|
driver_name: "Union[str, EmptyType]" = Empty
|
|
28
|
-
"""
|
|
31
|
+
"""Full dotted path to the ADBC driver's connect function (e.g., 'adbc_driver_sqlite.dbapi.connect')"""
|
|
29
32
|
db_kwargs: "Optional[dict[str, Any]]" = None
|
|
30
33
|
"""Additional database-specific connection parameters"""
|
|
34
|
+
conn_kwargs: "Optional[dict[str, Any]]" = None
|
|
35
|
+
"""Additional database-specific connection parameters"""
|
|
36
|
+
connection_type: "type[Connection]" = field(init=False, default_factory=lambda: Connection)
|
|
37
|
+
"""Type of the connection object"""
|
|
38
|
+
driver_type: "type[AdbcDriver]" = field(init=False, default_factory=lambda: AdbcDriver) # type: ignore[type-abstract,unused-ignore]
|
|
39
|
+
"""Type of the driver object"""
|
|
40
|
+
pool_instance: None = field(init=False, default=None)
|
|
41
|
+
"""No connection pool is used for ADBC connections"""
|
|
42
|
+
_is_in_memory: bool = field(init=False, default=False)
|
|
43
|
+
"""Flag indicating if the connection is for an in-memory database"""
|
|
44
|
+
|
|
45
|
+
def _set_adbc(self) -> str: # noqa: PLR0912
|
|
46
|
+
"""Identify the driver type based on the URI (if provided) or preset driver name.
|
|
47
|
+
|
|
48
|
+
Also sets the `_is_in_memory` flag for specific in-memory URIs.
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
ImproperConfigurationError: If the driver name is not recognized or supported.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
str: The driver name to be used for the connection.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
if isinstance(self.driver_name, str):
|
|
58
|
+
if self.driver_name != "adbc_driver_sqlite.dbapi.connect" and self.driver_name in {
|
|
59
|
+
"sqlite",
|
|
60
|
+
"sqlite3",
|
|
61
|
+
"adbc_driver_sqlite",
|
|
62
|
+
}:
|
|
63
|
+
self.driver_name = "adbc_driver_sqlite.dbapi.connect"
|
|
64
|
+
elif self.driver_name != "adbc_driver_duckdb.dbapi.connect" and self.driver_name in {
|
|
65
|
+
"duckdb",
|
|
66
|
+
"adbc_driver_duckdb",
|
|
67
|
+
}:
|
|
68
|
+
self.driver_name = "adbc_driver_duckdb.dbapi.connect"
|
|
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
|
+
}:
|
|
75
|
+
self.driver_name = "adbc_driver_postgresql.dbapi.connect"
|
|
76
|
+
elif self.driver_name != "adbc_driver_snowflake.dbapi.connect" and self.driver_name in {
|
|
77
|
+
"snowflake",
|
|
78
|
+
"adbc_driver_snowflake",
|
|
79
|
+
"sf",
|
|
80
|
+
}:
|
|
81
|
+
self.driver_name = "adbc_driver_snowflake.dbapi.connect"
|
|
82
|
+
elif self.driver_name != "adbc_driver_bigquery.dbapi.connect" and self.driver_name in {
|
|
83
|
+
"bigquery",
|
|
84
|
+
"adbc_driver_bigquery",
|
|
85
|
+
"bq",
|
|
86
|
+
}:
|
|
87
|
+
self.driver_name = "adbc_driver_bigquery.dbapi.connect"
|
|
88
|
+
elif self.driver_name != "adbc_driver_flightsql.dbapi.connect" and self.driver_name in {
|
|
89
|
+
"flightsql",
|
|
90
|
+
"adbc_driver_flightsql",
|
|
91
|
+
"grpc",
|
|
92
|
+
}:
|
|
93
|
+
self.driver_name = "adbc_driver_flightsql.dbapi.connect"
|
|
94
|
+
return self.driver_name
|
|
95
|
+
|
|
96
|
+
# If driver_name wasn't explicit, try to determine from URI
|
|
97
|
+
if isinstance(self.uri, str) and self.uri.startswith("postgresql://"):
|
|
98
|
+
self.driver_name = "adbc_driver_postgresql.dbapi.connect"
|
|
99
|
+
elif isinstance(self.uri, str) and self.uri.startswith("sqlite://"):
|
|
100
|
+
self.driver_name = "adbc_driver_sqlite.dbapi.connect"
|
|
101
|
+
elif isinstance(self.uri, str) and self.uri.startswith("grpc://"):
|
|
102
|
+
self.driver_name = "adbc_driver_flightsql.dbapi.connect"
|
|
103
|
+
elif isinstance(self.uri, str) and self.uri.startswith("snowflake://"):
|
|
104
|
+
self.driver_name = "adbc_driver_snowflake.dbapi.connect"
|
|
105
|
+
elif isinstance(self.uri, str) and self.uri.startswith("bigquery://"):
|
|
106
|
+
self.driver_name = "adbc_driver_bigquery.dbapi.connect"
|
|
107
|
+
elif isinstance(self.uri, str) and self.uri.startswith("duckdb://"):
|
|
108
|
+
self.driver_name = "adbc_driver_duckdb.dbapi.connect"
|
|
109
|
+
|
|
110
|
+
# Check if we successfully determined a driver name
|
|
111
|
+
if self.driver_name is Empty or not isinstance(self.driver_name, str):
|
|
112
|
+
msg = (
|
|
113
|
+
"Could not determine ADBC driver connect path. Please specify 'driver_name' "
|
|
114
|
+
"(e.g., 'adbc_driver_sqlite.dbapi.connect') or provide a supported 'uri'. "
|
|
115
|
+
f"URI: {self.uri}, Driver Name: {self.driver_name}"
|
|
116
|
+
)
|
|
117
|
+
raise ImproperConfigurationError(msg)
|
|
118
|
+
return self.driver_name
|
|
31
119
|
|
|
32
120
|
@property
|
|
33
|
-
def
|
|
34
|
-
"""Return the connection
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
121
|
+
def connection_config_dict(self) -> "dict[str, Any]":
|
|
122
|
+
"""Return the connection configuration as a dict.
|
|
123
|
+
|
|
124
|
+
Omits the 'uri' key for known in-memory database types.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
A string keyed dict of config kwargs for the adbc_driver_manager.dbapi.connect function.
|
|
128
|
+
"""
|
|
129
|
+
config = {}
|
|
130
|
+
db_kwargs = self.db_kwargs or {}
|
|
131
|
+
conn_kwargs = self.conn_kwargs or {}
|
|
132
|
+
if isinstance(self.uri, str) and self.uri.startswith("sqlite://"):
|
|
133
|
+
db_kwargs["uri"] = self.uri.replace("sqlite://", "")
|
|
134
|
+
elif isinstance(self.uri, str) and self.uri.startswith("duckdb://"):
|
|
135
|
+
db_kwargs["path"] = self.uri.replace("duckdb://", "")
|
|
136
|
+
elif isinstance(self.uri, str):
|
|
137
|
+
db_kwargs["uri"] = self.uri
|
|
138
|
+
if isinstance(self.driver_name, str) and self.driver_name.startswith("adbc_driver_bigquery"):
|
|
139
|
+
config["db_kwargs"] = db_kwargs
|
|
140
|
+
else:
|
|
141
|
+
config = db_kwargs
|
|
142
|
+
if conn_kwargs:
|
|
143
|
+
config["conn_kwargs"] = conn_kwargs
|
|
144
|
+
return config
|
|
145
|
+
|
|
146
|
+
def _get_connect_func(self) -> "Callable[..., Connection]":
|
|
147
|
+
self._set_adbc()
|
|
148
|
+
driver_path = cast("str", self.driver_name)
|
|
149
|
+
try:
|
|
150
|
+
connect_func = import_string(driver_path)
|
|
151
|
+
except ImportError as e:
|
|
152
|
+
# Check if the error is likely due to missing suffix and try again
|
|
153
|
+
if ".dbapi.connect" not in driver_path:
|
|
154
|
+
try:
|
|
155
|
+
driver_path += ".dbapi.connect"
|
|
156
|
+
connect_func = import_string(driver_path)
|
|
157
|
+
except ImportError as e2:
|
|
158
|
+
msg = f"Failed to import ADBC connect function from '{self.driver_name}' or '{driver_path}'. Is the driver installed and the path correct? Original error: {e} / {e2}"
|
|
159
|
+
raise ImproperConfigurationError(msg) from e2
|
|
160
|
+
else:
|
|
161
|
+
# Original import failed, and suffix was already present or added
|
|
162
|
+
msg = f"Failed to import ADBC connect function from '{driver_path}'. Is the driver installed and the path correct? Original error: {e}"
|
|
163
|
+
raise ImproperConfigurationError(msg) from e
|
|
164
|
+
if not callable(connect_func):
|
|
165
|
+
msg = f"The path '{driver_path}' did not resolve to a callable function."
|
|
166
|
+
raise ImproperConfigurationError(msg)
|
|
167
|
+
return connect_func # type: ignore[no-any-return]
|
|
168
|
+
|
|
169
|
+
def create_connection(self) -> "Connection":
|
|
170
|
+
"""Create and return a new database connection using the specific driver.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
A new ADBC connection instance.
|
|
174
|
+
|
|
175
|
+
Raises:
|
|
176
|
+
ImproperConfigurationError: If the connection could not be established.
|
|
177
|
+
"""
|
|
178
|
+
try:
|
|
179
|
+
connect_func = self._get_connect_func()
|
|
180
|
+
return connect_func(**self.connection_config_dict)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
# Include driver name in error message for better context
|
|
183
|
+
driver_name = self.driver_name if isinstance(self.driver_name, str) else "Unknown/Missing"
|
|
184
|
+
# Use the potentially modified driver_path from _get_connect_func if available,
|
|
185
|
+
# otherwise fallback to self.driver_name for the error message.
|
|
186
|
+
# This requires _get_connect_func to potentially return the used path or store it.
|
|
187
|
+
# For simplicity now, we stick to self.driver_name in the message.
|
|
188
|
+
msg = f"Could not configure the ADBC connection using driver path '{driver_name}'. Error: {e!s}"
|
|
189
|
+
raise ImproperConfigurationError(msg) from e
|
|
40
190
|
|
|
41
191
|
@contextmanager
|
|
42
192
|
def provide_connection(self, *args: "Any", **kwargs: "Any") -> "Generator[Connection, None, None]":
|
|
43
|
-
"""Create and provide a database connection.
|
|
44
|
-
from adbc_driver_manager.dbapi import connect
|
|
193
|
+
"""Create and provide a database connection using the specific driver.
|
|
45
194
|
|
|
46
|
-
|
|
195
|
+
Yields:
|
|
196
|
+
Connection: A database connection instance.
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
connection = self.create_connection()
|
|
200
|
+
try:
|
|
47
201
|
yield connection
|
|
202
|
+
finally:
|
|
203
|
+
connection.close()
|
|
204
|
+
|
|
205
|
+
@contextmanager
|
|
206
|
+
def provide_session(self, *args: Any, **kwargs: Any) -> "Generator[AdbcDriver, None, None]":
|
|
207
|
+
"""Create and provide a database session.
|
|
208
|
+
|
|
209
|
+
Yields:
|
|
210
|
+
An ADBC driver instance with an active connection.
|
|
211
|
+
"""
|
|
212
|
+
with self.provide_connection(*args, **kwargs) as connection:
|
|
213
|
+
yield self.driver_type(connection)
|