sqlspec 0.47.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- f68e0789eb443ecb1c2c__mypyc.cp314-win_amd64.pyd +0 -0
- sqlspec/__init__.py +167 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_typing.py +714 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +13 -0
- sqlspec/adapters/adbc/_typing.py +106 -0
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +1280 -0
- sqlspec/adapters/adbc/config.py +378 -0
- sqlspec/adapters/adbc/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/adbc/core.py +922 -0
- sqlspec/adapters/adbc/data_dictionary.py +339 -0
- sqlspec/adapters/adbc/driver.py +534 -0
- sqlspec/adapters/adbc/events/__init__.py +5 -0
- sqlspec/adapters/adbc/events/store.py +285 -0
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +534 -0
- sqlspec/adapters/adbc/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/adbc/type_converter.py +142 -0
- sqlspec/adapters/aiomysql/__init__.py +21 -0
- sqlspec/adapters/aiomysql/_typing.py +137 -0
- sqlspec/adapters/aiomysql/adk/__init__.py +5 -0
- sqlspec/adapters/aiomysql/adk/store.py +678 -0
- sqlspec/adapters/aiomysql/config.py +305 -0
- sqlspec/adapters/aiomysql/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiomysql/core.py +536 -0
- sqlspec/adapters/aiomysql/data_dictionary.py +121 -0
- sqlspec/adapters/aiomysql/driver.py +386 -0
- sqlspec/adapters/aiomysql/events/__init__.py +5 -0
- sqlspec/adapters/aiomysql/events/store.py +104 -0
- sqlspec/adapters/aiomysql/litestar/__init__.py +5 -0
- sqlspec/adapters/aiomysql/litestar/store.py +314 -0
- sqlspec/adapters/aiosqlite/__init__.py +26 -0
- sqlspec/adapters/aiosqlite/_typing.py +109 -0
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +829 -0
- sqlspec/adapters/aiosqlite/config.py +315 -0
- sqlspec/adapters/aiosqlite/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiosqlite/core.py +315 -0
- sqlspec/adapters/aiosqlite/data_dictionary.py +202 -0
- sqlspec/adapters/aiosqlite/driver.py +311 -0
- sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/events/store.py +20 -0
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
- sqlspec/adapters/aiosqlite/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiosqlite/pool.py +734 -0
- sqlspec/adapters/asyncmy/__init__.py +21 -0
- sqlspec/adapters/asyncmy/_typing.py +113 -0
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +644 -0
- sqlspec/adapters/asyncmy/config.py +307 -0
- sqlspec/adapters/asyncmy/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/asyncmy/core.py +538 -0
- sqlspec/adapters/asyncmy/data_dictionary.py +122 -0
- sqlspec/adapters/asyncmy/driver.py +391 -0
- sqlspec/adapters/asyncmy/events/__init__.py +5 -0
- sqlspec/adapters/asyncmy/events/store.py +104 -0
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +26 -0
- sqlspec/adapters/asyncpg/_typing.py +103 -0
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +483 -0
- sqlspec/adapters/asyncpg/config.py +575 -0
- sqlspec/adapters/asyncpg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/asyncpg/core.py +480 -0
- sqlspec/adapters/asyncpg/data_dictionary.py +157 -0
- sqlspec/adapters/asyncpg/driver.py +487 -0
- sqlspec/adapters/asyncpg/events/__init__.py +6 -0
- sqlspec/adapters/asyncpg/events/_hub.py +181 -0
- sqlspec/adapters/asyncpg/events/backend.py +210 -0
- sqlspec/adapters/asyncpg/events/store.py +40 -0
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +251 -0
- sqlspec/adapters/bigquery/__init__.py +15 -0
- sqlspec/adapters/bigquery/_typing.py +108 -0
- sqlspec/adapters/bigquery/config.py +362 -0
- sqlspec/adapters/bigquery/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/bigquery/core.py +768 -0
- sqlspec/adapters/bigquery/data_dictionary.py +120 -0
- sqlspec/adapters/bigquery/driver.py +542 -0
- sqlspec/adapters/bigquery/events/__init__.py +5 -0
- sqlspec/adapters/bigquery/events/store.py +139 -0
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +325 -0
- sqlspec/adapters/bigquery/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/bigquery/type_converter.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/__init__.py +26 -0
- sqlspec/adapters/cockroach_asyncpg/_typing.py +73 -0
- sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/adk/store.py +465 -0
- sqlspec/adapters/cockroach_asyncpg/config.py +248 -0
- sqlspec/adapters/cockroach_asyncpg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
- sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +110 -0
- sqlspec/adapters/cockroach_asyncpg/driver.py +142 -0
- sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
- sqlspec/adapters/cockroach_psycopg/__init__.py +39 -0
- sqlspec/adapters/cockroach_psycopg/_typing.py +137 -0
- sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
- sqlspec/adapters/cockroach_psycopg/adk/store.py +1039 -0
- sqlspec/adapters/cockroach_psycopg/config.py +511 -0
- sqlspec/adapters/cockroach_psycopg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/cockroach_psycopg/core.py +63 -0
- sqlspec/adapters/cockroach_psycopg/data_dictionary.py +220 -0
- sqlspec/adapters/cockroach_psycopg/driver.py +273 -0
- sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
- sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
- sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_psycopg/litestar/store.py +327 -0
- sqlspec/adapters/duckdb/__init__.py +29 -0
- sqlspec/adapters/duckdb/_typing.py +104 -0
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +935 -0
- sqlspec/adapters/duckdb/config.py +386 -0
- sqlspec/adapters/duckdb/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/core.py +332 -0
- sqlspec/adapters/duckdb/data_dictionary.py +140 -0
- sqlspec/adapters/duckdb/driver.py +426 -0
- sqlspec/adapters/duckdb/events/__init__.py +5 -0
- sqlspec/adapters/duckdb/events/store.py +57 -0
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +330 -0
- sqlspec/adapters/duckdb/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/pool.py +350 -0
- sqlspec/adapters/duckdb/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/type_converter.py +118 -0
- sqlspec/adapters/mysqlconnector/__init__.py +39 -0
- sqlspec/adapters/mysqlconnector/_typing.py +186 -0
- sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
- sqlspec/adapters/mysqlconnector/adk/store.py +1183 -0
- sqlspec/adapters/mysqlconnector/config.py +421 -0
- sqlspec/adapters/mysqlconnector/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/mysqlconnector/core.py +472 -0
- sqlspec/adapters/mysqlconnector/data_dictionary.py +230 -0
- sqlspec/adapters/mysqlconnector/driver.py +516 -0
- sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
- sqlspec/adapters/mysqlconnector/events/store.py +98 -0
- sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
- sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
- sqlspec/adapters/oracledb/__init__.py +39 -0
- sqlspec/adapters/oracledb/_json_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_json_handlers.py +196 -0
- sqlspec/adapters/oracledb/_param_types.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_param_types.py +46 -0
- sqlspec/adapters/oracledb/_typing.py +258 -0
- sqlspec/adapters/oracledb/_uuid_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_uuid_handlers.py +163 -0
- sqlspec/adapters/oracledb/_vector_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_vector_handlers.py +228 -0
- sqlspec/adapters/oracledb/adk/__init__.py +21 -0
- sqlspec/adapters/oracledb/adk/store.py +2453 -0
- sqlspec/adapters/oracledb/config.py +575 -0
- sqlspec/adapters/oracledb/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/core.py +820 -0
- sqlspec/adapters/oracledb/data_dictionary.py +404 -0
- sqlspec/adapters/oracledb/driver.py +1277 -0
- sqlspec/adapters/oracledb/events/__init__.py +16 -0
- sqlspec/adapters/oracledb/events/_hub.py +345 -0
- sqlspec/adapters/oracledb/events/backend.py +300 -0
- sqlspec/adapters/oracledb/events/store.py +420 -0
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +781 -0
- sqlspec/adapters/oracledb/migrations.py +539 -0
- sqlspec/adapters/oracledb/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/type_converter.py +211 -0
- sqlspec/adapters/psqlpy/__init__.py +18 -0
- sqlspec/adapters/psqlpy/_typing.py +121 -0
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +591 -0
- sqlspec/adapters/psqlpy/config.py +376 -0
- sqlspec/adapters/psqlpy/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psqlpy/core.py +694 -0
- sqlspec/adapters/psqlpy/data_dictionary.py +121 -0
- sqlspec/adapters/psqlpy/driver.py +411 -0
- sqlspec/adapters/psqlpy/events/__init__.py +6 -0
- sqlspec/adapters/psqlpy/events/_hub.py +204 -0
- sqlspec/adapters/psqlpy/events/backend.py +210 -0
- sqlspec/adapters/psqlpy/events/store.py +20 -0
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +270 -0
- sqlspec/adapters/psqlpy/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psqlpy/type_converter.py +113 -0
- sqlspec/adapters/psycopg/__init__.py +38 -0
- sqlspec/adapters/psycopg/_typing.py +218 -0
- sqlspec/adapters/psycopg/adk/__init__.py +10 -0
- sqlspec/adapters/psycopg/adk/store.py +1106 -0
- sqlspec/adapters/psycopg/config.py +695 -0
- sqlspec/adapters/psycopg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psycopg/core.py +520 -0
- sqlspec/adapters/psycopg/data_dictionary.py +278 -0
- sqlspec/adapters/psycopg/driver.py +1033 -0
- sqlspec/adapters/psycopg/events/__init__.py +20 -0
- sqlspec/adapters/psycopg/events/_hub.py +388 -0
- sqlspec/adapters/psycopg/events/backend.py +398 -0
- sqlspec/adapters/psycopg/events/store.py +42 -0
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +554 -0
- sqlspec/adapters/psycopg/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psycopg/type_converter.py +93 -0
- sqlspec/adapters/pymysql/__init__.py +21 -0
- sqlspec/adapters/pymysql/_typing.py +92 -0
- sqlspec/adapters/pymysql/adk/__init__.py +5 -0
- sqlspec/adapters/pymysql/adk/store.py +657 -0
- sqlspec/adapters/pymysql/config.py +176 -0
- sqlspec/adapters/pymysql/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/pymysql/core.py +469 -0
- sqlspec/adapters/pymysql/data_dictionary.py +120 -0
- sqlspec/adapters/pymysql/driver.py +271 -0
- sqlspec/adapters/pymysql/events/__init__.py +5 -0
- sqlspec/adapters/pymysql/events/store.py +50 -0
- sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
- sqlspec/adapters/pymysql/litestar/store.py +232 -0
- sqlspec/adapters/pymysql/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/pymysql/pool.py +184 -0
- sqlspec/adapters/spanner/__init__.py +33 -0
- sqlspec/adapters/spanner/_typing.py +102 -0
- sqlspec/adapters/spanner/adk/__init__.py +5 -0
- sqlspec/adapters/spanner/adk/store.py +758 -0
- sqlspec/adapters/spanner/config.py +355 -0
- sqlspec/adapters/spanner/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/spanner/core.py +263 -0
- sqlspec/adapters/spanner/data_dictionary.py +120 -0
- sqlspec/adapters/spanner/driver.py +407 -0
- sqlspec/adapters/spanner/events/__init__.py +5 -0
- sqlspec/adapters/spanner/events/store.py +187 -0
- sqlspec/adapters/spanner/litestar/__init__.py +5 -0
- sqlspec/adapters/spanner/litestar/store.py +291 -0
- sqlspec/adapters/spanner/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/spanner/type_converter.py +342 -0
- sqlspec/adapters/sqlite/__init__.py +19 -0
- sqlspec/adapters/sqlite/_typing.py +123 -0
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +992 -0
- sqlspec/adapters/sqlite/config.py +240 -0
- sqlspec/adapters/sqlite/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/core.py +357 -0
- sqlspec/adapters/sqlite/data_dictionary.py +198 -0
- sqlspec/adapters/sqlite/driver.py +527 -0
- sqlspec/adapters/sqlite/events/__init__.py +5 -0
- sqlspec/adapters/sqlite/events/store.py +20 -0
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +316 -0
- sqlspec/adapters/sqlite/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/pool.py +237 -0
- sqlspec/adapters/sqlite/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/type_converter.py +114 -0
- sqlspec/base.py +832 -0
- sqlspec/builder/__init__.py +181 -0
- sqlspec/builder/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_base.py +1071 -0
- sqlspec/builder/_column.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_column.py +521 -0
- sqlspec/builder/_ddl.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_ddl.py +1691 -0
- sqlspec/builder/_delete.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_delete.py +95 -0
- sqlspec/builder/_dml.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_dml.py +386 -0
- sqlspec/builder/_explain.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_explain.py +579 -0
- sqlspec/builder/_expression_wrappers.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_expression_wrappers.py +46 -0
- sqlspec/builder/_factory.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_factory.py +1884 -0
- sqlspec/builder/_insert.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_insert.py +405 -0
- sqlspec/builder/_join.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_join.py +489 -0
- sqlspec/builder/_merge.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_merge.py +823 -0
- sqlspec/builder/_parsing_utils.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_parsing_utils.py +295 -0
- sqlspec/builder/_select.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_select.py +1666 -0
- sqlspec/builder/_temporal.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_temporal.py +167 -0
- sqlspec/builder/_update.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_update.py +173 -0
- sqlspec/builder/_vector_distance.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_vector_distance.py +330 -0
- sqlspec/cli.py +1095 -0
- sqlspec/config.py +2383 -0
- sqlspec/core/__init__.py +372 -0
- sqlspec/core/_correlation.cp314-win_amd64.pyd +0 -0
- sqlspec/core/_correlation.py +176 -0
- sqlspec/core/_pagination.py +42 -0
- sqlspec/core/_pool.cp314-win_amd64.pyd +0 -0
- sqlspec/core/_pool.py +76 -0
- sqlspec/core/cache.cp314-win_amd64.pyd +0 -0
- sqlspec/core/cache.py +1085 -0
- sqlspec/core/compiler.cp314-win_amd64.pyd +0 -0
- sqlspec/core/compiler.py +1090 -0
- sqlspec/core/config_runtime.cp314-win_amd64.pyd +0 -0
- sqlspec/core/config_runtime.py +174 -0
- sqlspec/core/explain.cp314-win_amd64.pyd +0 -0
- sqlspec/core/explain.py +275 -0
- sqlspec/core/filters.cp314-win_amd64.pyd +0 -0
- sqlspec/core/filters.py +969 -0
- sqlspec/core/hashing.cp314-win_amd64.pyd +0 -0
- sqlspec/core/hashing.py +266 -0
- sqlspec/core/metrics.cp314-win_amd64.pyd +0 -0
- sqlspec/core/metrics.py +83 -0
- sqlspec/core/parameters/__init__.py +72 -0
- sqlspec/core/parameters/_alignment.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_alignment.py +283 -0
- sqlspec/core/parameters/_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_converter.py +554 -0
- sqlspec/core/parameters/_processor.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_processor.py +1182 -0
- sqlspec/core/parameters/_registry.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_registry.py +206 -0
- sqlspec/core/parameters/_transformers.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_transformers.py +324 -0
- sqlspec/core/parameters/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_types.py +536 -0
- sqlspec/core/parameters/_validator.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_validator.py +171 -0
- sqlspec/core/pipeline.cp314-win_amd64.pyd +0 -0
- sqlspec/core/pipeline.py +333 -0
- sqlspec/core/query_modifiers.cp314-win_amd64.pyd +0 -0
- sqlspec/core/query_modifiers.py +508 -0
- sqlspec/core/result/__init__.py +25 -0
- sqlspec/core/result/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/core/result/_base.py +1232 -0
- sqlspec/core/result/_io.cp314-win_amd64.pyd +0 -0
- sqlspec/core/result/_io.py +28 -0
- sqlspec/core/splitter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/splitter.py +1021 -0
- sqlspec/core/sqlcommenter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/sqlcommenter.py +249 -0
- sqlspec/core/stack.cp314-win_amd64.pyd +0 -0
- sqlspec/core/stack.py +163 -0
- sqlspec/core/statement.cp314-win_amd64.pyd +0 -0
- sqlspec/core/statement.py +1865 -0
- sqlspec/core/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/type_converter.py +340 -0
- sqlspec/data_dictionary/__init__.py +22 -0
- sqlspec/data_dictionary/_loader.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_loader.py +138 -0
- sqlspec/data_dictionary/_registry.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_registry.py +74 -0
- sqlspec/data_dictionary/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_types.py +121 -0
- sqlspec/data_dictionary/dialects/__init__.py +21 -0
- sqlspec/data_dictionary/dialects/bigquery.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/bigquery.py +81 -0
- sqlspec/data_dictionary/dialects/cockroachdb.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/cockroachdb.py +54 -0
- sqlspec/data_dictionary/dialects/duckdb.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/duckdb.py +47 -0
- sqlspec/data_dictionary/dialects/mysql.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/mysql.py +53 -0
- sqlspec/data_dictionary/dialects/oracle.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/oracle.py +197 -0
- sqlspec/data_dictionary/dialects/postgres.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/postgres.py +69 -0
- sqlspec/data_dictionary/dialects/spanner.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/spanner.py +37 -0
- sqlspec/data_dictionary/dialects/sqlite.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/sqlite.py +59 -0
- sqlspec/data_dictionary/sql/.gitkeep +0 -0
- sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
- sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
- sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
- sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
- sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
- sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
- sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
- sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
- sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
- sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
- sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
- sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
- sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
- sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
- sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
- sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
- sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
- sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
- sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
- sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
- sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
- sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
- sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
- sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
- sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
- sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
- sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
- sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
- sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
- sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
- sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
- sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
- sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
- sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
- sqlspec/dialects/__init__.py +22 -0
- sqlspec/dialects/_compat.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/_compat.py +14 -0
- sqlspec/dialects/postgres/__init__.py +9 -0
- sqlspec/dialects/postgres/_generators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/postgres/_generators.py +57 -0
- sqlspec/dialects/postgres/_operators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/postgres/_operators.py +81 -0
- sqlspec/dialects/postgres/_paradedb.py +50 -0
- sqlspec/dialects/postgres/_pgvector.py +36 -0
- sqlspec/dialects/spanner/__init__.py +6 -0
- sqlspec/dialects/spanner/_generators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/spanner/_generators.py +206 -0
- sqlspec/dialects/spanner/_spangres.py +77 -0
- sqlspec/dialects/spanner/_spanner.py +179 -0
- sqlspec/driver/__init__.py +49 -0
- sqlspec/driver/_async.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_async.py +1830 -0
- sqlspec/driver/_common.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_common.py +2292 -0
- sqlspec/driver/_exception_handler.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_exception_handler.py +108 -0
- sqlspec/driver/_query_cache.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_query_cache.py +96 -0
- sqlspec/driver/_sql_helpers.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_sql_helpers.py +139 -0
- sqlspec/driver/_storage_helpers.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_storage_helpers.py +153 -0
- sqlspec/driver/_sync.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_sync.py +1817 -0
- sqlspec/exceptions.cp314-win_amd64.pyd +0 -0
- sqlspec/exceptions.py +480 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/adk/__init__.py +84 -0
- sqlspec/extensions/adk/_config_utils.py +199 -0
- sqlspec/extensions/adk/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/_types.py +41 -0
- sqlspec/extensions/adk/artifact/__init__.py +57 -0
- sqlspec/extensions/adk/artifact/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/artifact/_types.py +32 -0
- sqlspec/extensions/adk/artifact/service.py +508 -0
- sqlspec/extensions/adk/artifact/store.py +361 -0
- sqlspec/extensions/adk/converters.py +212 -0
- sqlspec/extensions/adk/memory/__init__.py +69 -0
- sqlspec/extensions/adk/memory/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/memory/_types.py +30 -0
- sqlspec/extensions/adk/memory/converters.py +225 -0
- sqlspec/extensions/adk/memory/service.py +316 -0
- sqlspec/extensions/adk/memory/store.py +525 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +184 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +279 -0
- sqlspec/extensions/adk/store.py +590 -0
- sqlspec/extensions/events/__init__.py +51 -0
- sqlspec/extensions/events/_channel.py +703 -0
- sqlspec/extensions/events/_hints.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/events/_hints.py +45 -0
- sqlspec/extensions/events/_models.py +23 -0
- sqlspec/extensions/events/_payload.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/events/_payload.py +69 -0
- sqlspec/extensions/events/_protocols.py +134 -0
- sqlspec/extensions/events/_queue.py +462 -0
- sqlspec/extensions/events/_store.py +209 -0
- sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
- sqlspec/extensions/events/migrations/__init__.py +3 -0
- sqlspec/extensions/fastapi/__init__.py +22 -0
- sqlspec/extensions/fastapi/extension.py +391 -0
- sqlspec/extensions/fastapi/providers.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/fastapi/providers.py +712 -0
- sqlspec/extensions/flask/__init__.py +38 -0
- sqlspec/extensions/flask/_state.py +87 -0
- sqlspec/extensions/flask/_utils.py +71 -0
- sqlspec/extensions/flask/extension.py +539 -0
- sqlspec/extensions/litestar/__init__.py +31 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/channels.py +165 -0
- sqlspec/extensions/litestar/cli.py +102 -0
- sqlspec/extensions/litestar/config.py +90 -0
- sqlspec/extensions/litestar/handlers.py +316 -0
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +1066 -0
- sqlspec/extensions/litestar/providers.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/litestar/providers.py +784 -0
- sqlspec/extensions/litestar/store.py +298 -0
- sqlspec/extensions/otel/__init__.py +58 -0
- sqlspec/extensions/prometheus/__init__.py +113 -0
- sqlspec/extensions/sanic/__init__.py +19 -0
- sqlspec/extensions/sanic/_state.py +43 -0
- sqlspec/extensions/sanic/_utils.py +127 -0
- sqlspec/extensions/sanic/extension.py +647 -0
- sqlspec/extensions/starlette/__init__.py +22 -0
- sqlspec/extensions/starlette/_state.py +42 -0
- sqlspec/extensions/starlette/_utils.py +96 -0
- sqlspec/extensions/starlette/extension.py +374 -0
- sqlspec/extensions/starlette/middleware.py +281 -0
- sqlspec/loader.cp314-win_amd64.pyd +0 -0
- sqlspec/loader.py +727 -0
- sqlspec/migrations/__init__.py +39 -0
- sqlspec/migrations/base.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/base.py +862 -0
- sqlspec/migrations/commands.py +2151 -0
- sqlspec/migrations/context.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/context.py +157 -0
- sqlspec/migrations/fix.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/fix.py +204 -0
- sqlspec/migrations/loaders.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/loaders.py +443 -0
- sqlspec/migrations/runner.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/runner.py +1195 -0
- sqlspec/migrations/squash.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/squash.py +490 -0
- sqlspec/migrations/templates.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/templates.py +234 -0
- sqlspec/migrations/tracker.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/tracker.py +792 -0
- sqlspec/migrations/utils.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/utils.py +256 -0
- sqlspec/migrations/validation.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/validation.py +359 -0
- sqlspec/migrations/version.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/version.py +446 -0
- sqlspec/observability/__init__.py +57 -0
- sqlspec/observability/_common.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_common.py +77 -0
- sqlspec/observability/_config.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_config.py +364 -0
- sqlspec/observability/_diagnostics.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_diagnostics.py +74 -0
- sqlspec/observability/_dispatcher.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_dispatcher.py +200 -0
- sqlspec/observability/_formatters/__init__.py +13 -0
- sqlspec/observability/_formatters/_aws.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_aws.py +102 -0
- sqlspec/observability/_formatters/_azure.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_azure.py +96 -0
- sqlspec/observability/_formatters/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_base.py +57 -0
- sqlspec/observability/_formatters/_gcp.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_gcp.py +131 -0
- sqlspec/observability/_formatting.py +58 -0
- sqlspec/observability/_observer.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_observer.py +361 -0
- sqlspec/observability/_runtime.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_runtime.py +461 -0
- sqlspec/observability/_sampling.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_sampling.py +188 -0
- sqlspec/observability/_spans.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_spans.py +161 -0
- sqlspec/protocols.py +955 -0
- sqlspec/py.typed +0 -0
- sqlspec/service.py +433 -0
- sqlspec/storage/__init__.py +48 -0
- sqlspec/storage/_arrow_payload.py +68 -0
- sqlspec/storage/_paths.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/_paths.py +58 -0
- sqlspec/storage/_utils.py +46 -0
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/base.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/backends/base.py +374 -0
- sqlspec/storage/backends/fsspec.py +574 -0
- sqlspec/storage/backends/local.py +468 -0
- sqlspec/storage/backends/obstore.py +956 -0
- sqlspec/storage/errors.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/errors.py +102 -0
- sqlspec/storage/pipeline.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/pipeline.py +628 -0
- sqlspec/storage/registry.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/registry.py +329 -0
- sqlspec/typing.py +405 -0
- sqlspec/utils/__init__.py +7 -0
- sqlspec/utils/arrow_helpers.py +384 -0
- sqlspec/utils/config_tools.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/config_tools.py +314 -0
- sqlspec/utils/correlation.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/correlation.py +134 -0
- sqlspec/utils/deprecation.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/deprecation.py +157 -0
- sqlspec/utils/dispatch.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/dispatch.py +101 -0
- sqlspec/utils/fixtures.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/fixtures.py +260 -0
- sqlspec/utils/logging.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/logging.py +251 -0
- sqlspec/utils/module_loader.py +306 -0
- sqlspec/utils/portal.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/portal.py +377 -0
- sqlspec/utils/schema.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/schema.py +1040 -0
- sqlspec/utils/serializers/__init__.py +30 -0
- sqlspec/utils/serializers/_json.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_json.py +415 -0
- sqlspec/utils/serializers/_numpy.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_numpy.py +65 -0
- sqlspec/utils/serializers/_schema.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_schema.py +285 -0
- sqlspec/utils/singleton.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/singleton.py +41 -0
- sqlspec/utils/sync_tools.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/sync_tools.py +316 -0
- sqlspec/utils/text.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/text.py +109 -0
- sqlspec/utils/type_converters.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/type_converters.py +216 -0
- sqlspec/utils/type_guards.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/type_guards.py +1508 -0
- sqlspec/utils/uuids.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/uuids.py +241 -0
- sqlspec-0.47.0.dist-info/METADATA +202 -0
- sqlspec-0.47.0.dist-info/RECORD +621 -0
- sqlspec-0.47.0.dist-info/WHEEL +4 -0
- sqlspec-0.47.0.dist-info/entry_points.txt +6 -0
- sqlspec-0.47.0.dist-info/licenses/LICENSE +21 -0
|
Binary file
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"""Migration squash engine for combining multiple migrations into a single file.
|
|
2
|
+
|
|
3
|
+
This module provides utilities to consolidate multiple sequential migrations
|
|
4
|
+
into a single "release" migration file, following the Django-style squash workflow.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import inspect
|
|
8
|
+
import shutil
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
13
|
+
|
|
14
|
+
from sqlspec.exceptions import SquashValidationError
|
|
15
|
+
from sqlspec.utils.logging import get_logger
|
|
16
|
+
from sqlspec.utils.sync_tools import await_
|
|
17
|
+
from sqlspec.utils.text import slugify
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from sqlspec.migrations.runner import SyncMigrationRunner
|
|
21
|
+
from sqlspec.migrations.templates import MigrationTemplateSettings
|
|
22
|
+
|
|
23
|
+
__all__ = ("MigrationSquasher", "SquashPlan", "group_migrations_by_type", "parse_version_range")
|
|
24
|
+
|
|
25
|
+
logger = get_logger("sqlspec.migrations.squash")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def parse_version_range(range_str: str) -> tuple[str, str]:
|
|
29
|
+
"""Parse a version range string into (start, end) tuple.
|
|
30
|
+
|
|
31
|
+
Accepts multiple formats: ``START:END``, ``START..END``, or ``START-END``.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
range_str: Version range string.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Tuple of (start_version, end_version) zero-padded to 4 digits.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
ValueError: If the format is not recognised.
|
|
41
|
+
"""
|
|
42
|
+
for sep in (":", "..", "-"):
|
|
43
|
+
if sep in range_str:
|
|
44
|
+
parts = range_str.split(sep, 1)
|
|
45
|
+
start = parts[0].strip().zfill(4)
|
|
46
|
+
end = parts[1].strip().zfill(4)
|
|
47
|
+
return start, end
|
|
48
|
+
msg = f"Invalid VERSION_RANGE format: '{range_str}'. Use START:END, START..END, or START-END (e.g., 1:7)"
|
|
49
|
+
raise ValueError(msg)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def group_migrations_by_type(migrations: list[tuple[str, Path]]) -> list[tuple[str, list[tuple[str, Path]]]]:
|
|
53
|
+
"""Group consecutive migrations by file type (sql or py).
|
|
54
|
+
|
|
55
|
+
Partitions a list of migrations into groups where each group contains
|
|
56
|
+
consecutive migrations of the same type. This enables squashing mixed
|
|
57
|
+
SQL and Python migrations into separate output files.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
migrations: List of (version, path) tuples to group.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
List of (type, migrations) tuples where type is "sql" or "py"
|
|
64
|
+
and migrations is the list of (version, path) for that group.
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
if not migrations:
|
|
68
|
+
return []
|
|
69
|
+
|
|
70
|
+
groups: list[tuple[str, list[tuple[str, Path]]]] = []
|
|
71
|
+
current_type: str | None = None
|
|
72
|
+
current_group: list[tuple[str, Path]] = []
|
|
73
|
+
|
|
74
|
+
for version, path in migrations:
|
|
75
|
+
file_type = "py" if path.suffix == ".py" else "sql"
|
|
76
|
+
|
|
77
|
+
if file_type != current_type:
|
|
78
|
+
if current_group and current_type is not None:
|
|
79
|
+
groups.append((current_type, current_group))
|
|
80
|
+
current_type = file_type
|
|
81
|
+
current_group = [(version, path)]
|
|
82
|
+
else:
|
|
83
|
+
current_group.append((version, path))
|
|
84
|
+
|
|
85
|
+
if current_group and current_type is not None:
|
|
86
|
+
groups.append((current_type, current_group))
|
|
87
|
+
|
|
88
|
+
return groups
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass(slots=True)
|
|
92
|
+
class SquashPlan:
|
|
93
|
+
"""Represents a planned squash operation.
|
|
94
|
+
|
|
95
|
+
Attributes:
|
|
96
|
+
source_migrations: List of (version, path) tuples for migrations being squashed.
|
|
97
|
+
target_version: The version string for the squashed migration.
|
|
98
|
+
target_path: Output file path for the squashed migration.
|
|
99
|
+
description: Combined description for the squashed migration.
|
|
100
|
+
source_versions: List of version strings being replaced (for tracking table updates).
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
source_migrations: list[tuple[str, Path]]
|
|
104
|
+
target_version: str
|
|
105
|
+
target_path: Path
|
|
106
|
+
description: str
|
|
107
|
+
source_versions: list[str]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class MigrationSquasher:
|
|
111
|
+
"""Core squash engine for combining migrations.
|
|
112
|
+
|
|
113
|
+
Provides functionality to plan, validate, and execute migration squash operations.
|
|
114
|
+
Combines multiple sequential migrations into a single file with merged UP/DOWN SQL.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
__slots__ = ("backup_path", "migrations_path", "runner", "template_settings")
|
|
118
|
+
|
|
119
|
+
def __init__(
|
|
120
|
+
self,
|
|
121
|
+
migrations_path: Path,
|
|
122
|
+
runner: "SyncMigrationRunner",
|
|
123
|
+
template_settings: "MigrationTemplateSettings | None" = None,
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Initialize the migration squasher.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
migrations_path: Path to the migrations directory.
|
|
129
|
+
runner: SyncMigrationRunner instance for loading migrations.
|
|
130
|
+
template_settings: Optional template settings for generating squashed file.
|
|
131
|
+
"""
|
|
132
|
+
self.migrations_path = migrations_path
|
|
133
|
+
self.runner = runner
|
|
134
|
+
self.template_settings = template_settings
|
|
135
|
+
self.backup_path: Path | None = None
|
|
136
|
+
|
|
137
|
+
def plan_squash(
|
|
138
|
+
self,
|
|
139
|
+
start_version: str,
|
|
140
|
+
end_version: str,
|
|
141
|
+
description: str,
|
|
142
|
+
*,
|
|
143
|
+
allow_gaps: bool = False,
|
|
144
|
+
output_format: str = "sql",
|
|
145
|
+
) -> list[SquashPlan]:
|
|
146
|
+
"""Plan a squash operation for a range of migrations.
|
|
147
|
+
|
|
148
|
+
For homogeneous migrations (all SQL or all Python), returns a single plan.
|
|
149
|
+
For mixed SQL/Python migrations, returns multiple plans - one per
|
|
150
|
+
consecutive group of same-type migrations.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
start_version: First version in the range to squash (inclusive).
|
|
154
|
+
end_version: Last version in the range to squash (inclusive).
|
|
155
|
+
description: Description for the squashed migration file.
|
|
156
|
+
allow_gaps: If True, allow gaps in version sequence.
|
|
157
|
+
output_format: Output file format ("sql" or "py").
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
List of SquashPlan objects with details of planned operations.
|
|
161
|
+
|
|
162
|
+
Raises:
|
|
163
|
+
SquashValidationError: If validation fails (invalid range, gaps, etc.).
|
|
164
|
+
"""
|
|
165
|
+
# Validate range direction
|
|
166
|
+
if int(start_version) > int(end_version):
|
|
167
|
+
msg = f"Invalid range: start version {start_version} is greater than end version {end_version}"
|
|
168
|
+
raise SquashValidationError(msg)
|
|
169
|
+
|
|
170
|
+
# Get all migrations from runner
|
|
171
|
+
all_migrations = self.runner.get_migration_files()
|
|
172
|
+
version_map = dict(all_migrations)
|
|
173
|
+
|
|
174
|
+
# Validate versions exist
|
|
175
|
+
if start_version not in version_map:
|
|
176
|
+
msg = f"Start version {start_version} not found in migrations"
|
|
177
|
+
raise SquashValidationError(msg)
|
|
178
|
+
if end_version not in version_map:
|
|
179
|
+
msg = f"End version {end_version} not found in migrations"
|
|
180
|
+
raise SquashValidationError(msg)
|
|
181
|
+
|
|
182
|
+
# Filter migrations in range
|
|
183
|
+
start_int = int(start_version)
|
|
184
|
+
end_int = int(end_version)
|
|
185
|
+
source_migrations: list[tuple[str, Path]] = []
|
|
186
|
+
|
|
187
|
+
for version, path in all_migrations:
|
|
188
|
+
try:
|
|
189
|
+
version_int = int(version)
|
|
190
|
+
except ValueError:
|
|
191
|
+
continue # Skip non-sequential versions (ext_*, timestamps)
|
|
192
|
+
|
|
193
|
+
if start_int <= version_int <= end_int:
|
|
194
|
+
source_migrations.append((version, path))
|
|
195
|
+
|
|
196
|
+
# Validate no gaps in sequence (unless allow_gaps is True)
|
|
197
|
+
if not allow_gaps and len(source_migrations) > 1:
|
|
198
|
+
source_versions_int = sorted(int(v) for v, _ in source_migrations)
|
|
199
|
+
for i in range(1, len(source_versions_int)):
|
|
200
|
+
if source_versions_int[i] - source_versions_int[i - 1] != 1:
|
|
201
|
+
msg = f"Gap detected in version sequence between {source_versions_int[i - 1]:04d} and {source_versions_int[i]:04d}"
|
|
202
|
+
raise SquashValidationError(msg)
|
|
203
|
+
|
|
204
|
+
# Slugify description for safe filenames
|
|
205
|
+
safe_description = slugify(description, separator="_")[:50] or "migration"
|
|
206
|
+
|
|
207
|
+
# Group migrations by type (sql vs py) unless output_format forces a specific format
|
|
208
|
+
if output_format == "py":
|
|
209
|
+
# Force all output to Python format - single plan with all migrations
|
|
210
|
+
extension = ".py"
|
|
211
|
+
target_version = f"{int(start_version):04d}"
|
|
212
|
+
target_path = self.migrations_path / f"{target_version}_{safe_description}{extension}"
|
|
213
|
+
return [
|
|
214
|
+
SquashPlan(
|
|
215
|
+
source_migrations=source_migrations,
|
|
216
|
+
target_version=target_version,
|
|
217
|
+
target_path=target_path,
|
|
218
|
+
description=description,
|
|
219
|
+
source_versions=[v for v, _ in source_migrations],
|
|
220
|
+
)
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
# Default: group by type and generate appropriate files
|
|
224
|
+
groups = group_migrations_by_type(source_migrations)
|
|
225
|
+
|
|
226
|
+
# Build plans for each group
|
|
227
|
+
plans: list[SquashPlan] = []
|
|
228
|
+
version_counter = int(start_version)
|
|
229
|
+
|
|
230
|
+
for file_type, group_migrations in groups:
|
|
231
|
+
group_versions = [v for v, _ in group_migrations]
|
|
232
|
+
target_version = f"{version_counter:04d}"
|
|
233
|
+
extension = ".py" if file_type == "py" else ".sql"
|
|
234
|
+
target_path = self.migrations_path / f"{target_version}_{safe_description}{extension}"
|
|
235
|
+
|
|
236
|
+
plans.append(
|
|
237
|
+
SquashPlan(
|
|
238
|
+
source_migrations=group_migrations,
|
|
239
|
+
target_version=target_version,
|
|
240
|
+
target_path=target_path,
|
|
241
|
+
description=description,
|
|
242
|
+
source_versions=group_versions,
|
|
243
|
+
)
|
|
244
|
+
)
|
|
245
|
+
version_counter += 1
|
|
246
|
+
|
|
247
|
+
return plans
|
|
248
|
+
|
|
249
|
+
def extract_sql(self, migrations: list[tuple[str, Path]]) -> tuple[list[str], list[str]]:
|
|
250
|
+
"""Extract UP and DOWN SQL statements from migrations.
|
|
251
|
+
|
|
252
|
+
UP statements are accumulated in version order.
|
|
253
|
+
DOWN statements are accumulated in REVERSE version order for proper rollback.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
migrations: List of (version, path) tuples to extract SQL from.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Tuple of (up_statements, down_statements) lists.
|
|
260
|
+
"""
|
|
261
|
+
up_statements: list[str] = []
|
|
262
|
+
down_statements: list[str] = []
|
|
263
|
+
|
|
264
|
+
# Load and collect SQL from each migration (UP in order)
|
|
265
|
+
migration_sql: list[tuple[str, list[str], list[str]]] = []
|
|
266
|
+
|
|
267
|
+
for version, path in migrations:
|
|
268
|
+
migration_data = self.runner.load_migration(path, version)
|
|
269
|
+
loader = migration_data["loader"]
|
|
270
|
+
|
|
271
|
+
# Get UP SQL (handle async loaders via await_ bridge)
|
|
272
|
+
up_method = loader.get_up_sql
|
|
273
|
+
up_sql = (
|
|
274
|
+
await_(up_method, raise_sync_error=False)(path)
|
|
275
|
+
if inspect.iscoroutinefunction(up_method)
|
|
276
|
+
else up_method(path)
|
|
277
|
+
)
|
|
278
|
+
if up_sql:
|
|
279
|
+
if isinstance(up_sql, list):
|
|
280
|
+
up_statements.extend(up_sql)
|
|
281
|
+
else:
|
|
282
|
+
up_statements.append(up_sql)
|
|
283
|
+
|
|
284
|
+
# Get DOWN SQL (handle async loaders via await_ bridge)
|
|
285
|
+
down_method = loader.get_down_sql
|
|
286
|
+
down_sql = (
|
|
287
|
+
await_(down_method, raise_sync_error=False)(path)
|
|
288
|
+
if inspect.iscoroutinefunction(down_method)
|
|
289
|
+
else down_method(path)
|
|
290
|
+
)
|
|
291
|
+
if down_sql:
|
|
292
|
+
if isinstance(down_sql, list):
|
|
293
|
+
migration_sql.append((version, [], list(down_sql)))
|
|
294
|
+
else:
|
|
295
|
+
migration_sql.append((version, [], [down_sql]))
|
|
296
|
+
else:
|
|
297
|
+
migration_sql.append((version, [], []))
|
|
298
|
+
|
|
299
|
+
# DOWN statements in REVERSE order
|
|
300
|
+
for _, _, down_sql in reversed(migration_sql):
|
|
301
|
+
down_statements.extend(down_sql)
|
|
302
|
+
|
|
303
|
+
return up_statements, down_statements
|
|
304
|
+
|
|
305
|
+
def generate_squashed_content(self, plan: SquashPlan, up_sql: list[str], down_sql: list[str]) -> str:
|
|
306
|
+
"""Generate the content for a squashed migration file.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
plan: The SquashPlan describing the squash operation.
|
|
310
|
+
up_sql: List of UP SQL statements (in execution order).
|
|
311
|
+
down_sql: List of DOWN SQL statements (in rollback order).
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Complete SQL file content as a string.
|
|
315
|
+
"""
|
|
316
|
+
lines: list[str] = []
|
|
317
|
+
|
|
318
|
+
# Header section
|
|
319
|
+
title = "SQLSpec Migration"
|
|
320
|
+
if self.template_settings and self.template_settings.profile:
|
|
321
|
+
title = self.template_settings.profile.title
|
|
322
|
+
|
|
323
|
+
lines.extend((
|
|
324
|
+
f"-- {title}",
|
|
325
|
+
f"-- Version: {plan.target_version}",
|
|
326
|
+
f"-- Description: {plan.description}",
|
|
327
|
+
f"-- Squashed from: {', '.join(plan.source_versions)}",
|
|
328
|
+
"",
|
|
329
|
+
f"-- name: migrate-{plan.target_version}-up",
|
|
330
|
+
))
|
|
331
|
+
for statement in up_sql:
|
|
332
|
+
lines.append(statement.rstrip())
|
|
333
|
+
if not statement.rstrip().endswith(";"):
|
|
334
|
+
pass # Don't add extra semicolons
|
|
335
|
+
lines.append("")
|
|
336
|
+
|
|
337
|
+
# DOWN section (only if there are statements)
|
|
338
|
+
if down_sql:
|
|
339
|
+
lines.append(f"-- name: migrate-{plan.target_version}-down")
|
|
340
|
+
lines.extend(statement.rstrip() for statement in down_sql)
|
|
341
|
+
lines.append("")
|
|
342
|
+
|
|
343
|
+
return "\n".join(lines)
|
|
344
|
+
|
|
345
|
+
def generate_python_squash(self, plan: SquashPlan, up_sql: list[str], down_sql: list[str]) -> str:
|
|
346
|
+
"""Generate Python migration file content instead of SQL.
|
|
347
|
+
|
|
348
|
+
Creates a Python migration file with up() and down() functions
|
|
349
|
+
that return the SQL statements as lists.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
plan: The SquashPlan describing the squash operation.
|
|
353
|
+
up_sql: List of UP SQL statements (in execution order).
|
|
354
|
+
down_sql: List of DOWN SQL statements (in rollback order).
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
Complete Python file content as a string.
|
|
358
|
+
"""
|
|
359
|
+
lines: list[str] = []
|
|
360
|
+
|
|
361
|
+
# Module docstring
|
|
362
|
+
title = "SQLSpec Migration"
|
|
363
|
+
if self.template_settings and self.template_settings.profile:
|
|
364
|
+
title = self.template_settings.profile.title
|
|
365
|
+
|
|
366
|
+
lines.extend([
|
|
367
|
+
'"""' + title + ".",
|
|
368
|
+
"",
|
|
369
|
+
f"Version: {plan.target_version}",
|
|
370
|
+
f"Description: {plan.description}",
|
|
371
|
+
f"Squashed from: {', '.join(plan.source_versions)}",
|
|
372
|
+
'"""',
|
|
373
|
+
"",
|
|
374
|
+
])
|
|
375
|
+
|
|
376
|
+
# Generate up() function
|
|
377
|
+
lines.extend(["def up() -> list[str]:", ' """Return UP migration SQL statements."""', " return ["])
|
|
378
|
+
lines.extend(f" {statement!r}," for statement in up_sql)
|
|
379
|
+
lines.extend([" ]", ""])
|
|
380
|
+
|
|
381
|
+
# Generate down() function
|
|
382
|
+
lines.extend(["def down() -> list[str] | None:", ' """Return DOWN migration SQL statements."""'])
|
|
383
|
+
if down_sql:
|
|
384
|
+
lines.append(" return [")
|
|
385
|
+
lines.extend(f" {statement!r}," for statement in down_sql)
|
|
386
|
+
lines.extend([" ]", ""])
|
|
387
|
+
else:
|
|
388
|
+
lines.extend([" return None", ""])
|
|
389
|
+
|
|
390
|
+
return "\n".join(lines)
|
|
391
|
+
|
|
392
|
+
def apply_squash(self, plans: list[SquashPlan], *, dry_run: bool = False) -> None:
|
|
393
|
+
"""Apply the squash operation for one or more plans.
|
|
394
|
+
|
|
395
|
+
Creates backup, writes squashed files, deletes source migrations,
|
|
396
|
+
and cleans up backup on success. Rolls back on error.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
plans: List of SquashPlan objects to execute.
|
|
400
|
+
dry_run: If True, no files are modified (preview only).
|
|
401
|
+
"""
|
|
402
|
+
if dry_run:
|
|
403
|
+
logger.debug("Dry run mode - no changes will be made")
|
|
404
|
+
return
|
|
405
|
+
|
|
406
|
+
# Create backup before making changes
|
|
407
|
+
self._create_backup()
|
|
408
|
+
|
|
409
|
+
try:
|
|
410
|
+
for plan in plans:
|
|
411
|
+
# Extract SQL from source migrations
|
|
412
|
+
up_sql, down_sql = self.extract_sql(plan.source_migrations)
|
|
413
|
+
|
|
414
|
+
# Generate squashed content based on target file type
|
|
415
|
+
if plan.target_path.suffix == ".py":
|
|
416
|
+
content = self.generate_python_squash(plan, up_sql, down_sql)
|
|
417
|
+
else:
|
|
418
|
+
content = self.generate_squashed_content(plan, up_sql, down_sql)
|
|
419
|
+
|
|
420
|
+
# Write the squashed file
|
|
421
|
+
plan.target_path.write_text(content, encoding="utf-8")
|
|
422
|
+
logger.debug("Wrote squashed migration to %s", plan.target_path)
|
|
423
|
+
|
|
424
|
+
# Collect all source paths to delete (avoid duplicates across plans)
|
|
425
|
+
all_source_paths = {source_path for plan in plans for _, source_path in plan.source_migrations}
|
|
426
|
+
|
|
427
|
+
# Delete all source migration files
|
|
428
|
+
for source_path in all_source_paths:
|
|
429
|
+
if source_path.exists():
|
|
430
|
+
source_path.unlink()
|
|
431
|
+
logger.debug("Deleted source migration %s", source_path)
|
|
432
|
+
|
|
433
|
+
# Clean up backup on success
|
|
434
|
+
self._cleanup_backup()
|
|
435
|
+
|
|
436
|
+
except Exception:
|
|
437
|
+
# Rollback on error
|
|
438
|
+
self._rollback_backup()
|
|
439
|
+
raise
|
|
440
|
+
|
|
441
|
+
def _create_backup(self) -> Path:
|
|
442
|
+
"""Create timestamped backup directory with all migration files.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
Path to created backup directory.
|
|
446
|
+
"""
|
|
447
|
+
timestamp = datetime.now(tz=timezone.utc).strftime("%Y%m%d_%H%M%S")
|
|
448
|
+
backup_dir = self.migrations_path / f".backup_{timestamp}"
|
|
449
|
+
|
|
450
|
+
backup_dir.mkdir(parents=True, exist_ok=False)
|
|
451
|
+
|
|
452
|
+
for file_path in self.migrations_path.iterdir():
|
|
453
|
+
if file_path.is_file() and not file_path.name.startswith("."):
|
|
454
|
+
shutil.copy2(file_path, backup_dir / file_path.name)
|
|
455
|
+
|
|
456
|
+
self.backup_path = backup_dir
|
|
457
|
+
logger.debug("Created backup at %s", backup_dir)
|
|
458
|
+
return backup_dir
|
|
459
|
+
|
|
460
|
+
def _cleanup_backup(self) -> None:
|
|
461
|
+
"""Remove backup directory after successful operation."""
|
|
462
|
+
if not self.backup_path or not self.backup_path.exists():
|
|
463
|
+
return
|
|
464
|
+
|
|
465
|
+
shutil.rmtree(self.backup_path)
|
|
466
|
+
logger.debug("Cleaned up backup at %s", self.backup_path)
|
|
467
|
+
self.backup_path = None
|
|
468
|
+
|
|
469
|
+
def _rollback_backup(self) -> None:
|
|
470
|
+
"""Restore migration files from backup on error."""
|
|
471
|
+
if not self.backup_path or not self.backup_path.exists():
|
|
472
|
+
return
|
|
473
|
+
|
|
474
|
+
backup_dir = self.backup_path
|
|
475
|
+
|
|
476
|
+
# Delete any partially created files
|
|
477
|
+
for file_path in self.migrations_path.iterdir():
|
|
478
|
+
if file_path.is_file() and not file_path.name.startswith("."):
|
|
479
|
+
file_path.unlink()
|
|
480
|
+
|
|
481
|
+
# Restore from backup
|
|
482
|
+
for backup_file in backup_dir.iterdir():
|
|
483
|
+
if backup_file.is_file():
|
|
484
|
+
shutil.copy2(backup_file, self.migrations_path / backup_file.name)
|
|
485
|
+
|
|
486
|
+
# Clean up the backup directory itself
|
|
487
|
+
shutil.rmtree(backup_dir)
|
|
488
|
+
self.backup_path = None
|
|
489
|
+
|
|
490
|
+
logger.debug("Rolled back from backup at %s", backup_dir)
|
|
Binary file
|