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,426 @@
|
|
|
1
|
+
"""MysqlConnector session store for Litestar integration."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Final, cast
|
|
5
|
+
|
|
6
|
+
import mysql.connector
|
|
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.mysqlconnector.config import MysqlConnectorAsyncConfig, MysqlConnectorSyncConfig
|
|
14
|
+
|
|
15
|
+
logger = get_logger("sqlspec.adapters.mysqlconnector.litestar.store")
|
|
16
|
+
|
|
17
|
+
__all__ = ("MysqlConnectorAsyncStore", "MysqlConnectorSyncStore")
|
|
18
|
+
|
|
19
|
+
MYSQL_TABLE_NOT_FOUND_ERROR: Final = 1146
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MysqlConnectorAsyncStore(BaseSQLSpecStore["MysqlConnectorAsyncConfig"]):
|
|
23
|
+
"""MySQL/MariaDB session store using mysql-connector async driver."""
|
|
24
|
+
|
|
25
|
+
__slots__ = ()
|
|
26
|
+
|
|
27
|
+
def __init__(self, config: "MysqlConnectorAsyncConfig") -> 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
|
+
async def create_table(self) -> None:
|
|
49
|
+
sql = self._get_create_table_sql()
|
|
50
|
+
async with self._config.provide_session() as driver:
|
|
51
|
+
await driver.execute_script(sql)
|
|
52
|
+
self._log_table_created()
|
|
53
|
+
|
|
54
|
+
async def get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
55
|
+
sql = f"""
|
|
56
|
+
SELECT data, expires_at FROM {self._table_name}
|
|
57
|
+
WHERE session_id = %s
|
|
58
|
+
AND (expires_at IS NULL OR expires_at > UTC_TIMESTAMP(6))
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
async with self._config.provide_connection() as conn:
|
|
63
|
+
cursor = await conn.cursor()
|
|
64
|
+
try:
|
|
65
|
+
await cursor.execute(sql, (key,))
|
|
66
|
+
row = await cursor.fetchone()
|
|
67
|
+
finally:
|
|
68
|
+
await cursor.close()
|
|
69
|
+
|
|
70
|
+
if row is None:
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
data_value: Any = row[0]
|
|
74
|
+
expires_at: Any = row[1]
|
|
75
|
+
|
|
76
|
+
if renew_for is not None and expires_at is not None:
|
|
77
|
+
new_expires_at = self._calculate_expires_at(renew_for)
|
|
78
|
+
if new_expires_at is not None:
|
|
79
|
+
naive_expires_at = new_expires_at.replace(tzinfo=None)
|
|
80
|
+
update_sql = f"""
|
|
81
|
+
UPDATE {self._table_name}
|
|
82
|
+
SET expires_at = %s, updated_at = UTC_TIMESTAMP(6)
|
|
83
|
+
WHERE session_id = %s
|
|
84
|
+
"""
|
|
85
|
+
update_cursor = await conn.cursor()
|
|
86
|
+
try:
|
|
87
|
+
await update_cursor.execute(update_sql, (naive_expires_at, key))
|
|
88
|
+
finally:
|
|
89
|
+
await update_cursor.close()
|
|
90
|
+
await conn.commit()
|
|
91
|
+
|
|
92
|
+
return bytes(cast("bytes", data_value))
|
|
93
|
+
except mysql.connector.Error as exc:
|
|
94
|
+
if "doesn't exist" in str(exc) or getattr(exc, "errno", None) == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
95
|
+
return None
|
|
96
|
+
raise
|
|
97
|
+
|
|
98
|
+
async def set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
99
|
+
data = self._value_to_bytes(value)
|
|
100
|
+
expires_at = self._calculate_expires_at(expires_in)
|
|
101
|
+
naive_expires_at = expires_at.replace(tzinfo=None) if expires_at else None
|
|
102
|
+
|
|
103
|
+
sql = f"""
|
|
104
|
+
INSERT INTO {self._table_name} (session_id, data, expires_at)
|
|
105
|
+
VALUES (%s, %s, %s) AS new
|
|
106
|
+
ON DUPLICATE KEY UPDATE
|
|
107
|
+
data = new.data,
|
|
108
|
+
expires_at = new.expires_at,
|
|
109
|
+
updated_at = UTC_TIMESTAMP(6)
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
async with self._config.provide_connection() as conn:
|
|
113
|
+
cursor = await conn.cursor()
|
|
114
|
+
try:
|
|
115
|
+
await cursor.execute(sql, (key, data, naive_expires_at))
|
|
116
|
+
finally:
|
|
117
|
+
await cursor.close()
|
|
118
|
+
await conn.commit()
|
|
119
|
+
|
|
120
|
+
async def delete(self, key: str) -> None:
|
|
121
|
+
sql = f"DELETE FROM {self._table_name} WHERE session_id = %s"
|
|
122
|
+
|
|
123
|
+
async with self._config.provide_connection() as conn:
|
|
124
|
+
cursor = await conn.cursor()
|
|
125
|
+
try:
|
|
126
|
+
await cursor.execute(sql, (key,))
|
|
127
|
+
finally:
|
|
128
|
+
await cursor.close()
|
|
129
|
+
await conn.commit()
|
|
130
|
+
|
|
131
|
+
async def delete_all(self) -> None:
|
|
132
|
+
sql = f"DELETE FROM {self._table_name}"
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
async with self._config.provide_connection() as conn:
|
|
136
|
+
cursor = await conn.cursor()
|
|
137
|
+
try:
|
|
138
|
+
await cursor.execute(sql)
|
|
139
|
+
finally:
|
|
140
|
+
await cursor.close()
|
|
141
|
+
await conn.commit()
|
|
142
|
+
self._log_delete_all()
|
|
143
|
+
except mysql.connector.Error as exc:
|
|
144
|
+
if "doesn't exist" in str(exc) or getattr(exc, "errno", None) == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
145
|
+
logger.debug("Table %s does not exist, skipping delete_all", self._table_name)
|
|
146
|
+
return
|
|
147
|
+
raise
|
|
148
|
+
|
|
149
|
+
async def exists(self, key: str) -> bool:
|
|
150
|
+
sql = f"""
|
|
151
|
+
SELECT 1 FROM {self._table_name}
|
|
152
|
+
WHERE session_id = %s
|
|
153
|
+
AND (expires_at IS NULL OR expires_at > UTC_TIMESTAMP(6))
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
async with self._config.provide_connection() as conn:
|
|
158
|
+
cursor = await conn.cursor()
|
|
159
|
+
try:
|
|
160
|
+
await cursor.execute(sql, (key,))
|
|
161
|
+
result = await cursor.fetchone()
|
|
162
|
+
finally:
|
|
163
|
+
await cursor.close()
|
|
164
|
+
return result is not None
|
|
165
|
+
except mysql.connector.Error as exc:
|
|
166
|
+
if "doesn't exist" in str(exc) or getattr(exc, "errno", None) == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
167
|
+
return False
|
|
168
|
+
raise
|
|
169
|
+
|
|
170
|
+
async def expires_in(self, key: str) -> "int | None":
|
|
171
|
+
sql = f"""
|
|
172
|
+
SELECT expires_at FROM {self._table_name}
|
|
173
|
+
WHERE session_id = %s
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
async with self._config.provide_connection() as conn:
|
|
177
|
+
cursor = await conn.cursor()
|
|
178
|
+
try:
|
|
179
|
+
await cursor.execute(sql, (key,))
|
|
180
|
+
row = await cursor.fetchone()
|
|
181
|
+
finally:
|
|
182
|
+
await cursor.close()
|
|
183
|
+
|
|
184
|
+
if row is None or row[0] is None:
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
expires_at_naive: datetime = cast("datetime", row[0])
|
|
188
|
+
expires_at_utc = expires_at_naive.replace(tzinfo=timezone.utc)
|
|
189
|
+
now = datetime.now(timezone.utc)
|
|
190
|
+
|
|
191
|
+
if expires_at_utc <= now:
|
|
192
|
+
return 0
|
|
193
|
+
|
|
194
|
+
delta = expires_at_utc - now
|
|
195
|
+
return int(delta.total_seconds())
|
|
196
|
+
|
|
197
|
+
async def delete_expired(self) -> int:
|
|
198
|
+
sql = f"DELETE FROM {self._table_name} WHERE expires_at <= UTC_TIMESTAMP(6)"
|
|
199
|
+
|
|
200
|
+
async with self._config.provide_connection() as conn:
|
|
201
|
+
cursor = await conn.cursor()
|
|
202
|
+
try:
|
|
203
|
+
await cursor.execute(sql)
|
|
204
|
+
await conn.commit()
|
|
205
|
+
count: int = cursor.rowcount
|
|
206
|
+
finally:
|
|
207
|
+
await cursor.close()
|
|
208
|
+
if count > 0:
|
|
209
|
+
self._log_delete_expired(count)
|
|
210
|
+
return count
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class MysqlConnectorSyncStore(BaseSQLSpecStore["MysqlConnectorSyncConfig"]):
|
|
214
|
+
"""MySQL/MariaDB session store using mysql-connector sync driver."""
|
|
215
|
+
|
|
216
|
+
__slots__ = ()
|
|
217
|
+
|
|
218
|
+
def __init__(self, config: "MysqlConnectorSyncConfig") -> None:
|
|
219
|
+
super().__init__(config)
|
|
220
|
+
|
|
221
|
+
def _get_create_table_sql(self) -> str:
|
|
222
|
+
return f"""
|
|
223
|
+
CREATE TABLE IF NOT EXISTS {self._table_name} (
|
|
224
|
+
session_id VARCHAR(255) PRIMARY KEY,
|
|
225
|
+
data LONGBLOB NOT NULL,
|
|
226
|
+
expires_at DATETIME(6),
|
|
227
|
+
created_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6),
|
|
228
|
+
updated_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
|
229
|
+
INDEX idx_{self._table_name}_expires_at (expires_at)
|
|
230
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
def _get_drop_table_sql(self) -> "list[str]":
|
|
234
|
+
return [
|
|
235
|
+
f"DROP INDEX idx_{self._table_name}_expires_at ON {self._table_name}",
|
|
236
|
+
f"DROP TABLE IF EXISTS {self._table_name}",
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
def _create_table(self) -> None:
|
|
240
|
+
sql = self._get_create_table_sql()
|
|
241
|
+
with self._config.provide_session() as driver:
|
|
242
|
+
driver.execute_script(sql)
|
|
243
|
+
driver.commit()
|
|
244
|
+
self._log_table_created()
|
|
245
|
+
|
|
246
|
+
async def create_table(self) -> None:
|
|
247
|
+
await async_(self._create_table)()
|
|
248
|
+
|
|
249
|
+
def _get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
250
|
+
sql = f"""
|
|
251
|
+
SELECT data, expires_at FROM {self._table_name}
|
|
252
|
+
WHERE session_id = %s
|
|
253
|
+
AND (expires_at IS NULL OR expires_at > UTC_TIMESTAMP(6))
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
with self._config.provide_connection() as conn:
|
|
258
|
+
cursor = conn.cursor()
|
|
259
|
+
try:
|
|
260
|
+
cursor.execute(sql, (key,))
|
|
261
|
+
row = cursor.fetchone()
|
|
262
|
+
finally:
|
|
263
|
+
cursor.close()
|
|
264
|
+
|
|
265
|
+
if row is None:
|
|
266
|
+
return None
|
|
267
|
+
|
|
268
|
+
data_value: Any = row[0]
|
|
269
|
+
expires_at: Any = row[1]
|
|
270
|
+
|
|
271
|
+
if renew_for is not None and expires_at is not None:
|
|
272
|
+
new_expires_at = self._calculate_expires_at(renew_for)
|
|
273
|
+
if new_expires_at is not None:
|
|
274
|
+
naive_expires_at = new_expires_at.replace(tzinfo=None)
|
|
275
|
+
update_sql = f"""
|
|
276
|
+
UPDATE {self._table_name}
|
|
277
|
+
SET expires_at = %s, updated_at = UTC_TIMESTAMP(6)
|
|
278
|
+
WHERE session_id = %s
|
|
279
|
+
"""
|
|
280
|
+
update_cursor = conn.cursor()
|
|
281
|
+
try:
|
|
282
|
+
update_cursor.execute(update_sql, (naive_expires_at, key))
|
|
283
|
+
finally:
|
|
284
|
+
update_cursor.close()
|
|
285
|
+
conn.commit()
|
|
286
|
+
|
|
287
|
+
return bytes(cast("bytes", data_value))
|
|
288
|
+
except mysql.connector.Error as exc:
|
|
289
|
+
if "doesn't exist" in str(exc) or getattr(exc, "errno", None) == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
290
|
+
return None
|
|
291
|
+
raise
|
|
292
|
+
|
|
293
|
+
async def get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
294
|
+
return await async_(self._get)(key, renew_for)
|
|
295
|
+
|
|
296
|
+
def _set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
297
|
+
data = self._value_to_bytes(value)
|
|
298
|
+
expires_at = self._calculate_expires_at(expires_in)
|
|
299
|
+
naive_expires_at = expires_at.replace(tzinfo=None) if expires_at else None
|
|
300
|
+
|
|
301
|
+
sql = f"""
|
|
302
|
+
INSERT INTO {self._table_name} (session_id, data, expires_at)
|
|
303
|
+
VALUES (%s, %s, %s) AS new
|
|
304
|
+
ON DUPLICATE KEY UPDATE
|
|
305
|
+
data = new.data,
|
|
306
|
+
expires_at = new.expires_at,
|
|
307
|
+
updated_at = UTC_TIMESTAMP(6)
|
|
308
|
+
"""
|
|
309
|
+
|
|
310
|
+
with self._config.provide_connection() as conn:
|
|
311
|
+
cursor = conn.cursor()
|
|
312
|
+
try:
|
|
313
|
+
cursor.execute(sql, (key, data, naive_expires_at))
|
|
314
|
+
finally:
|
|
315
|
+
cursor.close()
|
|
316
|
+
conn.commit()
|
|
317
|
+
|
|
318
|
+
async def set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
319
|
+
await async_(self._set)(key, value, expires_in)
|
|
320
|
+
|
|
321
|
+
def _delete(self, key: str) -> None:
|
|
322
|
+
sql = f"DELETE FROM {self._table_name} WHERE session_id = %s"
|
|
323
|
+
|
|
324
|
+
with self._config.provide_connection() as conn:
|
|
325
|
+
cursor = conn.cursor()
|
|
326
|
+
try:
|
|
327
|
+
cursor.execute(sql, (key,))
|
|
328
|
+
finally:
|
|
329
|
+
cursor.close()
|
|
330
|
+
conn.commit()
|
|
331
|
+
|
|
332
|
+
async def delete(self, key: str) -> None:
|
|
333
|
+
await async_(self._delete)(key)
|
|
334
|
+
|
|
335
|
+
def _delete_all(self) -> None:
|
|
336
|
+
sql = f"DELETE FROM {self._table_name}"
|
|
337
|
+
|
|
338
|
+
try:
|
|
339
|
+
with self._config.provide_connection() as conn:
|
|
340
|
+
cursor = conn.cursor()
|
|
341
|
+
try:
|
|
342
|
+
cursor.execute(sql)
|
|
343
|
+
finally:
|
|
344
|
+
cursor.close()
|
|
345
|
+
conn.commit()
|
|
346
|
+
self._log_delete_all()
|
|
347
|
+
except mysql.connector.Error as exc:
|
|
348
|
+
if "doesn't exist" in str(exc) or getattr(exc, "errno", None) == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
349
|
+
logger.debug("Table %s does not exist, skipping delete_all", self._table_name)
|
|
350
|
+
return
|
|
351
|
+
raise
|
|
352
|
+
|
|
353
|
+
async def delete_all(self) -> None:
|
|
354
|
+
await async_(self._delete_all)()
|
|
355
|
+
|
|
356
|
+
def _exists(self, key: str) -> bool:
|
|
357
|
+
sql = f"""
|
|
358
|
+
SELECT 1 FROM {self._table_name}
|
|
359
|
+
WHERE session_id = %s
|
|
360
|
+
AND (expires_at IS NULL OR expires_at > UTC_TIMESTAMP(6))
|
|
361
|
+
"""
|
|
362
|
+
|
|
363
|
+
try:
|
|
364
|
+
with self._config.provide_connection() as conn:
|
|
365
|
+
cursor = conn.cursor()
|
|
366
|
+
try:
|
|
367
|
+
cursor.execute(sql, (key,))
|
|
368
|
+
result = cursor.fetchone()
|
|
369
|
+
finally:
|
|
370
|
+
cursor.close()
|
|
371
|
+
return result is not None
|
|
372
|
+
except mysql.connector.Error as exc:
|
|
373
|
+
if "doesn't exist" in str(exc) or getattr(exc, "errno", None) == MYSQL_TABLE_NOT_FOUND_ERROR:
|
|
374
|
+
return False
|
|
375
|
+
raise
|
|
376
|
+
|
|
377
|
+
async def exists(self, key: str) -> bool:
|
|
378
|
+
return await async_(self._exists)(key)
|
|
379
|
+
|
|
380
|
+
def _expires_in(self, key: str) -> "int | None":
|
|
381
|
+
sql = f"""
|
|
382
|
+
SELECT expires_at FROM {self._table_name}
|
|
383
|
+
WHERE session_id = %s
|
|
384
|
+
"""
|
|
385
|
+
|
|
386
|
+
with self._config.provide_connection() as conn:
|
|
387
|
+
cursor = conn.cursor()
|
|
388
|
+
try:
|
|
389
|
+
cursor.execute(sql, (key,))
|
|
390
|
+
row = cursor.fetchone()
|
|
391
|
+
finally:
|
|
392
|
+
cursor.close()
|
|
393
|
+
|
|
394
|
+
if row is None or row[0] is None:
|
|
395
|
+
return None
|
|
396
|
+
|
|
397
|
+
expires_at_naive: datetime = cast("datetime", row[0])
|
|
398
|
+
expires_at_utc = expires_at_naive.replace(tzinfo=timezone.utc)
|
|
399
|
+
now = datetime.now(timezone.utc)
|
|
400
|
+
|
|
401
|
+
if expires_at_utc <= now:
|
|
402
|
+
return 0
|
|
403
|
+
|
|
404
|
+
delta = expires_at_utc - now
|
|
405
|
+
return int(delta.total_seconds())
|
|
406
|
+
|
|
407
|
+
async def expires_in(self, key: str) -> "int | None":
|
|
408
|
+
return await async_(self._expires_in)(key)
|
|
409
|
+
|
|
410
|
+
def _delete_expired(self) -> int:
|
|
411
|
+
sql = f"DELETE FROM {self._table_name} WHERE expires_at <= UTC_TIMESTAMP(6)"
|
|
412
|
+
|
|
413
|
+
with self._config.provide_connection() as conn:
|
|
414
|
+
cursor = conn.cursor()
|
|
415
|
+
try:
|
|
416
|
+
cursor.execute(sql)
|
|
417
|
+
conn.commit()
|
|
418
|
+
count: int = cursor.rowcount
|
|
419
|
+
finally:
|
|
420
|
+
cursor.close()
|
|
421
|
+
if count > 0:
|
|
422
|
+
self._log_delete_expired(count)
|
|
423
|
+
return count
|
|
424
|
+
|
|
425
|
+
async def delete_expired(self) -> int:
|
|
426
|
+
return await async_(self._delete_expired)()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from sqlspec.adapters.oracledb._param_types import OracleBlob, OracleClob, OracleJson
|
|
2
|
+
from sqlspec.adapters.oracledb.config import (
|
|
3
|
+
OracleAsyncConfig,
|
|
4
|
+
OracleConnectionParams,
|
|
5
|
+
OracleDriverFeatures,
|
|
6
|
+
OraclePoolParams,
|
|
7
|
+
OracleSyncConfig,
|
|
8
|
+
)
|
|
9
|
+
from sqlspec.adapters.oracledb.core import default_statement_config
|
|
10
|
+
from sqlspec.adapters.oracledb.data_dictionary import (
|
|
11
|
+
OracledbAsyncDataDictionary,
|
|
12
|
+
OracledbSyncDataDictionary,
|
|
13
|
+
OracleVersionInfo,
|
|
14
|
+
)
|
|
15
|
+
from sqlspec.adapters.oracledb.driver import (
|
|
16
|
+
OracleAsyncDriver,
|
|
17
|
+
OracleAsyncExceptionHandler,
|
|
18
|
+
OracleSyncDriver,
|
|
19
|
+
OracleSyncExceptionHandler,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = (
|
|
23
|
+
"OracleAsyncConfig",
|
|
24
|
+
"OracleAsyncDriver",
|
|
25
|
+
"OracleAsyncExceptionHandler",
|
|
26
|
+
"OracleBlob",
|
|
27
|
+
"OracleClob",
|
|
28
|
+
"OracleConnectionParams",
|
|
29
|
+
"OracleDriverFeatures",
|
|
30
|
+
"OracleJson",
|
|
31
|
+
"OraclePoolParams",
|
|
32
|
+
"OracleSyncConfig",
|
|
33
|
+
"OracleSyncDriver",
|
|
34
|
+
"OracleSyncExceptionHandler",
|
|
35
|
+
"OracleVersionInfo",
|
|
36
|
+
"OracledbAsyncDataDictionary",
|
|
37
|
+
"OracledbSyncDataDictionary",
|
|
38
|
+
"default_statement_config",
|
|
39
|
+
)
|
|
Binary file
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""Oracle native JSON type handlers.
|
|
2
|
+
|
|
3
|
+
Provides automatic conversion between Python ``dict`` / ``list`` / ``tuple`` values
|
|
4
|
+
and Oracle's JSON storage types via connection type handlers.
|
|
5
|
+
|
|
6
|
+
Routing matrix (input):
|
|
7
|
+
|
|
8
|
+
* Oracle 21c+ native ``JSON``: bind via ``DB_TYPE_JSON`` (binary OSON).
|
|
9
|
+
* Oracle 19c-20c with ``BLOB CHECK (... IS JSON)``: bind via ``DB_TYPE_BLOB`` with
|
|
10
|
+
UTF-8 JSON bytes.
|
|
11
|
+
* Oracle 12c-18c with ``CLOB CHECK (... IS JSON)``: bind via ``DB_TYPE_CLOB`` with
|
|
12
|
+
serialized JSON string.
|
|
13
|
+
* Server major version is read from ``connection._sqlspec_oracle_major`` (set in
|
|
14
|
+
``OracleSyncConfig._init_connection`` / ``OracleAsyncConfig._init_connection``).
|
|
15
|
+
When unknown, default to 21c+ behavior.
|
|
16
|
+
|
|
17
|
+
Routing matrix (output):
|
|
18
|
+
|
|
19
|
+
* ``DB_TYPE_JSON``: passthrough (python-oracledb already returns ``dict``).
|
|
20
|
+
* ``DB_TYPE_BLOB`` with ``JSON`` in column ``type_name``: parse via
|
|
21
|
+
``json_converter_out_blob``.
|
|
22
|
+
* ``DB_TYPE_CLOB`` with ``JSON`` in column ``type_name``: parse via
|
|
23
|
+
``json_converter_out_clob``.
|
|
24
|
+
|
|
25
|
+
Handlers chain to any pre-existing ``inputtypehandler`` / ``outputtypehandler``
|
|
26
|
+
registered on the connection (e.g. NumPy vector, UUID), so registration order
|
|
27
|
+
matters: register JSON after numpy, before UUID is also safe because each
|
|
28
|
+
handler returns ``None`` for values it does not own.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from typing import TYPE_CHECKING, Any
|
|
32
|
+
|
|
33
|
+
from sqlspec.adapters.oracledb._typing import DB_TYPE_BLOB, DB_TYPE_CLOB, DB_TYPE_JSON
|
|
34
|
+
from sqlspec.utils.serializers import from_json, to_json
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from oracledb import AsyncConnection, AsyncCursor, Connection, Cursor
|
|
38
|
+
|
|
39
|
+
__all__ = (
|
|
40
|
+
"json_converter_in_blob",
|
|
41
|
+
"json_converter_in_clob",
|
|
42
|
+
"json_converter_out_blob",
|
|
43
|
+
"json_converter_out_clob",
|
|
44
|
+
"json_input_type_handler",
|
|
45
|
+
"json_output_type_handler",
|
|
46
|
+
"register_json_handlers",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_JSON_TYPE_NAME_MARKER = "JSON"
|
|
51
|
+
|
|
52
|
+
# Server-version thresholds for JSON binding strategy selection.
|
|
53
|
+
# 21c+ supports DB_TYPE_JSON (binary OSON); 19c-20c uses BLOB CHECK (... IS JSON);
|
|
54
|
+
# pre-19c uses CLOB CHECK (... IS JSON).
|
|
55
|
+
_NATIVE_JSON_MIN_MAJOR = 21
|
|
56
|
+
_BLOB_IS_JSON_MIN_MAJOR = 19
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def json_converter_in_clob(value: Any) -> str:
|
|
60
|
+
"""Serialize a Python value to a JSON string for CLOB binding."""
|
|
61
|
+
return to_json(value)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def json_converter_in_blob(value: Any) -> bytes:
|
|
65
|
+
"""Serialize a Python value to UTF-8 JSON bytes for BLOB binding."""
|
|
66
|
+
return to_json(value, as_bytes=True)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def json_converter_out_clob(value: "str | None") -> Any:
|
|
70
|
+
"""Parse a JSON string from a CLOB read back into a Python value."""
|
|
71
|
+
if value is None:
|
|
72
|
+
return None
|
|
73
|
+
return from_json(value)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def json_converter_out_blob(value: "bytes | None") -> Any:
|
|
77
|
+
"""Parse JSON bytes from a BLOB read back into a Python value."""
|
|
78
|
+
if value is None:
|
|
79
|
+
return None
|
|
80
|
+
return from_json(value)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _is_json_payload(value: Any) -> bool:
|
|
84
|
+
"""Return True if the value should be claimed by the JSON input handler.
|
|
85
|
+
|
|
86
|
+
``dict`` and ``tuple``/``list`` of dicts are claimed. Sequences whose first
|
|
87
|
+
element is a number are NOT claimed — those are vector embeddings and
|
|
88
|
+
belong to the vector handler.
|
|
89
|
+
"""
|
|
90
|
+
if isinstance(value, dict):
|
|
91
|
+
return True
|
|
92
|
+
if isinstance(value, (list, tuple)):
|
|
93
|
+
if not value:
|
|
94
|
+
# Empty sequence: ambiguous (could be empty vector or empty list).
|
|
95
|
+
# Defer to the next handler in the chain.
|
|
96
|
+
return False
|
|
97
|
+
first = value[0]
|
|
98
|
+
# Reject sequences of numbers (vector embeddings).
|
|
99
|
+
return not (isinstance(first, (int, float)) and not isinstance(first, bool))
|
|
100
|
+
return False
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _input_type_handler(cursor: "Cursor | AsyncCursor", value: Any, arraysize: int) -> Any:
|
|
104
|
+
"""Oracle input type handler for JSON-shaped Python values."""
|
|
105
|
+
if not _is_json_payload(value):
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
server_major = getattr(cursor.connection, "_sqlspec_oracle_major", None)
|
|
109
|
+
|
|
110
|
+
if server_major is None or server_major >= _NATIVE_JSON_MIN_MAJOR:
|
|
111
|
+
return cursor.var(DB_TYPE_JSON, arraysize=arraysize)
|
|
112
|
+
if server_major >= _BLOB_IS_JSON_MIN_MAJOR:
|
|
113
|
+
return cursor.var(DB_TYPE_BLOB, arraysize=arraysize, inconverter=json_converter_in_blob)
|
|
114
|
+
return cursor.var(DB_TYPE_CLOB, arraysize=arraysize, inconverter=json_converter_in_clob)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _output_type_handler(cursor: "Cursor | AsyncCursor", metadata: Any) -> Any:
|
|
118
|
+
"""Oracle output type handler for JSON-bearing column reads."""
|
|
119
|
+
type_code = getattr(metadata, "type_code", None)
|
|
120
|
+
|
|
121
|
+
if type_code is DB_TYPE_JSON:
|
|
122
|
+
# Native JSON: python-oracledb returns dict/list directly. No conversion.
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
type_name = (getattr(metadata, "type_name", "") or "").upper()
|
|
126
|
+
if _JSON_TYPE_NAME_MARKER not in type_name:
|
|
127
|
+
return None
|
|
128
|
+
|
|
129
|
+
if type_code is DB_TYPE_BLOB:
|
|
130
|
+
return cursor.var(DB_TYPE_BLOB, arraysize=cursor.arraysize, outconverter=json_converter_out_blob)
|
|
131
|
+
if type_code is DB_TYPE_CLOB:
|
|
132
|
+
return cursor.var(DB_TYPE_CLOB, arraysize=cursor.arraysize, outconverter=json_converter_out_clob)
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def json_input_type_handler(cursor: "Cursor | AsyncCursor", value: Any, arraysize: int) -> Any:
|
|
137
|
+
"""Public input type handler entry point."""
|
|
138
|
+
return _input_type_handler(cursor, value, arraysize)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def json_output_type_handler(cursor: "Cursor | AsyncCursor", metadata: Any) -> Any:
|
|
142
|
+
"""Public output type handler entry point."""
|
|
143
|
+
return _output_type_handler(cursor, metadata)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def register_json_handlers(connection: "Connection | AsyncConnection") -> None:
|
|
147
|
+
"""Register JSON type handlers on an Oracle connection.
|
|
148
|
+
|
|
149
|
+
Chains to any existing handlers via ``_JsonInputHandler`` / ``_JsonOutputHandler``
|
|
150
|
+
wrapper classes so vector / UUID handlers continue to fire for non-JSON values.
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
existing_input = connection.inputtypehandler
|
|
154
|
+
except AttributeError:
|
|
155
|
+
existing_input = None
|
|
156
|
+
try:
|
|
157
|
+
existing_output = connection.outputtypehandler
|
|
158
|
+
except AttributeError:
|
|
159
|
+
existing_output = None
|
|
160
|
+
|
|
161
|
+
connection.inputtypehandler = _JsonInputHandler(existing_input)
|
|
162
|
+
connection.outputtypehandler = _JsonOutputHandler(existing_output)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class _JsonInputHandler:
|
|
166
|
+
"""Chaining wrapper that claims dict/list/tuple values, falling back otherwise."""
|
|
167
|
+
|
|
168
|
+
__slots__ = ("_fallback",)
|
|
169
|
+
|
|
170
|
+
def __init__(self, fallback: "Any | None") -> None:
|
|
171
|
+
self._fallback = fallback
|
|
172
|
+
|
|
173
|
+
def __call__(self, cursor: "Cursor | AsyncCursor", value: Any, arraysize: int) -> Any:
|
|
174
|
+
result = _input_type_handler(cursor, value, arraysize)
|
|
175
|
+
if result is not None:
|
|
176
|
+
return result
|
|
177
|
+
if self._fallback is not None:
|
|
178
|
+
return self._fallback(cursor, value, arraysize)
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class _JsonOutputHandler:
|
|
183
|
+
"""Chaining wrapper that claims JSON-bearing columns, falling back otherwise."""
|
|
184
|
+
|
|
185
|
+
__slots__ = ("_fallback",)
|
|
186
|
+
|
|
187
|
+
def __init__(self, fallback: "Any | None") -> None:
|
|
188
|
+
self._fallback = fallback
|
|
189
|
+
|
|
190
|
+
def __call__(self, cursor: "Cursor | AsyncCursor", metadata: Any) -> Any:
|
|
191
|
+
result = _output_type_handler(cursor, metadata)
|
|
192
|
+
if result is not None:
|
|
193
|
+
return result
|
|
194
|
+
if self._fallback is not None:
|
|
195
|
+
return self._fallback(cursor, metadata)
|
|
196
|
+
return None
|
|
Binary file
|