sqlspec 0.16.0__cp313-cp313-macosx_14_0_arm64.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-313-darwin.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 +1347 -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 +440 -0
  52. sqlspec/builder/_column.py +324 -0
  53. sqlspec/builder/_ddl.py +1383 -0
  54. sqlspec/builder/_ddl_utils.py +104 -0
  55. sqlspec/builder/_delete.py +77 -0
  56. sqlspec/builder/_insert.py +241 -0
  57. sqlspec/builder/_merge.py +56 -0
  58. sqlspec/builder/_parsing_utils.py +140 -0
  59. sqlspec/builder/_select.py +174 -0
  60. sqlspec/builder/_update.py +186 -0
  61. sqlspec/builder/mixins/__init__.py +55 -0
  62. sqlspec/builder/mixins/_cte_and_set_ops.py +195 -0
  63. sqlspec/builder/mixins/_delete_operations.py +36 -0
  64. sqlspec/builder/mixins/_insert_operations.py +152 -0
  65. sqlspec/builder/mixins/_join_operations.py +115 -0
  66. sqlspec/builder/mixins/_merge_operations.py +416 -0
  67. sqlspec/builder/mixins/_order_limit_operations.py +123 -0
  68. sqlspec/builder/mixins/_pivot_operations.py +144 -0
  69. sqlspec/builder/mixins/_select_operations.py +599 -0
  70. sqlspec/builder/mixins/_update_operations.py +164 -0
  71. sqlspec/builder/mixins/_where_clause.py +609 -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-313-darwin.so +0 -0
  76. sqlspec/core/cache.py +873 -0
  77. sqlspec/core/compiler.cpython-313-darwin.so +0 -0
  78. sqlspec/core/compiler.py +396 -0
  79. sqlspec/core/filters.cpython-313-darwin.so +0 -0
  80. sqlspec/core/filters.py +830 -0
  81. sqlspec/core/hashing.cpython-313-darwin.so +0 -0
  82. sqlspec/core/hashing.py +310 -0
  83. sqlspec/core/parameters.cpython-313-darwin.so +0 -0
  84. sqlspec/core/parameters.py +1209 -0
  85. sqlspec/core/result.cpython-313-darwin.so +0 -0
  86. sqlspec/core/result.py +664 -0
  87. sqlspec/core/splitter.cpython-313-darwin.so +0 -0
  88. sqlspec/core/splitter.py +819 -0
  89. sqlspec/core/statement.cpython-313-darwin.so +0 -0
  90. sqlspec/core/statement.py +666 -0
  91. sqlspec/driver/__init__.py +19 -0
  92. sqlspec/driver/_async.py +472 -0
  93. sqlspec/driver/_common.py +612 -0
  94. sqlspec/driver/_sync.py +473 -0
  95. sqlspec/driver/mixins/__init__.py +6 -0
  96. sqlspec/driver/mixins/_result_tools.py +164 -0
  97. sqlspec/driver/mixins/_sql_translator.py +36 -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-313-darwin.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 +400 -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-313-darwin.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-313-darwin.so +0 -0
  138. sqlspec/utils/sync_tools.py +237 -0
  139. sqlspec/utils/text.cpython-313-darwin.so +0 -0
  140. sqlspec/utils/text.py +96 -0
  141. sqlspec/utils/type_guards.cpython-313-darwin.so +0 -0
  142. sqlspec/utils/type_guards.py +1135 -0
  143. sqlspec-0.16.0.dist-info/METADATA +365 -0
  144. sqlspec-0.16.0.dist-info/RECORD +148 -0
  145. sqlspec-0.16.0.dist-info/WHEEL +4 -0
  146. sqlspec-0.16.0.dist-info/entry_points.txt +2 -0
  147. sqlspec-0.16.0.dist-info/licenses/LICENSE +21 -0
  148. sqlspec-0.16.0.dist-info/licenses/NOTICE +29 -0
sqlspec/exceptions.py ADDED
@@ -0,0 +1,193 @@
1
+ from collections.abc import Generator
2
+ from contextlib import contextmanager
3
+ from typing import Any, Optional, Union
4
+
5
+ __all__ = (
6
+ "FileNotFoundInStorageError",
7
+ "ImproperConfigurationError",
8
+ "IntegrityError",
9
+ "MissingDependencyError",
10
+ "MultipleResultsFoundError",
11
+ "NotFoundError",
12
+ "RepositoryError",
13
+ "SQLBuilderError",
14
+ "SQLConversionError",
15
+ "SQLFileNotFoundError",
16
+ "SQLFileParseError",
17
+ "SQLParsingError",
18
+ "SQLSpecError",
19
+ "SerializationError",
20
+ "StorageOperationFailedError",
21
+ )
22
+
23
+
24
+ class SQLSpecError(Exception):
25
+ """Base exception class for SQLSpec exceptions."""
26
+
27
+ detail: str
28
+
29
+ def __init__(self, *args: Any, detail: str = "") -> None:
30
+ """Initialize SQLSpecError.
31
+
32
+ Args:
33
+ *args: args are converted to :class:`str` before passing to :class:`Exception`
34
+ detail: detail of the exception.
35
+ """
36
+ str_args = [str(arg) for arg in args if arg]
37
+ if not detail:
38
+ if str_args:
39
+ detail, *str_args = str_args
40
+ elif hasattr(self, "detail"):
41
+ detail = self.detail
42
+ self.detail = detail
43
+ super().__init__(*str_args)
44
+
45
+ def __repr__(self) -> str:
46
+ if self.detail:
47
+ return f"{self.__class__.__name__} - {self.detail}"
48
+ return self.__class__.__name__
49
+
50
+ def __str__(self) -> str:
51
+ return " ".join((*self.args, self.detail)).strip()
52
+
53
+
54
+ class MissingDependencyError(SQLSpecError, ImportError):
55
+ """Raised when a required dependency is not installed."""
56
+
57
+ def __init__(self, package: str, install_package: Optional[str] = None) -> None:
58
+ super().__init__(
59
+ f"Package {package!r} is not installed but required. You can install it by running "
60
+ f"'pip install sqlspec[{install_package or package}]' to install sqlspec with the required extra "
61
+ f"or 'pip install {install_package or package}' to install the package separately"
62
+ )
63
+
64
+
65
+ class BackendNotRegisteredError(SQLSpecError):
66
+ """Raised when a requested storage backend key is not registered."""
67
+
68
+ def __init__(self, backend_key: str) -> None:
69
+ super().__init__(f"Storage backend '{backend_key}' is not registered. Please register it before use.")
70
+
71
+
72
+ class SQLParsingError(SQLSpecError):
73
+ """Issues parsing SQL statements."""
74
+
75
+ def __init__(self, message: Optional[str] = None) -> None:
76
+ if message is None:
77
+ message = "Issues parsing SQL statement."
78
+ super().__init__(message)
79
+
80
+
81
+ class SQLBuilderError(SQLSpecError):
82
+ """Issues Building or Generating SQL statements."""
83
+
84
+ def __init__(self, message: Optional[str] = None) -> None:
85
+ if message is None:
86
+ message = "Issues building SQL statement."
87
+ super().__init__(message)
88
+
89
+
90
+ class SQLConversionError(SQLSpecError):
91
+ """Issues converting SQL statements."""
92
+
93
+ def __init__(self, message: Optional[str] = None) -> None:
94
+ if message is None:
95
+ message = "Issues converting SQL statement."
96
+ super().__init__(message)
97
+
98
+
99
+ class ImproperConfigurationError(SQLSpecError):
100
+ """Raised when configuration is invalid or incomplete."""
101
+
102
+
103
+ class SerializationError(SQLSpecError):
104
+ """Encoding or decoding of an object failed."""
105
+
106
+
107
+ class RepositoryError(SQLSpecError):
108
+ """Base repository exception type."""
109
+
110
+
111
+ class IntegrityError(RepositoryError):
112
+ """Data integrity error."""
113
+
114
+
115
+ class NotFoundError(RepositoryError):
116
+ """An identity does not exist."""
117
+
118
+
119
+ class MultipleResultsFoundError(RepositoryError):
120
+ """A single database result was required but more than one were found."""
121
+
122
+
123
+ class StorageOperationFailedError(SQLSpecError):
124
+ """Raised when a storage backend operation fails (e.g., network, permission, API error)."""
125
+
126
+
127
+ class FileNotFoundInStorageError(StorageOperationFailedError):
128
+ """Raised when a file or object is not found in the storage backend."""
129
+
130
+
131
+ class SQLFileNotFoundError(SQLSpecError):
132
+ """Raised when a SQL file cannot be found."""
133
+
134
+ def __init__(self, name: str, path: "Optional[str]" = None) -> None:
135
+ """Initialize the error.
136
+
137
+ Args:
138
+ name: Name of the SQL file.
139
+ path: Optional path where the file was expected.
140
+ """
141
+ message = f"SQL file '{name}' not found at path: {path}" if path else f"SQL file '{name}' not found"
142
+ super().__init__(message)
143
+ self.name = name
144
+ self.path = path
145
+
146
+
147
+ class SQLFileParseError(SQLSpecError):
148
+ """Raised when a SQL file cannot be parsed."""
149
+
150
+ def __init__(self, name: str, path: str, original_error: "Exception") -> None:
151
+ """Initialize the error.
152
+
153
+ Args:
154
+ name: Name of the SQL file.
155
+ path: Path to the SQL file.
156
+ original_error: The underlying parsing error.
157
+ """
158
+ message = f"Failed to parse SQL file '{name}' at {path}: {original_error}"
159
+ super().__init__(message)
160
+ self.name = name
161
+ self.path = path
162
+ self.original_error = original_error
163
+
164
+
165
+ @contextmanager
166
+ def wrap_exceptions(
167
+ wrap_exceptions: bool = True, suppress: "Optional[Union[type[Exception], tuple[type[Exception], ...]]]" = None
168
+ ) -> Generator[None, None, None]:
169
+ """Context manager for exception handling with optional suppression.
170
+
171
+ Args:
172
+ wrap_exceptions: If True, wrap exceptions in RepositoryError. If False, let them pass through.
173
+ suppress: Exception type(s) to suppress completely (like contextlib.suppress).
174
+ If provided, these exceptions are caught and ignored.
175
+ """
176
+ try:
177
+ yield
178
+
179
+ except Exception as exc:
180
+ if suppress is not None and (
181
+ (isinstance(suppress, type) and isinstance(exc, suppress))
182
+ or (isinstance(suppress, tuple) and isinstance(exc, suppress))
183
+ ):
184
+ return # Suppress this exception
185
+
186
+ # If it's already a SQLSpec exception, don't wrap it
187
+ if isinstance(exc, SQLSpecError):
188
+ raise
189
+
190
+ if wrap_exceptions is False:
191
+ raise
192
+ msg = "An error occurred during the operation."
193
+ raise RepositoryError(detail=msg) from exc
File without changes
@@ -0,0 +1,10 @@
1
+ """SQLSpec aiosql integration for loading SQL files.
2
+
3
+ This module provides a simple way to load aiosql-style SQL files and use them
4
+ with SQLSpec drivers. It focuses on just the file parsing functionality,
5
+ returning SQL objects that work with existing SQLSpec execution.
6
+ """
7
+
8
+ from sqlspec.extensions.aiosql.adapter import AiosqlAsyncAdapter, AiosqlSyncAdapter
9
+
10
+ __all__ = ("AiosqlAsyncAdapter", "AiosqlSyncAdapter")
@@ -0,0 +1,461 @@
1
+ """AioSQL adapter implementation for SQLSpec.
2
+
3
+ This module provides adapter classes that implement the aiosql adapter protocols
4
+ while using SQLSpec drivers under the hood. This enables users to load SQL queries
5
+ from files using aiosql while leveraging all of SQLSpec's advanced features.
6
+ """
7
+
8
+ import logging
9
+ from collections.abc import AsyncGenerator, Generator
10
+ from contextlib import asynccontextmanager, contextmanager
11
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypeVar, Union, cast
12
+
13
+ from sqlspec.core.result import SQLResult
14
+ from sqlspec.core.statement import SQL, StatementConfig
15
+ from sqlspec.exceptions import MissingDependencyError
16
+ from sqlspec.typing import AIOSQL_INSTALLED
17
+
18
+ if TYPE_CHECKING:
19
+ from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
20
+
21
+ logger = logging.getLogger("sqlspec.extensions.aiosql")
22
+
23
+ __all__ = ("AiosqlAsyncAdapter", "AiosqlSyncAdapter")
24
+
25
+ T = TypeVar("T")
26
+
27
+
28
+ class AsyncCursorLike:
29
+ def __init__(self, result: Any) -> None:
30
+ self.result = result
31
+
32
+ async def fetchall(self) -> list[Any]:
33
+ if isinstance(self.result, SQLResult) and self.result.data is not None:
34
+ return list(self.result.data)
35
+ return []
36
+
37
+ async def fetchone(self) -> Optional[Any]:
38
+ rows = await self.fetchall()
39
+ return rows[0] if rows else None
40
+
41
+
42
+ class CursorLike:
43
+ def __init__(self, result: Any) -> None:
44
+ self.result = result
45
+
46
+ def fetchall(self) -> list[Any]:
47
+ if isinstance(self.result, SQLResult) and self.result.data is not None:
48
+ return list(self.result.data)
49
+ return []
50
+
51
+ def fetchone(self) -> Optional[Any]:
52
+ rows = self.fetchall()
53
+ return rows[0] if rows else None
54
+
55
+
56
+ def _check_aiosql_available() -> None:
57
+ if not AIOSQL_INSTALLED:
58
+ msg = "aiosql"
59
+ raise MissingDependencyError(msg, "aiosql")
60
+
61
+
62
+ def _normalize_dialect(dialect: "Union[str, Any, None]") -> str:
63
+ """Normalize dialect name for SQLGlot compatibility.
64
+
65
+ Args:
66
+ dialect: Original dialect name (can be str, Dialect, type[Dialect], or None)
67
+
68
+ Returns:
69
+ Converted dialect name compatible with SQLGlot
70
+ """
71
+ if dialect is None:
72
+ return "sql"
73
+
74
+ if hasattr(dialect, "__name__"):
75
+ dialect_str = str(dialect.__name__).lower() # pyright: ignore
76
+ elif hasattr(dialect, "name"):
77
+ dialect_str = str(dialect.name).lower() # pyright: ignore
78
+ elif isinstance(dialect, str):
79
+ dialect_str = dialect.lower()
80
+ else:
81
+ dialect_str = str(dialect).lower()
82
+
83
+ dialect_mapping = {
84
+ "postgresql": "postgres",
85
+ "psycopg": "postgres",
86
+ "asyncpg": "postgres",
87
+ "psqlpy": "postgres",
88
+ "sqlite3": "sqlite",
89
+ "aiosqlite": "sqlite",
90
+ }
91
+ return dialect_mapping.get(dialect_str, dialect_str)
92
+
93
+
94
+ class _AiosqlAdapterBase:
95
+ """Base adapter class providing common functionality for aiosql integration."""
96
+
97
+ def __init__(self, driver: "Union[SyncDriverAdapterBase, AsyncDriverAdapterBase]") -> None:
98
+ """Initialize the base adapter.
99
+
100
+ Args:
101
+ driver: SQLSpec driver to use for execution.
102
+ """
103
+ _check_aiosql_available()
104
+ self.driver = driver
105
+
106
+ def process_sql(self, query_name: str, op_type: "Any", sql: str) -> str:
107
+ """Process SQL string for aiosql compatibility.
108
+
109
+ Args:
110
+ query_name: Name of the query
111
+ op_type: Operation type
112
+ sql: SQL string to process
113
+
114
+ Returns:
115
+ Processed SQL string
116
+ """
117
+ return sql
118
+
119
+ def _create_sql_object(self, sql: str, parameters: "Any" = None) -> SQL:
120
+ """Create SQL object with proper configuration.
121
+
122
+ Args:
123
+ sql: SQL string
124
+ parameters: Query parameters
125
+
126
+ Returns:
127
+ Configured SQL object
128
+ """
129
+ return SQL(
130
+ sql,
131
+ parameters,
132
+ config=StatementConfig(enable_validation=False),
133
+ dialect=_normalize_dialect(getattr(self.driver, "dialect", "sqlite")),
134
+ )
135
+
136
+
137
+ class AiosqlSyncAdapter(_AiosqlAdapterBase):
138
+ """Synchronous adapter that implements aiosql protocol using SQLSpec drivers.
139
+
140
+ This adapter bridges aiosql's synchronous driver protocol with SQLSpec's sync drivers,
141
+ enabling queries loaded by aiosql to be executed with SQLSpec drivers.
142
+ """
143
+
144
+ is_aio_driver: ClassVar[bool] = False
145
+
146
+ def __init__(self, driver: "SyncDriverAdapterBase") -> None:
147
+ """Initialize the sync adapter.
148
+
149
+ Args:
150
+ driver: SQLSpec sync driver to use for execution
151
+ """
152
+ super().__init__(driver)
153
+
154
+ def select(
155
+ self, conn: Any, query_name: str, sql: str, parameters: "Any", record_class: Optional[Any] = None
156
+ ) -> Generator[Any, None, None]:
157
+ """Execute a SELECT query and return results as generator.
158
+
159
+ Args:
160
+ conn: Database connection (passed through to SQLSpec driver)
161
+ query_name: Name of the query
162
+ sql: SQL string
163
+ parameters: Query parameters
164
+ record_class: Deprecated - use schema_type in driver.execute instead
165
+
166
+ Yields:
167
+ Query result rows
168
+
169
+ Note:
170
+ The record_class parameter is ignored for compatibility. Use schema_type
171
+ in driver.execute or _sqlspec_schema_type in parameters for type mapping.
172
+ """
173
+ if record_class is not None:
174
+ logger.warning(
175
+ "record_class parameter is deprecated and ignored. "
176
+ "Use schema_type in driver.execute or _sqlspec_schema_type in parameters."
177
+ )
178
+
179
+ result = self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
180
+
181
+ if isinstance(result, SQLResult) and result.data is not None:
182
+ yield from result.data
183
+
184
+ def select_one(
185
+ self, conn: Any, query_name: str, sql: str, parameters: "Any", record_class: Optional[Any] = None
186
+ ) -> Optional[dict[str, Any]]:
187
+ """Execute a SELECT query and return first result.
188
+
189
+ Args:
190
+ conn: Database connection
191
+ query_name: Name of the query
192
+ sql: SQL string
193
+ parameters: Query parameters
194
+ record_class: Deprecated - use schema_type in driver.execute instead
195
+
196
+ Returns:
197
+ First result row or None
198
+
199
+ Note:
200
+ The record_class parameter is ignored for compatibility. Use schema_type
201
+ in driver.execute or _sqlspec_schema_type in parameters for type mapping.
202
+ """
203
+ if record_class is not None:
204
+ logger.warning(
205
+ "record_class parameter is deprecated and ignored. "
206
+ "Use schema_type in driver.execute or _sqlspec_schema_type in parameters."
207
+ )
208
+
209
+ result = cast("SQLResult", self.driver.execute(self._create_sql_object(sql, parameters), connection=conn))
210
+
211
+ if hasattr(result, "data") and result.data and isinstance(result, SQLResult):
212
+ return cast("Optional[dict[str, Any]]", result.data[0])
213
+ return None
214
+
215
+ def select_value(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> Optional[Any]:
216
+ """Execute a SELECT query and return first value of first row.
217
+
218
+ Args:
219
+ conn: Database connection
220
+ query_name: Name of the query
221
+ sql: SQL string
222
+ parameters: Query parameters
223
+
224
+ Returns:
225
+ First value of first row or None
226
+ """
227
+ row = self.select_one(conn, query_name, sql, parameters)
228
+ if row is None:
229
+ return None
230
+
231
+ if isinstance(row, dict):
232
+ return next(iter(row.values())) if row else None
233
+ if hasattr(row, "__getitem__"):
234
+ return row[0] if len(row) > 0 else None
235
+ return row
236
+
237
+ @contextmanager
238
+ def select_cursor(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> Generator[Any, None, None]:
239
+ """Execute a SELECT query and return cursor context manager.
240
+
241
+ Args:
242
+ conn: Database connection
243
+ query_name: Name of the query
244
+ sql: SQL string
245
+ parameters: Query parameters
246
+
247
+ Yields:
248
+ Cursor-like object with results
249
+ """
250
+ result = self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
251
+
252
+ yield CursorLike(result)
253
+
254
+ def insert_update_delete(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> int:
255
+ """Execute INSERT/UPDATE/DELETE and return affected rows.
256
+
257
+ Args:
258
+ conn: Database connection
259
+ query_name: Name of the query
260
+ sql: SQL string
261
+ parameters: Query parameters
262
+
263
+ Returns:
264
+ Number of affected rows
265
+ """
266
+ result = cast("SQLResult", self.driver.execute(self._create_sql_object(sql, parameters), connection=conn))
267
+
268
+ return result.rows_affected if hasattr(result, "rows_affected") else 0
269
+
270
+ def insert_update_delete_many(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> int:
271
+ """Execute INSERT/UPDATE/DELETE with many parameter sets.
272
+
273
+ Args:
274
+ conn: Database connection
275
+ query_name: Name of the query
276
+ sql: SQL string
277
+ parameters: Sequence of parameter sets
278
+
279
+ Returns:
280
+ Number of affected rows
281
+ """
282
+ result = cast(
283
+ "SQLResult", self.driver.execute_many(self._create_sql_object(sql), parameters=parameters, connection=conn)
284
+ )
285
+
286
+ return result.rows_affected if hasattr(result, "rows_affected") else 0
287
+
288
+ def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> Optional[Any]:
289
+ """Execute INSERT with RETURNING and return result.
290
+
291
+ Args:
292
+ conn: Database connection
293
+ query_name: Name of the query
294
+ sql: SQL string
295
+ parameters: Query parameters
296
+
297
+ Returns:
298
+ Returned value or None
299
+ """
300
+ return self.select_one(conn, query_name, sql, parameters)
301
+
302
+
303
+ class AiosqlAsyncAdapter(_AiosqlAdapterBase):
304
+ """Asynchronous adapter that implements aiosql protocol using SQLSpec drivers.
305
+
306
+ This adapter bridges aiosql's async driver protocol with SQLSpec's async drivers,
307
+ enabling queries loaded by aiosql to be executed with SQLSpec async drivers.
308
+ """
309
+
310
+ is_aio_driver: ClassVar[bool] = True
311
+
312
+ def __init__(self, driver: "AsyncDriverAdapterBase") -> None:
313
+ """Initialize the async adapter.
314
+
315
+ Args:
316
+ driver: SQLSpec async driver to use for execution
317
+ """
318
+ super().__init__(driver)
319
+
320
+ async def select(
321
+ self, conn: Any, query_name: str, sql: str, parameters: "Any", record_class: Optional[Any] = None
322
+ ) -> list[Any]:
323
+ """Execute a SELECT query and return results as list.
324
+
325
+ Args:
326
+ conn: Database connection
327
+ query_name: Name of the query
328
+ sql: SQL string
329
+ parameters: Query parameters
330
+ record_class: Deprecated - use schema_type in driver.execute instead
331
+
332
+ Returns:
333
+ List of query result rows
334
+
335
+ Note:
336
+ The record_class parameter is ignored for compatibility. Use schema_type
337
+ in driver.execute or _sqlspec_schema_type in parameters for type mapping.
338
+ """
339
+ if record_class is not None:
340
+ logger.warning(
341
+ "record_class parameter is deprecated and ignored. "
342
+ "Use schema_type in driver.execute or _sqlspec_schema_type in parameters."
343
+ )
344
+
345
+ result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn) # type: ignore[misc]
346
+
347
+ if hasattr(result, "data") and result.data is not None and isinstance(result, SQLResult):
348
+ return list(result.data)
349
+ return []
350
+
351
+ async def select_one(
352
+ self, conn: Any, query_name: str, sql: str, parameters: "Any", record_class: Optional[Any] = None
353
+ ) -> Optional[Any]:
354
+ """Execute a SELECT query and return first result.
355
+
356
+ Args:
357
+ conn: Database connection
358
+ query_name: Name of the query
359
+ sql: SQL string
360
+ parameters: Query parameters
361
+ record_class: Deprecated - use schema_type in driver.execute instead
362
+
363
+ Returns:
364
+ First result row or None
365
+
366
+ Note:
367
+ The record_class parameter is ignored for compatibility. Use schema_type
368
+ in driver.execute or _sqlspec_schema_type in parameters for type mapping.
369
+ """
370
+ if record_class is not None:
371
+ logger.warning(
372
+ "record_class parameter is deprecated and ignored. "
373
+ "Use schema_type in driver.execute or _sqlspec_schema_type in parameters."
374
+ )
375
+
376
+ result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn) # type: ignore[misc]
377
+
378
+ if hasattr(result, "data") and result.data and isinstance(result, SQLResult):
379
+ return result.data[0]
380
+ return None
381
+
382
+ async def select_value(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> Optional[Any]:
383
+ """Execute a SELECT query and return first value of first row.
384
+
385
+ Args:
386
+ conn: Database connection
387
+ query_name: Name of the query
388
+ sql: SQL string
389
+ parameters: Query parameters
390
+
391
+ Returns:
392
+ First value of first row or None
393
+ """
394
+ row = await self.select_one(conn, query_name, sql, parameters)
395
+ if row is None:
396
+ return None
397
+
398
+ if isinstance(row, dict):
399
+ return next(iter(row.values())) if row else None
400
+ if hasattr(row, "__getitem__"):
401
+ return row[0] if len(row) > 0 else None
402
+ return row
403
+
404
+ @asynccontextmanager
405
+ async def select_cursor(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> AsyncGenerator[Any, None]:
406
+ """Execute a SELECT query and return cursor context manager.
407
+
408
+ Args:
409
+ conn: Database connection
410
+ query_name: Name of the query
411
+ sql: SQL string
412
+ parameters: Query parameters
413
+
414
+ Yields:
415
+ Cursor-like object with results
416
+ """
417
+ result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn) # type: ignore[misc]
418
+
419
+ yield AsyncCursorLike(result)
420
+
421
+ async def insert_update_delete(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> None:
422
+ """Execute INSERT/UPDATE/DELETE.
423
+
424
+ Args:
425
+ conn: Database connection
426
+ query_name: Name of the query
427
+ sql: SQL string
428
+ parameters: Query parameters
429
+
430
+ Note:
431
+ Returns None per aiosql async protocol
432
+ """
433
+ await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn) # type: ignore[misc]
434
+
435
+ async def insert_update_delete_many(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> None:
436
+ """Execute INSERT/UPDATE/DELETE with many parameter sets.
437
+
438
+ Args:
439
+ conn: Database connection
440
+ query_name: Name of the query
441
+ sql: SQL string
442
+ parameters: Sequence of parameter sets
443
+
444
+ Note:
445
+ Returns None per aiosql async protocol
446
+ """
447
+ await self.driver.execute_many(self._create_sql_object(sql), parameters=parameters, connection=conn) # type: ignore[misc]
448
+
449
+ async def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: "Any") -> Optional[Any]:
450
+ """Execute INSERT with RETURNING and return result.
451
+
452
+ Args:
453
+ conn: Database connection
454
+ query_name: Name of the query
455
+ sql: SQL string
456
+ parameters: Query parameters
457
+
458
+ Returns:
459
+ Returned value or None
460
+ """
461
+ return await self.select_one(conn, query_name, sql, parameters)
@@ -0,0 +1,6 @@
1
+ from sqlspec.extensions.litestar import handlers, providers
2
+ from sqlspec.extensions.litestar.cli import database_group
3
+ from sqlspec.extensions.litestar.config import DatabaseConfig
4
+ from sqlspec.extensions.litestar.plugin import SQLSpec
5
+
6
+ __all__ = ("DatabaseConfig", "SQLSpec", "database_group", "handlers", "providers")