sqlspec 0.27.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.

Files changed (64) hide show
  1. sqlspec/_typing.py +93 -0
  2. sqlspec/adapters/adbc/adk/store.py +21 -11
  3. sqlspec/adapters/adbc/data_dictionary.py +27 -5
  4. sqlspec/adapters/adbc/driver.py +83 -14
  5. sqlspec/adapters/aiosqlite/adk/store.py +27 -18
  6. sqlspec/adapters/asyncmy/adk/store.py +26 -16
  7. sqlspec/adapters/asyncpg/adk/store.py +26 -16
  8. sqlspec/adapters/asyncpg/data_dictionary.py +24 -17
  9. sqlspec/adapters/bigquery/adk/store.py +30 -21
  10. sqlspec/adapters/bigquery/config.py +11 -0
  11. sqlspec/adapters/bigquery/driver.py +138 -1
  12. sqlspec/adapters/duckdb/adk/store.py +21 -11
  13. sqlspec/adapters/duckdb/driver.py +87 -1
  14. sqlspec/adapters/oracledb/adk/store.py +89 -206
  15. sqlspec/adapters/oracledb/driver.py +183 -2
  16. sqlspec/adapters/oracledb/litestar/store.py +22 -24
  17. sqlspec/adapters/psqlpy/adk/store.py +28 -27
  18. sqlspec/adapters/psqlpy/data_dictionary.py +24 -17
  19. sqlspec/adapters/psqlpy/driver.py +7 -10
  20. sqlspec/adapters/psycopg/adk/store.py +51 -33
  21. sqlspec/adapters/psycopg/data_dictionary.py +48 -34
  22. sqlspec/adapters/sqlite/adk/store.py +29 -19
  23. sqlspec/config.py +100 -2
  24. sqlspec/core/filters.py +18 -10
  25. sqlspec/core/result.py +133 -2
  26. sqlspec/driver/_async.py +89 -0
  27. sqlspec/driver/_common.py +64 -29
  28. sqlspec/driver/_sync.py +95 -0
  29. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +2 -2
  30. sqlspec/extensions/adk/service.py +3 -3
  31. sqlspec/extensions/adk/store.py +8 -8
  32. sqlspec/extensions/aiosql/adapter.py +3 -15
  33. sqlspec/extensions/fastapi/__init__.py +21 -0
  34. sqlspec/extensions/fastapi/extension.py +331 -0
  35. sqlspec/extensions/fastapi/providers.py +543 -0
  36. sqlspec/extensions/flask/__init__.py +36 -0
  37. sqlspec/extensions/flask/_state.py +71 -0
  38. sqlspec/extensions/flask/_utils.py +40 -0
  39. sqlspec/extensions/flask/extension.py +389 -0
  40. sqlspec/extensions/litestar/config.py +3 -6
  41. sqlspec/extensions/litestar/plugin.py +26 -2
  42. sqlspec/extensions/starlette/__init__.py +10 -0
  43. sqlspec/extensions/starlette/_state.py +25 -0
  44. sqlspec/extensions/starlette/_utils.py +52 -0
  45. sqlspec/extensions/starlette/extension.py +254 -0
  46. sqlspec/extensions/starlette/middleware.py +154 -0
  47. sqlspec/protocols.py +40 -0
  48. sqlspec/storage/_utils.py +1 -14
  49. sqlspec/storage/backends/fsspec.py +3 -5
  50. sqlspec/storage/backends/local.py +1 -1
  51. sqlspec/storage/backends/obstore.py +10 -18
  52. sqlspec/typing.py +16 -0
  53. sqlspec/utils/__init__.py +25 -4
  54. sqlspec/utils/arrow_helpers.py +81 -0
  55. sqlspec/utils/module_loader.py +203 -3
  56. sqlspec/utils/portal.py +311 -0
  57. sqlspec/utils/serializers.py +110 -1
  58. sqlspec/utils/sync_tools.py +15 -5
  59. sqlspec/utils/type_guards.py +25 -0
  60. {sqlspec-0.27.0.dist-info → sqlspec-0.28.0.dist-info}/METADATA +2 -2
  61. {sqlspec-0.27.0.dist-info → sqlspec-0.28.0.dist-info}/RECORD +64 -50
  62. {sqlspec-0.27.0.dist-info → sqlspec-0.28.0.dist-info}/WHEEL +0 -0
  63. {sqlspec-0.27.0.dist-info → sqlspec-0.28.0.dist-info}/entry_points.txt +0 -0
  64. {sqlspec-0.27.0.dist-info → sqlspec-0.28.0.dist-info}/licenses/LICENSE +0 -0
@@ -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)