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,180 @@
1
+ """Asyncmy database configuration with direct field-based configuration."""
2
+
3
+ import logging
4
+ from collections.abc import AsyncGenerator
5
+ from contextlib import asynccontextmanager
6
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypedDict, Union
7
+
8
+ import asyncmy
9
+ from asyncmy.cursors import Cursor, DictCursor
10
+ from asyncmy.pool import Pool as AsyncmyPool
11
+ from typing_extensions import NotRequired
12
+
13
+ from sqlspec.adapters.asyncmy._types import AsyncmyConnection
14
+ from sqlspec.adapters.asyncmy.driver import AsyncmyCursor, AsyncmyDriver, asyncmy_statement_config
15
+ from sqlspec.config import AsyncDatabaseConfig
16
+
17
+ if TYPE_CHECKING:
18
+ from asyncmy.cursors import Cursor, DictCursor
19
+ from asyncmy.pool import Pool
20
+
21
+ from sqlspec.core.statement import StatementConfig
22
+
23
+
24
+ __all__ = ("AsyncmyConfig", "AsyncmyConnectionParams", "AsyncmyPoolParams")
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class AsyncmyConnectionParams(TypedDict, total=False):
30
+ """Asyncmy connection parameters."""
31
+
32
+ host: NotRequired[str]
33
+ user: NotRequired[str]
34
+ password: NotRequired[str]
35
+ database: NotRequired[str]
36
+ port: NotRequired[int]
37
+ unix_socket: NotRequired[str]
38
+ charset: NotRequired[str]
39
+ connect_timeout: NotRequired[int]
40
+ read_default_file: NotRequired[str]
41
+ read_default_group: NotRequired[str]
42
+ autocommit: NotRequired[bool]
43
+ local_infile: NotRequired[bool]
44
+ ssl: NotRequired[Any]
45
+ sql_mode: NotRequired[str]
46
+ init_command: NotRequired[str]
47
+ cursor_class: NotRequired[Union[type["Cursor"], type["DictCursor"]]]
48
+ extra: NotRequired[dict[str, Any]]
49
+
50
+
51
+ class AsyncmyPoolParams(AsyncmyConnectionParams, total=False):
52
+ """Asyncmy pool parameters."""
53
+
54
+ minsize: NotRequired[int]
55
+ maxsize: NotRequired[int]
56
+ echo: NotRequired[bool]
57
+ pool_recycle: NotRequired[int]
58
+
59
+
60
+ class AsyncmyConfig(AsyncDatabaseConfig[AsyncmyConnection, "Pool", AsyncmyDriver]): # pyright: ignore
61
+ """Configuration for Asyncmy database connections with direct field-based configuration."""
62
+
63
+ driver_type: ClassVar[type[AsyncmyDriver]] = AsyncmyDriver
64
+ connection_type: "ClassVar[type[AsyncmyConnection]]" = AsyncmyConnection # pyright: ignore
65
+
66
+ def __init__(
67
+ self,
68
+ *,
69
+ pool_config: "Optional[Union[AsyncmyPoolParams, dict[str, Any]]]" = None,
70
+ pool_instance: "Optional[Pool]" = None,
71
+ migration_config: Optional[dict[str, Any]] = None,
72
+ statement_config: "Optional[StatementConfig]" = None,
73
+ ) -> None:
74
+ """Initialize Asyncmy configuration.
75
+
76
+ Args:
77
+ pool_config: Pool configuration parameters
78
+ pool_instance: Existing pool instance to use
79
+ migration_config: Migration configuration
80
+ statement_config: Statement configuration override
81
+ """
82
+ processed_pool_config: dict[str, Any] = dict(pool_config) if pool_config else {}
83
+ if "extra" in processed_pool_config:
84
+ extras = processed_pool_config.pop("extra")
85
+ processed_pool_config.update(extras)
86
+
87
+ if "host" not in processed_pool_config:
88
+ processed_pool_config["host"] = "localhost"
89
+ if "port" not in processed_pool_config:
90
+ processed_pool_config["port"] = 3306
91
+
92
+ if statement_config is None:
93
+ statement_config = asyncmy_statement_config
94
+
95
+ super().__init__(
96
+ pool_config=processed_pool_config,
97
+ pool_instance=pool_instance,
98
+ migration_config=migration_config,
99
+ statement_config=statement_config,
100
+ driver_features={},
101
+ )
102
+
103
+ async def _create_pool(self) -> "Pool": # pyright: ignore
104
+ """Create the actual async connection pool."""
105
+ return await asyncmy.create_pool(**dict(self.pool_config))
106
+
107
+ async def _close_pool(self) -> None:
108
+ """Close the actual async connection pool."""
109
+ if self.pool_instance:
110
+ await self.pool_instance.close()
111
+
112
+ async def create_connection(self) -> AsyncmyConnection: # pyright: ignore
113
+ """Create a single async connection (not from pool).
114
+
115
+ Returns:
116
+ An Asyncmy connection instance.
117
+ """
118
+ if self.pool_instance is None:
119
+ self.pool_instance = await self.create_pool()
120
+ return await self.pool_instance.acquire() # pyright: ignore
121
+
122
+ @asynccontextmanager
123
+ async def provide_connection(self, *args: Any, **kwargs: Any) -> AsyncGenerator[AsyncmyConnection, None]: # pyright: ignore
124
+ """Provide an async connection context manager.
125
+
126
+ Args:
127
+ *args: Additional arguments.
128
+ **kwargs: Additional keyword arguments.
129
+
130
+ Yields:
131
+ An Asyncmy connection instance.
132
+ """
133
+ if self.pool_instance is None:
134
+ self.pool_instance = await self.create_pool()
135
+ async with self.pool_instance.acquire() as connection: # pyright: ignore
136
+ yield connection
137
+
138
+ @asynccontextmanager
139
+ async def provide_session(
140
+ self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
141
+ ) -> AsyncGenerator[AsyncmyDriver, None]:
142
+ """Provide an async driver session context manager.
143
+
144
+ Args:
145
+ *args: Additional arguments.
146
+ statement_config: Optional statement configuration override.
147
+ **kwargs: Additional keyword arguments.
148
+
149
+ Yields:
150
+ An AsyncmyDriver instance.
151
+ """
152
+ async with self.provide_connection(*args, **kwargs) as connection:
153
+ final_statement_config = statement_config or asyncmy_statement_config
154
+ yield self.driver_type(connection=connection, statement_config=final_statement_config)
155
+
156
+ async def provide_pool(self, *args: Any, **kwargs: Any) -> "Pool": # pyright: ignore
157
+ """Provide async pool instance.
158
+
159
+ Returns:
160
+ The async connection pool.
161
+ """
162
+ if not self.pool_instance:
163
+ self.pool_instance = await self.create_pool()
164
+ return self.pool_instance
165
+
166
+ def get_signature_namespace(self) -> "dict[str, type[Any]]":
167
+ """Get the signature namespace for Asyncmy types.
168
+
169
+ This provides all Asyncmy-specific types that Litestar needs to recognize
170
+ to avoid serialization attempts.
171
+
172
+ Returns:
173
+ Dictionary mapping type names to types.
174
+ """
175
+
176
+ namespace = super().get_signature_namespace()
177
+ namespace.update(
178
+ {"AsyncmyConnection": AsyncmyConnection, "AsyncmyPool": AsyncmyPool, "AsyncmyCursor": AsyncmyCursor}
179
+ )
180
+ return namespace
@@ -0,0 +1,274 @@
1
+ """AsyncMy MySQL driver implementation for async MySQL operations.
2
+
3
+ Provides async MySQL/MariaDB connectivity with:
4
+ - Parameter style conversion (QMARK to POSITIONAL_PYFORMAT)
5
+ - MySQL-specific type coercion and data handling
6
+ - Error categorization for MySQL/MariaDB
7
+ - Transaction management
8
+ """
9
+
10
+ import logging
11
+ from typing import TYPE_CHECKING, Any, Optional, Union
12
+
13
+ import asyncmy
14
+ import asyncmy.errors
15
+ from asyncmy.cursors import Cursor, DictCursor
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.asyncmy._types import AsyncmyConnection
28
+ from sqlspec.core.result import SQLResult
29
+ from sqlspec.core.statement import SQL
30
+ from sqlspec.driver import ExecutionResult
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+ __all__ = ("AsyncmyCursor", "AsyncmyDriver", "AsyncmyExceptionHandler", "asyncmy_statement_config")
35
+
36
+
37
+ # Enhanced AsyncMy statement configuration using core modules with performance optimizations
38
+ asyncmy_statement_config = StatementConfig(
39
+ dialect="mysql",
40
+ parameter_config=ParameterStyleConfig(
41
+ default_parameter_style=ParameterStyle.QMARK,
42
+ supported_parameter_styles={ParameterStyle.QMARK, ParameterStyle.POSITIONAL_PYFORMAT},
43
+ default_execution_parameter_style=ParameterStyle.POSITIONAL_PYFORMAT,
44
+ supported_execution_parameter_styles={ParameterStyle.POSITIONAL_PYFORMAT},
45
+ type_coercion_map={
46
+ dict: to_json,
47
+ list: to_json,
48
+ tuple: lambda v: to_json(list(v)),
49
+ bool: int, # MySQL represents booleans as integers
50
+ },
51
+ has_native_list_expansion=False,
52
+ needs_static_script_compilation=True,
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 AsyncmyCursor:
63
+ """Async context manager for AsyncMy cursor management."""
64
+
65
+ __slots__ = ("connection", "cursor")
66
+
67
+ def __init__(self, connection: "AsyncmyConnection") -> None:
68
+ self.connection = connection
69
+ self.cursor: Optional[Union[Cursor, DictCursor]] = None
70
+
71
+ async def __aenter__(self) -> Union[Cursor, DictCursor]:
72
+ self.cursor = 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
+ await self.cursor.close()
79
+
80
+
81
+ class AsyncmyExceptionHandler:
82
+ """Custom async context manager for handling AsyncMy database exceptions."""
83
+
84
+ __slots__ = ()
85
+
86
+ async def __aenter__(self) -> None:
87
+ return None
88
+
89
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
90
+ if exc_type is None:
91
+ return
92
+
93
+ if issubclass(exc_type, asyncmy.errors.IntegrityError):
94
+ e = exc_val
95
+ msg = f"AsyncMy MySQL integrity constraint violation: {e}"
96
+ raise SQLSpecError(msg) from e
97
+ if issubclass(exc_type, asyncmy.errors.ProgrammingError):
98
+ e = exc_val
99
+ error_msg = str(e).lower()
100
+ if "syntax" in error_msg or "parse" in error_msg:
101
+ msg = f"AsyncMy MySQL SQL syntax error: {e}"
102
+ raise SQLParsingError(msg) from e
103
+ msg = f"AsyncMy MySQL programming error: {e}"
104
+ raise SQLSpecError(msg) from e
105
+ if issubclass(exc_type, asyncmy.errors.OperationalError):
106
+ e = exc_val
107
+ msg = f"AsyncMy MySQL operational error: {e}"
108
+ raise SQLSpecError(msg) from e
109
+ if issubclass(exc_type, asyncmy.errors.DatabaseError):
110
+ e = exc_val
111
+ msg = f"AsyncMy MySQL database error: {e}"
112
+ raise SQLSpecError(msg) from e
113
+ if issubclass(exc_type, asyncmy.errors.Error):
114
+ e = exc_val
115
+ msg = f"AsyncMy MySQL error: {e}"
116
+ raise SQLSpecError(msg) from e
117
+ if issubclass(exc_type, Exception):
118
+ e = exc_val
119
+ error_msg = str(e).lower()
120
+ if "parse" in error_msg or "syntax" in error_msg:
121
+ msg = f"SQL parsing failed: {e}"
122
+ raise SQLParsingError(msg) from e
123
+ msg = f"Unexpected async database operation error: {e}"
124
+ raise SQLSpecError(msg) from e
125
+
126
+
127
+ class AsyncmyDriver(AsyncDriverAdapterBase):
128
+ """AsyncMy MySQL/MariaDB driver for async database operations.
129
+
130
+ Provides MySQL/MariaDB connectivity with:
131
+ - Parameter style conversion (QMARK to POSITIONAL_PYFORMAT)
132
+ - MySQL-specific type coercion (bool -> int, dict/list -> JSON)
133
+ - Error categorization for MySQL/MariaDB
134
+ - Transaction management
135
+ """
136
+
137
+ __slots__ = ()
138
+ dialect = "mysql"
139
+
140
+ def __init__(
141
+ self,
142
+ connection: "AsyncmyConnection",
143
+ statement_config: "Optional[StatementConfig]" = None,
144
+ driver_features: "Optional[dict[str, Any]]" = None,
145
+ ) -> None:
146
+ if statement_config is None:
147
+ cache_config = get_cache_config()
148
+ enhanced_config = asyncmy_statement_config.replace(
149
+ enable_caching=cache_config.compiled_cache_enabled,
150
+ enable_parsing=True,
151
+ enable_validation=True,
152
+ dialect="mysql",
153
+ )
154
+ statement_config = enhanced_config
155
+
156
+ super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
157
+
158
+ def with_cursor(self, connection: "AsyncmyConnection") -> "AsyncmyCursor":
159
+ """Create async context manager for AsyncMy cursor."""
160
+ return AsyncmyCursor(connection)
161
+
162
+ def handle_database_exceptions(self) -> "AbstractAsyncContextManager[None]":
163
+ """Handle database-specific exceptions and wrap them appropriately."""
164
+ return AsyncmyExceptionHandler()
165
+
166
+ async def _try_special_handling(self, cursor: Any, statement: "SQL") -> "Optional[SQLResult]":
167
+ """Hook for AsyncMy-specific special operations.
168
+
169
+ Args:
170
+ cursor: AsyncMy cursor object
171
+ statement: SQL statement to analyze
172
+
173
+ Returns:
174
+ None - always proceeds with standard execution for AsyncMy
175
+ """
176
+ _ = (cursor, statement) # Mark as intentionally unused
177
+ return None
178
+
179
+ async def _execute_script(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
180
+ """Execute SQL script using enhanced statement splitting and parameter handling.
181
+
182
+ Uses core module optimization for statement parsing and parameter processing.
183
+ Parameters are embedded as static values for script execution compatibility.
184
+ """
185
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
186
+ statements = self.split_script_statements(sql, statement.statement_config, strip_trailing_semicolon=True)
187
+
188
+ successful_count = 0
189
+ last_cursor = cursor
190
+
191
+ for stmt in statements:
192
+ await cursor.execute(stmt, prepared_parameters or None)
193
+ successful_count += 1
194
+
195
+ return self.create_execution_result(
196
+ last_cursor, statement_count=len(statements), successful_statements=successful_count, is_script_result=True
197
+ )
198
+
199
+ async def _execute_many(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
200
+ """Execute SQL with multiple parameter sets using optimized AsyncMy batch processing.
201
+
202
+ Leverages core parameter processing for enhanced MySQL type handling and parameter conversion.
203
+ """
204
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
205
+
206
+ # Enhanced parameter validation for executemany
207
+ if not prepared_parameters:
208
+ msg = "execute_many requires parameters"
209
+ raise ValueError(msg)
210
+
211
+ await cursor.executemany(sql, prepared_parameters)
212
+
213
+ # Calculate affected rows based on parameter count for AsyncMy
214
+ affected_rows = len(prepared_parameters) if prepared_parameters else 0
215
+
216
+ return self.create_execution_result(cursor, rowcount_override=affected_rows, is_many_result=True)
217
+
218
+ async def _execute_statement(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
219
+ """Execute single SQL statement with enhanced AsyncMy MySQL data handling and performance optimization.
220
+
221
+ Uses core processing for optimal parameter handling and MySQL result processing.
222
+ """
223
+ sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
224
+ await cursor.execute(sql, prepared_parameters or None)
225
+
226
+ # Enhanced SELECT result processing for MySQL
227
+ if statement.returns_rows():
228
+ fetched_data = await cursor.fetchall()
229
+ column_names = [desc[0] for desc in cursor.description or []]
230
+
231
+ # AsyncMy may return tuples or dicts - ensure consistent dict format
232
+ if fetched_data and not isinstance(fetched_data[0], dict):
233
+ data = [dict(zip(column_names, row)) for row in fetched_data]
234
+ else:
235
+ data = fetched_data
236
+
237
+ return self.create_execution_result(
238
+ cursor, selected_data=data, column_names=column_names, data_row_count=len(data), is_select_result=True
239
+ )
240
+
241
+ # Enhanced non-SELECT result processing for MySQL
242
+ affected_rows = cursor.rowcount if cursor.rowcount is not None else -1
243
+ last_id = getattr(cursor, "lastrowid", None) if cursor.rowcount and cursor.rowcount > 0 else None
244
+ return self.create_execution_result(cursor, rowcount_override=affected_rows, last_inserted_id=last_id)
245
+
246
+ # MySQL transaction management with enhanced async error handling
247
+ async def begin(self) -> None:
248
+ """Begin a database transaction with enhanced async error handling.
249
+
250
+ Explicitly starts a MySQL transaction to ensure proper transaction boundaries.
251
+ """
252
+ try:
253
+ # Execute explicit BEGIN to start transaction
254
+ async with AsyncmyCursor(self.connection) as cursor:
255
+ await cursor.execute("BEGIN")
256
+ except asyncmy.errors.MySQLError as e:
257
+ msg = f"Failed to begin MySQL transaction: {e}"
258
+ raise SQLSpecError(msg) from e
259
+
260
+ async def rollback(self) -> None:
261
+ """Rollback the current transaction with enhanced async error handling."""
262
+ try:
263
+ await self.connection.rollback()
264
+ except asyncmy.errors.MySQLError as e:
265
+ msg = f"Failed to rollback MySQL transaction: {e}"
266
+ raise SQLSpecError(msg) from e
267
+
268
+ async def commit(self) -> None:
269
+ """Commit the current transaction with enhanced async error handling."""
270
+ try:
271
+ await self.connection.commit()
272
+ except asyncmy.errors.MySQLError as e:
273
+ msg = f"Failed to commit MySQL transaction: {e}"
274
+ raise SQLSpecError(msg) from e
@@ -0,0 +1,21 @@
1
+ """AsyncPG adapter for SQLSpec."""
2
+
3
+ from sqlspec.adapters.asyncpg._types import AsyncpgConnection
4
+ from sqlspec.adapters.asyncpg.config import AsyncpgConfig, AsyncpgConnectionConfig, AsyncpgPoolConfig
5
+ from sqlspec.adapters.asyncpg.driver import (
6
+ AsyncpgCursor,
7
+ AsyncpgDriver,
8
+ AsyncpgExceptionHandler,
9
+ asyncpg_statement_config,
10
+ )
11
+
12
+ __all__ = (
13
+ "AsyncpgConfig",
14
+ "AsyncpgConnection",
15
+ "AsyncpgConnectionConfig",
16
+ "AsyncpgCursor",
17
+ "AsyncpgDriver",
18
+ "AsyncpgExceptionHandler",
19
+ "AsyncpgPoolConfig",
20
+ "asyncpg_statement_config",
21
+ )
@@ -0,0 +1,17 @@
1
+ from typing import TYPE_CHECKING, Union
2
+
3
+ from asyncpg import Connection
4
+ from asyncpg.pool import PoolConnectionProxy
5
+
6
+ if TYPE_CHECKING:
7
+ from asyncpg import Record
8
+ from typing_extensions import TypeAlias
9
+
10
+
11
+ if TYPE_CHECKING:
12
+ AsyncpgConnection: TypeAlias = Union[Connection[Record], PoolConnectionProxy[Record]]
13
+ else:
14
+ AsyncpgConnection = Union[Connection, PoolConnectionProxy]
15
+
16
+
17
+ __all__ = ("AsyncpgConnection",)