sqlspec 0.47.0__cp314-cp314-win_amd64.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.
- f68e0789eb443ecb1c2c__mypyc.cp314-win_amd64.pyd +0 -0
- sqlspec/__init__.py +167 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_typing.py +714 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +13 -0
- sqlspec/adapters/adbc/_typing.py +106 -0
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +1280 -0
- sqlspec/adapters/adbc/config.py +378 -0
- sqlspec/adapters/adbc/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/adbc/core.py +922 -0
- sqlspec/adapters/adbc/data_dictionary.py +339 -0
- sqlspec/adapters/adbc/driver.py +534 -0
- sqlspec/adapters/adbc/events/__init__.py +5 -0
- sqlspec/adapters/adbc/events/store.py +285 -0
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +534 -0
- sqlspec/adapters/adbc/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/adbc/type_converter.py +142 -0
- sqlspec/adapters/aiomysql/__init__.py +21 -0
- sqlspec/adapters/aiomysql/_typing.py +137 -0
- sqlspec/adapters/aiomysql/adk/__init__.py +5 -0
- sqlspec/adapters/aiomysql/adk/store.py +678 -0
- sqlspec/adapters/aiomysql/config.py +305 -0
- sqlspec/adapters/aiomysql/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiomysql/core.py +536 -0
- sqlspec/adapters/aiomysql/data_dictionary.py +121 -0
- sqlspec/adapters/aiomysql/driver.py +386 -0
- sqlspec/adapters/aiomysql/events/__init__.py +5 -0
- sqlspec/adapters/aiomysql/events/store.py +104 -0
- sqlspec/adapters/aiomysql/litestar/__init__.py +5 -0
- sqlspec/adapters/aiomysql/litestar/store.py +314 -0
- sqlspec/adapters/aiosqlite/__init__.py +26 -0
- sqlspec/adapters/aiosqlite/_typing.py +109 -0
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +829 -0
- sqlspec/adapters/aiosqlite/config.py +315 -0
- sqlspec/adapters/aiosqlite/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiosqlite/core.py +315 -0
- sqlspec/adapters/aiosqlite/data_dictionary.py +202 -0
- sqlspec/adapters/aiosqlite/driver.py +311 -0
- sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/events/store.py +20 -0
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
- sqlspec/adapters/aiosqlite/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiosqlite/pool.py +734 -0
- sqlspec/adapters/asyncmy/__init__.py +21 -0
- sqlspec/adapters/asyncmy/_typing.py +113 -0
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +644 -0
- sqlspec/adapters/asyncmy/config.py +307 -0
- sqlspec/adapters/asyncmy/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/asyncmy/core.py +538 -0
- sqlspec/adapters/asyncmy/data_dictionary.py +122 -0
- sqlspec/adapters/asyncmy/driver.py +391 -0
- sqlspec/adapters/asyncmy/events/__init__.py +5 -0
- sqlspec/adapters/asyncmy/events/store.py +104 -0
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +26 -0
- sqlspec/adapters/asyncpg/_typing.py +103 -0
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +483 -0
- sqlspec/adapters/asyncpg/config.py +575 -0
- sqlspec/adapters/asyncpg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/asyncpg/core.py +480 -0
- sqlspec/adapters/asyncpg/data_dictionary.py +157 -0
- sqlspec/adapters/asyncpg/driver.py +487 -0
- sqlspec/adapters/asyncpg/events/__init__.py +6 -0
- sqlspec/adapters/asyncpg/events/_hub.py +181 -0
- sqlspec/adapters/asyncpg/events/backend.py +210 -0
- sqlspec/adapters/asyncpg/events/store.py +40 -0
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +251 -0
- sqlspec/adapters/bigquery/__init__.py +15 -0
- sqlspec/adapters/bigquery/_typing.py +108 -0
- sqlspec/adapters/bigquery/config.py +362 -0
- sqlspec/adapters/bigquery/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/bigquery/core.py +768 -0
- sqlspec/adapters/bigquery/data_dictionary.py +120 -0
- sqlspec/adapters/bigquery/driver.py +542 -0
- sqlspec/adapters/bigquery/events/__init__.py +5 -0
- sqlspec/adapters/bigquery/events/store.py +139 -0
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +325 -0
- sqlspec/adapters/bigquery/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/bigquery/type_converter.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/__init__.py +26 -0
- sqlspec/adapters/cockroach_asyncpg/_typing.py +73 -0
- sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/adk/store.py +465 -0
- sqlspec/adapters/cockroach_asyncpg/config.py +248 -0
- sqlspec/adapters/cockroach_asyncpg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
- sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +110 -0
- sqlspec/adapters/cockroach_asyncpg/driver.py +142 -0
- sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
- sqlspec/adapters/cockroach_psycopg/__init__.py +39 -0
- sqlspec/adapters/cockroach_psycopg/_typing.py +137 -0
- sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
- sqlspec/adapters/cockroach_psycopg/adk/store.py +1039 -0
- sqlspec/adapters/cockroach_psycopg/config.py +511 -0
- sqlspec/adapters/cockroach_psycopg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/cockroach_psycopg/core.py +63 -0
- sqlspec/adapters/cockroach_psycopg/data_dictionary.py +220 -0
- sqlspec/adapters/cockroach_psycopg/driver.py +273 -0
- sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
- sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
- sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_psycopg/litestar/store.py +327 -0
- sqlspec/adapters/duckdb/__init__.py +29 -0
- sqlspec/adapters/duckdb/_typing.py +104 -0
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +935 -0
- sqlspec/adapters/duckdb/config.py +386 -0
- sqlspec/adapters/duckdb/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/core.py +332 -0
- sqlspec/adapters/duckdb/data_dictionary.py +140 -0
- sqlspec/adapters/duckdb/driver.py +426 -0
- sqlspec/adapters/duckdb/events/__init__.py +5 -0
- sqlspec/adapters/duckdb/events/store.py +57 -0
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +330 -0
- sqlspec/adapters/duckdb/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/pool.py +350 -0
- sqlspec/adapters/duckdb/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/type_converter.py +118 -0
- sqlspec/adapters/mysqlconnector/__init__.py +39 -0
- sqlspec/adapters/mysqlconnector/_typing.py +186 -0
- sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
- sqlspec/adapters/mysqlconnector/adk/store.py +1183 -0
- sqlspec/adapters/mysqlconnector/config.py +421 -0
- sqlspec/adapters/mysqlconnector/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/mysqlconnector/core.py +472 -0
- sqlspec/adapters/mysqlconnector/data_dictionary.py +230 -0
- sqlspec/adapters/mysqlconnector/driver.py +516 -0
- sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
- sqlspec/adapters/mysqlconnector/events/store.py +98 -0
- sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
- sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
- sqlspec/adapters/oracledb/__init__.py +39 -0
- sqlspec/adapters/oracledb/_json_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_json_handlers.py +196 -0
- sqlspec/adapters/oracledb/_param_types.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_param_types.py +46 -0
- sqlspec/adapters/oracledb/_typing.py +258 -0
- sqlspec/adapters/oracledb/_uuid_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_uuid_handlers.py +163 -0
- sqlspec/adapters/oracledb/_vector_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_vector_handlers.py +228 -0
- sqlspec/adapters/oracledb/adk/__init__.py +21 -0
- sqlspec/adapters/oracledb/adk/store.py +2453 -0
- sqlspec/adapters/oracledb/config.py +575 -0
- sqlspec/adapters/oracledb/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/core.py +820 -0
- sqlspec/adapters/oracledb/data_dictionary.py +404 -0
- sqlspec/adapters/oracledb/driver.py +1277 -0
- sqlspec/adapters/oracledb/events/__init__.py +16 -0
- sqlspec/adapters/oracledb/events/_hub.py +345 -0
- sqlspec/adapters/oracledb/events/backend.py +300 -0
- sqlspec/adapters/oracledb/events/store.py +420 -0
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +781 -0
- sqlspec/adapters/oracledb/migrations.py +539 -0
- sqlspec/adapters/oracledb/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/type_converter.py +211 -0
- sqlspec/adapters/psqlpy/__init__.py +18 -0
- sqlspec/adapters/psqlpy/_typing.py +121 -0
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +591 -0
- sqlspec/adapters/psqlpy/config.py +376 -0
- sqlspec/adapters/psqlpy/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psqlpy/core.py +694 -0
- sqlspec/adapters/psqlpy/data_dictionary.py +121 -0
- sqlspec/adapters/psqlpy/driver.py +411 -0
- sqlspec/adapters/psqlpy/events/__init__.py +6 -0
- sqlspec/adapters/psqlpy/events/_hub.py +204 -0
- sqlspec/adapters/psqlpy/events/backend.py +210 -0
- sqlspec/adapters/psqlpy/events/store.py +20 -0
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +270 -0
- sqlspec/adapters/psqlpy/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psqlpy/type_converter.py +113 -0
- sqlspec/adapters/psycopg/__init__.py +38 -0
- sqlspec/adapters/psycopg/_typing.py +218 -0
- sqlspec/adapters/psycopg/adk/__init__.py +10 -0
- sqlspec/adapters/psycopg/adk/store.py +1106 -0
- sqlspec/adapters/psycopg/config.py +695 -0
- sqlspec/adapters/psycopg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psycopg/core.py +520 -0
- sqlspec/adapters/psycopg/data_dictionary.py +278 -0
- sqlspec/adapters/psycopg/driver.py +1033 -0
- sqlspec/adapters/psycopg/events/__init__.py +20 -0
- sqlspec/adapters/psycopg/events/_hub.py +388 -0
- sqlspec/adapters/psycopg/events/backend.py +398 -0
- sqlspec/adapters/psycopg/events/store.py +42 -0
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +554 -0
- sqlspec/adapters/psycopg/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psycopg/type_converter.py +93 -0
- sqlspec/adapters/pymysql/__init__.py +21 -0
- sqlspec/adapters/pymysql/_typing.py +92 -0
- sqlspec/adapters/pymysql/adk/__init__.py +5 -0
- sqlspec/adapters/pymysql/adk/store.py +657 -0
- sqlspec/adapters/pymysql/config.py +176 -0
- sqlspec/adapters/pymysql/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/pymysql/core.py +469 -0
- sqlspec/adapters/pymysql/data_dictionary.py +120 -0
- sqlspec/adapters/pymysql/driver.py +271 -0
- sqlspec/adapters/pymysql/events/__init__.py +5 -0
- sqlspec/adapters/pymysql/events/store.py +50 -0
- sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
- sqlspec/adapters/pymysql/litestar/store.py +232 -0
- sqlspec/adapters/pymysql/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/pymysql/pool.py +184 -0
- sqlspec/adapters/spanner/__init__.py +33 -0
- sqlspec/adapters/spanner/_typing.py +102 -0
- sqlspec/adapters/spanner/adk/__init__.py +5 -0
- sqlspec/adapters/spanner/adk/store.py +758 -0
- sqlspec/adapters/spanner/config.py +355 -0
- sqlspec/adapters/spanner/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/spanner/core.py +263 -0
- sqlspec/adapters/spanner/data_dictionary.py +120 -0
- sqlspec/adapters/spanner/driver.py +407 -0
- sqlspec/adapters/spanner/events/__init__.py +5 -0
- sqlspec/adapters/spanner/events/store.py +187 -0
- sqlspec/adapters/spanner/litestar/__init__.py +5 -0
- sqlspec/adapters/spanner/litestar/store.py +291 -0
- sqlspec/adapters/spanner/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/spanner/type_converter.py +342 -0
- sqlspec/adapters/sqlite/__init__.py +19 -0
- sqlspec/adapters/sqlite/_typing.py +123 -0
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +992 -0
- sqlspec/adapters/sqlite/config.py +240 -0
- sqlspec/adapters/sqlite/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/core.py +357 -0
- sqlspec/adapters/sqlite/data_dictionary.py +198 -0
- sqlspec/adapters/sqlite/driver.py +527 -0
- sqlspec/adapters/sqlite/events/__init__.py +5 -0
- sqlspec/adapters/sqlite/events/store.py +20 -0
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +316 -0
- sqlspec/adapters/sqlite/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/pool.py +237 -0
- sqlspec/adapters/sqlite/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/type_converter.py +114 -0
- sqlspec/base.py +832 -0
- sqlspec/builder/__init__.py +181 -0
- sqlspec/builder/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_base.py +1071 -0
- sqlspec/builder/_column.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_column.py +521 -0
- sqlspec/builder/_ddl.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_ddl.py +1691 -0
- sqlspec/builder/_delete.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_delete.py +95 -0
- sqlspec/builder/_dml.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_dml.py +386 -0
- sqlspec/builder/_explain.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_explain.py +579 -0
- sqlspec/builder/_expression_wrappers.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_expression_wrappers.py +46 -0
- sqlspec/builder/_factory.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_factory.py +1884 -0
- sqlspec/builder/_insert.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_insert.py +405 -0
- sqlspec/builder/_join.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_join.py +489 -0
- sqlspec/builder/_merge.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_merge.py +823 -0
- sqlspec/builder/_parsing_utils.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_parsing_utils.py +295 -0
- sqlspec/builder/_select.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_select.py +1666 -0
- sqlspec/builder/_temporal.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_temporal.py +167 -0
- sqlspec/builder/_update.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_update.py +173 -0
- sqlspec/builder/_vector_distance.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_vector_distance.py +330 -0
- sqlspec/cli.py +1095 -0
- sqlspec/config.py +2383 -0
- sqlspec/core/__init__.py +372 -0
- sqlspec/core/_correlation.cp314-win_amd64.pyd +0 -0
- sqlspec/core/_correlation.py +176 -0
- sqlspec/core/_pagination.py +42 -0
- sqlspec/core/_pool.cp314-win_amd64.pyd +0 -0
- sqlspec/core/_pool.py +76 -0
- sqlspec/core/cache.cp314-win_amd64.pyd +0 -0
- sqlspec/core/cache.py +1085 -0
- sqlspec/core/compiler.cp314-win_amd64.pyd +0 -0
- sqlspec/core/compiler.py +1090 -0
- sqlspec/core/config_runtime.cp314-win_amd64.pyd +0 -0
- sqlspec/core/config_runtime.py +174 -0
- sqlspec/core/explain.cp314-win_amd64.pyd +0 -0
- sqlspec/core/explain.py +275 -0
- sqlspec/core/filters.cp314-win_amd64.pyd +0 -0
- sqlspec/core/filters.py +969 -0
- sqlspec/core/hashing.cp314-win_amd64.pyd +0 -0
- sqlspec/core/hashing.py +266 -0
- sqlspec/core/metrics.cp314-win_amd64.pyd +0 -0
- sqlspec/core/metrics.py +83 -0
- sqlspec/core/parameters/__init__.py +72 -0
- sqlspec/core/parameters/_alignment.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_alignment.py +283 -0
- sqlspec/core/parameters/_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_converter.py +554 -0
- sqlspec/core/parameters/_processor.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_processor.py +1182 -0
- sqlspec/core/parameters/_registry.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_registry.py +206 -0
- sqlspec/core/parameters/_transformers.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_transformers.py +324 -0
- sqlspec/core/parameters/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_types.py +536 -0
- sqlspec/core/parameters/_validator.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_validator.py +171 -0
- sqlspec/core/pipeline.cp314-win_amd64.pyd +0 -0
- sqlspec/core/pipeline.py +333 -0
- sqlspec/core/query_modifiers.cp314-win_amd64.pyd +0 -0
- sqlspec/core/query_modifiers.py +508 -0
- sqlspec/core/result/__init__.py +25 -0
- sqlspec/core/result/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/core/result/_base.py +1232 -0
- sqlspec/core/result/_io.cp314-win_amd64.pyd +0 -0
- sqlspec/core/result/_io.py +28 -0
- sqlspec/core/splitter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/splitter.py +1021 -0
- sqlspec/core/sqlcommenter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/sqlcommenter.py +249 -0
- sqlspec/core/stack.cp314-win_amd64.pyd +0 -0
- sqlspec/core/stack.py +163 -0
- sqlspec/core/statement.cp314-win_amd64.pyd +0 -0
- sqlspec/core/statement.py +1865 -0
- sqlspec/core/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/type_converter.py +340 -0
- sqlspec/data_dictionary/__init__.py +22 -0
- sqlspec/data_dictionary/_loader.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_loader.py +138 -0
- sqlspec/data_dictionary/_registry.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_registry.py +74 -0
- sqlspec/data_dictionary/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_types.py +121 -0
- sqlspec/data_dictionary/dialects/__init__.py +21 -0
- sqlspec/data_dictionary/dialects/bigquery.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/bigquery.py +81 -0
- sqlspec/data_dictionary/dialects/cockroachdb.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/cockroachdb.py +54 -0
- sqlspec/data_dictionary/dialects/duckdb.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/duckdb.py +47 -0
- sqlspec/data_dictionary/dialects/mysql.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/mysql.py +53 -0
- sqlspec/data_dictionary/dialects/oracle.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/oracle.py +197 -0
- sqlspec/data_dictionary/dialects/postgres.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/postgres.py +69 -0
- sqlspec/data_dictionary/dialects/spanner.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/spanner.py +37 -0
- sqlspec/data_dictionary/dialects/sqlite.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/sqlite.py +59 -0
- sqlspec/data_dictionary/sql/.gitkeep +0 -0
- sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
- sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
- sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
- sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
- sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
- sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
- sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
- sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
- sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
- sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
- sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
- sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
- sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
- sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
- sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
- sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
- sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
- sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
- sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
- sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
- sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
- sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
- sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
- sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
- sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
- sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
- sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
- sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
- sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
- sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
- sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
- sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
- sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
- sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
- sqlspec/dialects/__init__.py +22 -0
- sqlspec/dialects/_compat.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/_compat.py +14 -0
- sqlspec/dialects/postgres/__init__.py +9 -0
- sqlspec/dialects/postgres/_generators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/postgres/_generators.py +57 -0
- sqlspec/dialects/postgres/_operators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/postgres/_operators.py +81 -0
- sqlspec/dialects/postgres/_paradedb.py +50 -0
- sqlspec/dialects/postgres/_pgvector.py +36 -0
- sqlspec/dialects/spanner/__init__.py +6 -0
- sqlspec/dialects/spanner/_generators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/spanner/_generators.py +206 -0
- sqlspec/dialects/spanner/_spangres.py +77 -0
- sqlspec/dialects/spanner/_spanner.py +179 -0
- sqlspec/driver/__init__.py +49 -0
- sqlspec/driver/_async.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_async.py +1830 -0
- sqlspec/driver/_common.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_common.py +2292 -0
- sqlspec/driver/_exception_handler.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_exception_handler.py +108 -0
- sqlspec/driver/_query_cache.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_query_cache.py +96 -0
- sqlspec/driver/_sql_helpers.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_sql_helpers.py +139 -0
- sqlspec/driver/_storage_helpers.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_storage_helpers.py +153 -0
- sqlspec/driver/_sync.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_sync.py +1817 -0
- sqlspec/exceptions.cp314-win_amd64.pyd +0 -0
- sqlspec/exceptions.py +480 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/adk/__init__.py +84 -0
- sqlspec/extensions/adk/_config_utils.py +199 -0
- sqlspec/extensions/adk/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/_types.py +41 -0
- sqlspec/extensions/adk/artifact/__init__.py +57 -0
- sqlspec/extensions/adk/artifact/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/artifact/_types.py +32 -0
- sqlspec/extensions/adk/artifact/service.py +508 -0
- sqlspec/extensions/adk/artifact/store.py +361 -0
- sqlspec/extensions/adk/converters.py +212 -0
- sqlspec/extensions/adk/memory/__init__.py +69 -0
- sqlspec/extensions/adk/memory/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/memory/_types.py +30 -0
- sqlspec/extensions/adk/memory/converters.py +225 -0
- sqlspec/extensions/adk/memory/service.py +316 -0
- sqlspec/extensions/adk/memory/store.py +525 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +184 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +279 -0
- sqlspec/extensions/adk/store.py +590 -0
- sqlspec/extensions/events/__init__.py +51 -0
- sqlspec/extensions/events/_channel.py +703 -0
- sqlspec/extensions/events/_hints.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/events/_hints.py +45 -0
- sqlspec/extensions/events/_models.py +23 -0
- sqlspec/extensions/events/_payload.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/events/_payload.py +69 -0
- sqlspec/extensions/events/_protocols.py +134 -0
- sqlspec/extensions/events/_queue.py +462 -0
- sqlspec/extensions/events/_store.py +209 -0
- sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
- sqlspec/extensions/events/migrations/__init__.py +3 -0
- sqlspec/extensions/fastapi/__init__.py +22 -0
- sqlspec/extensions/fastapi/extension.py +391 -0
- sqlspec/extensions/fastapi/providers.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/fastapi/providers.py +712 -0
- sqlspec/extensions/flask/__init__.py +38 -0
- sqlspec/extensions/flask/_state.py +87 -0
- sqlspec/extensions/flask/_utils.py +71 -0
- sqlspec/extensions/flask/extension.py +539 -0
- sqlspec/extensions/litestar/__init__.py +31 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/channels.py +165 -0
- sqlspec/extensions/litestar/cli.py +102 -0
- sqlspec/extensions/litestar/config.py +90 -0
- sqlspec/extensions/litestar/handlers.py +316 -0
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +1066 -0
- sqlspec/extensions/litestar/providers.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/litestar/providers.py +784 -0
- sqlspec/extensions/litestar/store.py +298 -0
- sqlspec/extensions/otel/__init__.py +58 -0
- sqlspec/extensions/prometheus/__init__.py +113 -0
- sqlspec/extensions/sanic/__init__.py +19 -0
- sqlspec/extensions/sanic/_state.py +43 -0
- sqlspec/extensions/sanic/_utils.py +127 -0
- sqlspec/extensions/sanic/extension.py +647 -0
- sqlspec/extensions/starlette/__init__.py +22 -0
- sqlspec/extensions/starlette/_state.py +42 -0
- sqlspec/extensions/starlette/_utils.py +96 -0
- sqlspec/extensions/starlette/extension.py +374 -0
- sqlspec/extensions/starlette/middleware.py +281 -0
- sqlspec/loader.cp314-win_amd64.pyd +0 -0
- sqlspec/loader.py +727 -0
- sqlspec/migrations/__init__.py +39 -0
- sqlspec/migrations/base.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/base.py +862 -0
- sqlspec/migrations/commands.py +2151 -0
- sqlspec/migrations/context.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/context.py +157 -0
- sqlspec/migrations/fix.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/fix.py +204 -0
- sqlspec/migrations/loaders.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/loaders.py +443 -0
- sqlspec/migrations/runner.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/runner.py +1195 -0
- sqlspec/migrations/squash.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/squash.py +490 -0
- sqlspec/migrations/templates.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/templates.py +234 -0
- sqlspec/migrations/tracker.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/tracker.py +792 -0
- sqlspec/migrations/utils.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/utils.py +256 -0
- sqlspec/migrations/validation.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/validation.py +359 -0
- sqlspec/migrations/version.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/version.py +446 -0
- sqlspec/observability/__init__.py +57 -0
- sqlspec/observability/_common.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_common.py +77 -0
- sqlspec/observability/_config.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_config.py +364 -0
- sqlspec/observability/_diagnostics.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_diagnostics.py +74 -0
- sqlspec/observability/_dispatcher.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_dispatcher.py +200 -0
- sqlspec/observability/_formatters/__init__.py +13 -0
- sqlspec/observability/_formatters/_aws.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_aws.py +102 -0
- sqlspec/observability/_formatters/_azure.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_azure.py +96 -0
- sqlspec/observability/_formatters/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_base.py +57 -0
- sqlspec/observability/_formatters/_gcp.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_gcp.py +131 -0
- sqlspec/observability/_formatting.py +58 -0
- sqlspec/observability/_observer.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_observer.py +361 -0
- sqlspec/observability/_runtime.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_runtime.py +461 -0
- sqlspec/observability/_sampling.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_sampling.py +188 -0
- sqlspec/observability/_spans.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_spans.py +161 -0
- sqlspec/protocols.py +955 -0
- sqlspec/py.typed +0 -0
- sqlspec/service.py +433 -0
- sqlspec/storage/__init__.py +48 -0
- sqlspec/storage/_arrow_payload.py +68 -0
- sqlspec/storage/_paths.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/_paths.py +58 -0
- sqlspec/storage/_utils.py +46 -0
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/base.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/backends/base.py +374 -0
- sqlspec/storage/backends/fsspec.py +574 -0
- sqlspec/storage/backends/local.py +468 -0
- sqlspec/storage/backends/obstore.py +956 -0
- sqlspec/storage/errors.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/errors.py +102 -0
- sqlspec/storage/pipeline.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/pipeline.py +628 -0
- sqlspec/storage/registry.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/registry.py +329 -0
- sqlspec/typing.py +405 -0
- sqlspec/utils/__init__.py +7 -0
- sqlspec/utils/arrow_helpers.py +384 -0
- sqlspec/utils/config_tools.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/config_tools.py +314 -0
- sqlspec/utils/correlation.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/correlation.py +134 -0
- sqlspec/utils/deprecation.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/deprecation.py +157 -0
- sqlspec/utils/dispatch.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/dispatch.py +101 -0
- sqlspec/utils/fixtures.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/fixtures.py +260 -0
- sqlspec/utils/logging.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/logging.py +251 -0
- sqlspec/utils/module_loader.py +306 -0
- sqlspec/utils/portal.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/portal.py +377 -0
- sqlspec/utils/schema.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/schema.py +1040 -0
- sqlspec/utils/serializers/__init__.py +30 -0
- sqlspec/utils/serializers/_json.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_json.py +415 -0
- sqlspec/utils/serializers/_numpy.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_numpy.py +65 -0
- sqlspec/utils/serializers/_schema.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_schema.py +285 -0
- sqlspec/utils/singleton.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/singleton.py +41 -0
- sqlspec/utils/sync_tools.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/sync_tools.py +316 -0
- sqlspec/utils/text.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/text.py +109 -0
- sqlspec/utils/type_converters.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/type_converters.py +216 -0
- sqlspec/utils/type_guards.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/type_guards.py +1508 -0
- sqlspec/utils/uuids.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/uuids.py +241 -0
- sqlspec-0.47.0.dist-info/METADATA +202 -0
- sqlspec-0.47.0.dist-info/RECORD +621 -0
- sqlspec-0.47.0.dist-info/WHEEL +4 -0
- sqlspec-0.47.0.dist-info/entry_points.txt +6 -0
- sqlspec-0.47.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Litestar channels backend backed by SQLSpec's EventChannel."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import base64
|
|
5
|
+
import hashlib
|
|
6
|
+
import re
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
|
|
9
|
+
from litestar.channels.backends.base import ChannelsBackend
|
|
10
|
+
|
|
11
|
+
from sqlspec.utils.logging import get_logger
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import AsyncGenerator, Iterable
|
|
15
|
+
|
|
16
|
+
from sqlspec.extensions.events import AsyncEventChannel
|
|
17
|
+
|
|
18
|
+
logger = get_logger("sqlspec.extensions.litestar.channels")
|
|
19
|
+
|
|
20
|
+
_IDENTIFIER_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SQLSpecChannelsBackend(ChannelsBackend):
|
|
24
|
+
"""A Litestar Channels backend implemented on top of SQLSpec's EventChannel.
|
|
25
|
+
|
|
26
|
+
This backend allows Litestar's ChannelsPlugin to use a SQLSpec database as the
|
|
27
|
+
broker. Under the hood it relies on SQLSpec's events extension, which can be
|
|
28
|
+
configured to use a durable table queue or native adapter backends.
|
|
29
|
+
|
|
30
|
+
Notes:
|
|
31
|
+
Litestar channels may use arbitrary string names. SQLSpec event channel
|
|
32
|
+
names must be valid identifiers. This backend maps Litestar channel names
|
|
33
|
+
to deterministic database channel identifiers via hashing.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self, event_channel: "AsyncEventChannel", *, channel_prefix: str = "litestar", poll_interval: float = 0.2
|
|
38
|
+
) -> None:
|
|
39
|
+
if not _IDENTIFIER_PATTERN.match(channel_prefix):
|
|
40
|
+
msg = f"channel_prefix must be a valid identifier, got: {channel_prefix!r}"
|
|
41
|
+
raise ValueError(msg)
|
|
42
|
+
if poll_interval <= 0:
|
|
43
|
+
msg = "poll_interval must be greater than zero"
|
|
44
|
+
raise ValueError(msg)
|
|
45
|
+
self._event_channel = event_channel
|
|
46
|
+
self._channel_prefix = channel_prefix
|
|
47
|
+
self._poll_interval = poll_interval
|
|
48
|
+
self._output_queue: asyncio.Queue[tuple[str, bytes]] | None = None
|
|
49
|
+
self._shutdown = asyncio.Event()
|
|
50
|
+
self._tasks: dict[str, asyncio.Task[None]] = {}
|
|
51
|
+
self._to_db_channel: dict[str, str] = {}
|
|
52
|
+
self._to_litestar_channel: dict[str, str] = {}
|
|
53
|
+
|
|
54
|
+
async def on_startup(self) -> None:
|
|
55
|
+
self._shutdown.clear()
|
|
56
|
+
if self._output_queue is None:
|
|
57
|
+
self._output_queue = asyncio.Queue()
|
|
58
|
+
|
|
59
|
+
async def on_shutdown(self) -> None:
|
|
60
|
+
self._shutdown.set()
|
|
61
|
+
tasks = list(self._tasks.values())
|
|
62
|
+
self._tasks.clear()
|
|
63
|
+
for task in tasks:
|
|
64
|
+
task.cancel()
|
|
65
|
+
if tasks:
|
|
66
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
67
|
+
self._to_db_channel.clear()
|
|
68
|
+
self._to_litestar_channel.clear()
|
|
69
|
+
await self._event_channel.shutdown()
|
|
70
|
+
|
|
71
|
+
async def publish(self, data: bytes, channels: "Iterable[str]") -> None:
|
|
72
|
+
payload = {"data_b64": base64.b64encode(data).decode("ascii")}
|
|
73
|
+
for channel in channels:
|
|
74
|
+
db_channel = self._db_channel_name(channel)
|
|
75
|
+
await self._event_channel.publish(db_channel, payload)
|
|
76
|
+
|
|
77
|
+
async def subscribe(self, channels: "Iterable[str]") -> None:
|
|
78
|
+
for channel in channels:
|
|
79
|
+
if channel in self._tasks:
|
|
80
|
+
continue
|
|
81
|
+
db_channel = self._db_channel_name(channel)
|
|
82
|
+
task = asyncio.create_task(self._stream_channel(channel, db_channel))
|
|
83
|
+
self._tasks[channel] = task
|
|
84
|
+
|
|
85
|
+
async def unsubscribe(self, channels: "Iterable[str]") -> None:
|
|
86
|
+
cancelled: list[asyncio.Task[None]] = []
|
|
87
|
+
for channel in channels:
|
|
88
|
+
task = self._tasks.pop(channel, None)
|
|
89
|
+
if task is None:
|
|
90
|
+
continue
|
|
91
|
+
task.cancel()
|
|
92
|
+
cancelled.append(task)
|
|
93
|
+
if cancelled:
|
|
94
|
+
await asyncio.gather(*cancelled, return_exceptions=True)
|
|
95
|
+
self._cleanup_channel_mappings()
|
|
96
|
+
|
|
97
|
+
def stream_events(self) -> "AsyncGenerator[tuple[str, bytes], None]":
|
|
98
|
+
return self._event_generator()
|
|
99
|
+
|
|
100
|
+
async def get_history(self, channel: str, limit: int | None = None) -> list[bytes]:
|
|
101
|
+
"""Return history entries for a channel.
|
|
102
|
+
|
|
103
|
+
SQLSpec's event queue is primarily designed for durable delivery, not
|
|
104
|
+
for history replay. For now, this backend does not expose history.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
return []
|
|
108
|
+
|
|
109
|
+
def _cleanup_channel_mappings(self) -> None:
|
|
110
|
+
active = set(self._tasks)
|
|
111
|
+
removed = [name for name in self._to_db_channel if name not in active]
|
|
112
|
+
for name in removed:
|
|
113
|
+
db_name = self._to_db_channel.pop(name, None)
|
|
114
|
+
if db_name:
|
|
115
|
+
self._to_litestar_channel.pop(db_name, None)
|
|
116
|
+
|
|
117
|
+
async def _event_generator(self) -> "AsyncGenerator[tuple[str, bytes], None]":
|
|
118
|
+
if self._output_queue is None:
|
|
119
|
+
msg = "SQLSpecChannelsBackend not started - call ChannelsPlugin.on_startup() first"
|
|
120
|
+
raise RuntimeError(msg)
|
|
121
|
+
queue = self._output_queue
|
|
122
|
+
while True:
|
|
123
|
+
item = await queue.get()
|
|
124
|
+
yield item
|
|
125
|
+
|
|
126
|
+
def _db_channel_name(self, channel: str) -> str:
|
|
127
|
+
existing = self._to_db_channel.get(channel)
|
|
128
|
+
if existing:
|
|
129
|
+
return existing
|
|
130
|
+
digest = hashlib.sha256(channel.encode("utf-8")).hexdigest()[:24]
|
|
131
|
+
db_channel = f"{self._channel_prefix}_{digest}"
|
|
132
|
+
self._to_db_channel[channel] = db_channel
|
|
133
|
+
self._to_litestar_channel[db_channel] = channel
|
|
134
|
+
return db_channel
|
|
135
|
+
|
|
136
|
+
async def _stream_channel(self, channel: str, db_channel: str) -> None:
|
|
137
|
+
try:
|
|
138
|
+
async for message in self._event_channel.iter_events(db_channel, poll_interval=self._poll_interval):
|
|
139
|
+
if self._shutdown.is_set():
|
|
140
|
+
return
|
|
141
|
+
payload = message.payload
|
|
142
|
+
decoded = self._decode_payload(payload)
|
|
143
|
+
if decoded is None:
|
|
144
|
+
logger.warning("litestar channel %s dropped malformed payload: %r", channel, payload)
|
|
145
|
+
await self._event_channel.ack(message.event_id)
|
|
146
|
+
continue
|
|
147
|
+
assert self._output_queue is not None
|
|
148
|
+
await self._output_queue.put((channel, decoded))
|
|
149
|
+
await self._event_channel.ack(message.event_id)
|
|
150
|
+
except asyncio.CancelledError:
|
|
151
|
+
raise
|
|
152
|
+
except Exception as error: # pragma: no cover - defensive
|
|
153
|
+
logger.warning("litestar channel %s stream worker error: %s", channel, error)
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
def _decode_payload(payload: Any) -> bytes | None:
|
|
157
|
+
if not isinstance(payload, dict):
|
|
158
|
+
return None
|
|
159
|
+
encoded = payload.get("data_b64")
|
|
160
|
+
if not isinstance(encoded, str) or not encoded:
|
|
161
|
+
return None
|
|
162
|
+
try:
|
|
163
|
+
return base64.b64decode(encoded.encode("ascii"))
|
|
164
|
+
except (ValueError, UnicodeEncodeError):
|
|
165
|
+
return None
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Litestar CLI integration for SQLSpec migrations."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from contextlib import suppress
|
|
5
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
6
|
+
|
|
7
|
+
import anyio
|
|
8
|
+
import rich_click as click
|
|
9
|
+
from litestar.cli._utils import LitestarGroup
|
|
10
|
+
|
|
11
|
+
from sqlspec.cli import add_migration_commands
|
|
12
|
+
from sqlspec.exceptions import ImproperConfigurationError
|
|
13
|
+
from sqlspec.extensions.litestar.store import BaseSQLSpecStore
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from litestar import Litestar
|
|
17
|
+
|
|
18
|
+
from sqlspec.extensions.litestar.plugin import SQLSpecPlugin
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _safe_group(*, aliases: "list[str] | None" = None, **kwargs: Any) -> Callable[[Callable[..., Any]], Any]:
|
|
22
|
+
if aliases is None:
|
|
23
|
+
return cast("Callable[[Callable[..., Any]], Any]", click.group(**kwargs))
|
|
24
|
+
try:
|
|
25
|
+
return cast("Callable[[Callable[..., Any]], Any]", click.group(aliases=aliases, **kwargs))
|
|
26
|
+
except TypeError:
|
|
27
|
+
return cast("Callable[[Callable[..., Any]], Any]", click.group(**kwargs))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_database_migration_plugin(app: "Litestar") -> "SQLSpecPlugin":
|
|
31
|
+
"""Retrieve the SQLSpec plugin from the Litestar application's plugins.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
app: The Litestar application
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
The SQLSpec plugin
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
ImproperConfigurationError: If the SQLSpec plugin is not found
|
|
41
|
+
"""
|
|
42
|
+
from sqlspec.extensions.litestar.plugin import SQLSpecPlugin
|
|
43
|
+
|
|
44
|
+
with suppress(KeyError):
|
|
45
|
+
return app.plugins.get(SQLSpecPlugin)
|
|
46
|
+
msg = "Failed to initialize database migrations. The required SQLSpec plugin is missing."
|
|
47
|
+
raise ImproperConfigurationError(msg)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@_safe_group(cls=LitestarGroup, name="db", aliases=["database"])
|
|
51
|
+
def database_group(ctx: "click.Context") -> None:
|
|
52
|
+
"""Manage SQLSpec database components."""
|
|
53
|
+
ctx.obj = {"app": ctx.obj, "configs": get_database_migration_plugin(ctx.obj.app).config}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
add_migration_commands(database_group)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def add_sessions_delete_expired_command() -> None:
|
|
60
|
+
"""Add delete-expired command to Litestar's sessions CLI group."""
|
|
61
|
+
try:
|
|
62
|
+
from litestar.cli._utils import console
|
|
63
|
+
from litestar.cli.commands.sessions import get_session_backend, sessions_group
|
|
64
|
+
except ImportError:
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
@sessions_group.command("delete-expired") # type: ignore[untyped-decorator]
|
|
68
|
+
@click.option(
|
|
69
|
+
"--verbose", is_flag=True, default=False, help="Show detailed information about the cleanup operation"
|
|
70
|
+
)
|
|
71
|
+
def delete_expired_sessions_command(app: "Litestar", verbose: bool) -> None:
|
|
72
|
+
"""Delete expired sessions from the session store.
|
|
73
|
+
|
|
74
|
+
This command removes all sessions that have passed their expiration time.
|
|
75
|
+
It can be scheduled via cron or systemd timers for automatic maintenance.
|
|
76
|
+
|
|
77
|
+
Examples:
|
|
78
|
+
litestar sessions delete-expired
|
|
79
|
+
litestar sessions delete-expired --verbose
|
|
80
|
+
"""
|
|
81
|
+
backend = get_session_backend(app)
|
|
82
|
+
store = backend.config.get_store_from_app(app)
|
|
83
|
+
|
|
84
|
+
if not isinstance(store, BaseSQLSpecStore):
|
|
85
|
+
console.print(f"[red]{type(store).__name__} does not support deleting expired sessions")
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
async def _delete_expired() -> int:
|
|
89
|
+
return await store.delete_expired()
|
|
90
|
+
|
|
91
|
+
count = anyio.run(_delete_expired)
|
|
92
|
+
|
|
93
|
+
if count > 0:
|
|
94
|
+
if verbose:
|
|
95
|
+
console.print(f"[green]Successfully deleted {count} expired session(s)")
|
|
96
|
+
else:
|
|
97
|
+
console.print(f"[green]Deleted {count} expired session(s)")
|
|
98
|
+
else:
|
|
99
|
+
console.print("[yellow]No expired sessions found")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
add_sessions_delete_expired_command()
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Configuration types for Litestar session store extension."""
|
|
2
|
+
|
|
3
|
+
from typing_extensions import NotRequired, TypedDict
|
|
4
|
+
|
|
5
|
+
__all__ = ("LitestarConfig",)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LitestarConfig(TypedDict):
|
|
9
|
+
"""Configuration options for Litestar session store extension.
|
|
10
|
+
|
|
11
|
+
All fields are optional with sensible defaults. Use in extension_config["litestar"]:
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
from sqlspec.adapters.oracledb import OracleAsyncConfig
|
|
15
|
+
|
|
16
|
+
config = OracleAsyncConfig(
|
|
17
|
+
connection_config={"dsn": "oracle://localhost/XEPDB1"},
|
|
18
|
+
extension_config={
|
|
19
|
+
"litestar": {
|
|
20
|
+
"session_table": "my_sessions",
|
|
21
|
+
"in_memory": True
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
Notes:
|
|
27
|
+
This TypedDict provides type safety for extension config but is not required.
|
|
28
|
+
You can use plain dicts as well.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
session_table: NotRequired[str]
|
|
32
|
+
"""Name of the sessions table. Default: 'litestar_session'
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
"app_sessions"
|
|
36
|
+
"user_sessions"
|
|
37
|
+
"tenant_acme_sessions"
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
in_memory: NotRequired[bool]
|
|
41
|
+
"""Enable in-memory table storage (Oracle-specific). Default: False.
|
|
42
|
+
|
|
43
|
+
When enabled, tables are created with the in-memory attribute for databases that support it.
|
|
44
|
+
|
|
45
|
+
This is an Oracle-specific feature that requires:
|
|
46
|
+
- Oracle Database 12.1.0.2 or higher
|
|
47
|
+
- Database In-Memory option license (Enterprise Edition)
|
|
48
|
+
- Sufficient INMEMORY_SIZE configured in the database instance
|
|
49
|
+
|
|
50
|
+
Other database adapters ignore this setting.
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
Oracle with in-memory enabled:
|
|
54
|
+
config = OracleAsyncConfig(
|
|
55
|
+
connection_config={"dsn": "oracle://..."},
|
|
56
|
+
extension_config={
|
|
57
|
+
"litestar": {
|
|
58
|
+
"in_memory": True
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
Notes:
|
|
64
|
+
- Tables created with INMEMORY PRIORITY HIGH clause
|
|
65
|
+
- Ignored by unsupported adapters
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
shard_count: NotRequired[int]
|
|
69
|
+
"""Optional hash shard count for session table primary key.
|
|
70
|
+
|
|
71
|
+
When set (>1), adapters that support computed shard columns (e.g., Spanner)
|
|
72
|
+
will create a generated shard_id using MOD(FARM_FINGERPRINT(session_id), shard_count)
|
|
73
|
+
and include it in the primary key to reduce hotspotting. Ignored by adapters
|
|
74
|
+
that do not support computed shards.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
table_options: NotRequired[str]
|
|
78
|
+
"""Optional raw OPTIONS/engine-specific table options string.
|
|
79
|
+
|
|
80
|
+
Passed verbatim when the adapter supports table-level OPTIONS/clauses
|
|
81
|
+
(e.g., Spanner columnar/tiered storage). Ignored by adapters that do not
|
|
82
|
+
support table options.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
index_options: NotRequired[str]
|
|
86
|
+
"""Optional raw OPTIONS/engine-specific options for the expires_at index.
|
|
87
|
+
|
|
88
|
+
Passed verbatim to the index definition for adapters that support index
|
|
89
|
+
OPTIONS/clauses. Ignored by adapters that do not support index options.
|
|
90
|
+
"""
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import inspect
|
|
3
|
+
from collections.abc import AsyncGenerator, Callable
|
|
4
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager
|
|
5
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
6
|
+
|
|
7
|
+
from litestar.constants import HTTP_DISCONNECT, HTTP_RESPONSE_START, WEBSOCKET_CLOSE, WEBSOCKET_DISCONNECT
|
|
8
|
+
from litestar.params import Dependency
|
|
9
|
+
|
|
10
|
+
from sqlspec.exceptions import ImproperConfigurationError
|
|
11
|
+
from sqlspec.extensions.litestar._utils import (
|
|
12
|
+
delete_sqlspec_scope_state,
|
|
13
|
+
get_sqlspec_scope_state,
|
|
14
|
+
set_sqlspec_scope_state,
|
|
15
|
+
)
|
|
16
|
+
from sqlspec.utils.sync_tools import ensure_async_, with_ensure_async_
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from collections.abc import Awaitable, Coroutine
|
|
20
|
+
|
|
21
|
+
from litestar import Litestar
|
|
22
|
+
from litestar.datastructures.state import State
|
|
23
|
+
from litestar.types import Message, Scope
|
|
24
|
+
|
|
25
|
+
from sqlspec.config import DatabaseConfigProtocol, DriverT
|
|
26
|
+
from sqlspec.typing import ConnectionT, PoolT
|
|
27
|
+
|
|
28
|
+
SESSION_TERMINUS_ASGI_EVENTS = {HTTP_RESPONSE_START, HTTP_DISCONNECT, WEBSOCKET_DISCONNECT, WEBSOCKET_CLOSE}
|
|
29
|
+
|
|
30
|
+
__all__ = (
|
|
31
|
+
"SESSION_TERMINUS_ASGI_EVENTS",
|
|
32
|
+
"autocommit_handler_maker",
|
|
33
|
+
"connection_provider_maker",
|
|
34
|
+
"lifespan_handler_maker",
|
|
35
|
+
"manual_handler_maker",
|
|
36
|
+
"pool_provider_maker",
|
|
37
|
+
"session_provider_maker",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def manual_handler_maker(
|
|
42
|
+
connection_scope_key: str, is_async: bool = False
|
|
43
|
+
) -> "Callable[[Message, Scope], Coroutine[Any, Any, None]]":
|
|
44
|
+
"""Create handler for manual connection management.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
connection_scope_key: The key used to store the connection in the ASGI scope.
|
|
48
|
+
is_async: Whether the database driver is async (uses direct await) or sync (uses ensure_async_).
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
The handler callable.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
async def handler(message: "Message", scope: "Scope") -> None:
|
|
55
|
+
"""Handle closing and cleaning up connections before sending the response.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
message: ASGI Message.
|
|
59
|
+
scope: ASGI Scope.
|
|
60
|
+
"""
|
|
61
|
+
connection = get_sqlspec_scope_state(scope, connection_scope_key)
|
|
62
|
+
if connection and message["type"] in SESSION_TERMINUS_ASGI_EVENTS:
|
|
63
|
+
if is_async:
|
|
64
|
+
await connection.close()
|
|
65
|
+
else:
|
|
66
|
+
await ensure_async_(connection.close)()
|
|
67
|
+
delete_sqlspec_scope_state(scope, connection_scope_key)
|
|
68
|
+
|
|
69
|
+
return handler
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def autocommit_handler_maker(
|
|
73
|
+
connection_scope_key: str,
|
|
74
|
+
is_async: bool = False,
|
|
75
|
+
commit_on_redirect: bool = False,
|
|
76
|
+
extra_commit_statuses: "set[int] | None" = None,
|
|
77
|
+
extra_rollback_statuses: "set[int] | None" = None,
|
|
78
|
+
) -> "Callable[[Message, Scope], Coroutine[Any, Any, None]]":
|
|
79
|
+
"""Create handler for automatic transaction commit/rollback based on response status.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
connection_scope_key: The key used to store the connection in the ASGI scope.
|
|
83
|
+
is_async: Whether the database driver is async (uses direct await) or sync (uses ensure_async_).
|
|
84
|
+
commit_on_redirect: Issue a commit when the response status is a redirect (3XX).
|
|
85
|
+
extra_commit_statuses: A set of additional status codes that trigger a commit.
|
|
86
|
+
extra_rollback_statuses: A set of additional status codes that trigger a rollback.
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
ImproperConfigurationError: If extra_commit_statuses and extra_rollback_statuses share status codes.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
The handler callable.
|
|
93
|
+
"""
|
|
94
|
+
if extra_commit_statuses is None:
|
|
95
|
+
extra_commit_statuses = set()
|
|
96
|
+
|
|
97
|
+
if extra_rollback_statuses is None:
|
|
98
|
+
extra_rollback_statuses = set()
|
|
99
|
+
|
|
100
|
+
if len(extra_commit_statuses & extra_rollback_statuses) > 0:
|
|
101
|
+
msg = "Extra rollback statuses and commit statuses must not share any status codes"
|
|
102
|
+
raise ImproperConfigurationError(msg)
|
|
103
|
+
|
|
104
|
+
commit_range = range(200, 400 if commit_on_redirect else 300)
|
|
105
|
+
|
|
106
|
+
async def handler(message: "Message", scope: "Scope") -> None:
|
|
107
|
+
"""Handle commit/rollback, closing and cleaning up connections before sending.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
message: ASGI Message.
|
|
111
|
+
scope: ASGI Scope.
|
|
112
|
+
"""
|
|
113
|
+
connection = get_sqlspec_scope_state(scope, connection_scope_key)
|
|
114
|
+
try:
|
|
115
|
+
if connection is not None and message["type"] == HTTP_RESPONSE_START:
|
|
116
|
+
if (message["status"] in commit_range or message["status"] in extra_commit_statuses) and message[
|
|
117
|
+
"status"
|
|
118
|
+
] not in extra_rollback_statuses:
|
|
119
|
+
if is_async:
|
|
120
|
+
await connection.commit()
|
|
121
|
+
else:
|
|
122
|
+
await ensure_async_(connection.commit)()
|
|
123
|
+
elif is_async:
|
|
124
|
+
await connection.rollback()
|
|
125
|
+
else:
|
|
126
|
+
await ensure_async_(connection.rollback)()
|
|
127
|
+
finally:
|
|
128
|
+
if connection and message["type"] in SESSION_TERMINUS_ASGI_EVENTS:
|
|
129
|
+
if is_async:
|
|
130
|
+
await connection.close()
|
|
131
|
+
else:
|
|
132
|
+
await ensure_async_(connection.close)()
|
|
133
|
+
delete_sqlspec_scope_state(scope, connection_scope_key)
|
|
134
|
+
|
|
135
|
+
return handler
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def lifespan_handler_maker(
|
|
139
|
+
config: "DatabaseConfigProtocol[Any, Any, Any]", pool_key: str
|
|
140
|
+
) -> "Callable[[Litestar], AbstractAsyncContextManager[None]]":
|
|
141
|
+
"""Create lifespan handler for managing database connection pool lifecycle.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
config: The database configuration object.
|
|
145
|
+
pool_key: The key under which the connection pool will be stored in `app.state`.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
The lifespan handler function.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
@contextlib.asynccontextmanager
|
|
152
|
+
async def lifespan_handler(app: "Litestar") -> "AsyncGenerator[None, None]":
|
|
153
|
+
"""Manage database pool lifecycle for the application.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
app: The Litestar application instance.
|
|
157
|
+
|
|
158
|
+
Yields:
|
|
159
|
+
Control to application during pool lifetime.
|
|
160
|
+
"""
|
|
161
|
+
db_pool: Any
|
|
162
|
+
if config.is_async:
|
|
163
|
+
db_pool = await config.create_pool()
|
|
164
|
+
else:
|
|
165
|
+
db_pool = await ensure_async_(config.create_pool)()
|
|
166
|
+
app.state.update({pool_key: db_pool})
|
|
167
|
+
try:
|
|
168
|
+
yield
|
|
169
|
+
finally:
|
|
170
|
+
app.state.pop(pool_key, None)
|
|
171
|
+
try:
|
|
172
|
+
if config.is_async:
|
|
173
|
+
close_result = config.close_pool()
|
|
174
|
+
if close_result is not None:
|
|
175
|
+
await close_result
|
|
176
|
+
else:
|
|
177
|
+
await ensure_async_(config.close_pool)()
|
|
178
|
+
except Exception as e:
|
|
179
|
+
if app.logger:
|
|
180
|
+
app.logger.warning("Error closing database pool for %s. Error: %s", pool_key, e)
|
|
181
|
+
|
|
182
|
+
return lifespan_handler
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def pool_provider_maker(
|
|
186
|
+
config: "DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]", pool_key: str
|
|
187
|
+
) -> "Callable[[State, Scope], Awaitable[PoolT]]":
|
|
188
|
+
"""Create provider for injecting the application-level database pool.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
config: The database configuration object.
|
|
192
|
+
pool_key: The key used to store the connection pool in `app.state`.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
The pool provider function.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
async def provide_pool(state: "State", scope: "Scope") -> "PoolT":
|
|
199
|
+
"""Provide the database pool from application state.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
state: The Litestar application State object.
|
|
203
|
+
scope: The ASGI scope (unused for app-level pool).
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
The database connection pool.
|
|
207
|
+
|
|
208
|
+
Raises:
|
|
209
|
+
ImproperConfigurationError: If the pool is not found in `app.state`.
|
|
210
|
+
"""
|
|
211
|
+
if (db_pool := state.get(pool_key)) is None:
|
|
212
|
+
msg = (
|
|
213
|
+
f"Database pool with key '{pool_key}' not found in application state. "
|
|
214
|
+
"Ensure the SQLSpec lifespan handler is correctly configured and has run."
|
|
215
|
+
)
|
|
216
|
+
raise ImproperConfigurationError(msg)
|
|
217
|
+
return cast("PoolT", db_pool)
|
|
218
|
+
|
|
219
|
+
return provide_pool
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def connection_provider_maker(
|
|
223
|
+
config: "DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]", pool_key: str, connection_key: str
|
|
224
|
+
) -> "Callable[[State, Scope], AsyncGenerator[ConnectionT, None]]":
|
|
225
|
+
"""Create provider for database connections with proper lifecycle management.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
config: The database configuration object.
|
|
229
|
+
pool_key: The key used to retrieve the connection pool from `app.state`.
|
|
230
|
+
connection_key: The key used to store the connection in the ASGI scope.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
The connection provider function.
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
async def provide_connection(state: "State", scope: "Scope") -> "AsyncGenerator[ConnectionT, None]":
|
|
237
|
+
if (db_pool := state.get(pool_key)) is None:
|
|
238
|
+
msg = f"Database pool with key '{pool_key}' not found. Cannot create a connection."
|
|
239
|
+
raise ImproperConfigurationError(msg)
|
|
240
|
+
|
|
241
|
+
connection_cm: Any = config.provide_connection(db_pool)
|
|
242
|
+
context_manager: AbstractAsyncContextManager[ConnectionT] | None = None
|
|
243
|
+
|
|
244
|
+
if isinstance(connection_cm, AbstractAsyncContextManager):
|
|
245
|
+
context_manager = connection_cm
|
|
246
|
+
elif isinstance(connection_cm, AbstractContextManager):
|
|
247
|
+
context_manager = with_ensure_async_(connection_cm)
|
|
248
|
+
|
|
249
|
+
if context_manager is None:
|
|
250
|
+
conn_instance: ConnectionT
|
|
251
|
+
if inspect.isawaitable(connection_cm):
|
|
252
|
+
conn_instance = await cast("Awaitable[ConnectionT]", connection_cm)
|
|
253
|
+
else:
|
|
254
|
+
conn_instance = cast("ConnectionT", connection_cm)
|
|
255
|
+
set_sqlspec_scope_state(scope, connection_key, conn_instance)
|
|
256
|
+
yield conn_instance
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
entered_connection = await context_manager.__aenter__()
|
|
260
|
+
try:
|
|
261
|
+
set_sqlspec_scope_state(scope, connection_key, entered_connection)
|
|
262
|
+
yield entered_connection
|
|
263
|
+
finally:
|
|
264
|
+
await context_manager.__aexit__(None, None, None)
|
|
265
|
+
delete_sqlspec_scope_state(scope, connection_key)
|
|
266
|
+
|
|
267
|
+
return provide_connection
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def session_provider_maker(
|
|
271
|
+
config: "DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]", connection_dependency_key: str
|
|
272
|
+
) -> "Callable[[Any], AsyncGenerator[DriverT, None]]":
|
|
273
|
+
"""Create provider for database driver sessions.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
config: The database configuration object.
|
|
277
|
+
connection_dependency_key: The key used for connection dependency injection.
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
The session provider function.
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
async def provide_session(*args: Any, **kwargs: Any) -> "AsyncGenerator[DriverT, None]":
|
|
284
|
+
connection_obj = args[0] if args else kwargs.get(connection_dependency_key)
|
|
285
|
+
yield cast(
|
|
286
|
+
"DriverT",
|
|
287
|
+
config.driver_type(
|
|
288
|
+
connection=connection_obj,
|
|
289
|
+
statement_config=config.statement_config,
|
|
290
|
+
driver_features=config.driver_features,
|
|
291
|
+
),
|
|
292
|
+
) # pyright: ignore
|
|
293
|
+
|
|
294
|
+
conn_type_annotation = config.connection_type
|
|
295
|
+
|
|
296
|
+
db_conn_param = inspect.Parameter(
|
|
297
|
+
name=connection_dependency_key,
|
|
298
|
+
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
299
|
+
annotation=conn_type_annotation,
|
|
300
|
+
default=Dependency(skip_validation=True),
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
provider_signature = inspect.Signature(
|
|
304
|
+
parameters=[db_conn_param],
|
|
305
|
+
return_annotation=AsyncGenerator[config.driver_type, None], # type: ignore[name-defined]
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
provide_session.__signature__ = provider_signature # type: ignore[attr-defined]
|
|
309
|
+
|
|
310
|
+
if provide_session.__annotations__ is None:
|
|
311
|
+
provide_session.__annotations__ = {}
|
|
312
|
+
|
|
313
|
+
provide_session.__annotations__[connection_dependency_key] = conn_type_annotation
|
|
314
|
+
provide_session.__annotations__["return"] = AsyncGenerator[config.driver_type, None] # type: ignore[name-defined]
|
|
315
|
+
|
|
316
|
+
return provide_session
|