sqlspec 0.16.1__cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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.

Files changed (148) hide show
  1. 51ff5a9eadfdefd49f98__mypyc.cpython-39-aarch64-linux-gnu.so +0 -0
  2. sqlspec/__init__.py +92 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_serialization.py +77 -0
  6. sqlspec/_sql.py +1780 -0
  7. sqlspec/_typing.py +680 -0
  8. sqlspec/adapters/__init__.py +0 -0
  9. sqlspec/adapters/adbc/__init__.py +5 -0
  10. sqlspec/adapters/adbc/_types.py +12 -0
  11. sqlspec/adapters/adbc/config.py +361 -0
  12. sqlspec/adapters/adbc/driver.py +512 -0
  13. sqlspec/adapters/aiosqlite/__init__.py +19 -0
  14. sqlspec/adapters/aiosqlite/_types.py +13 -0
  15. sqlspec/adapters/aiosqlite/config.py +253 -0
  16. sqlspec/adapters/aiosqlite/driver.py +248 -0
  17. sqlspec/adapters/asyncmy/__init__.py +19 -0
  18. sqlspec/adapters/asyncmy/_types.py +12 -0
  19. sqlspec/adapters/asyncmy/config.py +180 -0
  20. sqlspec/adapters/asyncmy/driver.py +274 -0
  21. sqlspec/adapters/asyncpg/__init__.py +21 -0
  22. sqlspec/adapters/asyncpg/_types.py +17 -0
  23. sqlspec/adapters/asyncpg/config.py +229 -0
  24. sqlspec/adapters/asyncpg/driver.py +344 -0
  25. sqlspec/adapters/bigquery/__init__.py +18 -0
  26. sqlspec/adapters/bigquery/_types.py +12 -0
  27. sqlspec/adapters/bigquery/config.py +298 -0
  28. sqlspec/adapters/bigquery/driver.py +558 -0
  29. sqlspec/adapters/duckdb/__init__.py +22 -0
  30. sqlspec/adapters/duckdb/_types.py +12 -0
  31. sqlspec/adapters/duckdb/config.py +504 -0
  32. sqlspec/adapters/duckdb/driver.py +368 -0
  33. sqlspec/adapters/oracledb/__init__.py +32 -0
  34. sqlspec/adapters/oracledb/_types.py +14 -0
  35. sqlspec/adapters/oracledb/config.py +317 -0
  36. sqlspec/adapters/oracledb/driver.py +538 -0
  37. sqlspec/adapters/psqlpy/__init__.py +16 -0
  38. sqlspec/adapters/psqlpy/_types.py +11 -0
  39. sqlspec/adapters/psqlpy/config.py +214 -0
  40. sqlspec/adapters/psqlpy/driver.py +530 -0
  41. sqlspec/adapters/psycopg/__init__.py +32 -0
  42. sqlspec/adapters/psycopg/_types.py +17 -0
  43. sqlspec/adapters/psycopg/config.py +426 -0
  44. sqlspec/adapters/psycopg/driver.py +796 -0
  45. sqlspec/adapters/sqlite/__init__.py +15 -0
  46. sqlspec/adapters/sqlite/_types.py +11 -0
  47. sqlspec/adapters/sqlite/config.py +240 -0
  48. sqlspec/adapters/sqlite/driver.py +294 -0
  49. sqlspec/base.py +571 -0
  50. sqlspec/builder/__init__.py +62 -0
  51. sqlspec/builder/_base.py +473 -0
  52. sqlspec/builder/_column.py +320 -0
  53. sqlspec/builder/_ddl.py +1346 -0
  54. sqlspec/builder/_ddl_utils.py +103 -0
  55. sqlspec/builder/_delete.py +76 -0
  56. sqlspec/builder/_insert.py +256 -0
  57. sqlspec/builder/_merge.py +71 -0
  58. sqlspec/builder/_parsing_utils.py +140 -0
  59. sqlspec/builder/_select.py +170 -0
  60. sqlspec/builder/_update.py +188 -0
  61. sqlspec/builder/mixins/__init__.py +55 -0
  62. sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
  63. sqlspec/builder/mixins/_delete_operations.py +41 -0
  64. sqlspec/builder/mixins/_insert_operations.py +244 -0
  65. sqlspec/builder/mixins/_join_operations.py +122 -0
  66. sqlspec/builder/mixins/_merge_operations.py +476 -0
  67. sqlspec/builder/mixins/_order_limit_operations.py +135 -0
  68. sqlspec/builder/mixins/_pivot_operations.py +153 -0
  69. sqlspec/builder/mixins/_select_operations.py +603 -0
  70. sqlspec/builder/mixins/_update_operations.py +187 -0
  71. sqlspec/builder/mixins/_where_clause.py +621 -0
  72. sqlspec/cli.py +247 -0
  73. sqlspec/config.py +395 -0
  74. sqlspec/core/__init__.py +63 -0
  75. sqlspec/core/cache.cpython-39-aarch64-linux-gnu.so +0 -0
  76. sqlspec/core/cache.py +871 -0
  77. sqlspec/core/compiler.cpython-39-aarch64-linux-gnu.so +0 -0
  78. sqlspec/core/compiler.py +417 -0
  79. sqlspec/core/filters.cpython-39-aarch64-linux-gnu.so +0 -0
  80. sqlspec/core/filters.py +830 -0
  81. sqlspec/core/hashing.cpython-39-aarch64-linux-gnu.so +0 -0
  82. sqlspec/core/hashing.py +310 -0
  83. sqlspec/core/parameters.cpython-39-aarch64-linux-gnu.so +0 -0
  84. sqlspec/core/parameters.py +1237 -0
  85. sqlspec/core/result.cpython-39-aarch64-linux-gnu.so +0 -0
  86. sqlspec/core/result.py +677 -0
  87. sqlspec/core/splitter.cpython-39-aarch64-linux-gnu.so +0 -0
  88. sqlspec/core/splitter.py +819 -0
  89. sqlspec/core/statement.cpython-39-aarch64-linux-gnu.so +0 -0
  90. sqlspec/core/statement.py +676 -0
  91. sqlspec/driver/__init__.py +19 -0
  92. sqlspec/driver/_async.py +502 -0
  93. sqlspec/driver/_common.py +631 -0
  94. sqlspec/driver/_sync.py +503 -0
  95. sqlspec/driver/mixins/__init__.py +6 -0
  96. sqlspec/driver/mixins/_result_tools.py +193 -0
  97. sqlspec/driver/mixins/_sql_translator.py +86 -0
  98. sqlspec/exceptions.py +193 -0
  99. sqlspec/extensions/__init__.py +0 -0
  100. sqlspec/extensions/aiosql/__init__.py +10 -0
  101. sqlspec/extensions/aiosql/adapter.py +461 -0
  102. sqlspec/extensions/litestar/__init__.py +6 -0
  103. sqlspec/extensions/litestar/_utils.py +52 -0
  104. sqlspec/extensions/litestar/cli.py +48 -0
  105. sqlspec/extensions/litestar/config.py +92 -0
  106. sqlspec/extensions/litestar/handlers.py +260 -0
  107. sqlspec/extensions/litestar/plugin.py +145 -0
  108. sqlspec/extensions/litestar/providers.py +454 -0
  109. sqlspec/loader.cpython-39-aarch64-linux-gnu.so +0 -0
  110. sqlspec/loader.py +760 -0
  111. sqlspec/migrations/__init__.py +35 -0
  112. sqlspec/migrations/base.py +414 -0
  113. sqlspec/migrations/commands.py +443 -0
  114. sqlspec/migrations/loaders.py +402 -0
  115. sqlspec/migrations/runner.py +213 -0
  116. sqlspec/migrations/tracker.py +140 -0
  117. sqlspec/migrations/utils.py +129 -0
  118. sqlspec/protocols.py +407 -0
  119. sqlspec/py.typed +0 -0
  120. sqlspec/storage/__init__.py +23 -0
  121. sqlspec/storage/backends/__init__.py +0 -0
  122. sqlspec/storage/backends/base.py +163 -0
  123. sqlspec/storage/backends/fsspec.py +386 -0
  124. sqlspec/storage/backends/obstore.py +459 -0
  125. sqlspec/storage/capabilities.py +102 -0
  126. sqlspec/storage/registry.py +239 -0
  127. sqlspec/typing.py +299 -0
  128. sqlspec/utils/__init__.py +3 -0
  129. sqlspec/utils/correlation.py +150 -0
  130. sqlspec/utils/deprecation.py +106 -0
  131. sqlspec/utils/fixtures.cpython-39-aarch64-linux-gnu.so +0 -0
  132. sqlspec/utils/fixtures.py +58 -0
  133. sqlspec/utils/logging.py +127 -0
  134. sqlspec/utils/module_loader.py +89 -0
  135. sqlspec/utils/serializers.py +4 -0
  136. sqlspec/utils/singleton.py +32 -0
  137. sqlspec/utils/sync_tools.cpython-39-aarch64-linux-gnu.so +0 -0
  138. sqlspec/utils/sync_tools.py +237 -0
  139. sqlspec/utils/text.cpython-39-aarch64-linux-gnu.so +0 -0
  140. sqlspec/utils/text.py +96 -0
  141. sqlspec/utils/type_guards.cpython-39-aarch64-linux-gnu.so +0 -0
  142. sqlspec/utils/type_guards.py +1139 -0
  143. sqlspec-0.16.1.dist-info/METADATA +365 -0
  144. sqlspec-0.16.1.dist-info/RECORD +148 -0
  145. sqlspec-0.16.1.dist-info/WHEEL +7 -0
  146. sqlspec-0.16.1.dist-info/entry_points.txt +2 -0
  147. sqlspec-0.16.1.dist-info/licenses/LICENSE +21 -0
  148. sqlspec-0.16.1.dist-info/licenses/NOTICE +29 -0
@@ -0,0 +1,253 @@
1
+ """Aiosqlite database configuration with optimized connection management."""
2
+
3
+ import asyncio
4
+ import logging
5
+ from contextlib import asynccontextmanager
6
+ from typing import TYPE_CHECKING, Any, ClassVar, Final, Optional, TypedDict
7
+
8
+ import aiosqlite
9
+ from typing_extensions import NotRequired
10
+
11
+ from sqlspec.adapters.aiosqlite.driver import AiosqliteCursor, AiosqliteDriver, aiosqlite_statement_config
12
+ from sqlspec.config import AsyncDatabaseConfig
13
+
14
+ if TYPE_CHECKING:
15
+ from collections.abc import AsyncGenerator
16
+
17
+ from sqlspec.adapters.aiosqlite._types import AiosqliteConnection
18
+ from sqlspec.core.statement import StatementConfig
19
+
20
+ __all__ = ("AiosqliteConfig", "AiosqliteConnectionParams", "AiosqliteConnectionPool")
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ # Core PRAGMAs for SQLite performance optimization
25
+ WAL_PRAGMA_SQL: Final[str] = "PRAGMA journal_mode = WAL"
26
+ FOREIGN_KEYS_SQL: Final[str] = "PRAGMA foreign_keys = ON"
27
+ SYNC_NORMAL_SQL: Final[str] = "PRAGMA synchronous = NORMAL"
28
+ BUSY_TIMEOUT_SQL: Final[str] = "PRAGMA busy_timeout = 5000" # 5 seconds
29
+
30
+
31
+ class AiosqliteConnectionPool:
32
+ """Connection pool for Aiosqlite using a single shared connection approach.
33
+
34
+ Uses a single shared connection per database file since aiosqlite internally
35
+ handles queuing and serialization of operations.
36
+ """
37
+
38
+ __slots__ = ("_closed", "_connection", "_connection_parameters", "_lock")
39
+
40
+ def __init__(self, connection_parameters: "dict[str, Any]") -> None:
41
+ """Initialize connection manager.
42
+
43
+ Args:
44
+ connection_parameters: SQLite connection parameters
45
+ """
46
+ self._connection: Optional[AiosqliteConnection] = None
47
+ self._connection_parameters = connection_parameters
48
+ self._lock = asyncio.Lock()
49
+ self._closed = False
50
+
51
+ async def _ensure_connection(self) -> "AiosqliteConnection":
52
+ """Ensure we have a valid connection, creating one if needed."""
53
+ async with self._lock:
54
+ if self._connection is None or self._closed:
55
+ self._connection = await aiosqlite.connect(**self._connection_parameters)
56
+
57
+ await self._connection.execute(WAL_PRAGMA_SQL)
58
+ await self._connection.execute(FOREIGN_KEYS_SQL)
59
+ await self._connection.execute(SYNC_NORMAL_SQL)
60
+ await self._connection.execute(BUSY_TIMEOUT_SQL)
61
+ await self._connection.commit()
62
+
63
+ self._closed = False
64
+ logger.debug("Created new aiosqlite connection")
65
+
66
+ return self._connection
67
+
68
+ @asynccontextmanager
69
+ async def get_connection(self) -> "AsyncGenerator[AiosqliteConnection, None]":
70
+ """Get the shared connection.
71
+
72
+ Yields:
73
+ The shared Aiosqlite connection instance.
74
+ """
75
+ connection = await self._ensure_connection()
76
+ yield connection
77
+
78
+ async def close(self) -> None:
79
+ """Close the shared connection."""
80
+ async with self._lock:
81
+ if self._connection is not None and not self._closed:
82
+ await self._connection.close()
83
+ self._connection = None
84
+ self._closed = True
85
+ logger.debug("Closed aiosqlite connection")
86
+
87
+ def size(self) -> int:
88
+ """Get connection count."""
89
+ return 0 if self._closed or self._connection is None else 1
90
+
91
+ def checked_out(self) -> int:
92
+ """Get number of checked out connections."""
93
+ return 0
94
+
95
+ async def acquire(self) -> "AiosqliteConnection":
96
+ """Get the shared connection directly.
97
+
98
+ Returns:
99
+ The shared connection instance.
100
+ """
101
+ return await self._ensure_connection()
102
+
103
+ async def release(self, connection: "AiosqliteConnection") -> None:
104
+ """No-op release for compatibility.
105
+
106
+ Args:
107
+ connection: Connection to release (ignored)
108
+ """
109
+ _ = connection
110
+
111
+
112
+ class AiosqliteConnectionParams(TypedDict, total=False):
113
+ """aiosqlite connection parameters."""
114
+
115
+ database: NotRequired[str]
116
+ timeout: NotRequired[float]
117
+ detect_types: NotRequired[int]
118
+ isolation_level: NotRequired[Optional[str]]
119
+ check_same_thread: NotRequired[bool]
120
+ cached_statements: NotRequired[int]
121
+ uri: NotRequired[bool]
122
+
123
+
124
+ class AiosqliteConfig(AsyncDatabaseConfig):
125
+ """Database configuration for AioSQLite engine."""
126
+
127
+ driver_type: ClassVar[type[AiosqliteDriver]] = AiosqliteDriver
128
+ cursor_type: ClassVar[type[AiosqliteCursor]] = AiosqliteCursor
129
+
130
+ def __init__(
131
+ self,
132
+ *,
133
+ pool_instance: "Optional[AiosqliteConnectionPool]" = None,
134
+ pool_config: "Optional[dict[str, Any]]" = None,
135
+ migration_config: "Optional[dict[str, Any]]" = None,
136
+ statement_config: "Optional[StatementConfig]" = None,
137
+ **kwargs: Any,
138
+ ) -> None:
139
+ """Initialize AioSQLite configuration.
140
+
141
+ Args:
142
+ pool_instance: Optional pre-configured connection pool instance.
143
+ pool_config: Optional pool configuration dict (AiosqliteConnectionParams).
144
+ migration_config: Optional migration configuration.
145
+ statement_config: Optional statement configuration.
146
+ **kwargs: Additional connection parameters.
147
+ """
148
+ connection_params = {}
149
+ if pool_config:
150
+ connection_params.update(pool_config)
151
+ connection_params.update(kwargs)
152
+
153
+ super().__init__(
154
+ pool_config=connection_params,
155
+ pool_instance=pool_instance,
156
+ migration_config=migration_config or {},
157
+ statement_config=statement_config or aiosqlite_statement_config,
158
+ )
159
+
160
+ self._connection_parameters = self._parse_connection_parameters(connection_params)
161
+
162
+ if pool_instance is None:
163
+ self.pool_instance: AiosqliteConnectionPool = AiosqliteConnectionPool(self._connection_parameters)
164
+
165
+ def _parse_connection_parameters(self, params: "dict[str, Any]") -> "dict[str, Any]":
166
+ """Parse connection parameters for AioSQLite.
167
+
168
+ Args:
169
+ params: Connection parameters dict.
170
+
171
+ Returns:
172
+ Processed connection parameters dict.
173
+ """
174
+ result = params.copy()
175
+
176
+ if "database" not in result:
177
+ # Default to in-memory database
178
+ result["database"] = ":memory:"
179
+
180
+ # Convert regular :memory: to shared memory for multi-connection access
181
+ if result.get("database") == ":memory:":
182
+ result["database"] = "file::memory:?cache=shared"
183
+ result["uri"] = True
184
+
185
+ for pool_param in ["pool_min_size", "pool_max_size", "pool_timeout", "pool_recycle_seconds"]:
186
+ result.pop(pool_param, None)
187
+
188
+ return result
189
+
190
+ @asynccontextmanager
191
+ async def provide_connection(self) -> "AsyncGenerator[AiosqliteConnection, None]":
192
+ """Provide a database connection.
193
+
194
+ Yields:
195
+ AiosqliteConnection: Database connection instance.
196
+ """
197
+ async with self.pool_instance.get_connection() as connection:
198
+ yield connection
199
+
200
+ @asynccontextmanager
201
+ async def provide_session(
202
+ self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
203
+ ) -> "AsyncGenerator[AiosqliteDriver, None]":
204
+ """Provide an async database session.
205
+
206
+ Args:
207
+ *args: Additional positional arguments.
208
+ statement_config: Optional statement configuration override.
209
+ **kwargs: Additional keyword arguments.
210
+
211
+ Yields:
212
+ AiosqliteDriver: Database session instance.
213
+ """
214
+ _ = args, kwargs
215
+ effective_statement_config = statement_config or self.statement_config
216
+ async with self.pool_instance.get_connection() as connection:
217
+ session = self.driver_type(connection, statement_config=effective_statement_config)
218
+ try:
219
+ yield session
220
+ finally:
221
+ pass
222
+
223
+ async def close(self) -> None:
224
+ """Close the connection manager."""
225
+ if self.pool_instance:
226
+ await self.pool_instance.close()
227
+
228
+ def _get_connection_config_dict(self) -> "dict[str, Any]":
229
+ """Get connection configuration dictionary.
230
+
231
+ Returns:
232
+ Connection parameters for creating connections.
233
+ """
234
+ return self._connection_parameters.copy()
235
+
236
+ async def _create_pool(self) -> "AiosqliteConnectionPool":
237
+ """Create the connection manager instance.
238
+
239
+ Returns:
240
+ AiosqliteConnectionPool: The connection manager instance.
241
+ """
242
+ if self.pool_instance is None:
243
+ self.pool_instance = AiosqliteConnectionPool(self._connection_parameters)
244
+ return self.pool_instance
245
+
246
+ async def _close_pool(self) -> None:
247
+ """Close the connection manager."""
248
+ if self.pool_instance:
249
+ await self.pool_instance.close()
250
+
251
+ async def close_pool(self) -> None:
252
+ """Close the connection pool (delegates to _close_pool)."""
253
+ await self._close_pool()
@@ -0,0 +1,248 @@
1
+ """AIOSQLite driver implementation for async SQLite operations.
2
+
3
+ Provides async SQLite database connectivity with:
4
+ - Async parameter processing with type coercion
5
+ - Thread-safe caching system
6
+ - Context management for resource handling
7
+ - SQLite-specific optimizations
8
+ """
9
+
10
+ import contextlib
11
+ import datetime
12
+ from decimal import Decimal
13
+ from typing import TYPE_CHECKING, Any, Optional
14
+
15
+ import aiosqlite
16
+
17
+ from sqlspec.core.cache import get_cache_config
18
+ from sqlspec.core.parameters import ParameterStyle, ParameterStyleConfig
19
+ from sqlspec.core.statement import StatementConfig
20
+ from sqlspec.driver import AsyncDriverAdapterBase
21
+ from sqlspec.exceptions import SQLParsingError, SQLSpecError
22
+ from sqlspec.utils.serializers import to_json
23
+
24
+ if TYPE_CHECKING:
25
+ from contextlib import AbstractAsyncContextManager
26
+
27
+ from sqlspec.adapters.aiosqlite._types import AiosqliteConnection
28
+ from sqlspec.core.result import SQLResult
29
+ from sqlspec.core.statement import SQL
30
+ from sqlspec.driver import ExecutionResult
31
+
32
+ __all__ = ("AiosqliteCursor", "AiosqliteDriver", "AiosqliteExceptionHandler", "aiosqlite_statement_config")
33
+
34
+
35
+ aiosqlite_statement_config = StatementConfig(
36
+ dialect="sqlite",
37
+ parameter_config=ParameterStyleConfig(
38
+ default_parameter_style=ParameterStyle.QMARK,
39
+ supported_parameter_styles={ParameterStyle.QMARK},
40
+ default_execution_parameter_style=ParameterStyle.QMARK,
41
+ supported_execution_parameter_styles={ParameterStyle.QMARK},
42
+ type_coercion_map={
43
+ bool: int,
44
+ datetime.datetime: lambda v: v.isoformat(),
45
+ datetime.date: lambda v: v.isoformat(),
46
+ Decimal: str,
47
+ dict: to_json,
48
+ list: to_json,
49
+ tuple: lambda v: to_json(list(v)),
50
+ },
51
+ has_native_list_expansion=False,
52
+ needs_static_script_compilation=False,
53
+ preserve_parameter_format=True,
54
+ ),
55
+ enable_parsing=True,
56
+ enable_validation=True,
57
+ enable_caching=True,
58
+ enable_parameter_type_wrapping=True,
59
+ )
60
+
61
+
62
+ class AiosqliteCursor:
63
+ """Async context manager for AIOSQLite cursor management."""
64
+
65
+ __slots__ = ("connection", "cursor")
66
+
67
+ def __init__(self, connection: "AiosqliteConnection") -> None:
68
+ self.connection = connection
69
+ self.cursor: Optional[aiosqlite.Cursor] = None
70
+
71
+ async def __aenter__(self) -> "aiosqlite.Cursor":
72
+ self.cursor = await self.connection.cursor()
73
+ return self.cursor
74
+
75
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
76
+ _ = (exc_type, exc_val, exc_tb)
77
+ if self.cursor is not None:
78
+ with contextlib.suppress(Exception):
79
+ await self.cursor.close()
80
+
81
+
82
+ class AiosqliteExceptionHandler:
83
+ """Custom async context manager for handling AIOSQLite database exceptions."""
84
+
85
+ __slots__ = ()
86
+
87
+ async def __aenter__(self) -> None:
88
+ return None
89
+
90
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
91
+ if exc_type is None:
92
+ return
93
+ if issubclass(exc_type, aiosqlite.IntegrityError):
94
+ e = exc_val
95
+ msg = f"AIOSQLite integrity constraint violation: {e}"
96
+ raise SQLSpecError(msg) from e
97
+ if issubclass(exc_type, aiosqlite.OperationalError):
98
+ e = exc_val
99
+ error_msg = str(e).lower()
100
+ if "locked" in error_msg:
101
+ msg = f"AIOSQLite database locked: {e}. Consider enabling WAL mode or reducing concurrency."
102
+ raise SQLSpecError(msg) from e
103
+ if "syntax" in error_msg or "malformed" in error_msg:
104
+ msg = f"AIOSQLite SQL syntax error: {e}"
105
+ raise SQLParsingError(msg) from e
106
+ msg = f"AIOSQLite operational error: {e}"
107
+ raise SQLSpecError(msg) from e
108
+ if issubclass(exc_type, aiosqlite.DatabaseError):
109
+ e = exc_val
110
+ msg = f"AIOSQLite database error: {e}"
111
+ raise SQLSpecError(msg) from e
112
+ if issubclass(exc_type, aiosqlite.Error):
113
+ e = exc_val
114
+ msg = f"AIOSQLite error: {e}"
115
+ raise SQLSpecError(msg) from e
116
+ if issubclass(exc_type, Exception):
117
+ e = exc_val
118
+ error_msg = str(e).lower()
119
+ if "parse" in error_msg or "syntax" in error_msg:
120
+ msg = f"SQL parsing failed: {e}"
121
+ raise SQLParsingError(msg) from e
122
+ msg = f"Unexpected async database operation error: {e}"
123
+ raise SQLSpecError(msg) from e
124
+
125
+
126
+ class AiosqliteDriver(AsyncDriverAdapterBase):
127
+ """AIOSQLite driver for async SQLite database operations.
128
+
129
+ Provides async SQLite connectivity with:
130
+ - Statement processing and parameter handling
131
+ - Cursor management and resource cleanup
132
+ - Exception handling for SQLite operations
133
+ """
134
+
135
+ __slots__ = ()
136
+ dialect = "sqlite"
137
+
138
+ def __init__(
139
+ self,
140
+ connection: "AiosqliteConnection",
141
+ statement_config: "Optional[StatementConfig]" = None,
142
+ driver_features: "Optional[dict[str, Any]]" = None,
143
+ ) -> None:
144
+ if statement_config is None:
145
+ cache_config = get_cache_config()
146
+ enhanced_config = aiosqlite_statement_config.replace(
147
+ enable_caching=cache_config.compiled_cache_enabled,
148
+ enable_parsing=True,
149
+ enable_validation=True,
150
+ dialect="sqlite",
151
+ )
152
+ statement_config = enhanced_config
153
+
154
+ super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
155
+
156
+ def with_cursor(self, connection: "AiosqliteConnection") -> "AiosqliteCursor":
157
+ """Create async context manager for AIOSQLite cursor."""
158
+ return AiosqliteCursor(connection)
159
+
160
+ def handle_database_exceptions(self) -> "AbstractAsyncContextManager[None]":
161
+ """Handle AIOSQLite-specific exceptions."""
162
+ return AiosqliteExceptionHandler()
163
+
164
+ async def _try_special_handling(self, cursor: "aiosqlite.Cursor", statement: "SQL") -> "Optional[SQLResult]":
165
+ """Hook for AIOSQLite-specific special operations.
166
+
167
+ Args:
168
+ cursor: AIOSQLite cursor object
169
+ statement: SQL statement to analyze
170
+
171
+ Returns:
172
+ None - always proceeds with standard execution for AIOSQLite
173
+ """
174
+ _ = (cursor, statement)
175
+ return None
176
+
177
+ async def _execute_script(self, cursor: "aiosqlite.Cursor", statement: "SQL") -> "ExecutionResult":
178
+ """Execute SQL script using statement splitting and parameter handling."""
179
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
180
+ statements = self.split_script_statements(sql, statement.statement_config, strip_trailing_semicolon=True)
181
+
182
+ successful_count = 0
183
+ last_cursor = cursor
184
+
185
+ for stmt in statements:
186
+ await cursor.execute(stmt, prepared_parameters or ())
187
+ successful_count += 1
188
+
189
+ return self.create_execution_result(
190
+ last_cursor, statement_count=len(statements), successful_statements=successful_count, is_script_result=True
191
+ )
192
+
193
+ async def _execute_many(self, cursor: "aiosqlite.Cursor", statement: "SQL") -> "ExecutionResult":
194
+ """Execute SQL with multiple parameter sets using async batch processing."""
195
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
196
+
197
+ if not prepared_parameters:
198
+ msg = "execute_many requires parameters"
199
+ raise ValueError(msg)
200
+
201
+ await cursor.executemany(sql, prepared_parameters)
202
+
203
+ affected_rows = cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
204
+
205
+ return self.create_execution_result(cursor, rowcount_override=affected_rows, is_many_result=True)
206
+
207
+ async def _execute_statement(self, cursor: "aiosqlite.Cursor", statement: "SQL") -> "ExecutionResult":
208
+ """Execute single SQL statement with async data handling."""
209
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
210
+ await cursor.execute(sql, prepared_parameters or ())
211
+
212
+ if statement.returns_rows():
213
+ fetched_data = await cursor.fetchall()
214
+ column_names = [col[0] for col in cursor.description or []]
215
+
216
+ data = [dict(zip(column_names, row)) for row in fetched_data]
217
+
218
+ return self.create_execution_result(
219
+ cursor, selected_data=data, column_names=column_names, data_row_count=len(data), is_select_result=True
220
+ )
221
+
222
+ affected_rows = cursor.rowcount if cursor.rowcount and cursor.rowcount > 0 else 0
223
+ return self.create_execution_result(cursor, rowcount_override=affected_rows)
224
+
225
+ async def begin(self) -> None:
226
+ """Begin a database transaction."""
227
+ try:
228
+ if not self.connection.in_transaction:
229
+ await self.connection.execute("BEGIN")
230
+ except aiosqlite.Error as e:
231
+ msg = f"Failed to begin transaction: {e}"
232
+ raise SQLSpecError(msg) from e
233
+
234
+ async def rollback(self) -> None:
235
+ """Rollback the current transaction."""
236
+ try:
237
+ await self.connection.rollback()
238
+ except aiosqlite.Error as e:
239
+ msg = f"Failed to rollback transaction: {e}"
240
+ raise SQLSpecError(msg) from e
241
+
242
+ async def commit(self) -> None:
243
+ """Commit the current transaction."""
244
+ try:
245
+ await self.connection.commit()
246
+ except aiosqlite.Error as e:
247
+ msg = f"Failed to commit transaction: {e}"
248
+ raise SQLSpecError(msg) from e
@@ -0,0 +1,19 @@
1
+ from sqlspec.adapters.asyncmy._types import AsyncmyConnection
2
+ from sqlspec.adapters.asyncmy.config import AsyncmyConfig, AsyncmyConnectionParams, AsyncmyPoolParams
3
+ from sqlspec.adapters.asyncmy.driver import (
4
+ AsyncmyCursor,
5
+ AsyncmyDriver,
6
+ AsyncmyExceptionHandler,
7
+ asyncmy_statement_config,
8
+ )
9
+
10
+ __all__ = (
11
+ "AsyncmyConfig",
12
+ "AsyncmyConnection",
13
+ "AsyncmyConnectionParams",
14
+ "AsyncmyCursor",
15
+ "AsyncmyDriver",
16
+ "AsyncmyExceptionHandler",
17
+ "AsyncmyPoolParams",
18
+ "asyncmy_statement_config",
19
+ )
@@ -0,0 +1,12 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from asyncmy import Connection
4
+
5
+ if TYPE_CHECKING:
6
+ from typing_extensions import TypeAlias
7
+
8
+ AsyncmyConnection: TypeAlias = Connection
9
+ else:
10
+ AsyncmyConnection = Connection
11
+
12
+ __all__ = ("AsyncmyConnection",)