sqlspec 0.36.0__cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ac8f31065839703b4e70__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/__init__.py +140 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_serialization.py +315 -0
- sqlspec/_typing.py +700 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +5 -0
- sqlspec/adapters/adbc/_typing.py +82 -0
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +1273 -0
- sqlspec/adapters/adbc/config.py +295 -0
- sqlspec/adapters/adbc/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/adbc/core.py +735 -0
- sqlspec/adapters/adbc/data_dictionary.py +334 -0
- sqlspec/adapters/adbc/driver.py +529 -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 +502 -0
- sqlspec/adapters/adbc/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/adbc/type_converter.py +140 -0
- sqlspec/adapters/aiosqlite/__init__.py +25 -0
- sqlspec/adapters/aiosqlite/_typing.py +82 -0
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +818 -0
- sqlspec/adapters/aiosqlite/config.py +334 -0
- sqlspec/adapters/aiosqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/aiosqlite/core.py +315 -0
- sqlspec/adapters/aiosqlite/data_dictionary.py +208 -0
- sqlspec/adapters/aiosqlite/driver.py +313 -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.py +533 -0
- sqlspec/adapters/asyncmy/__init__.py +21 -0
- sqlspec/adapters/asyncmy/_typing.py +87 -0
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +703 -0
- sqlspec/adapters/asyncmy/config.py +302 -0
- sqlspec/adapters/asyncmy/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/asyncmy/core.py +360 -0
- sqlspec/adapters/asyncmy/data_dictionary.py +124 -0
- sqlspec/adapters/asyncmy/driver.py +383 -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 +19 -0
- sqlspec/adapters/asyncpg/_typing.py +88 -0
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +748 -0
- sqlspec/adapters/asyncpg/config.py +569 -0
- sqlspec/adapters/asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/asyncpg/core.py +367 -0
- sqlspec/adapters/asyncpg/data_dictionary.py +162 -0
- sqlspec/adapters/asyncpg/driver.py +487 -0
- sqlspec/adapters/asyncpg/events/__init__.py +6 -0
- sqlspec/adapters/asyncpg/events/backend.py +286 -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 +14 -0
- sqlspec/adapters/bigquery/_typing.py +86 -0
- sqlspec/adapters/bigquery/adk/__init__.py +5 -0
- sqlspec/adapters/bigquery/adk/store.py +827 -0
- sqlspec/adapters/bigquery/config.py +353 -0
- sqlspec/adapters/bigquery/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/bigquery/core.py +715 -0
- sqlspec/adapters/bigquery/data_dictionary.py +128 -0
- sqlspec/adapters/bigquery/driver.py +548 -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.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/bigquery/type_converter.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/__init__.py +24 -0
- sqlspec/adapters/cockroach_asyncpg/_typing.py +72 -0
- sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/adk/store.py +410 -0
- sqlspec/adapters/cockroach_asyncpg/config.py +238 -0
- sqlspec/adapters/cockroach_asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
- sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/driver.py +144 -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 +38 -0
- sqlspec/adapters/cockroach_psycopg/_typing.py +129 -0
- sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
- sqlspec/adapters/cockroach_psycopg/adk/store.py +868 -0
- sqlspec/adapters/cockroach_psycopg/config.py +484 -0
- sqlspec/adapters/cockroach_psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/cockroach_psycopg/core.py +63 -0
- sqlspec/adapters/cockroach_psycopg/data_dictionary.py +215 -0
- sqlspec/adapters/cockroach_psycopg/driver.py +284 -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 +325 -0
- sqlspec/adapters/duckdb/__init__.py +25 -0
- sqlspec/adapters/duckdb/_typing.py +81 -0
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +850 -0
- sqlspec/adapters/duckdb/config.py +463 -0
- sqlspec/adapters/duckdb/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/duckdb/core.py +257 -0
- sqlspec/adapters/duckdb/data_dictionary.py +140 -0
- sqlspec/adapters/duckdb/driver.py +430 -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.py +293 -0
- sqlspec/adapters/duckdb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/duckdb/type_converter.py +118 -0
- sqlspec/adapters/mock/__init__.py +72 -0
- sqlspec/adapters/mock/_typing.py +147 -0
- sqlspec/adapters/mock/config.py +483 -0
- sqlspec/adapters/mock/core.py +319 -0
- sqlspec/adapters/mock/data_dictionary.py +366 -0
- sqlspec/adapters/mock/driver.py +721 -0
- sqlspec/adapters/mysqlconnector/__init__.py +36 -0
- sqlspec/adapters/mysqlconnector/_typing.py +141 -0
- sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
- sqlspec/adapters/mysqlconnector/adk/store.py +1060 -0
- sqlspec/adapters/mysqlconnector/config.py +394 -0
- sqlspec/adapters/mysqlconnector/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/mysqlconnector/core.py +303 -0
- sqlspec/adapters/mysqlconnector/data_dictionary.py +235 -0
- sqlspec/adapters/mysqlconnector/driver.py +483 -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 +60 -0
- sqlspec/adapters/oracledb/_numpy_handlers.py +141 -0
- sqlspec/adapters/oracledb/_typing.py +182 -0
- sqlspec/adapters/oracledb/_uuid_handlers.py +166 -0
- sqlspec/adapters/oracledb/adk/__init__.py +10 -0
- sqlspec/adapters/oracledb/adk/store.py +2369 -0
- sqlspec/adapters/oracledb/config.py +550 -0
- sqlspec/adapters/oracledb/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/oracledb/core.py +543 -0
- sqlspec/adapters/oracledb/data_dictionary.py +536 -0
- sqlspec/adapters/oracledb/driver.py +1229 -0
- sqlspec/adapters/oracledb/events/__init__.py +16 -0
- sqlspec/adapters/oracledb/events/backend.py +347 -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 +535 -0
- sqlspec/adapters/oracledb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/oracledb/type_converter.py +211 -0
- sqlspec/adapters/psqlpy/__init__.py +17 -0
- sqlspec/adapters/psqlpy/_typing.py +79 -0
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +766 -0
- sqlspec/adapters/psqlpy/config.py +304 -0
- sqlspec/adapters/psqlpy/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psqlpy/core.py +480 -0
- sqlspec/adapters/psqlpy/data_dictionary.py +126 -0
- sqlspec/adapters/psqlpy/driver.py +438 -0
- sqlspec/adapters/psqlpy/events/__init__.py +6 -0
- sqlspec/adapters/psqlpy/events/backend.py +310 -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.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psqlpy/type_converter.py +113 -0
- sqlspec/adapters/psycopg/__init__.py +32 -0
- sqlspec/adapters/psycopg/_typing.py +164 -0
- sqlspec/adapters/psycopg/adk/__init__.py +10 -0
- sqlspec/adapters/psycopg/adk/store.py +1387 -0
- sqlspec/adapters/psycopg/config.py +576 -0
- sqlspec/adapters/psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psycopg/core.py +450 -0
- sqlspec/adapters/psycopg/data_dictionary.py +289 -0
- sqlspec/adapters/psycopg/driver.py +975 -0
- sqlspec/adapters/psycopg/events/__init__.py +20 -0
- sqlspec/adapters/psycopg/events/backend.py +458 -0
- sqlspec/adapters/psycopg/events/store.py +42 -0
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +552 -0
- sqlspec/adapters/psycopg/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psycopg/type_converter.py +93 -0
- sqlspec/adapters/pymysql/__init__.py +21 -0
- sqlspec/adapters/pymysql/_typing.py +71 -0
- sqlspec/adapters/pymysql/adk/__init__.py +5 -0
- sqlspec/adapters/pymysql/adk/store.py +540 -0
- sqlspec/adapters/pymysql/config.py +195 -0
- sqlspec/adapters/pymysql/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/pymysql/core.py +299 -0
- sqlspec/adapters/pymysql/data_dictionary.py +122 -0
- sqlspec/adapters/pymysql/driver.py +259 -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.py +137 -0
- sqlspec/adapters/spanner/__init__.py +40 -0
- sqlspec/adapters/spanner/_typing.py +86 -0
- sqlspec/adapters/spanner/adk/__init__.py +5 -0
- sqlspec/adapters/spanner/adk/store.py +732 -0
- sqlspec/adapters/spanner/config.py +352 -0
- sqlspec/adapters/spanner/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/spanner/core.py +188 -0
- sqlspec/adapters/spanner/data_dictionary.py +120 -0
- sqlspec/adapters/spanner/dialect/__init__.py +6 -0
- sqlspec/adapters/spanner/dialect/_spangres.py +57 -0
- sqlspec/adapters/spanner/dialect/_spanner.py +130 -0
- sqlspec/adapters/spanner/driver.py +373 -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.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/spanner/type_converter.py +331 -0
- sqlspec/adapters/sqlite/__init__.py +19 -0
- sqlspec/adapters/sqlite/_typing.py +80 -0
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +958 -0
- sqlspec/adapters/sqlite/config.py +280 -0
- sqlspec/adapters/sqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/sqlite/core.py +312 -0
- sqlspec/adapters/sqlite/data_dictionary.py +202 -0
- sqlspec/adapters/sqlite/driver.py +359 -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.py +198 -0
- sqlspec/adapters/sqlite/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/sqlite/type_converter.py +114 -0
- sqlspec/base.py +747 -0
- sqlspec/builder/__init__.py +179 -0
- sqlspec/builder/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_base.py +1022 -0
- sqlspec/builder/_column.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_column.py +521 -0
- sqlspec/builder/_ddl.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_ddl.py +1642 -0
- sqlspec/builder/_delete.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_delete.py +95 -0
- sqlspec/builder/_dml.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_dml.py +365 -0
- sqlspec/builder/_explain.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_explain.py +579 -0
- sqlspec/builder/_expression_wrappers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_expression_wrappers.py +46 -0
- sqlspec/builder/_factory.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_factory.py +1697 -0
- sqlspec/builder/_insert.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_insert.py +328 -0
- sqlspec/builder/_join.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_join.py +499 -0
- sqlspec/builder/_merge.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_merge.py +821 -0
- sqlspec/builder/_parsing_utils.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_parsing_utils.py +297 -0
- sqlspec/builder/_select.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_select.py +1660 -0
- sqlspec/builder/_temporal.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_temporal.py +139 -0
- sqlspec/builder/_update.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_update.py +173 -0
- sqlspec/builder/_vector_expressions.py +267 -0
- sqlspec/cli.py +911 -0
- sqlspec/config.py +1755 -0
- sqlspec/core/__init__.py +374 -0
- sqlspec/core/_correlation.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/_correlation.py +176 -0
- sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/cache.py +1069 -0
- sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/compiler.py +954 -0
- sqlspec/core/explain.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/explain.py +275 -0
- sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/filters.py +952 -0
- sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/hashing.py +262 -0
- sqlspec/core/metrics.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/metrics.py +83 -0
- sqlspec/core/parameters/__init__.py +71 -0
- sqlspec/core/parameters/_alignment.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_alignment.py +270 -0
- sqlspec/core/parameters/_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_converter.py +543 -0
- sqlspec/core/parameters/_processor.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_processor.py +505 -0
- sqlspec/core/parameters/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_registry.py +206 -0
- sqlspec/core/parameters/_transformers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_transformers.py +292 -0
- sqlspec/core/parameters/_types.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_types.py +499 -0
- sqlspec/core/parameters/_validator.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_validator.py +180 -0
- sqlspec/core/pipeline.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/pipeline.py +319 -0
- sqlspec/core/query_modifiers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/query_modifiers.py +437 -0
- sqlspec/core/result/__init__.py +23 -0
- sqlspec/core/result/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result/_base.py +1121 -0
- sqlspec/core/result/_io.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result/_io.py +28 -0
- sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/splitter.py +966 -0
- sqlspec/core/stack.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/stack.py +163 -0
- sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/statement.py +1503 -0
- sqlspec/core/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/type_converter.py +339 -0
- sqlspec/data_dictionary/__init__.py +22 -0
- sqlspec/data_dictionary/_loader.py +123 -0
- sqlspec/data_dictionary/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/_registry.py +74 -0
- sqlspec/data_dictionary/_types.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/_types.py +121 -0
- sqlspec/data_dictionary/dialects/__init__.py +21 -0
- sqlspec/data_dictionary/dialects/bigquery.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/bigquery.py +49 -0
- sqlspec/data_dictionary/dialects/cockroachdb.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/cockroachdb.py +43 -0
- sqlspec/data_dictionary/dialects/duckdb.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/duckdb.py +47 -0
- sqlspec/data_dictionary/dialects/mysql.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/mysql.py +42 -0
- sqlspec/data_dictionary/dialects/oracle.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/oracle.py +34 -0
- sqlspec/data_dictionary/dialects/postgres.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/postgres.py +46 -0
- sqlspec/data_dictionary/dialects/spanner.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/spanner.py +37 -0
- sqlspec/data_dictionary/dialects/sqlite.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/sqlite.py +42 -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/driver/__init__.py +32 -0
- sqlspec/driver/_async.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_async.py +1737 -0
- sqlspec/driver/_common.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_common.py +1478 -0
- sqlspec/driver/_sql_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_sql_helpers.py +148 -0
- sqlspec/driver/_storage_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_storage_helpers.py +144 -0
- sqlspec/driver/_sync.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_sync.py +1710 -0
- sqlspec/exceptions.py +338 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/adk/__init__.py +70 -0
- sqlspec/extensions/adk/_types.py +51 -0
- sqlspec/extensions/adk/converters.py +172 -0
- sqlspec/extensions/adk/memory/__init__.py +69 -0
- sqlspec/extensions/adk/memory/_types.py +30 -0
- sqlspec/extensions/adk/memory/converters.py +149 -0
- sqlspec/extensions/adk/memory/service.py +217 -0
- sqlspec/extensions/adk/memory/store.py +569 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +246 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +225 -0
- sqlspec/extensions/adk/store.py +567 -0
- sqlspec/extensions/events/__init__.py +51 -0
- sqlspec/extensions/events/_channel.py +703 -0
- sqlspec/extensions/events/_hints.py +45 -0
- sqlspec/extensions/events/_models.py +23 -0
- sqlspec/extensions/events/_payload.py +69 -0
- sqlspec/extensions/events/_protocols.py +134 -0
- sqlspec/extensions/events/_queue.py +461 -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 +19 -0
- sqlspec/extensions/fastapi/extension.py +351 -0
- sqlspec/extensions/fastapi/providers.py +607 -0
- sqlspec/extensions/flask/__init__.py +37 -0
- sqlspec/extensions/flask/_state.py +76 -0
- sqlspec/extensions/flask/_utils.py +71 -0
- sqlspec/extensions/flask/extension.py +519 -0
- sqlspec/extensions/litestar/__init__.py +28 -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 +671 -0
- sqlspec/extensions/litestar/providers.py +526 -0
- sqlspec/extensions/litestar/store.py +296 -0
- sqlspec/extensions/otel/__init__.py +58 -0
- sqlspec/extensions/prometheus/__init__.py +113 -0
- sqlspec/extensions/starlette/__init__.py +19 -0
- sqlspec/extensions/starlette/_state.py +30 -0
- sqlspec/extensions/starlette/_utils.py +96 -0
- sqlspec/extensions/starlette/extension.py +346 -0
- sqlspec/extensions/starlette/middleware.py +235 -0
- sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/loader.py +702 -0
- sqlspec/migrations/__init__.py +36 -0
- sqlspec/migrations/base.py +731 -0
- sqlspec/migrations/commands.py +1232 -0
- sqlspec/migrations/context.py +157 -0
- sqlspec/migrations/fix.py +204 -0
- sqlspec/migrations/loaders.py +443 -0
- sqlspec/migrations/runner.py +1172 -0
- sqlspec/migrations/templates.py +234 -0
- sqlspec/migrations/tracker.py +611 -0
- sqlspec/migrations/utils.py +256 -0
- sqlspec/migrations/validation.py +207 -0
- sqlspec/migrations/version.py +446 -0
- sqlspec/observability/__init__.py +55 -0
- sqlspec/observability/_common.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_common.py +77 -0
- sqlspec/observability/_config.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_config.py +348 -0
- sqlspec/observability/_diagnostics.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_diagnostics.py +74 -0
- sqlspec/observability/_dispatcher.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_dispatcher.py +152 -0
- sqlspec/observability/_formatters/__init__.py +13 -0
- sqlspec/observability/_formatters/_aws.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_aws.py +102 -0
- sqlspec/observability/_formatters/_azure.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_azure.py +96 -0
- sqlspec/observability/_formatters/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_base.py +57 -0
- sqlspec/observability/_formatters/_gcp.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_gcp.py +131 -0
- sqlspec/observability/_formatting.py +58 -0
- sqlspec/observability/_observer.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_observer.py +357 -0
- sqlspec/observability/_runtime.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_runtime.py +420 -0
- sqlspec/observability/_sampling.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_sampling.py +188 -0
- sqlspec/observability/_spans.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_spans.py +161 -0
- sqlspec/protocols.py +916 -0
- sqlspec/py.typed +0 -0
- sqlspec/storage/__init__.py +48 -0
- sqlspec/storage/_utils.py +104 -0
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/base.py +253 -0
- sqlspec/storage/backends/fsspec.py +529 -0
- sqlspec/storage/backends/local.py +441 -0
- sqlspec/storage/backends/obstore.py +916 -0
- sqlspec/storage/errors.py +104 -0
- sqlspec/storage/pipeline.py +582 -0
- sqlspec/storage/registry.py +301 -0
- sqlspec/typing.py +395 -0
- sqlspec/utils/__init__.py +7 -0
- sqlspec/utils/arrow_helpers.py +318 -0
- sqlspec/utils/config_tools.py +332 -0
- sqlspec/utils/correlation.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/correlation.py +134 -0
- sqlspec/utils/deprecation.py +190 -0
- sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/fixtures.py +258 -0
- sqlspec/utils/logging.py +222 -0
- sqlspec/utils/module_loader.py +306 -0
- sqlspec/utils/portal.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/portal.py +375 -0
- sqlspec/utils/schema.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/schema.py +485 -0
- sqlspec/utils/serializers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/serializers.py +408 -0
- sqlspec/utils/singleton.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/singleton.py +41 -0
- sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/sync_tools.py +311 -0
- sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/text.py +108 -0
- sqlspec/utils/type_converters.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_converters.py +128 -0
- sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_guards.py +1360 -0
- sqlspec/utils/uuids.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/uuids.py +225 -0
- sqlspec-0.36.0.dist-info/METADATA +205 -0
- sqlspec-0.36.0.dist-info/RECORD +531 -0
- sqlspec-0.36.0.dist-info/WHEEL +7 -0
- sqlspec-0.36.0.dist-info/entry_points.txt +2 -0
- sqlspec-0.36.0.dist-info/licenses/LICENSE +21 -0
sqlspec/config.py
ADDED
|
@@ -0,0 +1,1755 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from inspect import Signature, signature
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Generic, Literal, TypeAlias, TypeVar, cast
|
|
6
|
+
|
|
7
|
+
from typing_extensions import NotRequired, TypedDict
|
|
8
|
+
|
|
9
|
+
from sqlspec.core import ParameterStyle, ParameterStyleConfig, StatementConfig
|
|
10
|
+
from sqlspec.exceptions import MissingDependencyError
|
|
11
|
+
from sqlspec.extensions.events import EventRuntimeHints
|
|
12
|
+
from sqlspec.loader import SQLFileLoader
|
|
13
|
+
from sqlspec.migrations import AsyncMigrationTracker, SyncMigrationTracker, create_migration_commands
|
|
14
|
+
from sqlspec.observability import ObservabilityConfig, ObservabilityRuntime
|
|
15
|
+
from sqlspec.utils.logging import get_logger
|
|
16
|
+
from sqlspec.utils.module_loader import ensure_pyarrow
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from collections.abc import Awaitable
|
|
20
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager
|
|
21
|
+
|
|
22
|
+
from sqlspec.driver import AsyncDriverAdapterBase, SyncDriverAdapterBase
|
|
23
|
+
from sqlspec.migrations.commands import AsyncMigrationCommands, SyncMigrationCommands
|
|
24
|
+
from sqlspec.storage import StorageCapabilities
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
__all__ = (
|
|
28
|
+
"ADKConfig",
|
|
29
|
+
"AsyncConfigT",
|
|
30
|
+
"AsyncDatabaseConfig",
|
|
31
|
+
"ConfigT",
|
|
32
|
+
"DatabaseConfigProtocol",
|
|
33
|
+
"DriverT",
|
|
34
|
+
"EventsConfig",
|
|
35
|
+
"ExtensionConfigs",
|
|
36
|
+
"FastAPIConfig",
|
|
37
|
+
"FlaskConfig",
|
|
38
|
+
"LifecycleConfig",
|
|
39
|
+
"LitestarConfig",
|
|
40
|
+
"MigrationConfig",
|
|
41
|
+
"NoPoolAsyncConfig",
|
|
42
|
+
"NoPoolSyncConfig",
|
|
43
|
+
"OpenTelemetryConfig",
|
|
44
|
+
"PrometheusConfig",
|
|
45
|
+
"StarletteConfig",
|
|
46
|
+
"SyncConfigT",
|
|
47
|
+
"SyncDatabaseConfig",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
AsyncConfigT = TypeVar("AsyncConfigT", bound="AsyncDatabaseConfig[Any, Any, Any] | NoPoolAsyncConfig[Any, Any]")
|
|
51
|
+
SyncConfigT = TypeVar("SyncConfigT", bound="SyncDatabaseConfig[Any, Any, Any] | NoPoolSyncConfig[Any, Any]")
|
|
52
|
+
ConfigT = TypeVar(
|
|
53
|
+
"ConfigT",
|
|
54
|
+
bound="AsyncDatabaseConfig[Any, Any, Any] | NoPoolAsyncConfig[Any, Any] | SyncDatabaseConfig[Any, Any, Any] | NoPoolSyncConfig[Any, Any]",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
ConnectionT = TypeVar("ConnectionT")
|
|
58
|
+
PoolT = TypeVar("PoolT")
|
|
59
|
+
DriverT = TypeVar("DriverT", bound="SyncDriverAdapterBase | AsyncDriverAdapterBase")
|
|
60
|
+
|
|
61
|
+
logger = get_logger("sqlspec.config")
|
|
62
|
+
|
|
63
|
+
DRIVER_FEATURE_LIFECYCLE_HOOKS: dict[str, str | None] = {
|
|
64
|
+
"on_connection_create": "connection",
|
|
65
|
+
"on_connection_destroy": "connection",
|
|
66
|
+
"on_pool_create": "pool",
|
|
67
|
+
"on_pool_destroy": "pool",
|
|
68
|
+
"on_session_start": "session",
|
|
69
|
+
"on_session_end": "session",
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class _DriverFeatureHookWrapper:
|
|
74
|
+
__slots__ = ("_callback", "_context_key", "_expects_argument")
|
|
75
|
+
|
|
76
|
+
def __init__(self, callback: "Callable[..., Any]", context_key: "str | None", expects_argument: bool) -> None:
|
|
77
|
+
self._callback = callback
|
|
78
|
+
self._context_key = context_key
|
|
79
|
+
self._expects_argument = expects_argument
|
|
80
|
+
|
|
81
|
+
def __call__(self, context: "dict[str, Any]") -> None:
|
|
82
|
+
if not self._expects_argument:
|
|
83
|
+
self._callback()
|
|
84
|
+
return
|
|
85
|
+
if self._context_key is None:
|
|
86
|
+
self._callback(context)
|
|
87
|
+
return
|
|
88
|
+
self._callback(context.get(self._context_key))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class LifecycleConfig(TypedDict):
|
|
92
|
+
"""Lifecycle hooks for database adapters.
|
|
93
|
+
|
|
94
|
+
Each hook accepts a list of callables to support multiple handlers.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
on_connection_create: NotRequired[list[Callable[[Any], None]]]
|
|
98
|
+
on_connection_destroy: NotRequired[list[Callable[[Any], None]]]
|
|
99
|
+
on_pool_create: NotRequired[list[Callable[[Any], None]]]
|
|
100
|
+
on_pool_destroy: NotRequired[list[Callable[[Any], None]]]
|
|
101
|
+
on_session_start: NotRequired[list[Callable[[Any], None]]]
|
|
102
|
+
on_session_end: NotRequired[list[Callable[[Any], None]]]
|
|
103
|
+
on_query_start: NotRequired[list[Callable[[str, dict[str, Any]], None]]]
|
|
104
|
+
on_query_complete: NotRequired[list[Callable[[str, dict[str, Any], Any], None]]]
|
|
105
|
+
on_error: NotRequired[list[Callable[[Exception, str, dict[str, Any]], None]]]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class MigrationConfig(TypedDict):
|
|
109
|
+
"""Configuration options for database migrations.
|
|
110
|
+
|
|
111
|
+
All fields are optional with default values.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
script_location: NotRequired["str | Path"]
|
|
115
|
+
"""Path to the migrations directory. Accepts string or Path object. Defaults to 'migrations'."""
|
|
116
|
+
|
|
117
|
+
version_table_name: NotRequired[str]
|
|
118
|
+
"""Name of the table used to track applied migrations. Defaults to 'sqlspec_migrations'."""
|
|
119
|
+
|
|
120
|
+
project_root: NotRequired[str]
|
|
121
|
+
"""Path to the project root directory. Used for relative path resolution."""
|
|
122
|
+
|
|
123
|
+
enabled: NotRequired[bool]
|
|
124
|
+
"""Whether this configuration should be included in CLI operations. Defaults to True."""
|
|
125
|
+
|
|
126
|
+
auto_sync: NotRequired[bool]
|
|
127
|
+
"""Enable automatic version reconciliation during upgrade. When enabled (default), SQLSpec automatically updates database tracking when migrations are renamed from timestamp to sequential format. Defaults to True."""
|
|
128
|
+
|
|
129
|
+
strict_ordering: NotRequired[bool]
|
|
130
|
+
"""Enforce strict migration ordering. When enabled, prevents out-of-order migrations from being applied. Defaults to False."""
|
|
131
|
+
|
|
132
|
+
include_extensions: NotRequired["list[str]"]
|
|
133
|
+
"""List of extension names whose migrations should be included. Extension migrations maintain separate versioning and are prefixed with 'ext_{name}_'.
|
|
134
|
+
|
|
135
|
+
Note: Extensions with migration support (litestar, adk, events) are auto-included when
|
|
136
|
+
their settings are present in ``extension_config``. Use ``exclude_extensions`` to opt out.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
exclude_extensions: NotRequired["list[str]"]
|
|
140
|
+
"""List of extension names to exclude from automatic migration inclusion.
|
|
141
|
+
|
|
142
|
+
When an extension is configured in ``extension_config``, its migrations are automatically
|
|
143
|
+
included. Use this to prevent that for specific extensions:
|
|
144
|
+
|
|
145
|
+
Example:
|
|
146
|
+
migration_config={
|
|
147
|
+
"exclude_extensions": ["events"] # Use ephemeral listen_notify, skip queue table
|
|
148
|
+
}
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
transactional: NotRequired[bool]
|
|
152
|
+
"""Wrap migrations in transactions when supported. When enabled (default for adapters that support it), each migration runs in a transaction that is committed on success or rolled back on failure. This prevents partial migrations from leaving the database in an inconsistent state. Requires adapter support for transactional DDL. Defaults to True for PostgreSQL, SQLite, and DuckDB; False for MySQL, Oracle, and BigQuery. Individual migrations can override this with a '-- transactional: false' comment."""
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class FlaskConfig(TypedDict):
|
|
156
|
+
"""Configuration options for Flask SQLSpec extension.
|
|
157
|
+
|
|
158
|
+
All fields are optional with sensible defaults. Use in extension_config["flask"]:
|
|
159
|
+
|
|
160
|
+
Example:
|
|
161
|
+
from sqlspec.adapters.asyncpg import AsyncpgConfig
|
|
162
|
+
|
|
163
|
+
config = AsyncpgConfig(
|
|
164
|
+
connection_config={"dsn": "postgresql://localhost/mydb"},
|
|
165
|
+
extension_config={
|
|
166
|
+
"flask": {
|
|
167
|
+
"commit_mode": "autocommit",
|
|
168
|
+
"session_key": "db"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
Notes:
|
|
174
|
+
This TypedDict provides type safety for extension config.
|
|
175
|
+
Flask extension uses g object for request-scoped storage.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
connection_key: NotRequired[str]
|
|
179
|
+
"""Key for storing connection in Flask g object. Default: auto-generated from session_key."""
|
|
180
|
+
|
|
181
|
+
session_key: NotRequired[str]
|
|
182
|
+
"""Key for accessing session via plugin.get_session(). Default: 'db_session'."""
|
|
183
|
+
|
|
184
|
+
commit_mode: NotRequired[Literal["manual", "autocommit", "autocommit_include_redirect"]]
|
|
185
|
+
"""Transaction commit mode. Default: 'manual'.
|
|
186
|
+
- manual: No automatic commits, user handles explicitly
|
|
187
|
+
- autocommit: Commits on 2xx status, rollback otherwise
|
|
188
|
+
- autocommit_include_redirect: Commits on 2xx-3xx status, rollback otherwise
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
extra_commit_statuses: NotRequired[set[int]]
|
|
192
|
+
"""Additional HTTP status codes that trigger commit. Default: None."""
|
|
193
|
+
|
|
194
|
+
extra_rollback_statuses: NotRequired[set[int]]
|
|
195
|
+
"""Additional HTTP status codes that trigger rollback. Default: None."""
|
|
196
|
+
|
|
197
|
+
disable_di: NotRequired[bool]
|
|
198
|
+
"""Disable built-in dependency injection. Default: False.
|
|
199
|
+
When True, the Flask extension will not register request hooks for managing
|
|
200
|
+
database connections and sessions. Users are responsible for managing the
|
|
201
|
+
database lifecycle manually via their own DI solution.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class LitestarConfig(TypedDict):
|
|
206
|
+
"""Configuration options for Litestar SQLSpec plugin.
|
|
207
|
+
|
|
208
|
+
All fields are optional with sensible defaults.
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
session_table: NotRequired["bool | str"]
|
|
212
|
+
"""Enable session table for server-side session storage.
|
|
213
|
+
|
|
214
|
+
- ``True``: Use default table name ('litestar_session')
|
|
215
|
+
- ``"custom_name"``: Use custom table name
|
|
216
|
+
|
|
217
|
+
When set, litestar extension migrations are auto-included to create the session table.
|
|
218
|
+
If you're only using litestar for DI/connection management (not session storage),
|
|
219
|
+
leave this unset to skip the migrations.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
connection_key: NotRequired[str]
|
|
223
|
+
"""Key for storing connection in ASGI scope. Default: 'db_connection'"""
|
|
224
|
+
|
|
225
|
+
pool_key: NotRequired[str]
|
|
226
|
+
"""Key for storing connection pool in application state. Default: 'db_pool'"""
|
|
227
|
+
|
|
228
|
+
session_key: NotRequired[str]
|
|
229
|
+
"""Key for storing session in ASGI scope. Default: 'db_session'"""
|
|
230
|
+
|
|
231
|
+
commit_mode: NotRequired[Literal["manual", "autocommit", "autocommit_include_redirect"]]
|
|
232
|
+
"""Transaction commit mode. Default: 'manual'"""
|
|
233
|
+
|
|
234
|
+
enable_correlation_middleware: NotRequired[bool]
|
|
235
|
+
"""Enable request correlation ID middleware. Default: True"""
|
|
236
|
+
|
|
237
|
+
correlation_header: NotRequired[str]
|
|
238
|
+
"""HTTP header to read the request correlation ID from when middleware is enabled. Default: ``X-Request-ID``"""
|
|
239
|
+
|
|
240
|
+
extra_commit_statuses: NotRequired[set[int]]
|
|
241
|
+
"""Additional HTTP status codes that trigger commit. Default: set()"""
|
|
242
|
+
|
|
243
|
+
extra_rollback_statuses: NotRequired[set[int]]
|
|
244
|
+
"""Additional HTTP status codes that trigger rollback. Default: set()"""
|
|
245
|
+
|
|
246
|
+
disable_di: NotRequired[bool]
|
|
247
|
+
"""Disable built-in dependency injection. Default: False.
|
|
248
|
+
When True, the Litestar plugin will not register dependency providers for managing
|
|
249
|
+
database connections, pools, and sessions. Users are responsible for managing the
|
|
250
|
+
database lifecycle manually via their own DI solution.
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class StarletteConfig(TypedDict):
|
|
255
|
+
"""Configuration options for Starlette and FastAPI extensions.
|
|
256
|
+
|
|
257
|
+
All fields are optional with sensible defaults. Use in extension_config["starlette"]:
|
|
258
|
+
|
|
259
|
+
Example:
|
|
260
|
+
from sqlspec.adapters.asyncpg import AsyncpgConfig
|
|
261
|
+
|
|
262
|
+
config = AsyncpgConfig(
|
|
263
|
+
connection_config={"dsn": "postgresql://localhost/mydb"},
|
|
264
|
+
extension_config={
|
|
265
|
+
"starlette": {
|
|
266
|
+
"commit_mode": "autocommit",
|
|
267
|
+
"session_key": "db"
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
Notes:
|
|
273
|
+
Both Starlette and FastAPI extensions use the "starlette" key.
|
|
274
|
+
This TypedDict provides type safety for extension config.
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
connection_key: NotRequired[str]
|
|
278
|
+
"""Key for storing connection in request.state. Default: 'db_connection'"""
|
|
279
|
+
|
|
280
|
+
pool_key: NotRequired[str]
|
|
281
|
+
"""Key for storing connection pool in app.state. Default: 'db_pool'"""
|
|
282
|
+
|
|
283
|
+
session_key: NotRequired[str]
|
|
284
|
+
"""Key for storing session in request.state. Default: 'db_session'"""
|
|
285
|
+
|
|
286
|
+
commit_mode: NotRequired[Literal["manual", "autocommit", "autocommit_include_redirect"]]
|
|
287
|
+
"""Transaction commit mode. Default: 'manual'
|
|
288
|
+
|
|
289
|
+
- manual: No automatic commit/rollback
|
|
290
|
+
- autocommit: Commit on 2xx, rollback otherwise
|
|
291
|
+
- autocommit_include_redirect: Commit on 2xx-3xx, rollback otherwise
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
extra_commit_statuses: NotRequired[set[int]]
|
|
295
|
+
"""Additional HTTP status codes that trigger commit. Default: set()
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
extra_commit_statuses={201, 202}
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
extra_rollback_statuses: NotRequired[set[int]]
|
|
302
|
+
"""Additional HTTP status codes that trigger rollback. Default: set()
|
|
303
|
+
|
|
304
|
+
Example:
|
|
305
|
+
extra_rollback_statuses={409}
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
disable_di: NotRequired[bool]
|
|
309
|
+
"""Disable built-in dependency injection. Default: False.
|
|
310
|
+
When True, the Starlette/FastAPI extension will not add middleware for managing
|
|
311
|
+
database connections and sessions. Users are responsible for managing the
|
|
312
|
+
database lifecycle manually via their own DI solution.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
class FastAPIConfig(StarletteConfig):
|
|
317
|
+
"""Configuration options for FastAPI SQLSpec extension.
|
|
318
|
+
|
|
319
|
+
All fields are optional with sensible defaults. Use in extension_config["fastapi"]:
|
|
320
|
+
|
|
321
|
+
Example:
|
|
322
|
+
from sqlspec.adapters.asyncpg import AsyncpgConfig
|
|
323
|
+
|
|
324
|
+
config = AsyncpgConfig(
|
|
325
|
+
connection_config={"dsn": "postgresql://localhost/mydb"},
|
|
326
|
+
extension_config={
|
|
327
|
+
"fastapi": {
|
|
328
|
+
"commit_mode": "autocommit",
|
|
329
|
+
"session_key": "db"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
class ADKConfig(TypedDict):
|
|
336
|
+
"""Configuration options for ADK session and memory store extension.
|
|
337
|
+
|
|
338
|
+
All fields are optional with sensible defaults. Use in extension_config["adk"]:
|
|
339
|
+
|
|
340
|
+
Configuration supports three deployment scenarios:
|
|
341
|
+
1. SQLSpec manages everything (runtime + migrations)
|
|
342
|
+
2. SQLSpec runtime only (external migration tools like Alembic/Flyway)
|
|
343
|
+
3. Selective features (sessions OR memory, not both)
|
|
344
|
+
|
|
345
|
+
Example:
|
|
346
|
+
from sqlspec.adapters.asyncpg import AsyncpgConfig
|
|
347
|
+
|
|
348
|
+
config = AsyncpgConfig(
|
|
349
|
+
connection_config={"dsn": "postgresql://localhost/mydb"},
|
|
350
|
+
extension_config={
|
|
351
|
+
"adk": {
|
|
352
|
+
"session_table": "my_sessions",
|
|
353
|
+
"events_table": "my_events",
|
|
354
|
+
"memory_table": "my_memories",
|
|
355
|
+
"memory_use_fts": True,
|
|
356
|
+
"owner_id_column": "tenant_id INTEGER REFERENCES tenants(id)"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
Notes:
|
|
362
|
+
This TypedDict provides type safety for extension config but is not required.
|
|
363
|
+
You can use plain dicts as well.
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
enable_sessions: NotRequired[bool]
|
|
367
|
+
"""Enable session store at runtime. Default: True.
|
|
368
|
+
|
|
369
|
+
When False: session service unavailable, session store operations disabled.
|
|
370
|
+
Independent of migration control - can use externally-managed tables.
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
enable_memory: NotRequired[bool]
|
|
374
|
+
"""Enable memory store at runtime. Default: True.
|
|
375
|
+
|
|
376
|
+
When False: memory service unavailable, memory store operations disabled.
|
|
377
|
+
Independent of migration control - can use externally-managed tables.
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
include_sessions_migration: NotRequired[bool]
|
|
381
|
+
"""Include session tables in SQLSpec migrations. Default: True.
|
|
382
|
+
|
|
383
|
+
When False: session migration DDL skipped (use external migration tools).
|
|
384
|
+
Decoupled from enable_sessions - allows external table management with SQLSpec runtime.
|
|
385
|
+
"""
|
|
386
|
+
|
|
387
|
+
include_memory_migration: NotRequired[bool]
|
|
388
|
+
"""Include memory tables in SQLSpec migrations. Default: True.
|
|
389
|
+
|
|
390
|
+
When False: memory migration DDL skipped (use external migration tools).
|
|
391
|
+
Decoupled from enable_memory - allows external table management with SQLSpec runtime.
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
session_table: NotRequired[str]
|
|
395
|
+
"""Name of the sessions table. Default: 'adk_sessions'
|
|
396
|
+
|
|
397
|
+
Examples:
|
|
398
|
+
"agent_sessions"
|
|
399
|
+
"my_app_sessions"
|
|
400
|
+
"tenant_acme_sessions"
|
|
401
|
+
"""
|
|
402
|
+
|
|
403
|
+
events_table: NotRequired[str]
|
|
404
|
+
"""Name of the events table. Default: 'adk_events'
|
|
405
|
+
|
|
406
|
+
Examples:
|
|
407
|
+
"agent_events"
|
|
408
|
+
"my_app_events"
|
|
409
|
+
"tenant_acme_events"
|
|
410
|
+
"""
|
|
411
|
+
|
|
412
|
+
memory_table: NotRequired[str]
|
|
413
|
+
"""Name of the memory entries table. Default: 'adk_memory_entries'
|
|
414
|
+
|
|
415
|
+
Examples:
|
|
416
|
+
"agent_memories"
|
|
417
|
+
"my_app_memories"
|
|
418
|
+
"tenant_acme_memories"
|
|
419
|
+
"""
|
|
420
|
+
|
|
421
|
+
memory_use_fts: NotRequired[bool]
|
|
422
|
+
"""Enable full-text search when supported. Default: False.
|
|
423
|
+
|
|
424
|
+
When True, adapters will use their native FTS capabilities where available:
|
|
425
|
+
- PostgreSQL: to_tsvector/to_tsquery with GIN index
|
|
426
|
+
- SQLite: FTS5 virtual table
|
|
427
|
+
- DuckDB: FTS extension with match_bm25
|
|
428
|
+
- Oracle: CONTAINS() with CTXSYS.CONTEXT index
|
|
429
|
+
- BigQuery: SEARCH() function (requires search index)
|
|
430
|
+
- Spanner: TOKENIZE_FULLTEXT with search index
|
|
431
|
+
- MySQL: MATCH...AGAINST with FULLTEXT index
|
|
432
|
+
|
|
433
|
+
When False, adapters use simple LIKE/ILIKE queries (works without indexes).
|
|
434
|
+
"""
|
|
435
|
+
|
|
436
|
+
memory_max_results: NotRequired[int]
|
|
437
|
+
"""Maximum number of results for memory search queries. Default: 20.
|
|
438
|
+
|
|
439
|
+
Limits the number of memory entries returned by search_memory().
|
|
440
|
+
Can be overridden per-query via the limit parameter.
|
|
441
|
+
"""
|
|
442
|
+
|
|
443
|
+
owner_id_column: NotRequired[str]
|
|
444
|
+
"""Optional owner ID column definition to link sessions/memories to a user, tenant, team, or other entity.
|
|
445
|
+
|
|
446
|
+
Format: "column_name TYPE [NOT NULL] REFERENCES table(column) [options...]"
|
|
447
|
+
|
|
448
|
+
The entire definition is passed through to DDL verbatim. We only parse
|
|
449
|
+
the column name (first word) for use in INSERT/SELECT statements.
|
|
450
|
+
|
|
451
|
+
This column is added to both session and memory tables for consistent
|
|
452
|
+
multi-tenant isolation.
|
|
453
|
+
|
|
454
|
+
Supports:
|
|
455
|
+
- Foreign key constraints: REFERENCES table(column)
|
|
456
|
+
- Nullable or NOT NULL
|
|
457
|
+
- CASCADE options: ON DELETE CASCADE, ON UPDATE CASCADE
|
|
458
|
+
- Dialect-specific options (DEFERRABLE, ENABLE VALIDATE, etc.)
|
|
459
|
+
- Plain columns without FK (just extra column storage)
|
|
460
|
+
|
|
461
|
+
Examples:
|
|
462
|
+
PostgreSQL with UUID FK:
|
|
463
|
+
"account_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE"
|
|
464
|
+
|
|
465
|
+
MySQL with BIGINT FK:
|
|
466
|
+
"user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT"
|
|
467
|
+
|
|
468
|
+
Oracle with NUMBER FK:
|
|
469
|
+
"user_id NUMBER(10) REFERENCES users(id) ENABLE VALIDATE"
|
|
470
|
+
|
|
471
|
+
SQLite with INTEGER FK:
|
|
472
|
+
"tenant_id INTEGER NOT NULL REFERENCES tenants(id)"
|
|
473
|
+
|
|
474
|
+
Nullable FK (optional relationship):
|
|
475
|
+
"workspace_id UUID REFERENCES workspaces(id) ON DELETE SET NULL"
|
|
476
|
+
|
|
477
|
+
No FK (just extra column):
|
|
478
|
+
"organization_name VARCHAR(128) NOT NULL"
|
|
479
|
+
|
|
480
|
+
Deferred constraint (PostgreSQL):
|
|
481
|
+
"user_id UUID REFERENCES users(id) DEFERRABLE INITIALLY DEFERRED"
|
|
482
|
+
|
|
483
|
+
Notes:
|
|
484
|
+
- Column name (first word) is extracted for INSERT/SELECT queries
|
|
485
|
+
- Rest of definition is passed through to CREATE TABLE DDL
|
|
486
|
+
- Database validates the DDL syntax (fail-fast on errors)
|
|
487
|
+
- Works with all database dialects (PostgreSQL, MySQL, SQLite, Oracle, etc.)
|
|
488
|
+
"""
|
|
489
|
+
|
|
490
|
+
in_memory: NotRequired[bool]
|
|
491
|
+
"""Enable in-memory table storage (Oracle-specific). Default: False.
|
|
492
|
+
|
|
493
|
+
When enabled, tables are created with the INMEMORY clause for Oracle Database,
|
|
494
|
+
which stores table data in columnar format in memory for faster query performance.
|
|
495
|
+
|
|
496
|
+
This is an Oracle-specific feature that requires:
|
|
497
|
+
- Oracle Database 12.1.0.2 or higher
|
|
498
|
+
- Database In-Memory option license (Enterprise Edition)
|
|
499
|
+
- Sufficient INMEMORY_SIZE configured in the database instance
|
|
500
|
+
|
|
501
|
+
Other database adapters ignore this setting.
|
|
502
|
+
|
|
503
|
+
Examples:
|
|
504
|
+
Oracle with in-memory enabled:
|
|
505
|
+
config = OracleAsyncConfig(
|
|
506
|
+
connection_config={"dsn": "oracle://..."},
|
|
507
|
+
extension_config={
|
|
508
|
+
"adk": {
|
|
509
|
+
"in_memory": True
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
Notes:
|
|
515
|
+
- Improves query performance for analytics (10-100x faster)
|
|
516
|
+
- Tables created with INMEMORY clause
|
|
517
|
+
- Requires Oracle Database In-Memory option license
|
|
518
|
+
- Ignored by non-Oracle adapters
|
|
519
|
+
"""
|
|
520
|
+
|
|
521
|
+
shard_count: NotRequired[int]
|
|
522
|
+
"""Optional hash shard count for session/event tables to reduce hotspotting.
|
|
523
|
+
|
|
524
|
+
When set (>1), adapters that support computed shard columns will create a
|
|
525
|
+
generated shard_id using MOD(FARM_FINGERPRINT(primary_key), shard_count) and
|
|
526
|
+
include it in the primary key and filters. Ignored by adapters that do not
|
|
527
|
+
support computed shards.
|
|
528
|
+
"""
|
|
529
|
+
|
|
530
|
+
session_table_options: NotRequired[str]
|
|
531
|
+
"""Adapter-specific table OPTIONS/clauses for the sessions table.
|
|
532
|
+
|
|
533
|
+
Passed verbatim when supported (e.g., Spanner columnar/tiered storage). Ignored by
|
|
534
|
+
adapters without table OPTIONS support.
|
|
535
|
+
"""
|
|
536
|
+
|
|
537
|
+
events_table_options: NotRequired[str]
|
|
538
|
+
"""Adapter-specific table OPTIONS/clauses for the events table."""
|
|
539
|
+
|
|
540
|
+
memory_table_options: NotRequired[str]
|
|
541
|
+
"""Adapter-specific table OPTIONS/clauses for the memory table."""
|
|
542
|
+
|
|
543
|
+
expires_index_options: NotRequired[str]
|
|
544
|
+
"""Adapter-specific options for the expires/index used in ADK stores."""
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
class EventsConfig(TypedDict):
|
|
548
|
+
"""Configuration options for the events extension.
|
|
549
|
+
|
|
550
|
+
Use in ``extension_config["events"]``.
|
|
551
|
+
"""
|
|
552
|
+
|
|
553
|
+
backend: NotRequired[Literal["listen_notify", "table_queue", "listen_notify_durable", "advanced_queue"]]
|
|
554
|
+
"""Backend implementation. PostgreSQL adapters default to 'listen_notify', others to 'table_queue'.
|
|
555
|
+
|
|
556
|
+
- listen_notify: Real-time PostgreSQL LISTEN/NOTIFY (ephemeral)
|
|
557
|
+
- table_queue: Durable table-backed queue with retries (all adapters)
|
|
558
|
+
- listen_notify_durable: Hybrid combining both (PostgreSQL only)
|
|
559
|
+
- advanced_queue: Oracle Advanced Queueing
|
|
560
|
+
"""
|
|
561
|
+
|
|
562
|
+
queue_table: NotRequired[str]
|
|
563
|
+
"""Name of the fallback queue table. Defaults to 'sqlspec_event_queue'."""
|
|
564
|
+
|
|
565
|
+
lease_seconds: NotRequired[int]
|
|
566
|
+
"""Lease duration for claimed events before they can be retried. Defaults to 30 seconds."""
|
|
567
|
+
|
|
568
|
+
retention_seconds: NotRequired[int]
|
|
569
|
+
"""Retention window for acknowledged events before cleanup. Defaults to 86400 (24 hours)."""
|
|
570
|
+
|
|
571
|
+
poll_interval: NotRequired[float]
|
|
572
|
+
"""Default poll interval in seconds for event consumers. Defaults to 1.0."""
|
|
573
|
+
|
|
574
|
+
select_for_update: NotRequired[bool]
|
|
575
|
+
"""Use SELECT FOR UPDATE locking when claiming events. Defaults to False."""
|
|
576
|
+
|
|
577
|
+
skip_locked: NotRequired[bool]
|
|
578
|
+
"""Use SKIP LOCKED for non-blocking event claims. Defaults to False."""
|
|
579
|
+
|
|
580
|
+
json_passthrough: NotRequired[bool]
|
|
581
|
+
"""Skip JSON encoding/decoding for payloads. Defaults to False."""
|
|
582
|
+
|
|
583
|
+
in_memory: NotRequired[bool]
|
|
584
|
+
"""Enable Oracle INMEMORY clause for the queue table. Ignored by other adapters. Defaults to False.
|
|
585
|
+
|
|
586
|
+
Note: To skip events migrations (e.g., when using ephemeral 'listen_notify' backend),
|
|
587
|
+
use ``migration_config={"exclude_extensions": ["events"]}``.
|
|
588
|
+
"""
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
class OpenTelemetryConfig(TypedDict):
|
|
592
|
+
"""Configuration options for OpenTelemetry integration.
|
|
593
|
+
|
|
594
|
+
Use in ``extension_config["otel"]``.
|
|
595
|
+
"""
|
|
596
|
+
|
|
597
|
+
enabled: NotRequired[bool]
|
|
598
|
+
"""Enable the extension. Default: True."""
|
|
599
|
+
|
|
600
|
+
enable_spans: NotRequired[bool]
|
|
601
|
+
"""Enable span emission (set False to disable while keeping other settings)."""
|
|
602
|
+
|
|
603
|
+
resource_attributes: NotRequired[dict[str, Any]]
|
|
604
|
+
"""Additional resource attributes passed to the tracer provider factory."""
|
|
605
|
+
|
|
606
|
+
tracer_provider: NotRequired[Any]
|
|
607
|
+
"""Tracer provider instance to reuse. Mutually exclusive with ``tracer_provider_factory``."""
|
|
608
|
+
|
|
609
|
+
tracer_provider_factory: NotRequired[Callable[[], Any]]
|
|
610
|
+
"""Factory returning a tracer provider. Invoked lazily when spans are needed."""
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
class PrometheusConfig(TypedDict):
|
|
614
|
+
"""Configuration options for Prometheus metrics.
|
|
615
|
+
|
|
616
|
+
Use in ``extension_config["prometheus"]``.
|
|
617
|
+
"""
|
|
618
|
+
|
|
619
|
+
enabled: NotRequired[bool]
|
|
620
|
+
"""Enable the extension. Default: True."""
|
|
621
|
+
|
|
622
|
+
namespace: NotRequired[str]
|
|
623
|
+
"""Prometheus metric namespace. Default: ``"sqlspec"``."""
|
|
624
|
+
|
|
625
|
+
subsystem: NotRequired[str]
|
|
626
|
+
"""Prometheus metric subsystem. Default: ``"driver"``."""
|
|
627
|
+
|
|
628
|
+
registry: NotRequired[Any]
|
|
629
|
+
"""Custom Prometheus registry (defaults to the global registry)."""
|
|
630
|
+
|
|
631
|
+
label_names: NotRequired[tuple[str, ...]]
|
|
632
|
+
"""Labels applied to metrics. Default: ("driver", "operation")."""
|
|
633
|
+
|
|
634
|
+
duration_buckets: NotRequired[tuple[float, ...]]
|
|
635
|
+
"""Histogram buckets for query duration (seconds)."""
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
ExtensionConfigs: TypeAlias = dict[
|
|
639
|
+
str,
|
|
640
|
+
dict[str, Any]
|
|
641
|
+
| LitestarConfig
|
|
642
|
+
| FastAPIConfig
|
|
643
|
+
| StarletteConfig
|
|
644
|
+
| FlaskConfig
|
|
645
|
+
| ADKConfig
|
|
646
|
+
| EventsConfig
|
|
647
|
+
| OpenTelemetryConfig
|
|
648
|
+
| PrometheusConfig,
|
|
649
|
+
]
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
|
|
653
|
+
"""Protocol defining the interface for database configurations."""
|
|
654
|
+
|
|
655
|
+
__slots__ = (
|
|
656
|
+
"_migration_commands",
|
|
657
|
+
"_migration_loader",
|
|
658
|
+
"_observability_runtime",
|
|
659
|
+
"_storage_capabilities",
|
|
660
|
+
"bind_key",
|
|
661
|
+
"connection_instance",
|
|
662
|
+
"driver_features",
|
|
663
|
+
"extension_config",
|
|
664
|
+
"migration_config",
|
|
665
|
+
"observability_config",
|
|
666
|
+
"statement_config",
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
_migration_loader: "SQLFileLoader"
|
|
670
|
+
_migration_commands: "SyncMigrationCommands[Any] | AsyncMigrationCommands[Any]"
|
|
671
|
+
driver_type: "ClassVar[type[Any]]"
|
|
672
|
+
connection_type: "ClassVar[type[Any]]"
|
|
673
|
+
is_async: "ClassVar[bool]" = False
|
|
674
|
+
supports_connection_pooling: "ClassVar[bool]" = False
|
|
675
|
+
supports_transactional_ddl: "ClassVar[bool]" = False
|
|
676
|
+
supports_native_arrow_import: "ClassVar[bool]" = False
|
|
677
|
+
supports_native_arrow_export: "ClassVar[bool]" = False
|
|
678
|
+
supports_native_parquet_import: "ClassVar[bool]" = False
|
|
679
|
+
supports_native_parquet_export: "ClassVar[bool]" = False
|
|
680
|
+
requires_staging_for_load: "ClassVar[bool]" = False
|
|
681
|
+
staging_protocols: "ClassVar[tuple[str, ...]]" = ()
|
|
682
|
+
default_storage_profile: "ClassVar[str | None]" = None
|
|
683
|
+
storage_partition_strategies: "ClassVar[tuple[str, ...]]" = ("fixed",)
|
|
684
|
+
bind_key: "str | None"
|
|
685
|
+
statement_config: "StatementConfig"
|
|
686
|
+
connection_instance: "PoolT | None"
|
|
687
|
+
migration_config: "dict[str, Any] | MigrationConfig"
|
|
688
|
+
extension_config: "ExtensionConfigs"
|
|
689
|
+
driver_features: "dict[str, Any]"
|
|
690
|
+
_storage_capabilities: "StorageCapabilities | None"
|
|
691
|
+
observability_config: "ObservabilityConfig | None"
|
|
692
|
+
_observability_runtime: "ObservabilityRuntime | None"
|
|
693
|
+
|
|
694
|
+
def __hash__(self) -> int:
|
|
695
|
+
return id(self)
|
|
696
|
+
|
|
697
|
+
def __eq__(self, other: object) -> bool:
|
|
698
|
+
if not isinstance(other, type(self)):
|
|
699
|
+
return False
|
|
700
|
+
return bool(
|
|
701
|
+
self.connection_instance == other.connection_instance and self.migration_config == other.migration_config
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
def __repr__(self) -> str:
|
|
705
|
+
parts = ", ".join([
|
|
706
|
+
f"connection_instance={self.connection_instance!r}",
|
|
707
|
+
f"migration_config={self.migration_config!r}",
|
|
708
|
+
])
|
|
709
|
+
return f"{type(self).__name__}({parts})"
|
|
710
|
+
|
|
711
|
+
def storage_capabilities(self) -> "StorageCapabilities":
|
|
712
|
+
"""Return cached storage capabilities for this configuration."""
|
|
713
|
+
|
|
714
|
+
if self._storage_capabilities is None:
|
|
715
|
+
self._storage_capabilities = self._build_storage_capabilities()
|
|
716
|
+
return cast("StorageCapabilities", dict(self._storage_capabilities))
|
|
717
|
+
|
|
718
|
+
def reset_storage_capabilities_cache(self) -> None:
|
|
719
|
+
"""Clear the cached capability snapshot."""
|
|
720
|
+
|
|
721
|
+
self._storage_capabilities = None
|
|
722
|
+
|
|
723
|
+
def _ensure_extension_migrations(self) -> None:
|
|
724
|
+
"""Auto-include extension migrations when extension_config has them configured.
|
|
725
|
+
|
|
726
|
+
Extensions with migration support are automatically included in
|
|
727
|
+
``migration_config["include_extensions"]`` based on their settings:
|
|
728
|
+
|
|
729
|
+
- **litestar**: Only when ``session_table`` is set (for session storage)
|
|
730
|
+
- **adk**: When any adk settings are present
|
|
731
|
+
- **events**: When any events settings are present
|
|
732
|
+
|
|
733
|
+
Use ``exclude_extensions`` to opt out of auto-inclusion.
|
|
734
|
+
"""
|
|
735
|
+
extension_settings = cast("dict[str, Any]", self.extension_config)
|
|
736
|
+
migration_config = cast("dict[str, Any]", self.migration_config)
|
|
737
|
+
|
|
738
|
+
exclude_extensions = migration_config.get("exclude_extensions", [])
|
|
739
|
+
if isinstance(exclude_extensions, tuple):
|
|
740
|
+
exclude_extensions = list(exclude_extensions) # pyright: ignore
|
|
741
|
+
|
|
742
|
+
extensions_to_add: list[str] = []
|
|
743
|
+
|
|
744
|
+
litestar_settings = extension_settings.get("litestar")
|
|
745
|
+
if (
|
|
746
|
+
litestar_settings is not None
|
|
747
|
+
and "session_table" in litestar_settings
|
|
748
|
+
and "litestar" not in exclude_extensions
|
|
749
|
+
):
|
|
750
|
+
extensions_to_add.append("litestar")
|
|
751
|
+
|
|
752
|
+
adk_settings = extension_settings.get("adk")
|
|
753
|
+
if adk_settings is not None and "adk" not in exclude_extensions:
|
|
754
|
+
extensions_to_add.append("adk")
|
|
755
|
+
|
|
756
|
+
events_settings = extension_settings.get("events")
|
|
757
|
+
if events_settings is not None and "events" not in exclude_extensions:
|
|
758
|
+
extensions_to_add.append("events")
|
|
759
|
+
|
|
760
|
+
if not extensions_to_add:
|
|
761
|
+
return
|
|
762
|
+
|
|
763
|
+
include_extensions = migration_config.get("include_extensions")
|
|
764
|
+
if include_extensions is None:
|
|
765
|
+
include_list: list[str] = []
|
|
766
|
+
migration_config["include_extensions"] = include_list
|
|
767
|
+
elif isinstance(include_extensions, tuple):
|
|
768
|
+
include_list = list(include_extensions) # pyright: ignore
|
|
769
|
+
migration_config["include_extensions"] = include_list
|
|
770
|
+
else:
|
|
771
|
+
include_list = cast("list[str]", include_extensions)
|
|
772
|
+
|
|
773
|
+
for ext in extensions_to_add:
|
|
774
|
+
if ext not in include_list:
|
|
775
|
+
include_list.append(ext)
|
|
776
|
+
|
|
777
|
+
def get_event_runtime_hints(self) -> "EventRuntimeHints":
|
|
778
|
+
"""Return default event runtime hints for this configuration."""
|
|
779
|
+
|
|
780
|
+
return EventRuntimeHints()
|
|
781
|
+
|
|
782
|
+
def _build_storage_capabilities(self) -> "StorageCapabilities":
|
|
783
|
+
arrow_dependency_needed = self.supports_native_arrow_export or self.supports_native_arrow_import
|
|
784
|
+
parquet_dependency_needed = self.supports_native_parquet_export or self.supports_native_parquet_import
|
|
785
|
+
|
|
786
|
+
arrow_dependency_ready = self._dependency_available(ensure_pyarrow) if arrow_dependency_needed else False
|
|
787
|
+
parquet_dependency_ready = self._dependency_available(ensure_pyarrow) if parquet_dependency_needed else False
|
|
788
|
+
|
|
789
|
+
capabilities: StorageCapabilities = {
|
|
790
|
+
"arrow_export_enabled": bool(self.supports_native_arrow_export and arrow_dependency_ready),
|
|
791
|
+
"arrow_import_enabled": bool(self.supports_native_arrow_import and arrow_dependency_ready),
|
|
792
|
+
"parquet_export_enabled": bool(self.supports_native_parquet_export and parquet_dependency_ready),
|
|
793
|
+
"parquet_import_enabled": bool(self.supports_native_parquet_import and parquet_dependency_ready),
|
|
794
|
+
"requires_staging_for_load": self.requires_staging_for_load,
|
|
795
|
+
"staging_protocols": list(self.staging_protocols),
|
|
796
|
+
"partition_strategies": list(self.storage_partition_strategies),
|
|
797
|
+
}
|
|
798
|
+
if self.default_storage_profile is not None:
|
|
799
|
+
capabilities["default_storage_profile"] = self.default_storage_profile
|
|
800
|
+
return capabilities
|
|
801
|
+
|
|
802
|
+
def _init_observability(self, observability_config: "ObservabilityConfig | None" = None) -> None:
|
|
803
|
+
"""Initialize observability attributes for the configuration."""
|
|
804
|
+
|
|
805
|
+
self.observability_config = observability_config
|
|
806
|
+
self._observability_runtime = None
|
|
807
|
+
|
|
808
|
+
def _configure_observability_extensions(self) -> None:
|
|
809
|
+
"""Apply extension_config hooks (otel/prometheus) to ObservabilityConfig."""
|
|
810
|
+
|
|
811
|
+
config_map = cast("dict[str, Any]", self.extension_config)
|
|
812
|
+
if not config_map:
|
|
813
|
+
return
|
|
814
|
+
updated = self.observability_config
|
|
815
|
+
|
|
816
|
+
otel_config = cast("OpenTelemetryConfig | None", config_map.get("otel"))
|
|
817
|
+
if otel_config and otel_config.get("enabled", True):
|
|
818
|
+
from sqlspec.extensions import otel as otel_extension
|
|
819
|
+
|
|
820
|
+
updated = otel_extension.enable_tracing(
|
|
821
|
+
base_config=updated,
|
|
822
|
+
resource_attributes=otel_config.get("resource_attributes"),
|
|
823
|
+
tracer_provider=otel_config.get("tracer_provider"),
|
|
824
|
+
tracer_provider_factory=otel_config.get("tracer_provider_factory"),
|
|
825
|
+
enable_spans=otel_config.get("enable_spans", True),
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
prom_config = cast("PrometheusConfig | None", config_map.get("prometheus"))
|
|
829
|
+
if prom_config and prom_config.get("enabled", True):
|
|
830
|
+
from sqlspec.extensions import prometheus as prometheus_extension
|
|
831
|
+
|
|
832
|
+
label_names = tuple(prom_config.get("label_names", ("driver", "operation")))
|
|
833
|
+
duration_buckets = prom_config.get("duration_buckets")
|
|
834
|
+
if duration_buckets is not None:
|
|
835
|
+
duration_buckets = tuple(duration_buckets)
|
|
836
|
+
|
|
837
|
+
updated = prometheus_extension.enable_metrics(
|
|
838
|
+
base_config=updated,
|
|
839
|
+
namespace=prom_config.get("namespace", "sqlspec"),
|
|
840
|
+
subsystem=prom_config.get("subsystem", "driver"),
|
|
841
|
+
registry=prom_config.get("registry"),
|
|
842
|
+
label_names=label_names,
|
|
843
|
+
duration_buckets=duration_buckets,
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
if updated is not self.observability_config:
|
|
847
|
+
self.observability_config = updated
|
|
848
|
+
|
|
849
|
+
def _promote_driver_feature_hooks(self) -> None:
|
|
850
|
+
lifecycle_hooks: dict[str, list[Callable[[dict[str, Any]], None]]] = {}
|
|
851
|
+
|
|
852
|
+
for hook_name, context_key in DRIVER_FEATURE_LIFECYCLE_HOOKS.items():
|
|
853
|
+
callback = self.driver_features.pop(hook_name, None)
|
|
854
|
+
if callback is None:
|
|
855
|
+
continue
|
|
856
|
+
callbacks = callback if isinstance(callback, (list, tuple)) else (callback,) # pyright: ignore
|
|
857
|
+
wrapped_callbacks = [self._wrap_driver_feature_hook(cb, context_key) for cb in callbacks] # pyright: ignore
|
|
858
|
+
lifecycle_hooks.setdefault(hook_name, []).extend(wrapped_callbacks)
|
|
859
|
+
|
|
860
|
+
if not lifecycle_hooks:
|
|
861
|
+
return
|
|
862
|
+
|
|
863
|
+
lifecycle_config = cast("LifecycleConfig", lifecycle_hooks)
|
|
864
|
+
override = ObservabilityConfig(lifecycle=lifecycle_config)
|
|
865
|
+
if self.observability_config is None:
|
|
866
|
+
self.observability_config = override
|
|
867
|
+
else:
|
|
868
|
+
self.observability_config = ObservabilityConfig.merge(self.observability_config, override)
|
|
869
|
+
|
|
870
|
+
@staticmethod
|
|
871
|
+
def _wrap_driver_feature_hook(
|
|
872
|
+
callback: Callable[..., Any], context_key: str | None
|
|
873
|
+
) -> Callable[[dict[str, Any]], None]:
|
|
874
|
+
try:
|
|
875
|
+
hook_signature: Signature = signature(callback)
|
|
876
|
+
except (TypeError, ValueError): # pragma: no cover - builtins without signatures
|
|
877
|
+
hook_signature = Signature()
|
|
878
|
+
|
|
879
|
+
positional_params = [
|
|
880
|
+
param
|
|
881
|
+
for param in hook_signature.parameters.values()
|
|
882
|
+
if param.kind in {param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD} and param.default is param.empty
|
|
883
|
+
]
|
|
884
|
+
expects_argument = bool(positional_params)
|
|
885
|
+
|
|
886
|
+
return _DriverFeatureHookWrapper(callback, context_key, expects_argument)
|
|
887
|
+
|
|
888
|
+
def attach_observability(self, registry_config: "ObservabilityConfig | None") -> None:
|
|
889
|
+
"""Attach merged observability runtime composed from registry and adapter overrides."""
|
|
890
|
+
merged = ObservabilityConfig.merge(registry_config, self.observability_config)
|
|
891
|
+
self._observability_runtime = ObservabilityRuntime(
|
|
892
|
+
merged, bind_key=self.bind_key, config_name=type(self).__name__
|
|
893
|
+
)
|
|
894
|
+
|
|
895
|
+
def get_observability_runtime(self) -> "ObservabilityRuntime":
|
|
896
|
+
"""Return the attached runtime, creating a disabled instance when missing."""
|
|
897
|
+
|
|
898
|
+
if self._observability_runtime is None:
|
|
899
|
+
self.attach_observability(None)
|
|
900
|
+
assert self._observability_runtime is not None
|
|
901
|
+
return self._observability_runtime
|
|
902
|
+
|
|
903
|
+
def _prepare_driver(self, driver: DriverT) -> DriverT:
|
|
904
|
+
"""Attach observability runtime to driver instances before returning them."""
|
|
905
|
+
|
|
906
|
+
driver.attach_observability(self.get_observability_runtime())
|
|
907
|
+
return driver
|
|
908
|
+
|
|
909
|
+
@staticmethod
|
|
910
|
+
def _dependency_available(checker: "Callable[[], None]") -> bool:
|
|
911
|
+
try:
|
|
912
|
+
checker()
|
|
913
|
+
except MissingDependencyError:
|
|
914
|
+
return False
|
|
915
|
+
return True
|
|
916
|
+
|
|
917
|
+
@abstractmethod
|
|
918
|
+
def create_connection(self) -> "ConnectionT | Awaitable[ConnectionT]":
|
|
919
|
+
"""Create and return a new database connection."""
|
|
920
|
+
raise NotImplementedError
|
|
921
|
+
|
|
922
|
+
@abstractmethod
|
|
923
|
+
def provide_connection(
|
|
924
|
+
self, *args: Any, **kwargs: Any
|
|
925
|
+
) -> "AbstractContextManager[ConnectionT] | AbstractAsyncContextManager[ConnectionT]":
|
|
926
|
+
"""Provide a database connection context manager."""
|
|
927
|
+
raise NotImplementedError
|
|
928
|
+
|
|
929
|
+
@abstractmethod
|
|
930
|
+
def provide_session(
|
|
931
|
+
self, *args: Any, **kwargs: Any
|
|
932
|
+
) -> "AbstractContextManager[DriverT] | AbstractAsyncContextManager[DriverT]":
|
|
933
|
+
"""Provide a database session context manager."""
|
|
934
|
+
raise NotImplementedError
|
|
935
|
+
|
|
936
|
+
@abstractmethod
|
|
937
|
+
def create_pool(self) -> "PoolT | Awaitable[PoolT]":
|
|
938
|
+
"""Create and return connection pool."""
|
|
939
|
+
raise NotImplementedError
|
|
940
|
+
|
|
941
|
+
@abstractmethod
|
|
942
|
+
def close_pool(self) -> "Awaitable[None] | None":
|
|
943
|
+
"""Terminate the connection pool."""
|
|
944
|
+
raise NotImplementedError
|
|
945
|
+
|
|
946
|
+
@abstractmethod
|
|
947
|
+
def provide_pool(
|
|
948
|
+
self, *args: Any, **kwargs: Any
|
|
949
|
+
) -> "PoolT | Awaitable[PoolT] | AbstractContextManager[PoolT] | AbstractAsyncContextManager[PoolT]":
|
|
950
|
+
"""Provide pool instance."""
|
|
951
|
+
raise NotImplementedError
|
|
952
|
+
|
|
953
|
+
def get_signature_namespace(self) -> "dict[str, Any]":
|
|
954
|
+
"""Get the signature namespace for this database configuration.
|
|
955
|
+
|
|
956
|
+
Returns a dictionary of type names to objects (classes, functions, or
|
|
957
|
+
other callables) that should be registered with Litestar's signature
|
|
958
|
+
namespace to prevent serialization attempts on database-specific
|
|
959
|
+
structures.
|
|
960
|
+
|
|
961
|
+
Returns:
|
|
962
|
+
Dictionary mapping type names to objects.
|
|
963
|
+
"""
|
|
964
|
+
return {}
|
|
965
|
+
|
|
966
|
+
def _initialize_migration_components(self) -> None:
|
|
967
|
+
"""Initialize migration loader and migration command helpers."""
|
|
968
|
+
runtime = self.get_observability_runtime()
|
|
969
|
+
self._migration_loader = SQLFileLoader(runtime=runtime)
|
|
970
|
+
self._migration_commands = create_migration_commands(self) # pyright: ignore
|
|
971
|
+
|
|
972
|
+
def _ensure_migration_loader(self) -> "SQLFileLoader":
|
|
973
|
+
"""Get the migration SQL loader and auto-load files if needed.
|
|
974
|
+
|
|
975
|
+
Returns:
|
|
976
|
+
SQLFileLoader instance for migration files.
|
|
977
|
+
"""
|
|
978
|
+
migration_config = self.migration_config or {}
|
|
979
|
+
script_location = migration_config.get("script_location", "migrations")
|
|
980
|
+
|
|
981
|
+
migration_path = Path(script_location)
|
|
982
|
+
if migration_path.exists() and not self._migration_loader.list_files():
|
|
983
|
+
self._migration_loader.load_sql(migration_path)
|
|
984
|
+
logger.debug("Auto-loaded migration SQL files from %s", migration_path)
|
|
985
|
+
|
|
986
|
+
return self._migration_loader
|
|
987
|
+
|
|
988
|
+
def _ensure_migration_commands(self) -> "SyncMigrationCommands[Any] | AsyncMigrationCommands[Any]":
|
|
989
|
+
"""Get the migration commands instance.
|
|
990
|
+
|
|
991
|
+
Returns:
|
|
992
|
+
MigrationCommands instance for this config.
|
|
993
|
+
"""
|
|
994
|
+
return self._migration_commands
|
|
995
|
+
|
|
996
|
+
def get_migration_loader(self) -> "SQLFileLoader":
|
|
997
|
+
"""Get the SQL loader for migration files.
|
|
998
|
+
|
|
999
|
+
Provides access to migration SQL files loaded from the configured
|
|
1000
|
+
script_location directory. Files are loaded lazily on first access.
|
|
1001
|
+
|
|
1002
|
+
Returns:
|
|
1003
|
+
SQLFileLoader instance with migration files loaded.
|
|
1004
|
+
"""
|
|
1005
|
+
return self._ensure_migration_loader()
|
|
1006
|
+
|
|
1007
|
+
def load_migration_sql_files(self, *paths: "str | Path") -> None:
|
|
1008
|
+
"""Load additional migration SQL files from specified paths.
|
|
1009
|
+
|
|
1010
|
+
Args:
|
|
1011
|
+
*paths: One or more file paths or directory paths to load migration SQL files from.
|
|
1012
|
+
"""
|
|
1013
|
+
|
|
1014
|
+
loader = self._ensure_migration_loader()
|
|
1015
|
+
for path in paths:
|
|
1016
|
+
path_obj = Path(path)
|
|
1017
|
+
if path_obj.exists():
|
|
1018
|
+
loader.load_sql(path_obj)
|
|
1019
|
+
logger.debug("Loaded migration SQL files from %s", path_obj)
|
|
1020
|
+
else:
|
|
1021
|
+
logger.warning("Migration path does not exist: %s", path_obj)
|
|
1022
|
+
|
|
1023
|
+
def get_migration_commands(self) -> "SyncMigrationCommands[Any] | AsyncMigrationCommands[Any]":
|
|
1024
|
+
"""Get migration commands for this configuration.
|
|
1025
|
+
|
|
1026
|
+
Returns:
|
|
1027
|
+
MigrationCommands instance configured for this database.
|
|
1028
|
+
"""
|
|
1029
|
+
return self._ensure_migration_commands()
|
|
1030
|
+
|
|
1031
|
+
@abstractmethod
|
|
1032
|
+
def migrate_up(
|
|
1033
|
+
self, revision: str = "head", allow_missing: bool = False, auto_sync: bool = True, dry_run: bool = False
|
|
1034
|
+
) -> "Awaitable[None] | None":
|
|
1035
|
+
"""Apply database migrations up to specified revision.
|
|
1036
|
+
|
|
1037
|
+
Args:
|
|
1038
|
+
revision: Target revision or "head" for latest. Defaults to "head".
|
|
1039
|
+
allow_missing: Allow out-of-order migrations. Defaults to False.
|
|
1040
|
+
auto_sync: Auto-reconcile renamed migrations. Defaults to True.
|
|
1041
|
+
dry_run: Show what would be done without applying. Defaults to False.
|
|
1042
|
+
"""
|
|
1043
|
+
raise NotImplementedError
|
|
1044
|
+
|
|
1045
|
+
@abstractmethod
|
|
1046
|
+
def migrate_down(self, revision: str = "-1", *, dry_run: bool = False) -> "Awaitable[None] | None":
|
|
1047
|
+
"""Apply database migrations down to specified revision.
|
|
1048
|
+
|
|
1049
|
+
Args:
|
|
1050
|
+
revision: Target revision, "-1" for one step back, or "base" for all migrations. Defaults to "-1".
|
|
1051
|
+
dry_run: Show what would be done without applying. Defaults to False.
|
|
1052
|
+
"""
|
|
1053
|
+
raise NotImplementedError
|
|
1054
|
+
|
|
1055
|
+
@abstractmethod
|
|
1056
|
+
def get_current_migration(self, verbose: bool = False) -> "Awaitable[str | None] | str | None":
|
|
1057
|
+
"""Get the current migration version.
|
|
1058
|
+
|
|
1059
|
+
Args:
|
|
1060
|
+
verbose: Whether to show detailed migration history. Defaults to False.
|
|
1061
|
+
|
|
1062
|
+
Returns:
|
|
1063
|
+
Current migration version or None if no migrations applied.
|
|
1064
|
+
"""
|
|
1065
|
+
raise NotImplementedError
|
|
1066
|
+
|
|
1067
|
+
@abstractmethod
|
|
1068
|
+
def create_migration(self, message: str, file_type: str = "sql") -> "Awaitable[None] | None":
|
|
1069
|
+
"""Create a new migration file.
|
|
1070
|
+
|
|
1071
|
+
Args:
|
|
1072
|
+
message: Description for the migration.
|
|
1073
|
+
file_type: Type of migration file to create ('sql' or 'py'). Defaults to 'sql'.
|
|
1074
|
+
"""
|
|
1075
|
+
raise NotImplementedError
|
|
1076
|
+
|
|
1077
|
+
@abstractmethod
|
|
1078
|
+
def init_migrations(self, directory: "str | None" = None, package: bool = True) -> "Awaitable[None] | None":
|
|
1079
|
+
"""Initialize migration directory structure.
|
|
1080
|
+
|
|
1081
|
+
Args:
|
|
1082
|
+
directory: Directory to initialize migrations in. Uses script_location from migration_config if not provided.
|
|
1083
|
+
package: Whether to create __init__.py file. Defaults to True.
|
|
1084
|
+
"""
|
|
1085
|
+
raise NotImplementedError
|
|
1086
|
+
|
|
1087
|
+
@abstractmethod
|
|
1088
|
+
def stamp_migration(self, revision: str) -> "Awaitable[None] | None":
|
|
1089
|
+
"""Mark database as being at a specific revision without running migrations.
|
|
1090
|
+
|
|
1091
|
+
Args:
|
|
1092
|
+
revision: The revision to stamp.
|
|
1093
|
+
"""
|
|
1094
|
+
raise NotImplementedError
|
|
1095
|
+
|
|
1096
|
+
@abstractmethod
|
|
1097
|
+
def fix_migrations(
|
|
1098
|
+
self, dry_run: bool = False, update_database: bool = True, yes: bool = False
|
|
1099
|
+
) -> "Awaitable[None] | None":
|
|
1100
|
+
"""Convert timestamp migrations to sequential format.
|
|
1101
|
+
|
|
1102
|
+
Implements hybrid versioning workflow where development uses timestamps
|
|
1103
|
+
and production uses sequential numbers. Creates backup before changes
|
|
1104
|
+
and provides rollback on errors.
|
|
1105
|
+
|
|
1106
|
+
Args:
|
|
1107
|
+
dry_run: Preview changes without applying. Defaults to False.
|
|
1108
|
+
update_database: Update migration records in database. Defaults to True.
|
|
1109
|
+
yes: Skip confirmation prompt. Defaults to False.
|
|
1110
|
+
"""
|
|
1111
|
+
raise NotImplementedError
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
class NoPoolSyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
|
|
1115
|
+
"""Base class for sync database configurations that do not implement a pool."""
|
|
1116
|
+
|
|
1117
|
+
__slots__ = ("connection_config",)
|
|
1118
|
+
is_async: "ClassVar[bool]" = False
|
|
1119
|
+
supports_connection_pooling: "ClassVar[bool]" = False
|
|
1120
|
+
migration_tracker_type: "ClassVar[type[Any]]" = SyncMigrationTracker
|
|
1121
|
+
|
|
1122
|
+
def __init__(
|
|
1123
|
+
self,
|
|
1124
|
+
*,
|
|
1125
|
+
connection_config: dict[str, Any] | None = None,
|
|
1126
|
+
connection_instance: "Any" = None,
|
|
1127
|
+
migration_config: "dict[str, Any] | MigrationConfig | None" = None,
|
|
1128
|
+
statement_config: "StatementConfig | None" = None,
|
|
1129
|
+
driver_features: "dict[str, Any] | None" = None,
|
|
1130
|
+
bind_key: "str | None" = None,
|
|
1131
|
+
extension_config: "ExtensionConfigs | None" = None,
|
|
1132
|
+
observability_config: "ObservabilityConfig | None" = None,
|
|
1133
|
+
) -> None:
|
|
1134
|
+
self.bind_key = bind_key
|
|
1135
|
+
self.connection_instance = connection_instance
|
|
1136
|
+
self.connection_config = connection_config or {}
|
|
1137
|
+
self.extension_config = extension_config or {}
|
|
1138
|
+
self.migration_config: dict[str, Any] | MigrationConfig = migration_config or {}
|
|
1139
|
+
self._ensure_extension_migrations()
|
|
1140
|
+
self._init_observability(observability_config)
|
|
1141
|
+
self._initialize_migration_components()
|
|
1142
|
+
|
|
1143
|
+
if statement_config is None:
|
|
1144
|
+
default_parameter_config = ParameterStyleConfig(
|
|
1145
|
+
default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
|
|
1146
|
+
)
|
|
1147
|
+
self.statement_config = StatementConfig(dialect="sqlite", parameter_config=default_parameter_config)
|
|
1148
|
+
else:
|
|
1149
|
+
self.statement_config = statement_config
|
|
1150
|
+
self.driver_features = driver_features or {}
|
|
1151
|
+
self._storage_capabilities = None
|
|
1152
|
+
self.driver_features.setdefault("storage_capabilities", self.storage_capabilities())
|
|
1153
|
+
self._promote_driver_feature_hooks()
|
|
1154
|
+
self._configure_observability_extensions()
|
|
1155
|
+
|
|
1156
|
+
def create_connection(self) -> ConnectionT:
|
|
1157
|
+
"""Create a database connection."""
|
|
1158
|
+
raise NotImplementedError
|
|
1159
|
+
|
|
1160
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "AbstractContextManager[ConnectionT]":
|
|
1161
|
+
"""Provide a database connection context manager."""
|
|
1162
|
+
raise NotImplementedError
|
|
1163
|
+
|
|
1164
|
+
def provide_session(
|
|
1165
|
+
self, *args: Any, statement_config: "StatementConfig | None" = None, **kwargs: Any
|
|
1166
|
+
) -> "AbstractContextManager[DriverT]":
|
|
1167
|
+
"""Provide a database session context manager."""
|
|
1168
|
+
raise NotImplementedError
|
|
1169
|
+
|
|
1170
|
+
def create_pool(self) -> None:
|
|
1171
|
+
return None
|
|
1172
|
+
|
|
1173
|
+
def close_pool(self) -> None:
|
|
1174
|
+
return None
|
|
1175
|
+
|
|
1176
|
+
def provide_pool(self, *args: Any, **kwargs: Any) -> None:
|
|
1177
|
+
return None
|
|
1178
|
+
|
|
1179
|
+
def migrate_up(
|
|
1180
|
+
self, revision: str = "head", allow_missing: bool = False, auto_sync: bool = True, dry_run: bool = False
|
|
1181
|
+
) -> None:
|
|
1182
|
+
"""Apply database migrations up to specified revision.
|
|
1183
|
+
|
|
1184
|
+
Args:
|
|
1185
|
+
revision: Target revision or "head" for latest.
|
|
1186
|
+
allow_missing: Allow out-of-order migrations.
|
|
1187
|
+
auto_sync: Auto-reconcile renamed migrations.
|
|
1188
|
+
dry_run: Show what would be done without applying.
|
|
1189
|
+
"""
|
|
1190
|
+
commands = self._ensure_migration_commands()
|
|
1191
|
+
commands.upgrade(revision, allow_missing, auto_sync, dry_run)
|
|
1192
|
+
|
|
1193
|
+
def migrate_down(self, revision: str = "-1", *, dry_run: bool = False) -> None:
|
|
1194
|
+
"""Apply database migrations down to specified revision.
|
|
1195
|
+
|
|
1196
|
+
Args:
|
|
1197
|
+
revision: Target revision, "-1" for one step back, or "base" for all migrations.
|
|
1198
|
+
dry_run: Show what would be done without applying.
|
|
1199
|
+
"""
|
|
1200
|
+
commands = self._ensure_migration_commands()
|
|
1201
|
+
commands.downgrade(revision, dry_run=dry_run)
|
|
1202
|
+
|
|
1203
|
+
def get_current_migration(self, verbose: bool = False) -> "str | None":
|
|
1204
|
+
"""Get the current migration version.
|
|
1205
|
+
|
|
1206
|
+
Args:
|
|
1207
|
+
verbose: Whether to show detailed migration history.
|
|
1208
|
+
|
|
1209
|
+
Returns:
|
|
1210
|
+
Current migration version or None if no migrations applied.
|
|
1211
|
+
"""
|
|
1212
|
+
commands = cast("SyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1213
|
+
return commands.current(verbose=verbose)
|
|
1214
|
+
|
|
1215
|
+
def create_migration(self, message: str, file_type: str = "sql") -> None:
|
|
1216
|
+
"""Create a new migration file.
|
|
1217
|
+
|
|
1218
|
+
Args:
|
|
1219
|
+
message: Description for the migration.
|
|
1220
|
+
file_type: Type of migration file to create ('sql' or 'py').
|
|
1221
|
+
"""
|
|
1222
|
+
commands = self._ensure_migration_commands()
|
|
1223
|
+
commands.revision(message, file_type)
|
|
1224
|
+
|
|
1225
|
+
def init_migrations(self, directory: "str | None" = None, package: bool = True) -> None:
|
|
1226
|
+
"""Initialize migration directory structure.
|
|
1227
|
+
|
|
1228
|
+
Args:
|
|
1229
|
+
directory: Directory to initialize migrations in.
|
|
1230
|
+
package: Whether to create __init__.py file.
|
|
1231
|
+
"""
|
|
1232
|
+
if directory is None:
|
|
1233
|
+
migration_config = self.migration_config or {}
|
|
1234
|
+
directory = str(migration_config.get("script_location") or "migrations")
|
|
1235
|
+
|
|
1236
|
+
commands = self._ensure_migration_commands()
|
|
1237
|
+
assert directory is not None
|
|
1238
|
+
commands.init(directory, package)
|
|
1239
|
+
|
|
1240
|
+
def stamp_migration(self, revision: str) -> None:
|
|
1241
|
+
"""Mark database as being at a specific revision without running migrations.
|
|
1242
|
+
|
|
1243
|
+
Args:
|
|
1244
|
+
revision: The revision to stamp.
|
|
1245
|
+
"""
|
|
1246
|
+
commands = self._ensure_migration_commands()
|
|
1247
|
+
commands.stamp(revision)
|
|
1248
|
+
|
|
1249
|
+
def fix_migrations(self, dry_run: bool = False, update_database: bool = True, yes: bool = False) -> None:
|
|
1250
|
+
"""Convert timestamp migrations to sequential format.
|
|
1251
|
+
|
|
1252
|
+
Args:
|
|
1253
|
+
dry_run: Preview changes without applying.
|
|
1254
|
+
update_database: Update migration records in database.
|
|
1255
|
+
yes: Skip confirmation prompt.
|
|
1256
|
+
"""
|
|
1257
|
+
commands = self._ensure_migration_commands()
|
|
1258
|
+
commands.fix(dry_run, update_database, yes)
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
class NoPoolAsyncConfig(DatabaseConfigProtocol[ConnectionT, None, DriverT]):
|
|
1262
|
+
"""Base class for async database configurations that do not implement a pool."""
|
|
1263
|
+
|
|
1264
|
+
__slots__ = ("connection_config",)
|
|
1265
|
+
is_async: "ClassVar[bool]" = True
|
|
1266
|
+
supports_connection_pooling: "ClassVar[bool]" = False
|
|
1267
|
+
migration_tracker_type: "ClassVar[type[Any]]" = AsyncMigrationTracker
|
|
1268
|
+
|
|
1269
|
+
def __init__(
|
|
1270
|
+
self,
|
|
1271
|
+
*,
|
|
1272
|
+
connection_config: "dict[str, Any] | None" = None,
|
|
1273
|
+
connection_instance: "Any" = None,
|
|
1274
|
+
migration_config: "dict[str, Any] | MigrationConfig | None" = None,
|
|
1275
|
+
statement_config: "StatementConfig | None" = None,
|
|
1276
|
+
driver_features: "dict[str, Any] | None" = None,
|
|
1277
|
+
bind_key: "str | None" = None,
|
|
1278
|
+
extension_config: "ExtensionConfigs | None" = None,
|
|
1279
|
+
observability_config: "ObservabilityConfig | None" = None,
|
|
1280
|
+
) -> None:
|
|
1281
|
+
self.bind_key = bind_key
|
|
1282
|
+
self.connection_instance = connection_instance
|
|
1283
|
+
self.connection_config = connection_config or {}
|
|
1284
|
+
self.extension_config = extension_config or {}
|
|
1285
|
+
self.migration_config: dict[str, Any] | MigrationConfig = migration_config or {}
|
|
1286
|
+
self._ensure_extension_migrations()
|
|
1287
|
+
self._init_observability(observability_config)
|
|
1288
|
+
self._initialize_migration_components()
|
|
1289
|
+
|
|
1290
|
+
if statement_config is None:
|
|
1291
|
+
default_parameter_config = ParameterStyleConfig(
|
|
1292
|
+
default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
|
|
1293
|
+
)
|
|
1294
|
+
self.statement_config = StatementConfig(dialect="sqlite", parameter_config=default_parameter_config)
|
|
1295
|
+
else:
|
|
1296
|
+
self.statement_config = statement_config
|
|
1297
|
+
self.driver_features = driver_features or {}
|
|
1298
|
+
self._promote_driver_feature_hooks()
|
|
1299
|
+
self._configure_observability_extensions()
|
|
1300
|
+
|
|
1301
|
+
async def create_connection(self) -> ConnectionT:
|
|
1302
|
+
"""Create a database connection."""
|
|
1303
|
+
raise NotImplementedError
|
|
1304
|
+
|
|
1305
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "AbstractAsyncContextManager[ConnectionT]":
|
|
1306
|
+
"""Provide a database connection context manager."""
|
|
1307
|
+
raise NotImplementedError
|
|
1308
|
+
|
|
1309
|
+
def provide_session(
|
|
1310
|
+
self, *args: Any, statement_config: "StatementConfig | None" = None, **kwargs: Any
|
|
1311
|
+
) -> "AbstractAsyncContextManager[DriverT]":
|
|
1312
|
+
"""Provide a database session context manager."""
|
|
1313
|
+
raise NotImplementedError
|
|
1314
|
+
|
|
1315
|
+
async def create_pool(self) -> None:
|
|
1316
|
+
return None
|
|
1317
|
+
|
|
1318
|
+
async def close_pool(self) -> None:
|
|
1319
|
+
return None
|
|
1320
|
+
|
|
1321
|
+
def provide_pool(self, *args: Any, **kwargs: Any) -> None:
|
|
1322
|
+
return None
|
|
1323
|
+
|
|
1324
|
+
async def migrate_up(
|
|
1325
|
+
self, revision: str = "head", allow_missing: bool = False, auto_sync: bool = True, dry_run: bool = False
|
|
1326
|
+
) -> None:
|
|
1327
|
+
"""Apply database migrations up to specified revision.
|
|
1328
|
+
|
|
1329
|
+
Args:
|
|
1330
|
+
revision: Target revision or "head" for latest.
|
|
1331
|
+
allow_missing: Allow out-of-order migrations.
|
|
1332
|
+
auto_sync: Auto-reconcile renamed migrations.
|
|
1333
|
+
dry_run: Show what would be done without applying.
|
|
1334
|
+
"""
|
|
1335
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1336
|
+
await commands.upgrade(revision, allow_missing, auto_sync, dry_run)
|
|
1337
|
+
|
|
1338
|
+
async def migrate_down(self, revision: str = "-1", *, dry_run: bool = False) -> None:
|
|
1339
|
+
"""Apply database migrations down to specified revision.
|
|
1340
|
+
|
|
1341
|
+
Args:
|
|
1342
|
+
revision: Target revision, "-1" for one step back, or "base" for all migrations.
|
|
1343
|
+
dry_run: Show what would be done without applying.
|
|
1344
|
+
"""
|
|
1345
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1346
|
+
await commands.downgrade(revision, dry_run=dry_run)
|
|
1347
|
+
|
|
1348
|
+
async def get_current_migration(self, verbose: bool = False) -> "str | None":
|
|
1349
|
+
"""Get the current migration version.
|
|
1350
|
+
|
|
1351
|
+
Args:
|
|
1352
|
+
verbose: Whether to show detailed migration history.
|
|
1353
|
+
|
|
1354
|
+
Returns:
|
|
1355
|
+
Current migration version or None if no migrations applied.
|
|
1356
|
+
"""
|
|
1357
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1358
|
+
return await commands.current(verbose=verbose)
|
|
1359
|
+
|
|
1360
|
+
async def create_migration(self, message: str, file_type: str = "sql") -> None:
|
|
1361
|
+
"""Create a new migration file.
|
|
1362
|
+
|
|
1363
|
+
Args:
|
|
1364
|
+
message: Description for the migration.
|
|
1365
|
+
file_type: Type of migration file to create ('sql' or 'py').
|
|
1366
|
+
"""
|
|
1367
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1368
|
+
await commands.revision(message, file_type)
|
|
1369
|
+
|
|
1370
|
+
async def init_migrations(self, directory: "str | None" = None, package: bool = True) -> None:
|
|
1371
|
+
"""Initialize migration directory structure.
|
|
1372
|
+
|
|
1373
|
+
Args:
|
|
1374
|
+
directory: Directory to initialize migrations in.
|
|
1375
|
+
package: Whether to create __init__.py file.
|
|
1376
|
+
"""
|
|
1377
|
+
if directory is None:
|
|
1378
|
+
migration_config = self.migration_config or {}
|
|
1379
|
+
directory = str(migration_config.get("script_location") or "migrations")
|
|
1380
|
+
|
|
1381
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1382
|
+
assert directory is not None
|
|
1383
|
+
await commands.init(directory, package)
|
|
1384
|
+
|
|
1385
|
+
async def stamp_migration(self, revision: str) -> None:
|
|
1386
|
+
"""Mark database as being at a specific revision without running migrations.
|
|
1387
|
+
|
|
1388
|
+
Args:
|
|
1389
|
+
revision: The revision to stamp.
|
|
1390
|
+
"""
|
|
1391
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1392
|
+
await commands.stamp(revision)
|
|
1393
|
+
|
|
1394
|
+
async def fix_migrations(self, dry_run: bool = False, update_database: bool = True, yes: bool = False) -> None:
|
|
1395
|
+
"""Convert timestamp migrations to sequential format.
|
|
1396
|
+
|
|
1397
|
+
Args:
|
|
1398
|
+
dry_run: Preview changes without applying.
|
|
1399
|
+
update_database: Update migration records in database.
|
|
1400
|
+
yes: Skip confirmation prompt.
|
|
1401
|
+
"""
|
|
1402
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1403
|
+
await commands.fix(dry_run, update_database, yes)
|
|
1404
|
+
|
|
1405
|
+
|
|
1406
|
+
class SyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
|
|
1407
|
+
"""Base class for sync database configurations with connection pooling."""
|
|
1408
|
+
|
|
1409
|
+
__slots__ = ("connection_config",)
|
|
1410
|
+
is_async: "ClassVar[bool]" = False
|
|
1411
|
+
supports_connection_pooling: "ClassVar[bool]" = True
|
|
1412
|
+
migration_tracker_type: "ClassVar[type[Any]]" = SyncMigrationTracker
|
|
1413
|
+
|
|
1414
|
+
def __init__(
|
|
1415
|
+
self,
|
|
1416
|
+
*,
|
|
1417
|
+
connection_config: "dict[str, Any] | None" = None,
|
|
1418
|
+
connection_instance: "PoolT | None" = None,
|
|
1419
|
+
migration_config: "dict[str, Any] | MigrationConfig | None" = None,
|
|
1420
|
+
statement_config: "StatementConfig | None" = None,
|
|
1421
|
+
driver_features: "dict[str, Any] | None" = None,
|
|
1422
|
+
bind_key: "str | None" = None,
|
|
1423
|
+
extension_config: "ExtensionConfigs | None" = None,
|
|
1424
|
+
observability_config: "ObservabilityConfig | None" = None,
|
|
1425
|
+
**kwargs: Any,
|
|
1426
|
+
) -> None:
|
|
1427
|
+
self.bind_key = bind_key
|
|
1428
|
+
self.connection_instance = connection_instance
|
|
1429
|
+
self.connection_config = connection_config or {}
|
|
1430
|
+
self.extension_config = extension_config or {}
|
|
1431
|
+
self.migration_config: dict[str, Any] | MigrationConfig = migration_config or {}
|
|
1432
|
+
self._ensure_extension_migrations()
|
|
1433
|
+
self._init_observability(observability_config)
|
|
1434
|
+
self._initialize_migration_components()
|
|
1435
|
+
|
|
1436
|
+
if statement_config is None:
|
|
1437
|
+
default_parameter_config = ParameterStyleConfig(
|
|
1438
|
+
default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
|
|
1439
|
+
)
|
|
1440
|
+
self.statement_config = StatementConfig(dialect="postgres", parameter_config=default_parameter_config)
|
|
1441
|
+
else:
|
|
1442
|
+
self.statement_config = statement_config
|
|
1443
|
+
self.driver_features = driver_features or {}
|
|
1444
|
+
self._storage_capabilities = None
|
|
1445
|
+
self.driver_features.setdefault("storage_capabilities", self.storage_capabilities())
|
|
1446
|
+
self._promote_driver_feature_hooks()
|
|
1447
|
+
self._configure_observability_extensions()
|
|
1448
|
+
|
|
1449
|
+
def create_pool(self) -> PoolT:
|
|
1450
|
+
"""Create and return the connection pool.
|
|
1451
|
+
|
|
1452
|
+
Returns:
|
|
1453
|
+
The created pool.
|
|
1454
|
+
"""
|
|
1455
|
+
if self.connection_instance is not None:
|
|
1456
|
+
return self.connection_instance
|
|
1457
|
+
self.connection_instance = self._create_pool()
|
|
1458
|
+
self.get_observability_runtime().emit_pool_create(self.connection_instance)
|
|
1459
|
+
return self.connection_instance
|
|
1460
|
+
|
|
1461
|
+
def close_pool(self) -> None:
|
|
1462
|
+
"""Close the connection pool."""
|
|
1463
|
+
pool = self.connection_instance
|
|
1464
|
+
self._close_pool()
|
|
1465
|
+
if pool is not None:
|
|
1466
|
+
self.get_observability_runtime().emit_pool_destroy(pool)
|
|
1467
|
+
self.connection_instance = None
|
|
1468
|
+
|
|
1469
|
+
def provide_pool(self, *args: Any, **kwargs: Any) -> PoolT:
|
|
1470
|
+
"""Provide pool instance."""
|
|
1471
|
+
if self.connection_instance is None:
|
|
1472
|
+
self.connection_instance = self.create_pool()
|
|
1473
|
+
return self.connection_instance
|
|
1474
|
+
|
|
1475
|
+
def create_connection(self) -> ConnectionT:
|
|
1476
|
+
"""Create a database connection."""
|
|
1477
|
+
raise NotImplementedError
|
|
1478
|
+
|
|
1479
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "AbstractContextManager[ConnectionT]":
|
|
1480
|
+
"""Provide a database connection context manager."""
|
|
1481
|
+
raise NotImplementedError
|
|
1482
|
+
|
|
1483
|
+
def provide_session(
|
|
1484
|
+
self, *args: Any, statement_config: "StatementConfig | None" = None, **kwargs: Any
|
|
1485
|
+
) -> "AbstractContextManager[DriverT]":
|
|
1486
|
+
"""Provide a database session context manager."""
|
|
1487
|
+
raise NotImplementedError
|
|
1488
|
+
|
|
1489
|
+
@abstractmethod
|
|
1490
|
+
def _create_pool(self) -> PoolT:
|
|
1491
|
+
"""Actual pool creation implementation."""
|
|
1492
|
+
raise NotImplementedError
|
|
1493
|
+
|
|
1494
|
+
@abstractmethod
|
|
1495
|
+
def _close_pool(self) -> None:
|
|
1496
|
+
"""Actual pool destruction implementation."""
|
|
1497
|
+
raise NotImplementedError
|
|
1498
|
+
|
|
1499
|
+
def migrate_up(
|
|
1500
|
+
self, revision: str = "head", allow_missing: bool = False, auto_sync: bool = True, dry_run: bool = False
|
|
1501
|
+
) -> None:
|
|
1502
|
+
"""Apply database migrations up to specified revision.
|
|
1503
|
+
|
|
1504
|
+
Args:
|
|
1505
|
+
revision: Target revision or "head" for latest.
|
|
1506
|
+
allow_missing: Allow out-of-order migrations.
|
|
1507
|
+
auto_sync: Auto-reconcile renamed migrations.
|
|
1508
|
+
dry_run: Show what would be done without applying.
|
|
1509
|
+
"""
|
|
1510
|
+
commands = self._ensure_migration_commands()
|
|
1511
|
+
commands.upgrade(revision, allow_missing, auto_sync, dry_run)
|
|
1512
|
+
|
|
1513
|
+
def migrate_down(self, revision: str = "-1", *, dry_run: bool = False) -> None:
|
|
1514
|
+
"""Apply database migrations down to specified revision.
|
|
1515
|
+
|
|
1516
|
+
Args:
|
|
1517
|
+
revision: Target revision, "-1" for one step back, or "base" for all migrations.
|
|
1518
|
+
dry_run: Show what would be done without applying.
|
|
1519
|
+
"""
|
|
1520
|
+
commands = self._ensure_migration_commands()
|
|
1521
|
+
commands.downgrade(revision, dry_run=dry_run)
|
|
1522
|
+
|
|
1523
|
+
def get_current_migration(self, verbose: bool = False) -> "str | None":
|
|
1524
|
+
"""Get the current migration version.
|
|
1525
|
+
|
|
1526
|
+
Args:
|
|
1527
|
+
verbose: Whether to show detailed migration history.
|
|
1528
|
+
|
|
1529
|
+
Returns:
|
|
1530
|
+
Current migration version or None if no migrations applied.
|
|
1531
|
+
"""
|
|
1532
|
+
commands = cast("SyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1533
|
+
return commands.current(verbose=verbose)
|
|
1534
|
+
|
|
1535
|
+
def create_migration(self, message: str, file_type: str = "sql") -> None:
|
|
1536
|
+
"""Create a new migration file.
|
|
1537
|
+
|
|
1538
|
+
Args:
|
|
1539
|
+
message: Description for the migration.
|
|
1540
|
+
file_type: Type of migration file to create ('sql' or 'py').
|
|
1541
|
+
"""
|
|
1542
|
+
commands = self._ensure_migration_commands()
|
|
1543
|
+
commands.revision(message, file_type)
|
|
1544
|
+
|
|
1545
|
+
def init_migrations(self, directory: "str | None" = None, package: bool = True) -> None:
|
|
1546
|
+
"""Initialize migration directory structure.
|
|
1547
|
+
|
|
1548
|
+
Args:
|
|
1549
|
+
directory: Directory to initialize migrations in.
|
|
1550
|
+
package: Whether to create __init__.py file.
|
|
1551
|
+
"""
|
|
1552
|
+
if directory is None:
|
|
1553
|
+
migration_config = self.migration_config or {}
|
|
1554
|
+
directory = str(migration_config.get("script_location") or "migrations")
|
|
1555
|
+
|
|
1556
|
+
commands = self._ensure_migration_commands()
|
|
1557
|
+
assert directory is not None
|
|
1558
|
+
commands.init(directory, package)
|
|
1559
|
+
|
|
1560
|
+
def stamp_migration(self, revision: str) -> None:
|
|
1561
|
+
"""Mark database as being at a specific revision without running migrations.
|
|
1562
|
+
|
|
1563
|
+
Args:
|
|
1564
|
+
revision: The revision to stamp.
|
|
1565
|
+
"""
|
|
1566
|
+
commands = self._ensure_migration_commands()
|
|
1567
|
+
commands.stamp(revision)
|
|
1568
|
+
|
|
1569
|
+
def fix_migrations(self, dry_run: bool = False, update_database: bool = True, yes: bool = False) -> None:
|
|
1570
|
+
"""Convert timestamp migrations to sequential format.
|
|
1571
|
+
|
|
1572
|
+
Args:
|
|
1573
|
+
dry_run: Preview changes without applying.
|
|
1574
|
+
update_database: Update migration records in database.
|
|
1575
|
+
yes: Skip confirmation prompt.
|
|
1576
|
+
"""
|
|
1577
|
+
commands = self._ensure_migration_commands()
|
|
1578
|
+
commands.fix(dry_run, update_database, yes)
|
|
1579
|
+
|
|
1580
|
+
|
|
1581
|
+
class AsyncDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]):
|
|
1582
|
+
"""Base class for async database configurations with connection pooling."""
|
|
1583
|
+
|
|
1584
|
+
__slots__ = ("connection_config",)
|
|
1585
|
+
is_async: "ClassVar[bool]" = True
|
|
1586
|
+
supports_connection_pooling: "ClassVar[bool]" = True
|
|
1587
|
+
migration_tracker_type: "ClassVar[type[Any]]" = AsyncMigrationTracker
|
|
1588
|
+
|
|
1589
|
+
def __init__(
|
|
1590
|
+
self,
|
|
1591
|
+
*,
|
|
1592
|
+
connection_config: "dict[str, Any] | None" = None,
|
|
1593
|
+
connection_instance: "PoolT | None" = None,
|
|
1594
|
+
migration_config: "dict[str, Any] | MigrationConfig | None" = None,
|
|
1595
|
+
statement_config: "StatementConfig | None" = None,
|
|
1596
|
+
driver_features: "dict[str, Any] | None" = None,
|
|
1597
|
+
bind_key: "str | None" = None,
|
|
1598
|
+
extension_config: "ExtensionConfigs | None" = None,
|
|
1599
|
+
observability_config: "ObservabilityConfig | None" = None,
|
|
1600
|
+
**kwargs: Any,
|
|
1601
|
+
) -> None:
|
|
1602
|
+
self.bind_key = bind_key
|
|
1603
|
+
self.connection_instance = connection_instance
|
|
1604
|
+
self.connection_config = connection_config or {}
|
|
1605
|
+
self.extension_config = extension_config or {}
|
|
1606
|
+
self.migration_config: dict[str, Any] | MigrationConfig = migration_config or {}
|
|
1607
|
+
self._ensure_extension_migrations()
|
|
1608
|
+
self._init_observability(observability_config)
|
|
1609
|
+
self._initialize_migration_components()
|
|
1610
|
+
|
|
1611
|
+
if statement_config is None:
|
|
1612
|
+
self.statement_config = StatementConfig(
|
|
1613
|
+
parameter_config=ParameterStyleConfig(
|
|
1614
|
+
default_parameter_style=ParameterStyle.QMARK, supported_parameter_styles={ParameterStyle.QMARK}
|
|
1615
|
+
),
|
|
1616
|
+
dialect="postgres",
|
|
1617
|
+
)
|
|
1618
|
+
else:
|
|
1619
|
+
self.statement_config = statement_config
|
|
1620
|
+
self.driver_features = driver_features or {}
|
|
1621
|
+
self._storage_capabilities = None
|
|
1622
|
+
self.driver_features.setdefault("storage_capabilities", self.storage_capabilities())
|
|
1623
|
+
self._promote_driver_feature_hooks()
|
|
1624
|
+
self._configure_observability_extensions()
|
|
1625
|
+
|
|
1626
|
+
async def create_pool(self) -> PoolT:
|
|
1627
|
+
"""Create and return the connection pool.
|
|
1628
|
+
|
|
1629
|
+
Returns:
|
|
1630
|
+
The created pool.
|
|
1631
|
+
"""
|
|
1632
|
+
if self.connection_instance is not None:
|
|
1633
|
+
return self.connection_instance
|
|
1634
|
+
self.connection_instance = await self._create_pool()
|
|
1635
|
+
self.get_observability_runtime().emit_pool_create(self.connection_instance)
|
|
1636
|
+
return self.connection_instance
|
|
1637
|
+
|
|
1638
|
+
async def close_pool(self) -> None:
|
|
1639
|
+
"""Close the connection pool."""
|
|
1640
|
+
pool = self.connection_instance
|
|
1641
|
+
await self._close_pool()
|
|
1642
|
+
if pool is not None:
|
|
1643
|
+
self.get_observability_runtime().emit_pool_destroy(pool)
|
|
1644
|
+
self.connection_instance = None
|
|
1645
|
+
|
|
1646
|
+
async def provide_pool(self, *args: Any, **kwargs: Any) -> PoolT:
|
|
1647
|
+
"""Provide pool instance."""
|
|
1648
|
+
if self.connection_instance is None:
|
|
1649
|
+
self.connection_instance = await self.create_pool()
|
|
1650
|
+
return self.connection_instance
|
|
1651
|
+
|
|
1652
|
+
async def create_connection(self) -> ConnectionT:
|
|
1653
|
+
"""Create a database connection."""
|
|
1654
|
+
raise NotImplementedError
|
|
1655
|
+
|
|
1656
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "AbstractAsyncContextManager[ConnectionT]":
|
|
1657
|
+
"""Provide a database connection context manager."""
|
|
1658
|
+
raise NotImplementedError
|
|
1659
|
+
|
|
1660
|
+
def provide_session(
|
|
1661
|
+
self, *args: Any, statement_config: "StatementConfig | None" = None, **kwargs: Any
|
|
1662
|
+
) -> "AbstractAsyncContextManager[DriverT]":
|
|
1663
|
+
"""Provide a database session context manager."""
|
|
1664
|
+
raise NotImplementedError
|
|
1665
|
+
|
|
1666
|
+
@abstractmethod
|
|
1667
|
+
async def _create_pool(self) -> PoolT:
|
|
1668
|
+
"""Actual async pool creation implementation."""
|
|
1669
|
+
raise NotImplementedError
|
|
1670
|
+
|
|
1671
|
+
@abstractmethod
|
|
1672
|
+
async def _close_pool(self) -> None:
|
|
1673
|
+
"""Actual async pool destruction implementation."""
|
|
1674
|
+
raise NotImplementedError
|
|
1675
|
+
|
|
1676
|
+
async def migrate_up(
|
|
1677
|
+
self, revision: str = "head", allow_missing: bool = False, auto_sync: bool = True, dry_run: bool = False
|
|
1678
|
+
) -> None:
|
|
1679
|
+
"""Apply database migrations up to specified revision.
|
|
1680
|
+
|
|
1681
|
+
Args:
|
|
1682
|
+
revision: Target revision or "head" for latest.
|
|
1683
|
+
allow_missing: Allow out-of-order migrations.
|
|
1684
|
+
auto_sync: Auto-reconcile renamed migrations.
|
|
1685
|
+
dry_run: Show what would be done without applying.
|
|
1686
|
+
"""
|
|
1687
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1688
|
+
await commands.upgrade(revision, allow_missing, auto_sync, dry_run)
|
|
1689
|
+
|
|
1690
|
+
async def migrate_down(self, revision: str = "-1", *, dry_run: bool = False) -> None:
|
|
1691
|
+
"""Apply database migrations down to specified revision.
|
|
1692
|
+
|
|
1693
|
+
Args:
|
|
1694
|
+
revision: Target revision, "-1" for one step back, or "base" for all migrations.
|
|
1695
|
+
dry_run: Show what would be done without applying.
|
|
1696
|
+
"""
|
|
1697
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1698
|
+
await commands.downgrade(revision, dry_run=dry_run)
|
|
1699
|
+
|
|
1700
|
+
async def get_current_migration(self, verbose: bool = False) -> "str | None":
|
|
1701
|
+
"""Get the current migration version.
|
|
1702
|
+
|
|
1703
|
+
Args:
|
|
1704
|
+
verbose: Whether to show detailed migration history.
|
|
1705
|
+
|
|
1706
|
+
Returns:
|
|
1707
|
+
Current migration version or None if no migrations applied.
|
|
1708
|
+
"""
|
|
1709
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1710
|
+
return await commands.current(verbose=verbose)
|
|
1711
|
+
|
|
1712
|
+
async def create_migration(self, message: str, file_type: str = "sql") -> None:
|
|
1713
|
+
"""Create a new migration file.
|
|
1714
|
+
|
|
1715
|
+
Args:
|
|
1716
|
+
message: Description for the migration.
|
|
1717
|
+
file_type: Type of migration file to create ('sql' or 'py').
|
|
1718
|
+
"""
|
|
1719
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1720
|
+
await commands.revision(message, file_type)
|
|
1721
|
+
|
|
1722
|
+
async def init_migrations(self, directory: "str | None" = None, package: bool = True) -> None:
|
|
1723
|
+
"""Initialize migration directory structure.
|
|
1724
|
+
|
|
1725
|
+
Args:
|
|
1726
|
+
directory: Directory to initialize migrations in.
|
|
1727
|
+
package: Whether to create __init__.py file.
|
|
1728
|
+
"""
|
|
1729
|
+
if directory is None:
|
|
1730
|
+
migration_config = self.migration_config or {}
|
|
1731
|
+
directory = str(migration_config.get("script_location") or "migrations")
|
|
1732
|
+
|
|
1733
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1734
|
+
assert directory is not None
|
|
1735
|
+
await commands.init(directory, package)
|
|
1736
|
+
|
|
1737
|
+
async def stamp_migration(self, revision: str) -> None:
|
|
1738
|
+
"""Mark database as being at a specific revision without running migrations.
|
|
1739
|
+
|
|
1740
|
+
Args:
|
|
1741
|
+
revision: The revision to stamp.
|
|
1742
|
+
"""
|
|
1743
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1744
|
+
await commands.stamp(revision)
|
|
1745
|
+
|
|
1746
|
+
async def fix_migrations(self, dry_run: bool = False, update_database: bool = True, yes: bool = False) -> None:
|
|
1747
|
+
"""Convert timestamp migrations to sequential format.
|
|
1748
|
+
|
|
1749
|
+
Args:
|
|
1750
|
+
dry_run: Preview changes without applying.
|
|
1751
|
+
update_database: Update migration records in database.
|
|
1752
|
+
yes: Skip confirmation prompt.
|
|
1753
|
+
"""
|
|
1754
|
+
commands = cast("AsyncMigrationCommands[Any]", self._ensure_migration_commands())
|
|
1755
|
+
await commands.fix(dry_run, update_database, yes)
|