sqlspec 0.47.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- f68e0789eb443ecb1c2c__mypyc.cp314-win_amd64.pyd +0 -0
- sqlspec/__init__.py +167 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_typing.py +714 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +13 -0
- sqlspec/adapters/adbc/_typing.py +106 -0
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +1280 -0
- sqlspec/adapters/adbc/config.py +378 -0
- sqlspec/adapters/adbc/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/adbc/core.py +922 -0
- sqlspec/adapters/adbc/data_dictionary.py +339 -0
- sqlspec/adapters/adbc/driver.py +534 -0
- sqlspec/adapters/adbc/events/__init__.py +5 -0
- sqlspec/adapters/adbc/events/store.py +285 -0
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +534 -0
- sqlspec/adapters/adbc/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/adbc/type_converter.py +142 -0
- sqlspec/adapters/aiomysql/__init__.py +21 -0
- sqlspec/adapters/aiomysql/_typing.py +137 -0
- sqlspec/adapters/aiomysql/adk/__init__.py +5 -0
- sqlspec/adapters/aiomysql/adk/store.py +678 -0
- sqlspec/adapters/aiomysql/config.py +305 -0
- sqlspec/adapters/aiomysql/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiomysql/core.py +536 -0
- sqlspec/adapters/aiomysql/data_dictionary.py +121 -0
- sqlspec/adapters/aiomysql/driver.py +386 -0
- sqlspec/adapters/aiomysql/events/__init__.py +5 -0
- sqlspec/adapters/aiomysql/events/store.py +104 -0
- sqlspec/adapters/aiomysql/litestar/__init__.py +5 -0
- sqlspec/adapters/aiomysql/litestar/store.py +314 -0
- sqlspec/adapters/aiosqlite/__init__.py +26 -0
- sqlspec/adapters/aiosqlite/_typing.py +109 -0
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +829 -0
- sqlspec/adapters/aiosqlite/config.py +315 -0
- sqlspec/adapters/aiosqlite/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiosqlite/core.py +315 -0
- sqlspec/adapters/aiosqlite/data_dictionary.py +202 -0
- sqlspec/adapters/aiosqlite/driver.py +311 -0
- sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/events/store.py +20 -0
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
- sqlspec/adapters/aiosqlite/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiosqlite/pool.py +734 -0
- sqlspec/adapters/asyncmy/__init__.py +21 -0
- sqlspec/adapters/asyncmy/_typing.py +113 -0
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +644 -0
- sqlspec/adapters/asyncmy/config.py +307 -0
- sqlspec/adapters/asyncmy/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/asyncmy/core.py +538 -0
- sqlspec/adapters/asyncmy/data_dictionary.py +122 -0
- sqlspec/adapters/asyncmy/driver.py +391 -0
- sqlspec/adapters/asyncmy/events/__init__.py +5 -0
- sqlspec/adapters/asyncmy/events/store.py +104 -0
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +26 -0
- sqlspec/adapters/asyncpg/_typing.py +103 -0
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +483 -0
- sqlspec/adapters/asyncpg/config.py +575 -0
- sqlspec/adapters/asyncpg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/asyncpg/core.py +480 -0
- sqlspec/adapters/asyncpg/data_dictionary.py +157 -0
- sqlspec/adapters/asyncpg/driver.py +487 -0
- sqlspec/adapters/asyncpg/events/__init__.py +6 -0
- sqlspec/adapters/asyncpg/events/_hub.py +181 -0
- sqlspec/adapters/asyncpg/events/backend.py +210 -0
- sqlspec/adapters/asyncpg/events/store.py +40 -0
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +251 -0
- sqlspec/adapters/bigquery/__init__.py +15 -0
- sqlspec/adapters/bigquery/_typing.py +108 -0
- sqlspec/adapters/bigquery/config.py +362 -0
- sqlspec/adapters/bigquery/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/bigquery/core.py +768 -0
- sqlspec/adapters/bigquery/data_dictionary.py +120 -0
- sqlspec/adapters/bigquery/driver.py +542 -0
- sqlspec/adapters/bigquery/events/__init__.py +5 -0
- sqlspec/adapters/bigquery/events/store.py +139 -0
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +325 -0
- sqlspec/adapters/bigquery/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/bigquery/type_converter.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/__init__.py +26 -0
- sqlspec/adapters/cockroach_asyncpg/_typing.py +73 -0
- sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/adk/store.py +465 -0
- sqlspec/adapters/cockroach_asyncpg/config.py +248 -0
- sqlspec/adapters/cockroach_asyncpg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
- sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +110 -0
- sqlspec/adapters/cockroach_asyncpg/driver.py +142 -0
- sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
- sqlspec/adapters/cockroach_psycopg/__init__.py +39 -0
- sqlspec/adapters/cockroach_psycopg/_typing.py +137 -0
- sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
- sqlspec/adapters/cockroach_psycopg/adk/store.py +1039 -0
- sqlspec/adapters/cockroach_psycopg/config.py +511 -0
- sqlspec/adapters/cockroach_psycopg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/cockroach_psycopg/core.py +63 -0
- sqlspec/adapters/cockroach_psycopg/data_dictionary.py +220 -0
- sqlspec/adapters/cockroach_psycopg/driver.py +273 -0
- sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
- sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
- sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_psycopg/litestar/store.py +327 -0
- sqlspec/adapters/duckdb/__init__.py +29 -0
- sqlspec/adapters/duckdb/_typing.py +104 -0
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +935 -0
- sqlspec/adapters/duckdb/config.py +386 -0
- sqlspec/adapters/duckdb/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/core.py +332 -0
- sqlspec/adapters/duckdb/data_dictionary.py +140 -0
- sqlspec/adapters/duckdb/driver.py +426 -0
- sqlspec/adapters/duckdb/events/__init__.py +5 -0
- sqlspec/adapters/duckdb/events/store.py +57 -0
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +330 -0
- sqlspec/adapters/duckdb/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/pool.py +350 -0
- sqlspec/adapters/duckdb/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/type_converter.py +118 -0
- sqlspec/adapters/mysqlconnector/__init__.py +39 -0
- sqlspec/adapters/mysqlconnector/_typing.py +186 -0
- sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
- sqlspec/adapters/mysqlconnector/adk/store.py +1183 -0
- sqlspec/adapters/mysqlconnector/config.py +421 -0
- sqlspec/adapters/mysqlconnector/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/mysqlconnector/core.py +472 -0
- sqlspec/adapters/mysqlconnector/data_dictionary.py +230 -0
- sqlspec/adapters/mysqlconnector/driver.py +516 -0
- sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
- sqlspec/adapters/mysqlconnector/events/store.py +98 -0
- sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
- sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
- sqlspec/adapters/oracledb/__init__.py +39 -0
- sqlspec/adapters/oracledb/_json_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_json_handlers.py +196 -0
- sqlspec/adapters/oracledb/_param_types.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_param_types.py +46 -0
- sqlspec/adapters/oracledb/_typing.py +258 -0
- sqlspec/adapters/oracledb/_uuid_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_uuid_handlers.py +163 -0
- sqlspec/adapters/oracledb/_vector_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_vector_handlers.py +228 -0
- sqlspec/adapters/oracledb/adk/__init__.py +21 -0
- sqlspec/adapters/oracledb/adk/store.py +2453 -0
- sqlspec/adapters/oracledb/config.py +575 -0
- sqlspec/adapters/oracledb/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/core.py +820 -0
- sqlspec/adapters/oracledb/data_dictionary.py +404 -0
- sqlspec/adapters/oracledb/driver.py +1277 -0
- sqlspec/adapters/oracledb/events/__init__.py +16 -0
- sqlspec/adapters/oracledb/events/_hub.py +345 -0
- sqlspec/adapters/oracledb/events/backend.py +300 -0
- sqlspec/adapters/oracledb/events/store.py +420 -0
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +781 -0
- sqlspec/adapters/oracledb/migrations.py +539 -0
- sqlspec/adapters/oracledb/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/type_converter.py +211 -0
- sqlspec/adapters/psqlpy/__init__.py +18 -0
- sqlspec/adapters/psqlpy/_typing.py +121 -0
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +591 -0
- sqlspec/adapters/psqlpy/config.py +376 -0
- sqlspec/adapters/psqlpy/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psqlpy/core.py +694 -0
- sqlspec/adapters/psqlpy/data_dictionary.py +121 -0
- sqlspec/adapters/psqlpy/driver.py +411 -0
- sqlspec/adapters/psqlpy/events/__init__.py +6 -0
- sqlspec/adapters/psqlpy/events/_hub.py +204 -0
- sqlspec/adapters/psqlpy/events/backend.py +210 -0
- sqlspec/adapters/psqlpy/events/store.py +20 -0
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +270 -0
- sqlspec/adapters/psqlpy/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psqlpy/type_converter.py +113 -0
- sqlspec/adapters/psycopg/__init__.py +38 -0
- sqlspec/adapters/psycopg/_typing.py +218 -0
- sqlspec/adapters/psycopg/adk/__init__.py +10 -0
- sqlspec/adapters/psycopg/adk/store.py +1106 -0
- sqlspec/adapters/psycopg/config.py +695 -0
- sqlspec/adapters/psycopg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psycopg/core.py +520 -0
- sqlspec/adapters/psycopg/data_dictionary.py +278 -0
- sqlspec/adapters/psycopg/driver.py +1033 -0
- sqlspec/adapters/psycopg/events/__init__.py +20 -0
- sqlspec/adapters/psycopg/events/_hub.py +388 -0
- sqlspec/adapters/psycopg/events/backend.py +398 -0
- sqlspec/adapters/psycopg/events/store.py +42 -0
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +554 -0
- sqlspec/adapters/psycopg/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psycopg/type_converter.py +93 -0
- sqlspec/adapters/pymysql/__init__.py +21 -0
- sqlspec/adapters/pymysql/_typing.py +92 -0
- sqlspec/adapters/pymysql/adk/__init__.py +5 -0
- sqlspec/adapters/pymysql/adk/store.py +657 -0
- sqlspec/adapters/pymysql/config.py +176 -0
- sqlspec/adapters/pymysql/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/pymysql/core.py +469 -0
- sqlspec/adapters/pymysql/data_dictionary.py +120 -0
- sqlspec/adapters/pymysql/driver.py +271 -0
- sqlspec/adapters/pymysql/events/__init__.py +5 -0
- sqlspec/adapters/pymysql/events/store.py +50 -0
- sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
- sqlspec/adapters/pymysql/litestar/store.py +232 -0
- sqlspec/adapters/pymysql/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/pymysql/pool.py +184 -0
- sqlspec/adapters/spanner/__init__.py +33 -0
- sqlspec/adapters/spanner/_typing.py +102 -0
- sqlspec/adapters/spanner/adk/__init__.py +5 -0
- sqlspec/adapters/spanner/adk/store.py +758 -0
- sqlspec/adapters/spanner/config.py +355 -0
- sqlspec/adapters/spanner/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/spanner/core.py +263 -0
- sqlspec/adapters/spanner/data_dictionary.py +120 -0
- sqlspec/adapters/spanner/driver.py +407 -0
- sqlspec/adapters/spanner/events/__init__.py +5 -0
- sqlspec/adapters/spanner/events/store.py +187 -0
- sqlspec/adapters/spanner/litestar/__init__.py +5 -0
- sqlspec/adapters/spanner/litestar/store.py +291 -0
- sqlspec/adapters/spanner/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/spanner/type_converter.py +342 -0
- sqlspec/adapters/sqlite/__init__.py +19 -0
- sqlspec/adapters/sqlite/_typing.py +123 -0
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +992 -0
- sqlspec/adapters/sqlite/config.py +240 -0
- sqlspec/adapters/sqlite/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/core.py +357 -0
- sqlspec/adapters/sqlite/data_dictionary.py +198 -0
- sqlspec/adapters/sqlite/driver.py +527 -0
- sqlspec/adapters/sqlite/events/__init__.py +5 -0
- sqlspec/adapters/sqlite/events/store.py +20 -0
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +316 -0
- sqlspec/adapters/sqlite/pool.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/pool.py +237 -0
- sqlspec/adapters/sqlite/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/type_converter.py +114 -0
- sqlspec/base.py +832 -0
- sqlspec/builder/__init__.py +181 -0
- sqlspec/builder/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_base.py +1071 -0
- sqlspec/builder/_column.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_column.py +521 -0
- sqlspec/builder/_ddl.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_ddl.py +1691 -0
- sqlspec/builder/_delete.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_delete.py +95 -0
- sqlspec/builder/_dml.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_dml.py +386 -0
- sqlspec/builder/_explain.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_explain.py +579 -0
- sqlspec/builder/_expression_wrappers.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_expression_wrappers.py +46 -0
- sqlspec/builder/_factory.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_factory.py +1884 -0
- sqlspec/builder/_insert.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_insert.py +405 -0
- sqlspec/builder/_join.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_join.py +489 -0
- sqlspec/builder/_merge.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_merge.py +823 -0
- sqlspec/builder/_parsing_utils.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_parsing_utils.py +295 -0
- sqlspec/builder/_select.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_select.py +1666 -0
- sqlspec/builder/_temporal.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_temporal.py +167 -0
- sqlspec/builder/_update.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_update.py +173 -0
- sqlspec/builder/_vector_distance.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_vector_distance.py +330 -0
- sqlspec/cli.py +1095 -0
- sqlspec/config.py +2383 -0
- sqlspec/core/__init__.py +372 -0
- sqlspec/core/_correlation.cp314-win_amd64.pyd +0 -0
- sqlspec/core/_correlation.py +176 -0
- sqlspec/core/_pagination.py +42 -0
- sqlspec/core/_pool.cp314-win_amd64.pyd +0 -0
- sqlspec/core/_pool.py +76 -0
- sqlspec/core/cache.cp314-win_amd64.pyd +0 -0
- sqlspec/core/cache.py +1085 -0
- sqlspec/core/compiler.cp314-win_amd64.pyd +0 -0
- sqlspec/core/compiler.py +1090 -0
- sqlspec/core/config_runtime.cp314-win_amd64.pyd +0 -0
- sqlspec/core/config_runtime.py +174 -0
- sqlspec/core/explain.cp314-win_amd64.pyd +0 -0
- sqlspec/core/explain.py +275 -0
- sqlspec/core/filters.cp314-win_amd64.pyd +0 -0
- sqlspec/core/filters.py +969 -0
- sqlspec/core/hashing.cp314-win_amd64.pyd +0 -0
- sqlspec/core/hashing.py +266 -0
- sqlspec/core/metrics.cp314-win_amd64.pyd +0 -0
- sqlspec/core/metrics.py +83 -0
- sqlspec/core/parameters/__init__.py +72 -0
- sqlspec/core/parameters/_alignment.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_alignment.py +283 -0
- sqlspec/core/parameters/_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_converter.py +554 -0
- sqlspec/core/parameters/_processor.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_processor.py +1182 -0
- sqlspec/core/parameters/_registry.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_registry.py +206 -0
- sqlspec/core/parameters/_transformers.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_transformers.py +324 -0
- sqlspec/core/parameters/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_types.py +536 -0
- sqlspec/core/parameters/_validator.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_validator.py +171 -0
- sqlspec/core/pipeline.cp314-win_amd64.pyd +0 -0
- sqlspec/core/pipeline.py +333 -0
- sqlspec/core/query_modifiers.cp314-win_amd64.pyd +0 -0
- sqlspec/core/query_modifiers.py +508 -0
- sqlspec/core/result/__init__.py +25 -0
- sqlspec/core/result/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/core/result/_base.py +1232 -0
- sqlspec/core/result/_io.cp314-win_amd64.pyd +0 -0
- sqlspec/core/result/_io.py +28 -0
- sqlspec/core/splitter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/splitter.py +1021 -0
- sqlspec/core/sqlcommenter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/sqlcommenter.py +249 -0
- sqlspec/core/stack.cp314-win_amd64.pyd +0 -0
- sqlspec/core/stack.py +163 -0
- sqlspec/core/statement.cp314-win_amd64.pyd +0 -0
- sqlspec/core/statement.py +1865 -0
- sqlspec/core/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/type_converter.py +340 -0
- sqlspec/data_dictionary/__init__.py +22 -0
- sqlspec/data_dictionary/_loader.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_loader.py +138 -0
- sqlspec/data_dictionary/_registry.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_registry.py +74 -0
- sqlspec/data_dictionary/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_types.py +121 -0
- sqlspec/data_dictionary/dialects/__init__.py +21 -0
- sqlspec/data_dictionary/dialects/bigquery.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/bigquery.py +81 -0
- sqlspec/data_dictionary/dialects/cockroachdb.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/cockroachdb.py +54 -0
- sqlspec/data_dictionary/dialects/duckdb.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/duckdb.py +47 -0
- sqlspec/data_dictionary/dialects/mysql.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/mysql.py +53 -0
- sqlspec/data_dictionary/dialects/oracle.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/oracle.py +197 -0
- sqlspec/data_dictionary/dialects/postgres.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/postgres.py +69 -0
- sqlspec/data_dictionary/dialects/spanner.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/spanner.py +37 -0
- sqlspec/data_dictionary/dialects/sqlite.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/sqlite.py +59 -0
- sqlspec/data_dictionary/sql/.gitkeep +0 -0
- sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
- sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
- sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
- sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
- sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
- sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
- sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
- sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
- sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
- sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
- sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
- sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
- sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
- sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
- sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
- sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
- sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
- sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
- sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
- sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
- sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
- sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
- sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
- sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
- sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
- sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
- sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
- sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
- sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
- sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
- sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
- sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
- sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
- sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
- sqlspec/dialects/__init__.py +22 -0
- sqlspec/dialects/_compat.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/_compat.py +14 -0
- sqlspec/dialects/postgres/__init__.py +9 -0
- sqlspec/dialects/postgres/_generators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/postgres/_generators.py +57 -0
- sqlspec/dialects/postgres/_operators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/postgres/_operators.py +81 -0
- sqlspec/dialects/postgres/_paradedb.py +50 -0
- sqlspec/dialects/postgres/_pgvector.py +36 -0
- sqlspec/dialects/spanner/__init__.py +6 -0
- sqlspec/dialects/spanner/_generators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/spanner/_generators.py +206 -0
- sqlspec/dialects/spanner/_spangres.py +77 -0
- sqlspec/dialects/spanner/_spanner.py +179 -0
- sqlspec/driver/__init__.py +49 -0
- sqlspec/driver/_async.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_async.py +1830 -0
- sqlspec/driver/_common.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_common.py +2292 -0
- sqlspec/driver/_exception_handler.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_exception_handler.py +108 -0
- sqlspec/driver/_query_cache.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_query_cache.py +96 -0
- sqlspec/driver/_sql_helpers.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_sql_helpers.py +139 -0
- sqlspec/driver/_storage_helpers.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_storage_helpers.py +153 -0
- sqlspec/driver/_sync.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_sync.py +1817 -0
- sqlspec/exceptions.cp314-win_amd64.pyd +0 -0
- sqlspec/exceptions.py +480 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/adk/__init__.py +84 -0
- sqlspec/extensions/adk/_config_utils.py +199 -0
- sqlspec/extensions/adk/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/_types.py +41 -0
- sqlspec/extensions/adk/artifact/__init__.py +57 -0
- sqlspec/extensions/adk/artifact/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/artifact/_types.py +32 -0
- sqlspec/extensions/adk/artifact/service.py +508 -0
- sqlspec/extensions/adk/artifact/store.py +361 -0
- sqlspec/extensions/adk/converters.py +212 -0
- sqlspec/extensions/adk/memory/__init__.py +69 -0
- sqlspec/extensions/adk/memory/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/memory/_types.py +30 -0
- sqlspec/extensions/adk/memory/converters.py +225 -0
- sqlspec/extensions/adk/memory/service.py +316 -0
- sqlspec/extensions/adk/memory/store.py +525 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +184 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +279 -0
- sqlspec/extensions/adk/store.py +590 -0
- sqlspec/extensions/events/__init__.py +51 -0
- sqlspec/extensions/events/_channel.py +703 -0
- sqlspec/extensions/events/_hints.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/events/_hints.py +45 -0
- sqlspec/extensions/events/_models.py +23 -0
- sqlspec/extensions/events/_payload.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/events/_payload.py +69 -0
- sqlspec/extensions/events/_protocols.py +134 -0
- sqlspec/extensions/events/_queue.py +462 -0
- sqlspec/extensions/events/_store.py +209 -0
- sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
- sqlspec/extensions/events/migrations/__init__.py +3 -0
- sqlspec/extensions/fastapi/__init__.py +22 -0
- sqlspec/extensions/fastapi/extension.py +391 -0
- sqlspec/extensions/fastapi/providers.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/fastapi/providers.py +712 -0
- sqlspec/extensions/flask/__init__.py +38 -0
- sqlspec/extensions/flask/_state.py +87 -0
- sqlspec/extensions/flask/_utils.py +71 -0
- sqlspec/extensions/flask/extension.py +539 -0
- sqlspec/extensions/litestar/__init__.py +31 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/channels.py +165 -0
- sqlspec/extensions/litestar/cli.py +102 -0
- sqlspec/extensions/litestar/config.py +90 -0
- sqlspec/extensions/litestar/handlers.py +316 -0
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +1066 -0
- sqlspec/extensions/litestar/providers.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/litestar/providers.py +784 -0
- sqlspec/extensions/litestar/store.py +298 -0
- sqlspec/extensions/otel/__init__.py +58 -0
- sqlspec/extensions/prometheus/__init__.py +113 -0
- sqlspec/extensions/sanic/__init__.py +19 -0
- sqlspec/extensions/sanic/_state.py +43 -0
- sqlspec/extensions/sanic/_utils.py +127 -0
- sqlspec/extensions/sanic/extension.py +647 -0
- sqlspec/extensions/starlette/__init__.py +22 -0
- sqlspec/extensions/starlette/_state.py +42 -0
- sqlspec/extensions/starlette/_utils.py +96 -0
- sqlspec/extensions/starlette/extension.py +374 -0
- sqlspec/extensions/starlette/middleware.py +281 -0
- sqlspec/loader.cp314-win_amd64.pyd +0 -0
- sqlspec/loader.py +727 -0
- sqlspec/migrations/__init__.py +39 -0
- sqlspec/migrations/base.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/base.py +862 -0
- sqlspec/migrations/commands.py +2151 -0
- sqlspec/migrations/context.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/context.py +157 -0
- sqlspec/migrations/fix.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/fix.py +204 -0
- sqlspec/migrations/loaders.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/loaders.py +443 -0
- sqlspec/migrations/runner.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/runner.py +1195 -0
- sqlspec/migrations/squash.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/squash.py +490 -0
- sqlspec/migrations/templates.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/templates.py +234 -0
- sqlspec/migrations/tracker.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/tracker.py +792 -0
- sqlspec/migrations/utils.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/utils.py +256 -0
- sqlspec/migrations/validation.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/validation.py +359 -0
- sqlspec/migrations/version.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/version.py +446 -0
- sqlspec/observability/__init__.py +57 -0
- sqlspec/observability/_common.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_common.py +77 -0
- sqlspec/observability/_config.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_config.py +364 -0
- sqlspec/observability/_diagnostics.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_diagnostics.py +74 -0
- sqlspec/observability/_dispatcher.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_dispatcher.py +200 -0
- sqlspec/observability/_formatters/__init__.py +13 -0
- sqlspec/observability/_formatters/_aws.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_aws.py +102 -0
- sqlspec/observability/_formatters/_azure.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_azure.py +96 -0
- sqlspec/observability/_formatters/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_base.py +57 -0
- sqlspec/observability/_formatters/_gcp.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_gcp.py +131 -0
- sqlspec/observability/_formatting.py +58 -0
- sqlspec/observability/_observer.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_observer.py +361 -0
- sqlspec/observability/_runtime.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_runtime.py +461 -0
- sqlspec/observability/_sampling.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_sampling.py +188 -0
- sqlspec/observability/_spans.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_spans.py +161 -0
- sqlspec/protocols.py +955 -0
- sqlspec/py.typed +0 -0
- sqlspec/service.py +433 -0
- sqlspec/storage/__init__.py +48 -0
- sqlspec/storage/_arrow_payload.py +68 -0
- sqlspec/storage/_paths.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/_paths.py +58 -0
- sqlspec/storage/_utils.py +46 -0
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/base.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/backends/base.py +374 -0
- sqlspec/storage/backends/fsspec.py +574 -0
- sqlspec/storage/backends/local.py +468 -0
- sqlspec/storage/backends/obstore.py +956 -0
- sqlspec/storage/errors.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/errors.py +102 -0
- sqlspec/storage/pipeline.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/pipeline.py +628 -0
- sqlspec/storage/registry.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/registry.py +329 -0
- sqlspec/typing.py +405 -0
- sqlspec/utils/__init__.py +7 -0
- sqlspec/utils/arrow_helpers.py +384 -0
- sqlspec/utils/config_tools.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/config_tools.py +314 -0
- sqlspec/utils/correlation.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/correlation.py +134 -0
- sqlspec/utils/deprecation.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/deprecation.py +157 -0
- sqlspec/utils/dispatch.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/dispatch.py +101 -0
- sqlspec/utils/fixtures.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/fixtures.py +260 -0
- sqlspec/utils/logging.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/logging.py +251 -0
- sqlspec/utils/module_loader.py +306 -0
- sqlspec/utils/portal.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/portal.py +377 -0
- sqlspec/utils/schema.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/schema.py +1040 -0
- sqlspec/utils/serializers/__init__.py +30 -0
- sqlspec/utils/serializers/_json.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_json.py +415 -0
- sqlspec/utils/serializers/_numpy.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_numpy.py +65 -0
- sqlspec/utils/serializers/_schema.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_schema.py +285 -0
- sqlspec/utils/singleton.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/singleton.py +41 -0
- sqlspec/utils/sync_tools.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/sync_tools.py +316 -0
- sqlspec/utils/text.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/text.py +109 -0
- sqlspec/utils/type_converters.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/type_converters.py +216 -0
- sqlspec/utils/type_guards.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/type_guards.py +1508 -0
- sqlspec/utils/uuids.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/uuids.py +241 -0
- sqlspec-0.47.0.dist-info/METADATA +202 -0
- sqlspec-0.47.0.dist-info/RECORD +621 -0
- sqlspec-0.47.0.dist-info/WHEEL +4 -0
- sqlspec-0.47.0.dist-info/entry_points.txt +6 -0
- sqlspec-0.47.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""MySQL-specific data dictionary for metadata queries via PyMySQL."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
4
|
+
|
|
5
|
+
from mypy_extensions import mypyc_attr
|
|
6
|
+
|
|
7
|
+
from sqlspec.data_dictionary.dialects.mysql import resolve_mysql_json_type
|
|
8
|
+
from sqlspec.driver import SyncDataDictionaryBase
|
|
9
|
+
from sqlspec.typing import ColumnMetadata, ForeignKeyMetadata, IndexMetadata, TableMetadata, VersionInfo
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from sqlspec.adapters.pymysql.driver import PyMysqlDriver
|
|
13
|
+
|
|
14
|
+
__all__ = ("PyMysqlDataDictionary",)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@mypyc_attr(allow_interpreted_subclasses=True, native_class=False)
|
|
18
|
+
class PyMysqlDataDictionary(SyncDataDictionaryBase):
|
|
19
|
+
"""MySQL-specific sync data dictionary."""
|
|
20
|
+
|
|
21
|
+
dialect: ClassVar[str] = "mysql"
|
|
22
|
+
|
|
23
|
+
def __init__(self) -> None:
|
|
24
|
+
super().__init__()
|
|
25
|
+
|
|
26
|
+
def get_version(self, driver: "PyMysqlDriver") -> "VersionInfo | None":
|
|
27
|
+
"""Get MySQL database version information."""
|
|
28
|
+
driver_id = id(driver)
|
|
29
|
+
# Inline cache check to avoid cross-module method call that causes mypyc segfault
|
|
30
|
+
if driver_id in self._version_fetch_attempted:
|
|
31
|
+
return self._version_cache.get(driver_id)
|
|
32
|
+
# Not cached, fetch from database
|
|
33
|
+
|
|
34
|
+
version_value = driver.select_value_or_none(self.get_query("version"))
|
|
35
|
+
if not version_value:
|
|
36
|
+
self._log_version_unavailable(type(self).dialect, "missing")
|
|
37
|
+
self.cache_version(driver_id, None)
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
version_info = self.parse_version_with_pattern(self.get_dialect_config().version_pattern, str(version_value))
|
|
41
|
+
if version_info is None:
|
|
42
|
+
self._log_version_unavailable(type(self).dialect, "parse_failed")
|
|
43
|
+
self.cache_version(driver_id, None)
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
self._log_version_detected(type(self).dialect, version_info)
|
|
47
|
+
self.cache_version(driver_id, version_info)
|
|
48
|
+
return version_info
|
|
49
|
+
|
|
50
|
+
def get_feature_flag(self, driver: "PyMysqlDriver", feature: str) -> bool:
|
|
51
|
+
"""Check if MySQL database supports a specific feature."""
|
|
52
|
+
version_info = self.get_version(driver)
|
|
53
|
+
return self.resolve_feature_flag(feature, version_info)
|
|
54
|
+
|
|
55
|
+
def get_optimal_type(self, driver: "PyMysqlDriver", type_category: str) -> str:
|
|
56
|
+
"""Get optimal MySQL type for a category."""
|
|
57
|
+
config = self.get_dialect_config()
|
|
58
|
+
version_info = self.get_version(driver)
|
|
59
|
+
|
|
60
|
+
if type_category == "json":
|
|
61
|
+
return resolve_mysql_json_type(version_info)
|
|
62
|
+
|
|
63
|
+
return config.get_optimal_type(type_category)
|
|
64
|
+
|
|
65
|
+
def get_tables(self, driver: "PyMysqlDriver", schema: "str | None" = None) -> "list[TableMetadata]":
|
|
66
|
+
"""Get tables sorted by topological dependency order using the MySQL catalog."""
|
|
67
|
+
schema_name = self.resolve_schema(schema)
|
|
68
|
+
self._log_schema_introspect(driver, schema_name=schema_name, table_name=None, operation="tables")
|
|
69
|
+
return driver.select(self.get_query("tables_by_schema"), schema_name=schema_name, schema_type=TableMetadata)
|
|
70
|
+
|
|
71
|
+
def get_columns(
|
|
72
|
+
self, driver: "PyMysqlDriver", table: "str | None" = None, schema: "str | None" = None
|
|
73
|
+
) -> "list[ColumnMetadata]":
|
|
74
|
+
"""Get column information for a table or schema."""
|
|
75
|
+
schema_name = self.resolve_schema(schema)
|
|
76
|
+
if table is None:
|
|
77
|
+
self._log_schema_introspect(driver, schema_name=schema_name, table_name=None, operation="columns")
|
|
78
|
+
return driver.select(
|
|
79
|
+
self.get_query("columns_by_schema"), schema_name=schema_name, schema_type=ColumnMetadata
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
self._log_table_describe(driver, schema_name=schema_name, table_name=table, operation="columns")
|
|
83
|
+
return driver.select(
|
|
84
|
+
self.get_query("columns_by_table"), table_name=table, schema_name=schema_name, schema_type=ColumnMetadata
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def get_indexes(
|
|
88
|
+
self, driver: "PyMysqlDriver", table: "str | None" = None, schema: "str | None" = None
|
|
89
|
+
) -> "list[IndexMetadata]":
|
|
90
|
+
"""Get index metadata for a table or schema."""
|
|
91
|
+
schema_name = self.resolve_schema(schema)
|
|
92
|
+
if table is None:
|
|
93
|
+
self._log_schema_introspect(driver, schema_name=schema_name, table_name=None, operation="indexes")
|
|
94
|
+
return driver.select(
|
|
95
|
+
self.get_query("indexes_by_schema"), schema_name=schema_name, schema_type=IndexMetadata
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
self._log_table_describe(driver, schema_name=schema_name, table_name=table, operation="indexes")
|
|
99
|
+
return driver.select(
|
|
100
|
+
self.get_query("indexes_by_table"), table_name=table, schema_name=schema_name, schema_type=IndexMetadata
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def get_foreign_keys(
|
|
104
|
+
self, driver: "PyMysqlDriver", table: "str | None" = None, schema: "str | None" = None
|
|
105
|
+
) -> "list[ForeignKeyMetadata]":
|
|
106
|
+
"""Get foreign key metadata."""
|
|
107
|
+
schema_name = self.resolve_schema(schema)
|
|
108
|
+
if table is None:
|
|
109
|
+
self._log_schema_introspect(driver, schema_name=schema_name, table_name=None, operation="foreign_keys")
|
|
110
|
+
return driver.select(
|
|
111
|
+
self.get_query("foreign_keys_by_schema"), schema_name=schema_name, schema_type=ForeignKeyMetadata
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
self._log_table_describe(driver, schema_name=schema_name, table_name=table, operation="foreign_keys")
|
|
115
|
+
return driver.select(
|
|
116
|
+
self.get_query("foreign_keys_by_table"),
|
|
117
|
+
table_name=table,
|
|
118
|
+
schema_name=schema_name,
|
|
119
|
+
schema_type=ForeignKeyMetadata,
|
|
120
|
+
)
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"""PyMySQL MySQL driver implementation."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sized
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Final, cast
|
|
5
|
+
|
|
6
|
+
import pymysql
|
|
7
|
+
from pymysql.constants import FIELD_TYPE
|
|
8
|
+
|
|
9
|
+
from sqlspec.adapters.pymysql._typing import PyMysqlCursor, PyMysqlSessionContext
|
|
10
|
+
from sqlspec.adapters.pymysql.core import (
|
|
11
|
+
build_insert_statement,
|
|
12
|
+
collect_rows,
|
|
13
|
+
create_mapped_exception,
|
|
14
|
+
default_statement_config,
|
|
15
|
+
detect_json_columns_from_description,
|
|
16
|
+
driver_profile,
|
|
17
|
+
format_identifier,
|
|
18
|
+
normalize_execute_many_parameters,
|
|
19
|
+
normalize_execute_parameters,
|
|
20
|
+
normalize_lastrowid,
|
|
21
|
+
resolve_column_names,
|
|
22
|
+
resolve_many_rowcount,
|
|
23
|
+
resolve_rowcount,
|
|
24
|
+
)
|
|
25
|
+
from sqlspec.adapters.pymysql.data_dictionary import PyMysqlDataDictionary
|
|
26
|
+
from sqlspec.core import ArrowResult, get_cache_config, register_driver_profile
|
|
27
|
+
from sqlspec.driver import BaseSyncExceptionHandler, SyncDriverAdapterBase
|
|
28
|
+
from sqlspec.exceptions import SQLSpecError
|
|
29
|
+
from sqlspec.utils.logging import get_logger
|
|
30
|
+
from sqlspec.utils.serializers import from_json
|
|
31
|
+
from sqlspec.utils.type_guards import supports_json_type
|
|
32
|
+
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from collections.abc import Callable
|
|
35
|
+
|
|
36
|
+
from sqlspec.adapters.pymysql._typing import PyMysqlConnection
|
|
37
|
+
from sqlspec.core import SQL, StatementConfig
|
|
38
|
+
from sqlspec.driver import ExecutionResult
|
|
39
|
+
from sqlspec.storage import StorageBridgeJob, StorageDestination, StorageFormat, StorageTelemetry
|
|
40
|
+
|
|
41
|
+
__all__ = ("PyMysqlCursor", "PyMysqlDriver", "PyMysqlExceptionHandler", "PyMysqlSessionContext")
|
|
42
|
+
|
|
43
|
+
logger = get_logger("sqlspec.adapters.pymysql")
|
|
44
|
+
|
|
45
|
+
json_type_value = FIELD_TYPE.JSON if supports_json_type(FIELD_TYPE) else None
|
|
46
|
+
PYMYSQL_JSON_TYPE_CODES: Final[set[int]] = {json_type_value} if json_type_value is not None else set()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class PyMysqlExceptionHandler(BaseSyncExceptionHandler):
|
|
50
|
+
"""Context manager for handling PyMySQL exceptions."""
|
|
51
|
+
|
|
52
|
+
__slots__ = ()
|
|
53
|
+
|
|
54
|
+
def _handle_exception(self, exc_type: "type[BaseException] | None", exc_val: "BaseException") -> bool:
|
|
55
|
+
if exc_type is None:
|
|
56
|
+
return False
|
|
57
|
+
if issubclass(exc_type, pymysql.MySQLError):
|
|
58
|
+
result = create_mapped_exception(exc_val, logger=logger)
|
|
59
|
+
if result is True:
|
|
60
|
+
return True
|
|
61
|
+
self.pending_exception = cast("Exception", result)
|
|
62
|
+
return True
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class PyMysqlDriver(SyncDriverAdapterBase):
|
|
67
|
+
"""MySQL/MariaDB database driver using PyMySQL."""
|
|
68
|
+
|
|
69
|
+
__slots__ = ("_data_dictionary",)
|
|
70
|
+
dialect = "mysql"
|
|
71
|
+
|
|
72
|
+
def __init__(
|
|
73
|
+
self,
|
|
74
|
+
connection: "PyMysqlConnection",
|
|
75
|
+
statement_config: "StatementConfig | None" = None,
|
|
76
|
+
driver_features: "dict[str, Any] | None" = None,
|
|
77
|
+
) -> None:
|
|
78
|
+
if statement_config is None:
|
|
79
|
+
statement_config = default_statement_config.replace(
|
|
80
|
+
enable_caching=get_cache_config().compiled_cache_enabled
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
|
|
84
|
+
self._data_dictionary: PyMysqlDataDictionary | None = None
|
|
85
|
+
|
|
86
|
+
def dispatch_execute(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
|
|
87
|
+
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
88
|
+
cursor.execute(sql, normalize_execute_parameters(prepared_parameters))
|
|
89
|
+
|
|
90
|
+
if statement.returns_rows():
|
|
91
|
+
fetched_data = cursor.fetchall()
|
|
92
|
+
description = cursor.description or None
|
|
93
|
+
column_names = resolve_column_names(description)
|
|
94
|
+
json_indexes = detect_json_columns_from_description(description, PYMYSQL_JSON_TYPE_CODES)
|
|
95
|
+
deserializer = cast("Callable[[Any], Any]", self.driver_features.get("json_deserializer", from_json))
|
|
96
|
+
rows, column_names, row_format = collect_rows(
|
|
97
|
+
fetched_data, description, json_indexes, deserializer, column_names=column_names, logger=logger
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return self.create_execution_result(
|
|
101
|
+
cursor,
|
|
102
|
+
selected_data=rows,
|
|
103
|
+
column_names=column_names,
|
|
104
|
+
data_row_count=len(rows),
|
|
105
|
+
is_select_result=True,
|
|
106
|
+
row_format=row_format,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
affected_rows = resolve_rowcount(cursor)
|
|
110
|
+
last_id = normalize_lastrowid(cursor)
|
|
111
|
+
return self.create_execution_result(cursor, rowcount_override=affected_rows, last_inserted_id=last_id)
|
|
112
|
+
|
|
113
|
+
def dispatch_execute_many(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
|
|
114
|
+
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
115
|
+
|
|
116
|
+
prepared_parameters = normalize_execute_many_parameters(prepared_parameters)
|
|
117
|
+
parameter_count = len(prepared_parameters) if isinstance(prepared_parameters, Sized) else None
|
|
118
|
+
cursor.executemany(sql, prepared_parameters)
|
|
119
|
+
|
|
120
|
+
affected_rows = resolve_many_rowcount(cursor, prepared_parameters, fallback_count=parameter_count)
|
|
121
|
+
return self.create_execution_result(cursor, rowcount_override=affected_rows, is_many_result=True)
|
|
122
|
+
|
|
123
|
+
def dispatch_execute_script(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
|
|
124
|
+
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
125
|
+
statements = self.split_script_statements(sql, statement.statement_config, strip_trailing_semicolon=True)
|
|
126
|
+
|
|
127
|
+
successful_count = 0
|
|
128
|
+
last_cursor = cursor
|
|
129
|
+
|
|
130
|
+
for stmt in statements:
|
|
131
|
+
cursor.execute(stmt, normalize_execute_parameters(prepared_parameters))
|
|
132
|
+
successful_count += 1
|
|
133
|
+
|
|
134
|
+
return self.create_execution_result(
|
|
135
|
+
last_cursor, statement_count=len(statements), successful_statements=successful_count, is_script_result=True
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def begin(self) -> None:
|
|
139
|
+
try:
|
|
140
|
+
with PyMysqlCursor(self.connection) as cursor:
|
|
141
|
+
cursor.execute("BEGIN")
|
|
142
|
+
except pymysql.MySQLError as exc:
|
|
143
|
+
msg = f"Failed to begin MySQL transaction: {exc}"
|
|
144
|
+
raise SQLSpecError(msg) from exc
|
|
145
|
+
|
|
146
|
+
def commit(self) -> None:
|
|
147
|
+
try:
|
|
148
|
+
self.connection.commit()
|
|
149
|
+
except pymysql.MySQLError as exc:
|
|
150
|
+
msg = f"Failed to commit MySQL transaction: {exc}"
|
|
151
|
+
raise SQLSpecError(msg) from exc
|
|
152
|
+
|
|
153
|
+
def rollback(self) -> None:
|
|
154
|
+
try:
|
|
155
|
+
self.connection.rollback()
|
|
156
|
+
except pymysql.MySQLError as exc:
|
|
157
|
+
msg = f"Failed to rollback MySQL transaction: {exc}"
|
|
158
|
+
raise SQLSpecError(msg) from exc
|
|
159
|
+
|
|
160
|
+
def with_cursor(self, connection: "PyMysqlConnection") -> "PyMysqlCursor":
|
|
161
|
+
return PyMysqlCursor(connection)
|
|
162
|
+
|
|
163
|
+
def handle_database_exceptions(self) -> "PyMysqlExceptionHandler":
|
|
164
|
+
return PyMysqlExceptionHandler()
|
|
165
|
+
|
|
166
|
+
def select_to_storage(
|
|
167
|
+
self,
|
|
168
|
+
statement: "SQL | str",
|
|
169
|
+
destination: "StorageDestination",
|
|
170
|
+
/,
|
|
171
|
+
*parameters: Any,
|
|
172
|
+
statement_config: "StatementConfig | None" = None,
|
|
173
|
+
partitioner: "dict[str, object] | None" = None,
|
|
174
|
+
format_hint: "StorageFormat | None" = None,
|
|
175
|
+
telemetry: "StorageTelemetry | None" = None,
|
|
176
|
+
**kwargs: Any,
|
|
177
|
+
) -> "StorageBridgeJob":
|
|
178
|
+
self._require_capability("arrow_export_enabled")
|
|
179
|
+
arrow_result = self.select_to_arrow(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
180
|
+
pipeline = self._storage_pipeline()
|
|
181
|
+
telemetry_payload = self._write_result_to_storage_sync(
|
|
182
|
+
arrow_result, destination, format_hint=format_hint, pipeline=pipeline
|
|
183
|
+
)
|
|
184
|
+
self._attach_partition_telemetry(telemetry_payload, partitioner)
|
|
185
|
+
return self._create_storage_job(telemetry_payload, telemetry)
|
|
186
|
+
|
|
187
|
+
def load_from_arrow(
|
|
188
|
+
self,
|
|
189
|
+
table: str,
|
|
190
|
+
source: "ArrowResult | Any",
|
|
191
|
+
*,
|
|
192
|
+
partitioner: "dict[str, object] | None" = None,
|
|
193
|
+
overwrite: bool = False,
|
|
194
|
+
telemetry: "StorageTelemetry | None" = None,
|
|
195
|
+
) -> "StorageBridgeJob":
|
|
196
|
+
self._require_capability("arrow_import_enabled")
|
|
197
|
+
arrow_table = self._coerce_arrow_table(source)
|
|
198
|
+
if overwrite:
|
|
199
|
+
statement = f"TRUNCATE TABLE {format_identifier(table)}"
|
|
200
|
+
exc_handler = self.handle_database_exceptions()
|
|
201
|
+
with exc_handler, self.with_cursor(self.connection) as cursor:
|
|
202
|
+
cursor.execute(statement)
|
|
203
|
+
if exc_handler.pending_exception is not None:
|
|
204
|
+
raise exc_handler.pending_exception from None
|
|
205
|
+
|
|
206
|
+
columns, records = self._arrow_table_to_rows(arrow_table)
|
|
207
|
+
if records:
|
|
208
|
+
insert_sql = build_insert_statement(table, columns)
|
|
209
|
+
prepared_records = (
|
|
210
|
+
self.prepare_driver_parameters(records, self.statement_config, is_many=True)
|
|
211
|
+
if self._arrow_table_needs_parameter_preparation(arrow_table)
|
|
212
|
+
else records
|
|
213
|
+
)
|
|
214
|
+
exc_handler = self.handle_database_exceptions()
|
|
215
|
+
with exc_handler, self.with_cursor(self.connection) as cursor:
|
|
216
|
+
cursor.executemany(insert_sql, cast("Any", prepared_records))
|
|
217
|
+
if exc_handler.pending_exception is not None:
|
|
218
|
+
raise exc_handler.pending_exception from None
|
|
219
|
+
|
|
220
|
+
telemetry_payload = self._build_ingest_telemetry(arrow_table)
|
|
221
|
+
telemetry_payload["destination"] = table
|
|
222
|
+
self._attach_partition_telemetry(telemetry_payload, partitioner)
|
|
223
|
+
return self._create_storage_job(telemetry_payload, telemetry)
|
|
224
|
+
|
|
225
|
+
def load_from_storage(
|
|
226
|
+
self,
|
|
227
|
+
table: str,
|
|
228
|
+
source: "StorageDestination",
|
|
229
|
+
*,
|
|
230
|
+
file_format: "StorageFormat",
|
|
231
|
+
partitioner: "dict[str, object] | None" = None,
|
|
232
|
+
overwrite: bool = False,
|
|
233
|
+
) -> "StorageBridgeJob":
|
|
234
|
+
arrow_table, inbound = self._read_arrow_from_storage_sync(source, file_format=file_format)
|
|
235
|
+
return self.load_from_arrow(table, arrow_table, partitioner=partitioner, overwrite=overwrite, telemetry=inbound)
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def data_dictionary(self) -> "PyMysqlDataDictionary":
|
|
239
|
+
if self._data_dictionary is None:
|
|
240
|
+
self._data_dictionary = PyMysqlDataDictionary()
|
|
241
|
+
return self._data_dictionary
|
|
242
|
+
|
|
243
|
+
def collect_rows(self, cursor: Any, fetched: "list[Any]") -> "tuple[list[Any], list[str], int]":
|
|
244
|
+
"""Collect PyMySQL rows for the direct execution path."""
|
|
245
|
+
description = cursor.description or None
|
|
246
|
+
column_names = resolve_column_names(description)
|
|
247
|
+
json_indexes = detect_json_columns_from_description(description, PYMYSQL_JSON_TYPE_CODES)
|
|
248
|
+
deserializer = cast("Callable[[Any], Any]", self.driver_features.get("json_deserializer", from_json))
|
|
249
|
+
rows, column_names, _row_format = collect_rows(
|
|
250
|
+
fetched, description, json_indexes, deserializer, column_names=column_names, logger=logger
|
|
251
|
+
)
|
|
252
|
+
return rows, column_names, len(rows)
|
|
253
|
+
|
|
254
|
+
def resolve_rowcount(self, cursor: Any) -> int:
|
|
255
|
+
"""Resolve rowcount from PyMySQL cursor for the direct execution path."""
|
|
256
|
+
return resolve_rowcount(cursor)
|
|
257
|
+
|
|
258
|
+
def _connection_in_transaction(self) -> bool:
|
|
259
|
+
get_autocommit = getattr(self.connection, "get_autocommit", None)
|
|
260
|
+
if callable(get_autocommit):
|
|
261
|
+
return not bool(get_autocommit())
|
|
262
|
+
autocommit = getattr(self.connection, "autocommit", None)
|
|
263
|
+
if autocommit is not None:
|
|
264
|
+
try:
|
|
265
|
+
return not bool(autocommit)
|
|
266
|
+
except Exception:
|
|
267
|
+
return False
|
|
268
|
+
return False
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
register_driver_profile("pymysql", driver_profile)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""PyMySQL event queue store with MySQL-specific DDL."""
|
|
2
|
+
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
from sqlspec.adapters.pymysql.config import PyMysqlConfig
|
|
6
|
+
from sqlspec.extensions.events import BaseEventQueueStore
|
|
7
|
+
|
|
8
|
+
__all__ = ("PyMysqlEventQueueStore",)
|
|
9
|
+
|
|
10
|
+
SCHEMA_QUALIFIED_SEGMENTS: Final[int] = 2
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PyMysqlEventQueueStore(BaseEventQueueStore[PyMysqlConfig]):
|
|
14
|
+
"""Queue DDL for PyMySQL configs."""
|
|
15
|
+
|
|
16
|
+
__slots__ = ()
|
|
17
|
+
|
|
18
|
+
def _column_types(self) -> "tuple[str, str, str]":
|
|
19
|
+
return "JSON", "JSON", "DATETIME(6)"
|
|
20
|
+
|
|
21
|
+
def _timestamp_default(self) -> str:
|
|
22
|
+
return "CURRENT_TIMESTAMP(6)"
|
|
23
|
+
|
|
24
|
+
def _build_index_sql(self) -> str | None:
|
|
25
|
+
table_name = self.table_name
|
|
26
|
+
segments = table_name.split(".", 1)
|
|
27
|
+
|
|
28
|
+
if len(segments) == SCHEMA_QUALIFIED_SEGMENTS:
|
|
29
|
+
schema = segments[0]
|
|
30
|
+
table = segments[1]
|
|
31
|
+
schema_selector = f"'{schema}'"
|
|
32
|
+
else:
|
|
33
|
+
table = segments[0]
|
|
34
|
+
schema_selector = "DATABASE()"
|
|
35
|
+
|
|
36
|
+
index_name = self._index_name()
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
"SET @sqlspec_events_idx_exists := ("
|
|
40
|
+
"SELECT COUNT(1) FROM information_schema.statistics "
|
|
41
|
+
f"WHERE table_schema = {schema_selector} "
|
|
42
|
+
f"AND table_name = '{table}' "
|
|
43
|
+
f"AND index_name = '{index_name}');"
|
|
44
|
+
"SET @sqlspec_events_idx_stmt := IF(@sqlspec_events_idx_exists = 0, "
|
|
45
|
+
f"'ALTER TABLE {table_name} ADD INDEX {index_name} (channel, status, available_at)', "
|
|
46
|
+
"'SELECT 1');"
|
|
47
|
+
"PREPARE sqlspec_events_stmt FROM @sqlspec_events_idx_stmt;"
|
|
48
|
+
"EXECUTE sqlspec_events_stmt;"
|
|
49
|
+
"DEALLOCATE PREPARE sqlspec_events_stmt;"
|
|
50
|
+
)
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""PyMySQL session store for Litestar integration."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from typing import TYPE_CHECKING, Final
|
|
5
|
+
|
|
6
|
+
import pymysql
|
|
7
|
+
|
|
8
|
+
from sqlspec.extensions.litestar.store import BaseSQLSpecStore
|
|
9
|
+
from sqlspec.utils.logging import get_logger
|
|
10
|
+
from sqlspec.utils.sync_tools import async_
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from sqlspec.adapters.pymysql.config import PyMysqlConfig
|
|
14
|
+
|
|
15
|
+
logger = get_logger("sqlspec.adapters.pymysql.litestar.store")
|
|
16
|
+
|
|
17
|
+
__all__ = ("PyMysqlStore",)
|
|
18
|
+
|
|
19
|
+
MYSQL_TABLE_NOT_FOUND_ERROR: Final = 1146
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class PyMysqlStore(BaseSQLSpecStore["PyMysqlConfig"]):
|
|
23
|
+
"""MySQL/MariaDB session store using PyMySQL sync driver."""
|
|
24
|
+
|
|
25
|
+
__slots__ = ()
|
|
26
|
+
|
|
27
|
+
def __init__(self, config: "PyMysqlConfig") -> None:
|
|
28
|
+
super().__init__(config)
|
|
29
|
+
|
|
30
|
+
def _get_create_table_sql(self) -> str:
|
|
31
|
+
return f"""
|
|
32
|
+
CREATE TABLE IF NOT EXISTS {self._table_name} (
|
|
33
|
+
session_id VARCHAR(255) PRIMARY KEY,
|
|
34
|
+
data LONGBLOB NOT NULL,
|
|
35
|
+
expires_at DATETIME(6),
|
|
36
|
+
created_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6),
|
|
37
|
+
updated_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
|
38
|
+
INDEX idx_{self._table_name}_expires_at (expires_at)
|
|
39
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def _get_drop_table_sql(self) -> "list[str]":
|
|
43
|
+
return [
|
|
44
|
+
f"DROP INDEX idx_{self._table_name}_expires_at ON {self._table_name}",
|
|
45
|
+
f"DROP TABLE IF EXISTS {self._table_name}",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
def _create_table(self) -> None:
|
|
49
|
+
sql = self._get_create_table_sql()
|
|
50
|
+
with self._config.provide_session() as driver:
|
|
51
|
+
driver.execute_script(sql)
|
|
52
|
+
driver.commit()
|
|
53
|
+
self._log_table_created()
|
|
54
|
+
|
|
55
|
+
async def create_table(self) -> None:
|
|
56
|
+
await async_(self._create_table)()
|
|
57
|
+
|
|
58
|
+
def _get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
59
|
+
sql = f"""
|
|
60
|
+
SELECT data, expires_at FROM {self._table_name}
|
|
61
|
+
WHERE session_id = %s
|
|
62
|
+
AND (expires_at IS NULL OR expires_at > UTC_TIMESTAMP(6))
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
with self._config.provide_connection() as conn:
|
|
67
|
+
cursor = conn.cursor(pymysql.cursors.DictCursor)
|
|
68
|
+
try:
|
|
69
|
+
cursor.execute(sql, (key,))
|
|
70
|
+
row = cursor.fetchone()
|
|
71
|
+
finally:
|
|
72
|
+
cursor.close()
|
|
73
|
+
|
|
74
|
+
if row is None:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
if renew_for is not None and row["expires_at"] is not None:
|
|
78
|
+
new_expires_at = self._calculate_expires_at(renew_for)
|
|
79
|
+
if new_expires_at is not None:
|
|
80
|
+
naive_expires_at = new_expires_at.replace(tzinfo=None)
|
|
81
|
+
update_sql = f"""
|
|
82
|
+
UPDATE {self._table_name}
|
|
83
|
+
SET expires_at = %s, updated_at = UTC_TIMESTAMP(6)
|
|
84
|
+
WHERE session_id = %s
|
|
85
|
+
"""
|
|
86
|
+
update_cursor = conn.cursor()
|
|
87
|
+
try:
|
|
88
|
+
update_cursor.execute(update_sql, (naive_expires_at, key))
|
|
89
|
+
finally:
|
|
90
|
+
update_cursor.close()
|
|
91
|
+
conn.commit()
|
|
92
|
+
|
|
93
|
+
return bytes(row["data"])
|
|
94
|
+
except pymysql.MySQLError as exc:
|
|
95
|
+
if "doesn't exist" in str(exc) or getattr(exc, "args", [None])[0] == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
96
|
+
return None
|
|
97
|
+
raise
|
|
98
|
+
|
|
99
|
+
async def get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
100
|
+
return await async_(self._get)(key, renew_for)
|
|
101
|
+
|
|
102
|
+
def _set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
103
|
+
data = self._value_to_bytes(value)
|
|
104
|
+
expires_at = self._calculate_expires_at(expires_in)
|
|
105
|
+
naive_expires_at = expires_at.replace(tzinfo=None) if expires_at else None
|
|
106
|
+
|
|
107
|
+
sql = f"""
|
|
108
|
+
INSERT INTO {self._table_name} (session_id, data, expires_at)
|
|
109
|
+
VALUES (%s, %s, %s) AS new
|
|
110
|
+
ON DUPLICATE KEY UPDATE
|
|
111
|
+
data = new.data,
|
|
112
|
+
expires_at = new.expires_at,
|
|
113
|
+
updated_at = UTC_TIMESTAMP(6)
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
with self._config.provide_connection() as conn:
|
|
117
|
+
cursor = conn.cursor()
|
|
118
|
+
try:
|
|
119
|
+
cursor.execute(sql, (key, data, naive_expires_at))
|
|
120
|
+
finally:
|
|
121
|
+
cursor.close()
|
|
122
|
+
conn.commit()
|
|
123
|
+
|
|
124
|
+
async def set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
125
|
+
await async_(self._set)(key, value, expires_in)
|
|
126
|
+
|
|
127
|
+
def _delete(self, key: str) -> None:
|
|
128
|
+
sql = f"DELETE FROM {self._table_name} WHERE session_id = %s"
|
|
129
|
+
|
|
130
|
+
with self._config.provide_connection() as conn:
|
|
131
|
+
cursor = conn.cursor()
|
|
132
|
+
try:
|
|
133
|
+
cursor.execute(sql, (key,))
|
|
134
|
+
finally:
|
|
135
|
+
cursor.close()
|
|
136
|
+
conn.commit()
|
|
137
|
+
|
|
138
|
+
async def delete(self, key: str) -> None:
|
|
139
|
+
await async_(self._delete)(key)
|
|
140
|
+
|
|
141
|
+
def _delete_all(self) -> None:
|
|
142
|
+
sql = f"DELETE FROM {self._table_name}"
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
with self._config.provide_connection() as conn:
|
|
146
|
+
cursor = conn.cursor()
|
|
147
|
+
try:
|
|
148
|
+
cursor.execute(sql)
|
|
149
|
+
finally:
|
|
150
|
+
cursor.close()
|
|
151
|
+
conn.commit()
|
|
152
|
+
self._log_delete_all()
|
|
153
|
+
except pymysql.MySQLError as exc:
|
|
154
|
+
if "doesn't exist" in str(exc) or getattr(exc, "args", [None])[0] == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
155
|
+
logger.debug("Table %s does not exist, skipping delete_all", self._table_name)
|
|
156
|
+
return
|
|
157
|
+
raise
|
|
158
|
+
|
|
159
|
+
async def delete_all(self) -> None:
|
|
160
|
+
await async_(self._delete_all)()
|
|
161
|
+
|
|
162
|
+
def _exists(self, key: str) -> bool:
|
|
163
|
+
sql = f"""
|
|
164
|
+
SELECT 1 FROM {self._table_name}
|
|
165
|
+
WHERE session_id = %s
|
|
166
|
+
AND (expires_at IS NULL OR expires_at > UTC_TIMESTAMP(6))
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
with self._config.provide_connection() as conn:
|
|
171
|
+
cursor = conn.cursor()
|
|
172
|
+
try:
|
|
173
|
+
cursor.execute(sql, (key,))
|
|
174
|
+
result = cursor.fetchone()
|
|
175
|
+
finally:
|
|
176
|
+
cursor.close()
|
|
177
|
+
return result is not None
|
|
178
|
+
except pymysql.MySQLError as exc:
|
|
179
|
+
if "doesn't exist" in str(exc) or getattr(exc, "args", [None])[0] == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
180
|
+
return False
|
|
181
|
+
raise
|
|
182
|
+
|
|
183
|
+
async def exists(self, key: str) -> bool:
|
|
184
|
+
return await async_(self._exists)(key)
|
|
185
|
+
|
|
186
|
+
def _expires_in(self, key: str) -> "int | None":
|
|
187
|
+
sql = f"""
|
|
188
|
+
SELECT expires_at FROM {self._table_name}
|
|
189
|
+
WHERE session_id = %s
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
with self._config.provide_connection() as conn:
|
|
193
|
+
cursor = conn.cursor()
|
|
194
|
+
try:
|
|
195
|
+
cursor.execute(sql, (key,))
|
|
196
|
+
row = cursor.fetchone()
|
|
197
|
+
finally:
|
|
198
|
+
cursor.close()
|
|
199
|
+
|
|
200
|
+
if row is None or row[0] is None:
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
expires_at_naive = row[0]
|
|
204
|
+
expires_at_utc = expires_at_naive.replace(tzinfo=timezone.utc)
|
|
205
|
+
now = datetime.now(timezone.utc)
|
|
206
|
+
|
|
207
|
+
if expires_at_utc <= now:
|
|
208
|
+
return 0
|
|
209
|
+
|
|
210
|
+
delta = expires_at_utc - now
|
|
211
|
+
return int(delta.total_seconds())
|
|
212
|
+
|
|
213
|
+
async def expires_in(self, key: str) -> "int | None":
|
|
214
|
+
return await async_(self._expires_in)(key)
|
|
215
|
+
|
|
216
|
+
def _delete_expired(self) -> int:
|
|
217
|
+
sql = f"DELETE FROM {self._table_name} WHERE expires_at <= UTC_TIMESTAMP(6)"
|
|
218
|
+
|
|
219
|
+
with self._config.provide_connection() as conn:
|
|
220
|
+
cursor = conn.cursor()
|
|
221
|
+
try:
|
|
222
|
+
cursor.execute(sql)
|
|
223
|
+
conn.commit()
|
|
224
|
+
count: int = cursor.rowcount
|
|
225
|
+
finally:
|
|
226
|
+
cursor.close()
|
|
227
|
+
if count > 0:
|
|
228
|
+
self._log_delete_expired(count)
|
|
229
|
+
return count
|
|
230
|
+
|
|
231
|
+
async def delete_expired(self) -> int:
|
|
232
|
+
return await async_(self._delete_expired)()
|
|
Binary file
|