sqlspec 0.26.0__py3-none-any.whl → 0.28.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 +7 -15
- sqlspec/_serialization.py +55 -25
- sqlspec/_typing.py +155 -52
- sqlspec/adapters/adbc/_types.py +1 -1
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +880 -0
- sqlspec/adapters/adbc/config.py +62 -12
- sqlspec/adapters/adbc/data_dictionary.py +74 -2
- sqlspec/adapters/adbc/driver.py +226 -58
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +504 -0
- sqlspec/adapters/adbc/type_converter.py +44 -50
- sqlspec/adapters/aiosqlite/_types.py +1 -1
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +536 -0
- sqlspec/adapters/aiosqlite/config.py +86 -16
- sqlspec/adapters/aiosqlite/data_dictionary.py +34 -2
- sqlspec/adapters/aiosqlite/driver.py +127 -38
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +281 -0
- sqlspec/adapters/aiosqlite/pool.py +7 -7
- sqlspec/adapters/asyncmy/__init__.py +7 -1
- sqlspec/adapters/asyncmy/_types.py +1 -1
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +503 -0
- sqlspec/adapters/asyncmy/config.py +59 -17
- sqlspec/adapters/asyncmy/data_dictionary.py +41 -2
- sqlspec/adapters/asyncmy/driver.py +293 -62
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +2 -1
- sqlspec/adapters/asyncpg/_type_handlers.py +71 -0
- sqlspec/adapters/asyncpg/_types.py +11 -7
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +460 -0
- sqlspec/adapters/asyncpg/config.py +57 -36
- sqlspec/adapters/asyncpg/data_dictionary.py +48 -2
- sqlspec/adapters/asyncpg/driver.py +153 -23
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +253 -0
- sqlspec/adapters/bigquery/_types.py +1 -1
- sqlspec/adapters/bigquery/adk/__init__.py +5 -0
- sqlspec/adapters/bigquery/adk/store.py +585 -0
- sqlspec/adapters/bigquery/config.py +36 -11
- sqlspec/adapters/bigquery/data_dictionary.py +42 -2
- sqlspec/adapters/bigquery/driver.py +489 -144
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +327 -0
- sqlspec/adapters/bigquery/type_converter.py +55 -23
- sqlspec/adapters/duckdb/_types.py +2 -2
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +563 -0
- sqlspec/adapters/duckdb/config.py +79 -21
- sqlspec/adapters/duckdb/data_dictionary.py +41 -2
- sqlspec/adapters/duckdb/driver.py +225 -44
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +332 -0
- sqlspec/adapters/duckdb/pool.py +5 -5
- sqlspec/adapters/duckdb/type_converter.py +51 -21
- sqlspec/adapters/oracledb/_numpy_handlers.py +133 -0
- sqlspec/adapters/oracledb/_types.py +20 -2
- sqlspec/adapters/oracledb/adk/__init__.py +5 -0
- sqlspec/adapters/oracledb/adk/store.py +1628 -0
- sqlspec/adapters/oracledb/config.py +120 -36
- sqlspec/adapters/oracledb/data_dictionary.py +87 -20
- sqlspec/adapters/oracledb/driver.py +475 -86
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +765 -0
- sqlspec/adapters/oracledb/migrations.py +316 -25
- sqlspec/adapters/oracledb/type_converter.py +91 -16
- sqlspec/adapters/psqlpy/_type_handlers.py +44 -0
- sqlspec/adapters/psqlpy/_types.py +2 -1
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +483 -0
- sqlspec/adapters/psqlpy/config.py +45 -19
- sqlspec/adapters/psqlpy/data_dictionary.py +48 -2
- sqlspec/adapters/psqlpy/driver.py +108 -41
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +272 -0
- sqlspec/adapters/psqlpy/type_converter.py +40 -11
- sqlspec/adapters/psycopg/_type_handlers.py +80 -0
- sqlspec/adapters/psycopg/_types.py +2 -1
- sqlspec/adapters/psycopg/adk/__init__.py +5 -0
- sqlspec/adapters/psycopg/adk/store.py +962 -0
- sqlspec/adapters/psycopg/config.py +65 -37
- sqlspec/adapters/psycopg/data_dictionary.py +91 -3
- sqlspec/adapters/psycopg/driver.py +200 -78
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +554 -0
- sqlspec/adapters/sqlite/__init__.py +2 -1
- sqlspec/adapters/sqlite/_type_handlers.py +86 -0
- sqlspec/adapters/sqlite/_types.py +1 -1
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +582 -0
- sqlspec/adapters/sqlite/config.py +85 -16
- sqlspec/adapters/sqlite/data_dictionary.py +34 -2
- sqlspec/adapters/sqlite/driver.py +120 -52
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +318 -0
- sqlspec/adapters/sqlite/pool.py +5 -5
- sqlspec/base.py +45 -26
- sqlspec/builder/__init__.py +73 -4
- sqlspec/builder/_base.py +91 -58
- sqlspec/builder/_column.py +5 -5
- sqlspec/builder/_ddl.py +98 -89
- sqlspec/builder/_delete.py +5 -4
- sqlspec/builder/_dml.py +388 -0
- sqlspec/{_sql.py → builder/_factory.py} +41 -44
- sqlspec/builder/_insert.py +5 -82
- sqlspec/builder/{mixins/_join_operations.py → _join.py} +145 -143
- sqlspec/builder/_merge.py +446 -11
- sqlspec/builder/_parsing_utils.py +9 -11
- sqlspec/builder/_select.py +1313 -25
- sqlspec/builder/_update.py +11 -42
- sqlspec/cli.py +76 -69
- sqlspec/config.py +331 -62
- sqlspec/core/__init__.py +5 -4
- sqlspec/core/cache.py +18 -18
- sqlspec/core/compiler.py +6 -8
- sqlspec/core/filters.py +55 -47
- sqlspec/core/hashing.py +9 -9
- sqlspec/core/parameters.py +76 -45
- sqlspec/core/result.py +234 -47
- sqlspec/core/splitter.py +16 -17
- sqlspec/core/statement.py +32 -31
- sqlspec/core/type_conversion.py +3 -2
- sqlspec/driver/__init__.py +1 -3
- sqlspec/driver/_async.py +183 -160
- sqlspec/driver/_common.py +197 -109
- sqlspec/driver/_sync.py +189 -161
- sqlspec/driver/mixins/_result_tools.py +20 -236
- sqlspec/driver/mixins/_sql_translator.py +4 -4
- sqlspec/exceptions.py +70 -7
- sqlspec/extensions/adk/__init__.py +53 -0
- sqlspec/extensions/adk/_types.py +51 -0
- sqlspec/extensions/adk/converters.py +172 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +144 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +181 -0
- sqlspec/extensions/adk/store.py +536 -0
- sqlspec/extensions/aiosql/adapter.py +69 -61
- sqlspec/extensions/fastapi/__init__.py +21 -0
- sqlspec/extensions/fastapi/extension.py +331 -0
- sqlspec/extensions/fastapi/providers.py +543 -0
- sqlspec/extensions/flask/__init__.py +36 -0
- sqlspec/extensions/flask/_state.py +71 -0
- sqlspec/extensions/flask/_utils.py +40 -0
- sqlspec/extensions/flask/extension.py +389 -0
- sqlspec/extensions/litestar/__init__.py +21 -4
- sqlspec/extensions/litestar/cli.py +54 -10
- sqlspec/extensions/litestar/config.py +56 -266
- sqlspec/extensions/litestar/handlers.py +46 -17
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +349 -224
- sqlspec/extensions/litestar/providers.py +25 -25
- sqlspec/extensions/litestar/store.py +265 -0
- sqlspec/extensions/starlette/__init__.py +10 -0
- sqlspec/extensions/starlette/_state.py +25 -0
- sqlspec/extensions/starlette/_utils.py +52 -0
- sqlspec/extensions/starlette/extension.py +254 -0
- sqlspec/extensions/starlette/middleware.py +154 -0
- sqlspec/loader.py +30 -49
- sqlspec/migrations/base.py +200 -76
- sqlspec/migrations/commands.py +591 -62
- sqlspec/migrations/context.py +6 -9
- sqlspec/migrations/fix.py +199 -0
- sqlspec/migrations/loaders.py +47 -19
- sqlspec/migrations/runner.py +241 -75
- sqlspec/migrations/tracker.py +237 -21
- sqlspec/migrations/utils.py +51 -3
- sqlspec/migrations/validation.py +177 -0
- sqlspec/protocols.py +106 -36
- sqlspec/storage/_utils.py +85 -0
- sqlspec/storage/backends/fsspec.py +133 -107
- sqlspec/storage/backends/local.py +78 -51
- sqlspec/storage/backends/obstore.py +276 -168
- sqlspec/storage/registry.py +75 -39
- sqlspec/typing.py +30 -84
- sqlspec/utils/__init__.py +25 -4
- sqlspec/utils/arrow_helpers.py +81 -0
- sqlspec/utils/config_resolver.py +6 -6
- sqlspec/utils/correlation.py +4 -5
- sqlspec/utils/data_transformation.py +3 -2
- sqlspec/utils/deprecation.py +9 -8
- sqlspec/utils/fixtures.py +4 -4
- sqlspec/utils/logging.py +46 -6
- sqlspec/utils/module_loader.py +205 -5
- sqlspec/utils/portal.py +311 -0
- sqlspec/utils/schema.py +288 -0
- sqlspec/utils/serializers.py +113 -4
- sqlspec/utils/sync_tools.py +36 -22
- sqlspec/utils/text.py +1 -2
- sqlspec/utils/type_guards.py +136 -20
- sqlspec/utils/version.py +433 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/METADATA +41 -22
- sqlspec-0.28.0.dist-info/RECORD +221 -0
- sqlspec/builder/mixins/__init__.py +0 -55
- sqlspec/builder/mixins/_cte_and_set_ops.py +0 -253
- sqlspec/builder/mixins/_delete_operations.py +0 -50
- sqlspec/builder/mixins/_insert_operations.py +0 -282
- sqlspec/builder/mixins/_merge_operations.py +0 -698
- sqlspec/builder/mixins/_order_limit_operations.py +0 -145
- sqlspec/builder/mixins/_pivot_operations.py +0 -157
- sqlspec/builder/mixins/_select_operations.py +0 -930
- sqlspec/builder/mixins/_update_operations.py +0 -199
- sqlspec/builder/mixins/_where_clause.py +0 -1298
- sqlspec-0.26.0.dist-info/RECORD +0 -157
- sqlspec-0.26.0.dist-info/licenses/NOTICE +0 -29
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,23 +6,22 @@ from files using aiosql while using SQLSpec's features for execution and type ma
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import logging
|
|
9
|
-
from collections.abc import
|
|
10
|
-
from contextlib import
|
|
11
|
-
from typing import
|
|
9
|
+
from collections.abc import Generator
|
|
10
|
+
from contextlib import contextmanager
|
|
11
|
+
from typing import Any, ClassVar, Generic, TypeVar
|
|
12
12
|
|
|
13
13
|
from sqlspec.core.result import SQLResult
|
|
14
14
|
from sqlspec.core.statement import SQL, StatementConfig
|
|
15
|
-
from sqlspec.
|
|
16
|
-
from sqlspec.typing import
|
|
17
|
-
|
|
18
|
-
if TYPE_CHECKING:
|
|
19
|
-
from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
|
|
15
|
+
from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
|
|
16
|
+
from sqlspec.typing import AiosqlAsyncProtocol, AiosqlParamType, AiosqlSQLOperationType, AiosqlSyncProtocol
|
|
17
|
+
from sqlspec.utils.module_loader import ensure_aiosql
|
|
20
18
|
|
|
21
19
|
logger = logging.getLogger("sqlspec.extensions.aiosql")
|
|
22
20
|
|
|
23
21
|
__all__ = ("AiosqlAsyncAdapter", "AiosqlSyncAdapter")
|
|
24
22
|
|
|
25
23
|
T = TypeVar("T")
|
|
24
|
+
DriverT = TypeVar("DriverT", bound="SyncDriverAdapterBase | AsyncDriverAdapterBase")
|
|
26
25
|
|
|
27
26
|
|
|
28
27
|
class AsyncCursorLike:
|
|
@@ -34,7 +33,7 @@ class AsyncCursorLike:
|
|
|
34
33
|
return list(self.result.data)
|
|
35
34
|
return []
|
|
36
35
|
|
|
37
|
-
async def fetchone(self) ->
|
|
36
|
+
async def fetchone(self) -> Any | None:
|
|
38
37
|
rows = await self.fetchall()
|
|
39
38
|
return rows[0] if rows else None
|
|
40
39
|
|
|
@@ -48,18 +47,12 @@ class CursorLike:
|
|
|
48
47
|
return list(self.result.data)
|
|
49
48
|
return []
|
|
50
49
|
|
|
51
|
-
def fetchone(self) ->
|
|
50
|
+
def fetchone(self) -> Any | None:
|
|
52
51
|
rows = self.fetchall()
|
|
53
52
|
return rows[0] if rows else None
|
|
54
53
|
|
|
55
54
|
|
|
56
|
-
def
|
|
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:
|
|
55
|
+
def _normalize_dialect(dialect: "str | Any | None") -> str:
|
|
63
56
|
"""Normalize dialect name for SQLGlot compatibility.
|
|
64
57
|
|
|
65
58
|
Args:
|
|
@@ -71,12 +64,12 @@ def _normalize_dialect(dialect: "Union[str, Any, None]") -> str:
|
|
|
71
64
|
if dialect is None:
|
|
72
65
|
return "sql"
|
|
73
66
|
|
|
74
|
-
if
|
|
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):
|
|
67
|
+
if isinstance(dialect, str):
|
|
79
68
|
dialect_str = dialect.lower()
|
|
69
|
+
elif hasattr(dialect, "__name__"):
|
|
70
|
+
dialect_str = str(dialect.__name__).lower()
|
|
71
|
+
elif hasattr(dialect, "name"):
|
|
72
|
+
dialect_str = str(dialect.name).lower()
|
|
80
73
|
else:
|
|
81
74
|
dialect_str = str(dialect).lower()
|
|
82
75
|
|
|
@@ -91,19 +84,19 @@ def _normalize_dialect(dialect: "Union[str, Any, None]") -> str:
|
|
|
91
84
|
return dialect_mapping.get(dialect_str, dialect_str)
|
|
92
85
|
|
|
93
86
|
|
|
94
|
-
class _AiosqlAdapterBase:
|
|
87
|
+
class _AiosqlAdapterBase(Generic[DriverT]):
|
|
95
88
|
"""Base adapter class providing common functionality for aiosql integration."""
|
|
96
89
|
|
|
97
|
-
def __init__(self, driver:
|
|
90
|
+
def __init__(self, driver: DriverT) -> None:
|
|
98
91
|
"""Initialize the base adapter.
|
|
99
92
|
|
|
100
93
|
Args:
|
|
101
94
|
driver: SQLSpec driver to use for execution.
|
|
102
95
|
"""
|
|
103
|
-
|
|
104
|
-
self.driver = driver
|
|
96
|
+
ensure_aiosql()
|
|
97
|
+
self.driver: DriverT = driver
|
|
105
98
|
|
|
106
|
-
def process_sql(self, query_name: str, op_type: "
|
|
99
|
+
def process_sql(self, query_name: str, op_type: "AiosqlSQLOperationType", sql: str) -> str:
|
|
107
100
|
"""Process SQL string for aiosql compatibility.
|
|
108
101
|
|
|
109
102
|
Args:
|
|
@@ -116,7 +109,7 @@ class _AiosqlAdapterBase:
|
|
|
116
109
|
"""
|
|
117
110
|
return sql
|
|
118
111
|
|
|
119
|
-
def _create_sql_object(self, sql: str, parameters: "
|
|
112
|
+
def _create_sql_object(self, sql: str, parameters: "AiosqlParamType" = None) -> SQL:
|
|
120
113
|
"""Create SQL object with proper configuration.
|
|
121
114
|
|
|
122
115
|
Args:
|
|
@@ -134,7 +127,7 @@ class _AiosqlAdapterBase:
|
|
|
134
127
|
)
|
|
135
128
|
|
|
136
129
|
|
|
137
|
-
class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
130
|
+
class AiosqlSyncAdapter(_AiosqlAdapterBase[SyncDriverAdapterBase], AiosqlSyncProtocol):
|
|
138
131
|
"""Synchronous adapter that implements aiosql protocol using SQLSpec drivers.
|
|
139
132
|
|
|
140
133
|
This adapter bridges aiosql's synchronous driver protocol with SQLSpec's sync drivers,
|
|
@@ -152,7 +145,7 @@ class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
|
152
145
|
super().__init__(driver)
|
|
153
146
|
|
|
154
147
|
def select(
|
|
155
|
-
self, conn: Any, query_name: str, sql: str, parameters: "
|
|
148
|
+
self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType", record_class: Any | None = None
|
|
156
149
|
) -> Generator[Any, None, None]:
|
|
157
150
|
"""Execute a SELECT query and return results as generator.
|
|
158
151
|
|
|
@@ -182,8 +175,8 @@ class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
|
182
175
|
yield from result.data
|
|
183
176
|
|
|
184
177
|
def select_one(
|
|
185
|
-
self, conn: Any, query_name: str, sql: str, parameters: "
|
|
186
|
-
) ->
|
|
178
|
+
self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType", record_class: Any | None = None
|
|
179
|
+
) -> tuple[Any, ...] | None:
|
|
187
180
|
"""Execute a SELECT query and return first result.
|
|
188
181
|
|
|
189
182
|
Args:
|
|
@@ -206,13 +199,14 @@ class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
|
206
199
|
"Use schema_type in driver.execute or _sqlspec_schema_type in parameters."
|
|
207
200
|
)
|
|
208
201
|
|
|
209
|
-
result =
|
|
202
|
+
result = self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
210
203
|
|
|
211
204
|
if hasattr(result, "data") and result.data and isinstance(result, SQLResult):
|
|
212
|
-
|
|
205
|
+
row = result.data[0]
|
|
206
|
+
return tuple(row.values()) if isinstance(row, dict) else row
|
|
213
207
|
return None
|
|
214
208
|
|
|
215
|
-
def select_value(self, conn: Any, query_name: str, sql: str, parameters: "
|
|
209
|
+
def select_value(self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType") -> Any | None:
|
|
216
210
|
"""Execute a SELECT query and return first value of first row.
|
|
217
211
|
|
|
218
212
|
Args:
|
|
@@ -235,7 +229,9 @@ class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
|
235
229
|
return row
|
|
236
230
|
|
|
237
231
|
@contextmanager
|
|
238
|
-
def select_cursor(
|
|
232
|
+
def select_cursor(
|
|
233
|
+
self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType"
|
|
234
|
+
) -> Generator[Any, None, None]:
|
|
239
235
|
"""Execute a SELECT query and return cursor context manager.
|
|
240
236
|
|
|
241
237
|
Args:
|
|
@@ -251,7 +247,7 @@ class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
|
251
247
|
|
|
252
248
|
yield CursorLike(result)
|
|
253
249
|
|
|
254
|
-
def insert_update_delete(self, conn: Any, query_name: str, sql: str, parameters: "
|
|
250
|
+
def insert_update_delete(self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType") -> int:
|
|
255
251
|
"""Execute INSERT/UPDATE/DELETE and return affected rows.
|
|
256
252
|
|
|
257
253
|
Args:
|
|
@@ -263,11 +259,11 @@ class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
|
263
259
|
Returns:
|
|
264
260
|
Number of affected rows
|
|
265
261
|
"""
|
|
266
|
-
result =
|
|
262
|
+
result = self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
267
263
|
|
|
268
264
|
return result.rows_affected if hasattr(result, "rows_affected") else 0
|
|
269
265
|
|
|
270
|
-
def insert_update_delete_many(self, conn: Any, query_name: str, sql: str, parameters: "
|
|
266
|
+
def insert_update_delete_many(self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType") -> int:
|
|
271
267
|
"""Execute INSERT/UPDATE/DELETE with many parameter sets.
|
|
272
268
|
|
|
273
269
|
Args:
|
|
@@ -279,13 +275,11 @@ class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
|
279
275
|
Returns:
|
|
280
276
|
Number of affected rows
|
|
281
277
|
"""
|
|
282
|
-
result =
|
|
283
|
-
"SQLResult", self.driver.execute_many(self._create_sql_object(sql), parameters=parameters, connection=conn)
|
|
284
|
-
)
|
|
278
|
+
result = self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
285
279
|
|
|
286
280
|
return result.rows_affected if hasattr(result, "rows_affected") else 0
|
|
287
281
|
|
|
288
|
-
def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: "
|
|
282
|
+
def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType") -> Any | None:
|
|
289
283
|
"""Execute INSERT with RETURNING and return result.
|
|
290
284
|
|
|
291
285
|
Args:
|
|
@@ -300,7 +294,18 @@ class AiosqlSyncAdapter(_AiosqlAdapterBase):
|
|
|
300
294
|
return self.select_one(conn, query_name, sql, parameters)
|
|
301
295
|
|
|
302
296
|
|
|
303
|
-
class
|
|
297
|
+
class _AsyncCursorContextManager(Generic[T]):
|
|
298
|
+
def __init__(self, cursor_like: T) -> None:
|
|
299
|
+
self._cursor_like = cursor_like
|
|
300
|
+
|
|
301
|
+
async def __aenter__(self) -> T:
|
|
302
|
+
return self._cursor_like
|
|
303
|
+
|
|
304
|
+
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class AiosqlAsyncAdapter(_AiosqlAdapterBase[AsyncDriverAdapterBase], AiosqlAsyncProtocol):
|
|
304
309
|
"""Asynchronous adapter that implements aiosql protocol using SQLSpec drivers.
|
|
305
310
|
|
|
306
311
|
This adapter bridges aiosql's async driver protocol with SQLSpec's async drivers,
|
|
@@ -318,7 +323,7 @@ class AiosqlAsyncAdapter(_AiosqlAdapterBase):
|
|
|
318
323
|
super().__init__(driver)
|
|
319
324
|
|
|
320
325
|
async def select(
|
|
321
|
-
self, conn: Any, query_name: str, sql: str, parameters: "
|
|
326
|
+
self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType", record_class: Any | None = None
|
|
322
327
|
) -> list[Any]:
|
|
323
328
|
"""Execute a SELECT query and return results as list.
|
|
324
329
|
|
|
@@ -342,15 +347,15 @@ class AiosqlAsyncAdapter(_AiosqlAdapterBase):
|
|
|
342
347
|
"Use schema_type in driver.execute or _sqlspec_schema_type in parameters."
|
|
343
348
|
)
|
|
344
349
|
|
|
345
|
-
result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
350
|
+
result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
346
351
|
|
|
347
352
|
if hasattr(result, "data") and result.data is not None and isinstance(result, SQLResult):
|
|
348
353
|
return list(result.data)
|
|
349
354
|
return []
|
|
350
355
|
|
|
351
356
|
async def select_one(
|
|
352
|
-
self, conn: Any, query_name: str, sql: str, parameters: "
|
|
353
|
-
) ->
|
|
357
|
+
self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType", record_class: Any | None = None
|
|
358
|
+
) -> Any | None:
|
|
354
359
|
"""Execute a SELECT query and return first result.
|
|
355
360
|
|
|
356
361
|
Args:
|
|
@@ -373,13 +378,14 @@ class AiosqlAsyncAdapter(_AiosqlAdapterBase):
|
|
|
373
378
|
"Use schema_type in driver.execute or _sqlspec_schema_type in parameters."
|
|
374
379
|
)
|
|
375
380
|
|
|
376
|
-
result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
381
|
+
result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
377
382
|
|
|
378
383
|
if hasattr(result, "data") and result.data and isinstance(result, SQLResult):
|
|
379
|
-
|
|
384
|
+
row = result.data[0]
|
|
385
|
+
return tuple(row.values()) if isinstance(row, dict) else row
|
|
380
386
|
return None
|
|
381
387
|
|
|
382
|
-
async def select_value(self, conn: Any, query_name: str, sql: str, parameters: "
|
|
388
|
+
async def select_value(self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType") -> Any | None:
|
|
383
389
|
"""Execute a SELECT query and return first value of first row.
|
|
384
390
|
|
|
385
391
|
Args:
|
|
@@ -401,8 +407,9 @@ class AiosqlAsyncAdapter(_AiosqlAdapterBase):
|
|
|
401
407
|
return row[0] if len(row) > 0 else None
|
|
402
408
|
return row
|
|
403
409
|
|
|
404
|
-
|
|
405
|
-
|
|
410
|
+
async def select_cursor(
|
|
411
|
+
self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType"
|
|
412
|
+
) -> "_AsyncCursorContextManager[Any]":
|
|
406
413
|
"""Execute a SELECT query and return cursor context manager.
|
|
407
414
|
|
|
408
415
|
Args:
|
|
@@ -414,11 +421,10 @@ class AiosqlAsyncAdapter(_AiosqlAdapterBase):
|
|
|
414
421
|
Yields:
|
|
415
422
|
Cursor-like object with results
|
|
416
423
|
"""
|
|
417
|
-
result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
418
|
-
|
|
419
|
-
yield AsyncCursorLike(result)
|
|
424
|
+
result = await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
425
|
+
return _AsyncCursorContextManager(AsyncCursorLike(result))
|
|
420
426
|
|
|
421
|
-
async def insert_update_delete(self, conn: Any, query_name: str, sql: str, parameters: "
|
|
427
|
+
async def insert_update_delete(self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType") -> None:
|
|
422
428
|
"""Execute INSERT/UPDATE/DELETE.
|
|
423
429
|
|
|
424
430
|
Args:
|
|
@@ -430,9 +436,11 @@ class AiosqlAsyncAdapter(_AiosqlAdapterBase):
|
|
|
430
436
|
Note:
|
|
431
437
|
Returns None per aiosql async protocol
|
|
432
438
|
"""
|
|
433
|
-
await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
439
|
+
await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
434
440
|
|
|
435
|
-
async def insert_update_delete_many(
|
|
441
|
+
async def insert_update_delete_many(
|
|
442
|
+
self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType"
|
|
443
|
+
) -> None:
|
|
436
444
|
"""Execute INSERT/UPDATE/DELETE with many parameter sets.
|
|
437
445
|
|
|
438
446
|
Args:
|
|
@@ -444,9 +452,9 @@ class AiosqlAsyncAdapter(_AiosqlAdapterBase):
|
|
|
444
452
|
Note:
|
|
445
453
|
Returns None per aiosql async protocol
|
|
446
454
|
"""
|
|
447
|
-
await self.driver.
|
|
455
|
+
await self.driver.execute(self._create_sql_object(sql, parameters), connection=conn)
|
|
448
456
|
|
|
449
|
-
async def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: "
|
|
457
|
+
async def insert_returning(self, conn: Any, query_name: str, sql: str, parameters: "AiosqlParamType") -> Any | None:
|
|
450
458
|
"""Execute INSERT with RETURNING and return result.
|
|
451
459
|
|
|
452
460
|
Args:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""FastAPI extension for SQLSpec.
|
|
2
|
+
|
|
3
|
+
Extends Starlette integration with dependency injection helpers for FastAPI's
|
|
4
|
+
Depends() system, including filter dependency builders.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from sqlspec.config import StarletteConfig
|
|
8
|
+
from sqlspec.extensions.fastapi.extension import SQLSpecPlugin
|
|
9
|
+
from sqlspec.extensions.fastapi.providers import DependencyDefaults, FieldNameType, FilterConfig, provide_filters
|
|
10
|
+
from sqlspec.extensions.starlette.middleware import SQLSpecAutocommitMiddleware, SQLSpecManualMiddleware
|
|
11
|
+
|
|
12
|
+
__all__ = (
|
|
13
|
+
"DependencyDefaults",
|
|
14
|
+
"FieldNameType",
|
|
15
|
+
"FilterConfig",
|
|
16
|
+
"SQLSpecAutocommitMiddleware",
|
|
17
|
+
"SQLSpecManualMiddleware",
|
|
18
|
+
"SQLSpecPlugin",
|
|
19
|
+
"StarletteConfig",
|
|
20
|
+
"provide_filters",
|
|
21
|
+
)
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any, overload
|
|
2
|
+
|
|
3
|
+
from fastapi import Request
|
|
4
|
+
|
|
5
|
+
from sqlspec.extensions.fastapi.providers import DEPENDENCY_DEFAULTS
|
|
6
|
+
from sqlspec.extensions.fastapi.providers import provide_filters as _provide_filters
|
|
7
|
+
from sqlspec.extensions.starlette.extension import SQLSpecPlugin as _StarlettePlugin
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
|
|
12
|
+
from sqlspec.config import AsyncDatabaseConfig, SyncDatabaseConfig
|
|
13
|
+
from sqlspec.core.filters import FilterTypes
|
|
14
|
+
from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
|
|
15
|
+
from sqlspec.extensions.fastapi.providers import DependencyDefaults, FilterConfig
|
|
16
|
+
|
|
17
|
+
__all__ = ("SQLSpecPlugin",)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SQLSpecPlugin(_StarlettePlugin):
|
|
21
|
+
"""SQLSpec integration for FastAPI applications.
|
|
22
|
+
|
|
23
|
+
Extends Starlette integration with dependency injection helpers for FastAPI's
|
|
24
|
+
Depends() system.
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
from fastapi import Depends, FastAPI
|
|
28
|
+
from sqlspec import SQLSpec
|
|
29
|
+
from sqlspec.adapters.asyncpg import AsyncpgConfig
|
|
30
|
+
from sqlspec.extensions.fastapi import SQLSpecPlugin
|
|
31
|
+
|
|
32
|
+
sqlspec = SQLSpec()
|
|
33
|
+
config = AsyncpgConfig(
|
|
34
|
+
pool_config={"dsn": "postgresql://localhost/mydb"},
|
|
35
|
+
extension_config={
|
|
36
|
+
"starlette": {
|
|
37
|
+
"commit_mode": "autocommit",
|
|
38
|
+
"session_key": "db"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
sqlspec.add_config(config, name="default")
|
|
43
|
+
|
|
44
|
+
app = FastAPI()
|
|
45
|
+
db_ext = SQLSpecPlugin(sqlspec, app)
|
|
46
|
+
|
|
47
|
+
@app.get("/users")
|
|
48
|
+
async def list_users(db = Depends(db_ext.provide_session())):
|
|
49
|
+
result = await db.execute("SELECT * FROM users")
|
|
50
|
+
return {"users": result.all()}
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
@overload
|
|
54
|
+
def provide_session(
|
|
55
|
+
self, key: None = None
|
|
56
|
+
) -> "Callable[[Request], AsyncDriverAdapterBase | SyncDriverAdapterBase]": ...
|
|
57
|
+
|
|
58
|
+
@overload
|
|
59
|
+
def provide_session(self, key: str) -> "Callable[[Request], AsyncDriverAdapterBase | SyncDriverAdapterBase]": ...
|
|
60
|
+
|
|
61
|
+
@overload
|
|
62
|
+
def provide_session(self, key: "type[AsyncDatabaseConfig]") -> "Callable[[Request], AsyncDriverAdapterBase]": ...
|
|
63
|
+
|
|
64
|
+
@overload
|
|
65
|
+
def provide_session(self, key: "type[SyncDatabaseConfig]") -> "Callable[[Request], SyncDriverAdapterBase]": ...
|
|
66
|
+
|
|
67
|
+
@overload
|
|
68
|
+
def provide_session(self, key: "AsyncDatabaseConfig") -> "Callable[[Request], AsyncDriverAdapterBase]": ...
|
|
69
|
+
|
|
70
|
+
@overload
|
|
71
|
+
def provide_session(self, key: "SyncDatabaseConfig") -> "Callable[[Request], SyncDriverAdapterBase]": ...
|
|
72
|
+
|
|
73
|
+
def provide_session(
|
|
74
|
+
self,
|
|
75
|
+
key: "str | type[AsyncDatabaseConfig | SyncDatabaseConfig] | AsyncDatabaseConfig | SyncDatabaseConfig | None" = None,
|
|
76
|
+
) -> "Callable[[Request], AsyncDriverAdapterBase | SyncDriverAdapterBase]":
|
|
77
|
+
"""Create dependency factory for session injection.
|
|
78
|
+
|
|
79
|
+
Returns a callable that can be used with FastAPI's Depends() to inject
|
|
80
|
+
a database session into route handlers.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
key: Optional session key (str), config type for type narrowing, or None.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Dependency callable for FastAPI Depends().
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
# No args - returns union type
|
|
90
|
+
@app.get("/users")
|
|
91
|
+
async def get_users(db = Depends(db_ext.provide_session())):
|
|
92
|
+
return await db.execute("SELECT * FROM users")
|
|
93
|
+
|
|
94
|
+
# String key for multi-database
|
|
95
|
+
@app.get("/products")
|
|
96
|
+
async def get_products(db = Depends(db_ext.provide_session("products"))):
|
|
97
|
+
return await db.execute("SELECT * FROM products")
|
|
98
|
+
|
|
99
|
+
# Config instance for type narrowing
|
|
100
|
+
config = AsyncpgConfig(...)
|
|
101
|
+
@app.get("/typed")
|
|
102
|
+
async def typed_query(db = Depends(db_ext.provide_session(config))):
|
|
103
|
+
# db is properly typed as AsyncDriverAdapterBase
|
|
104
|
+
return await db.execute("SELECT 1")
|
|
105
|
+
|
|
106
|
+
# Config type/class for type narrowing
|
|
107
|
+
@app.get("/typed2")
|
|
108
|
+
async def typed_query2(db = Depends(db_ext.provide_session(AsyncpgConfig))):
|
|
109
|
+
# db is properly typed as AsyncDriverAdapterBase
|
|
110
|
+
return await db.execute("SELECT 1")
|
|
111
|
+
"""
|
|
112
|
+
# Extract string key if provided, ignore config types/instances (used only for type narrowing)
|
|
113
|
+
session_key = key if isinstance(key, str) or key is None else None
|
|
114
|
+
|
|
115
|
+
def dependency(request: Request) -> "AsyncDriverAdapterBase | SyncDriverAdapterBase":
|
|
116
|
+
return self.get_session(request, session_key) # type: ignore[no-any-return]
|
|
117
|
+
|
|
118
|
+
return dependency
|
|
119
|
+
|
|
120
|
+
def provide_async_session(self, key: "str | None" = None) -> "Callable[[Request], AsyncDriverAdapterBase]":
|
|
121
|
+
"""Create dependency factory for async session injection.
|
|
122
|
+
|
|
123
|
+
Type-narrowed version of provide_session() that returns AsyncDriverAdapterBase.
|
|
124
|
+
Useful when using string keys and you know the config is async.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
key: Optional session key for multi-database configurations.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Dependency callable that returns AsyncDriverAdapterBase.
|
|
131
|
+
|
|
132
|
+
Example:
|
|
133
|
+
@app.get("/users")
|
|
134
|
+
async def get_users(db = Depends(db_ext.provide_async_session())):
|
|
135
|
+
# db is AsyncDriverAdapterBase
|
|
136
|
+
return await db.execute("SELECT * FROM users")
|
|
137
|
+
|
|
138
|
+
@app.get("/products")
|
|
139
|
+
async def get_products(db = Depends(db_ext.provide_async_session("products_db"))):
|
|
140
|
+
# db is AsyncDriverAdapterBase for "products_db" key
|
|
141
|
+
return await db.execute("SELECT * FROM products")
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
def dependency(request: Request) -> "AsyncDriverAdapterBase":
|
|
145
|
+
return self.get_session(request, key) # type: ignore[no-any-return]
|
|
146
|
+
|
|
147
|
+
return dependency
|
|
148
|
+
|
|
149
|
+
def provide_sync_session(self, key: "str | None" = None) -> "Callable[[Request], SyncDriverAdapterBase]":
|
|
150
|
+
"""Create dependency factory for sync session injection.
|
|
151
|
+
|
|
152
|
+
Type-narrowed version of provide_session() that returns SyncDriverAdapterBase.
|
|
153
|
+
Useful when using string keys and you know the config is sync.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
key: Optional session key for multi-database configurations.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Dependency callable that returns SyncDriverAdapterBase.
|
|
160
|
+
|
|
161
|
+
Example:
|
|
162
|
+
@app.get("/users")
|
|
163
|
+
def get_users(db = Depends(db_ext.provide_sync_session())):
|
|
164
|
+
# db is SyncDriverAdapterBase
|
|
165
|
+
return db.execute("SELECT * FROM users")
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def dependency(request: Request) -> "SyncDriverAdapterBase":
|
|
169
|
+
return self.get_session(request, key) # type: ignore[no-any-return]
|
|
170
|
+
|
|
171
|
+
return dependency
|
|
172
|
+
|
|
173
|
+
@overload
|
|
174
|
+
def provide_connection(self, key: None = None) -> "Callable[[Request], Any]": ...
|
|
175
|
+
|
|
176
|
+
@overload
|
|
177
|
+
def provide_connection(self, key: str) -> "Callable[[Request], Any]": ...
|
|
178
|
+
|
|
179
|
+
@overload
|
|
180
|
+
def provide_connection(self, key: "type[AsyncDatabaseConfig]") -> "Callable[[Request], Any]": ...
|
|
181
|
+
|
|
182
|
+
@overload
|
|
183
|
+
def provide_connection(self, key: "type[SyncDatabaseConfig]") -> "Callable[[Request], Any]": ...
|
|
184
|
+
|
|
185
|
+
@overload
|
|
186
|
+
def provide_connection(self, key: "AsyncDatabaseConfig") -> "Callable[[Request], Any]": ...
|
|
187
|
+
|
|
188
|
+
@overload
|
|
189
|
+
def provide_connection(self, key: "SyncDatabaseConfig") -> "Callable[[Request], Any]": ...
|
|
190
|
+
|
|
191
|
+
def provide_connection(
|
|
192
|
+
self,
|
|
193
|
+
key: "str | type[AsyncDatabaseConfig | SyncDatabaseConfig] | AsyncDatabaseConfig | SyncDatabaseConfig | None" = None,
|
|
194
|
+
) -> "Callable[[Request], Any]":
|
|
195
|
+
"""Create dependency factory for connection injection.
|
|
196
|
+
|
|
197
|
+
Returns a callable that can be used with FastAPI's Depends() to inject
|
|
198
|
+
a database connection into route handlers.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
key: Optional session key (str), config type for type narrowing, or None.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Dependency callable for FastAPI Depends().
|
|
205
|
+
|
|
206
|
+
Example:
|
|
207
|
+
# No args
|
|
208
|
+
@app.get("/raw")
|
|
209
|
+
async def raw_query(conn = Depends(db_ext.provide_connection())):
|
|
210
|
+
cursor = await conn.cursor()
|
|
211
|
+
await cursor.execute("SELECT 1")
|
|
212
|
+
return await cursor.fetchone()
|
|
213
|
+
|
|
214
|
+
# With config instance
|
|
215
|
+
config = AsyncpgConfig(...)
|
|
216
|
+
@app.get("/typed")
|
|
217
|
+
async def typed_query(conn = Depends(db_ext.provide_connection(config))):
|
|
218
|
+
cursor = await conn.cursor()
|
|
219
|
+
await cursor.execute("SELECT 1")
|
|
220
|
+
return await cursor.fetchone()
|
|
221
|
+
|
|
222
|
+
# With config type/class
|
|
223
|
+
@app.get("/typed2")
|
|
224
|
+
async def typed_query2(conn = Depends(db_ext.provide_connection(AsyncpgConfig))):
|
|
225
|
+
cursor = await conn.cursor()
|
|
226
|
+
await cursor.execute("SELECT 1")
|
|
227
|
+
return await cursor.fetchone()
|
|
228
|
+
"""
|
|
229
|
+
# Extract string key if provided, ignore config types/instances (used only for type narrowing)
|
|
230
|
+
connection_key = key if isinstance(key, str) or key is None else None
|
|
231
|
+
|
|
232
|
+
def dependency(request: Request) -> Any:
|
|
233
|
+
return self.get_connection(request, connection_key)
|
|
234
|
+
|
|
235
|
+
return dependency
|
|
236
|
+
|
|
237
|
+
def provide_async_connection(self, key: "str | None" = None) -> "Callable[[Request], Any]":
|
|
238
|
+
"""Create dependency factory for async connection injection.
|
|
239
|
+
|
|
240
|
+
Type-narrowed version of provide_connection() for async connections.
|
|
241
|
+
Useful when using string keys and you know the config is async.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
key: Optional session key for multi-database configurations.
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Dependency callable for async connection.
|
|
248
|
+
|
|
249
|
+
Example:
|
|
250
|
+
@app.get("/raw")
|
|
251
|
+
async def raw_query(conn = Depends(db_ext.provide_async_connection())):
|
|
252
|
+
cursor = await conn.cursor()
|
|
253
|
+
await cursor.execute("SELECT 1")
|
|
254
|
+
return await cursor.fetchone()
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
def dependency(request: Request) -> Any:
|
|
258
|
+
return self.get_connection(request, key)
|
|
259
|
+
|
|
260
|
+
return dependency
|
|
261
|
+
|
|
262
|
+
def provide_sync_connection(self, key: "str | None" = None) -> "Callable[[Request], Any]":
|
|
263
|
+
"""Create dependency factory for sync connection injection.
|
|
264
|
+
|
|
265
|
+
Type-narrowed version of provide_connection() for sync connections.
|
|
266
|
+
Useful when using string keys and you know the config is sync.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
key: Optional session key for multi-database configurations.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Dependency callable for sync connection.
|
|
273
|
+
|
|
274
|
+
Example:
|
|
275
|
+
@app.get("/raw")
|
|
276
|
+
def raw_query(conn = Depends(db_ext.provide_sync_connection())):
|
|
277
|
+
cursor = conn.cursor()
|
|
278
|
+
cursor.execute("SELECT 1")
|
|
279
|
+
return cursor.fetchone()
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
def dependency(request: Request) -> Any:
|
|
283
|
+
return self.get_connection(request, key)
|
|
284
|
+
|
|
285
|
+
return dependency
|
|
286
|
+
|
|
287
|
+
@staticmethod
|
|
288
|
+
def provide_filters(
|
|
289
|
+
config: "FilterConfig", dep_defaults: "DependencyDefaults | None" = None
|
|
290
|
+
) -> "Callable[..., list[FilterTypes]]":
|
|
291
|
+
"""Create filter dependency for FastAPI routes.
|
|
292
|
+
|
|
293
|
+
Dynamically generates a FastAPI dependency function that parses query
|
|
294
|
+
parameters into SQLSpec filter objects. The returned callable can be used
|
|
295
|
+
with FastAPI's Depends() for automatic filter injection.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
config: Filter configuration specifying which filters to enable.
|
|
299
|
+
dep_defaults: Optional dependency defaults for customization.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Callable for use with Depends() that returns list of filters.
|
|
303
|
+
|
|
304
|
+
Example:
|
|
305
|
+
from fastapi import Depends
|
|
306
|
+
from sqlspec.extensions.fastapi import FilterConfig
|
|
307
|
+
|
|
308
|
+
@app.get("/users")
|
|
309
|
+
async def list_users(
|
|
310
|
+
db = Depends(db_ext.provide_session()),
|
|
311
|
+
filters = Depends(
|
|
312
|
+
db_ext.provide_filters({
|
|
313
|
+
"id_filter": UUID,
|
|
314
|
+
"search": "name,email",
|
|
315
|
+
"search_ignore_case": True,
|
|
316
|
+
"pagination_type": "limit_offset",
|
|
317
|
+
"sort_field": "created_at",
|
|
318
|
+
})
|
|
319
|
+
),
|
|
320
|
+
):
|
|
321
|
+
stmt = sql("SELECT * FROM users")
|
|
322
|
+
for filter in filters:
|
|
323
|
+
stmt = filter.append_to_statement(stmt)
|
|
324
|
+
result = await db.execute(stmt)
|
|
325
|
+
return result.all()
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
if dep_defaults is None:
|
|
329
|
+
dep_defaults = DEPENDENCY_DEFAULTS
|
|
330
|
+
|
|
331
|
+
return _provide_filters(config, dep_defaults=dep_defaults)
|