sqlspec 0.36.0__cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ac8f31065839703b4e70__mypyc.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/__init__.py +140 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_serialization.py +315 -0
- sqlspec/_typing.py +700 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +5 -0
- sqlspec/adapters/adbc/_typing.py +82 -0
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +1273 -0
- sqlspec/adapters/adbc/config.py +295 -0
- sqlspec/adapters/adbc/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/adbc/core.py +735 -0
- sqlspec/adapters/adbc/data_dictionary.py +334 -0
- sqlspec/adapters/adbc/driver.py +529 -0
- sqlspec/adapters/adbc/events/__init__.py +5 -0
- sqlspec/adapters/adbc/events/store.py +285 -0
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +502 -0
- sqlspec/adapters/adbc/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/adbc/type_converter.py +140 -0
- sqlspec/adapters/aiosqlite/__init__.py +25 -0
- sqlspec/adapters/aiosqlite/_typing.py +82 -0
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +818 -0
- sqlspec/adapters/aiosqlite/config.py +334 -0
- sqlspec/adapters/aiosqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/aiosqlite/core.py +315 -0
- sqlspec/adapters/aiosqlite/data_dictionary.py +208 -0
- sqlspec/adapters/aiosqlite/driver.py +313 -0
- sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/events/store.py +20 -0
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
- sqlspec/adapters/aiosqlite/pool.py +533 -0
- sqlspec/adapters/asyncmy/__init__.py +21 -0
- sqlspec/adapters/asyncmy/_typing.py +87 -0
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +703 -0
- sqlspec/adapters/asyncmy/config.py +302 -0
- sqlspec/adapters/asyncmy/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/asyncmy/core.py +360 -0
- sqlspec/adapters/asyncmy/data_dictionary.py +124 -0
- sqlspec/adapters/asyncmy/driver.py +383 -0
- sqlspec/adapters/asyncmy/events/__init__.py +5 -0
- sqlspec/adapters/asyncmy/events/store.py +104 -0
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +19 -0
- sqlspec/adapters/asyncpg/_typing.py +88 -0
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +748 -0
- sqlspec/adapters/asyncpg/config.py +569 -0
- sqlspec/adapters/asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/asyncpg/core.py +367 -0
- sqlspec/adapters/asyncpg/data_dictionary.py +162 -0
- sqlspec/adapters/asyncpg/driver.py +487 -0
- sqlspec/adapters/asyncpg/events/__init__.py +6 -0
- sqlspec/adapters/asyncpg/events/backend.py +286 -0
- sqlspec/adapters/asyncpg/events/store.py +40 -0
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +251 -0
- sqlspec/adapters/bigquery/__init__.py +14 -0
- sqlspec/adapters/bigquery/_typing.py +86 -0
- sqlspec/adapters/bigquery/adk/__init__.py +5 -0
- sqlspec/adapters/bigquery/adk/store.py +827 -0
- sqlspec/adapters/bigquery/config.py +353 -0
- sqlspec/adapters/bigquery/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/bigquery/core.py +715 -0
- sqlspec/adapters/bigquery/data_dictionary.py +128 -0
- sqlspec/adapters/bigquery/driver.py +548 -0
- sqlspec/adapters/bigquery/events/__init__.py +5 -0
- sqlspec/adapters/bigquery/events/store.py +139 -0
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +325 -0
- sqlspec/adapters/bigquery/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/bigquery/type_converter.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/__init__.py +24 -0
- sqlspec/adapters/cockroach_asyncpg/_typing.py +72 -0
- sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/adk/store.py +410 -0
- sqlspec/adapters/cockroach_asyncpg/config.py +238 -0
- sqlspec/adapters/cockroach_asyncpg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
- sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/driver.py +144 -0
- sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
- sqlspec/adapters/cockroach_psycopg/__init__.py +38 -0
- sqlspec/adapters/cockroach_psycopg/_typing.py +129 -0
- sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
- sqlspec/adapters/cockroach_psycopg/adk/store.py +868 -0
- sqlspec/adapters/cockroach_psycopg/config.py +484 -0
- sqlspec/adapters/cockroach_psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/cockroach_psycopg/core.py +63 -0
- sqlspec/adapters/cockroach_psycopg/data_dictionary.py +215 -0
- sqlspec/adapters/cockroach_psycopg/driver.py +284 -0
- sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
- sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
- sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
- sqlspec/adapters/cockroach_psycopg/litestar/store.py +325 -0
- sqlspec/adapters/duckdb/__init__.py +25 -0
- sqlspec/adapters/duckdb/_typing.py +81 -0
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +850 -0
- sqlspec/adapters/duckdb/config.py +463 -0
- sqlspec/adapters/duckdb/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/duckdb/core.py +257 -0
- sqlspec/adapters/duckdb/data_dictionary.py +140 -0
- sqlspec/adapters/duckdb/driver.py +430 -0
- sqlspec/adapters/duckdb/events/__init__.py +5 -0
- sqlspec/adapters/duckdb/events/store.py +57 -0
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +330 -0
- sqlspec/adapters/duckdb/pool.py +293 -0
- sqlspec/adapters/duckdb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/duckdb/type_converter.py +118 -0
- sqlspec/adapters/mock/__init__.py +72 -0
- sqlspec/adapters/mock/_typing.py +147 -0
- sqlspec/adapters/mock/config.py +483 -0
- sqlspec/adapters/mock/core.py +319 -0
- sqlspec/adapters/mock/data_dictionary.py +366 -0
- sqlspec/adapters/mock/driver.py +721 -0
- sqlspec/adapters/mysqlconnector/__init__.py +36 -0
- sqlspec/adapters/mysqlconnector/_typing.py +141 -0
- sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
- sqlspec/adapters/mysqlconnector/adk/store.py +1060 -0
- sqlspec/adapters/mysqlconnector/config.py +394 -0
- sqlspec/adapters/mysqlconnector/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/mysqlconnector/core.py +303 -0
- sqlspec/adapters/mysqlconnector/data_dictionary.py +235 -0
- sqlspec/adapters/mysqlconnector/driver.py +483 -0
- sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
- sqlspec/adapters/mysqlconnector/events/store.py +98 -0
- sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
- sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
- sqlspec/adapters/oracledb/__init__.py +60 -0
- sqlspec/adapters/oracledb/_numpy_handlers.py +141 -0
- sqlspec/adapters/oracledb/_typing.py +182 -0
- sqlspec/adapters/oracledb/_uuid_handlers.py +166 -0
- sqlspec/adapters/oracledb/adk/__init__.py +10 -0
- sqlspec/adapters/oracledb/adk/store.py +2369 -0
- sqlspec/adapters/oracledb/config.py +550 -0
- sqlspec/adapters/oracledb/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/oracledb/core.py +543 -0
- sqlspec/adapters/oracledb/data_dictionary.py +536 -0
- sqlspec/adapters/oracledb/driver.py +1229 -0
- sqlspec/adapters/oracledb/events/__init__.py +16 -0
- sqlspec/adapters/oracledb/events/backend.py +347 -0
- sqlspec/adapters/oracledb/events/store.py +420 -0
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +781 -0
- sqlspec/adapters/oracledb/migrations.py +535 -0
- sqlspec/adapters/oracledb/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/oracledb/type_converter.py +211 -0
- sqlspec/adapters/psqlpy/__init__.py +17 -0
- sqlspec/adapters/psqlpy/_typing.py +79 -0
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +766 -0
- sqlspec/adapters/psqlpy/config.py +304 -0
- sqlspec/adapters/psqlpy/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psqlpy/core.py +480 -0
- sqlspec/adapters/psqlpy/data_dictionary.py +126 -0
- sqlspec/adapters/psqlpy/driver.py +438 -0
- sqlspec/adapters/psqlpy/events/__init__.py +6 -0
- sqlspec/adapters/psqlpy/events/backend.py +310 -0
- sqlspec/adapters/psqlpy/events/store.py +20 -0
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +270 -0
- sqlspec/adapters/psqlpy/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psqlpy/type_converter.py +113 -0
- sqlspec/adapters/psycopg/__init__.py +32 -0
- sqlspec/adapters/psycopg/_typing.py +164 -0
- sqlspec/adapters/psycopg/adk/__init__.py +10 -0
- sqlspec/adapters/psycopg/adk/store.py +1387 -0
- sqlspec/adapters/psycopg/config.py +576 -0
- sqlspec/adapters/psycopg/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psycopg/core.py +450 -0
- sqlspec/adapters/psycopg/data_dictionary.py +289 -0
- sqlspec/adapters/psycopg/driver.py +975 -0
- sqlspec/adapters/psycopg/events/__init__.py +20 -0
- sqlspec/adapters/psycopg/events/backend.py +458 -0
- sqlspec/adapters/psycopg/events/store.py +42 -0
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +552 -0
- sqlspec/adapters/psycopg/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/psycopg/type_converter.py +93 -0
- sqlspec/adapters/pymysql/__init__.py +21 -0
- sqlspec/adapters/pymysql/_typing.py +71 -0
- sqlspec/adapters/pymysql/adk/__init__.py +5 -0
- sqlspec/adapters/pymysql/adk/store.py +540 -0
- sqlspec/adapters/pymysql/config.py +195 -0
- sqlspec/adapters/pymysql/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/pymysql/core.py +299 -0
- sqlspec/adapters/pymysql/data_dictionary.py +122 -0
- sqlspec/adapters/pymysql/driver.py +259 -0
- sqlspec/adapters/pymysql/events/__init__.py +5 -0
- sqlspec/adapters/pymysql/events/store.py +50 -0
- sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
- sqlspec/adapters/pymysql/litestar/store.py +232 -0
- sqlspec/adapters/pymysql/pool.py +137 -0
- sqlspec/adapters/spanner/__init__.py +40 -0
- sqlspec/adapters/spanner/_typing.py +86 -0
- sqlspec/adapters/spanner/adk/__init__.py +5 -0
- sqlspec/adapters/spanner/adk/store.py +732 -0
- sqlspec/adapters/spanner/config.py +352 -0
- sqlspec/adapters/spanner/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/spanner/core.py +188 -0
- sqlspec/adapters/spanner/data_dictionary.py +120 -0
- sqlspec/adapters/spanner/dialect/__init__.py +6 -0
- sqlspec/adapters/spanner/dialect/_spangres.py +57 -0
- sqlspec/adapters/spanner/dialect/_spanner.py +130 -0
- sqlspec/adapters/spanner/driver.py +373 -0
- sqlspec/adapters/spanner/events/__init__.py +5 -0
- sqlspec/adapters/spanner/events/store.py +187 -0
- sqlspec/adapters/spanner/litestar/__init__.py +5 -0
- sqlspec/adapters/spanner/litestar/store.py +291 -0
- sqlspec/adapters/spanner/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/spanner/type_converter.py +331 -0
- sqlspec/adapters/sqlite/__init__.py +19 -0
- sqlspec/adapters/sqlite/_typing.py +80 -0
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +958 -0
- sqlspec/adapters/sqlite/config.py +280 -0
- sqlspec/adapters/sqlite/core.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/sqlite/core.py +312 -0
- sqlspec/adapters/sqlite/data_dictionary.py +202 -0
- sqlspec/adapters/sqlite/driver.py +359 -0
- sqlspec/adapters/sqlite/events/__init__.py +5 -0
- sqlspec/adapters/sqlite/events/store.py +20 -0
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +316 -0
- sqlspec/adapters/sqlite/pool.py +198 -0
- sqlspec/adapters/sqlite/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/adapters/sqlite/type_converter.py +114 -0
- sqlspec/base.py +747 -0
- sqlspec/builder/__init__.py +179 -0
- sqlspec/builder/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_base.py +1022 -0
- sqlspec/builder/_column.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_column.py +521 -0
- sqlspec/builder/_ddl.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_ddl.py +1642 -0
- sqlspec/builder/_delete.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_delete.py +95 -0
- sqlspec/builder/_dml.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_dml.py +365 -0
- sqlspec/builder/_explain.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_explain.py +579 -0
- sqlspec/builder/_expression_wrappers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_expression_wrappers.py +46 -0
- sqlspec/builder/_factory.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_factory.py +1697 -0
- sqlspec/builder/_insert.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_insert.py +328 -0
- sqlspec/builder/_join.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_join.py +499 -0
- sqlspec/builder/_merge.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_merge.py +821 -0
- sqlspec/builder/_parsing_utils.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_parsing_utils.py +297 -0
- sqlspec/builder/_select.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_select.py +1660 -0
- sqlspec/builder/_temporal.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_temporal.py +139 -0
- sqlspec/builder/_update.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/builder/_update.py +173 -0
- sqlspec/builder/_vector_expressions.py +267 -0
- sqlspec/cli.py +911 -0
- sqlspec/config.py +1755 -0
- sqlspec/core/__init__.py +374 -0
- sqlspec/core/_correlation.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/_correlation.py +176 -0
- sqlspec/core/cache.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/cache.py +1069 -0
- sqlspec/core/compiler.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/compiler.py +954 -0
- sqlspec/core/explain.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/explain.py +275 -0
- sqlspec/core/filters.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/filters.py +952 -0
- sqlspec/core/hashing.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/hashing.py +262 -0
- sqlspec/core/metrics.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/metrics.py +83 -0
- sqlspec/core/parameters/__init__.py +71 -0
- sqlspec/core/parameters/_alignment.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_alignment.py +270 -0
- sqlspec/core/parameters/_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_converter.py +543 -0
- sqlspec/core/parameters/_processor.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_processor.py +505 -0
- sqlspec/core/parameters/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_registry.py +206 -0
- sqlspec/core/parameters/_transformers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_transformers.py +292 -0
- sqlspec/core/parameters/_types.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_types.py +499 -0
- sqlspec/core/parameters/_validator.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters/_validator.py +180 -0
- sqlspec/core/pipeline.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/pipeline.py +319 -0
- sqlspec/core/query_modifiers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/query_modifiers.py +437 -0
- sqlspec/core/result/__init__.py +23 -0
- sqlspec/core/result/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result/_base.py +1121 -0
- sqlspec/core/result/_io.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result/_io.py +28 -0
- sqlspec/core/splitter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/splitter.py +966 -0
- sqlspec/core/stack.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/stack.py +163 -0
- sqlspec/core/statement.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/statement.py +1503 -0
- sqlspec/core/type_converter.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/core/type_converter.py +339 -0
- sqlspec/data_dictionary/__init__.py +22 -0
- sqlspec/data_dictionary/_loader.py +123 -0
- sqlspec/data_dictionary/_registry.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/_registry.py +74 -0
- sqlspec/data_dictionary/_types.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/_types.py +121 -0
- sqlspec/data_dictionary/dialects/__init__.py +21 -0
- sqlspec/data_dictionary/dialects/bigquery.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/bigquery.py +49 -0
- sqlspec/data_dictionary/dialects/cockroachdb.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/cockroachdb.py +43 -0
- sqlspec/data_dictionary/dialects/duckdb.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/duckdb.py +47 -0
- sqlspec/data_dictionary/dialects/mysql.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/mysql.py +42 -0
- sqlspec/data_dictionary/dialects/oracle.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/oracle.py +34 -0
- sqlspec/data_dictionary/dialects/postgres.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/postgres.py +46 -0
- sqlspec/data_dictionary/dialects/spanner.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/spanner.py +37 -0
- sqlspec/data_dictionary/dialects/sqlite.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/data_dictionary/dialects/sqlite.py +42 -0
- sqlspec/data_dictionary/sql/.gitkeep +0 -0
- sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
- sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
- sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
- sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
- sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
- sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
- sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
- sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
- sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
- sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
- sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
- sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
- sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
- sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
- sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
- sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
- sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
- sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
- sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
- sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
- sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
- sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
- sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
- sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
- sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
- sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
- sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
- sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
- sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
- sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
- sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
- sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
- sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
- sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
- sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
- sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
- sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
- sqlspec/driver/__init__.py +32 -0
- sqlspec/driver/_async.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_async.py +1737 -0
- sqlspec/driver/_common.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_common.py +1478 -0
- sqlspec/driver/_sql_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_sql_helpers.py +148 -0
- sqlspec/driver/_storage_helpers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_storage_helpers.py +144 -0
- sqlspec/driver/_sync.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/driver/_sync.py +1710 -0
- sqlspec/exceptions.py +338 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/adk/__init__.py +70 -0
- sqlspec/extensions/adk/_types.py +51 -0
- sqlspec/extensions/adk/converters.py +172 -0
- sqlspec/extensions/adk/memory/__init__.py +69 -0
- sqlspec/extensions/adk/memory/_types.py +30 -0
- sqlspec/extensions/adk/memory/converters.py +149 -0
- sqlspec/extensions/adk/memory/service.py +217 -0
- sqlspec/extensions/adk/memory/store.py +569 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +246 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +225 -0
- sqlspec/extensions/adk/store.py +567 -0
- sqlspec/extensions/events/__init__.py +51 -0
- sqlspec/extensions/events/_channel.py +703 -0
- sqlspec/extensions/events/_hints.py +45 -0
- sqlspec/extensions/events/_models.py +23 -0
- sqlspec/extensions/events/_payload.py +69 -0
- sqlspec/extensions/events/_protocols.py +134 -0
- sqlspec/extensions/events/_queue.py +461 -0
- sqlspec/extensions/events/_store.py +209 -0
- sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
- sqlspec/extensions/events/migrations/__init__.py +3 -0
- sqlspec/extensions/fastapi/__init__.py +19 -0
- sqlspec/extensions/fastapi/extension.py +351 -0
- sqlspec/extensions/fastapi/providers.py +607 -0
- sqlspec/extensions/flask/__init__.py +37 -0
- sqlspec/extensions/flask/_state.py +76 -0
- sqlspec/extensions/flask/_utils.py +71 -0
- sqlspec/extensions/flask/extension.py +519 -0
- sqlspec/extensions/litestar/__init__.py +28 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/channels.py +165 -0
- sqlspec/extensions/litestar/cli.py +102 -0
- sqlspec/extensions/litestar/config.py +90 -0
- sqlspec/extensions/litestar/handlers.py +316 -0
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +671 -0
- sqlspec/extensions/litestar/providers.py +526 -0
- sqlspec/extensions/litestar/store.py +296 -0
- sqlspec/extensions/otel/__init__.py +58 -0
- sqlspec/extensions/prometheus/__init__.py +113 -0
- sqlspec/extensions/starlette/__init__.py +19 -0
- sqlspec/extensions/starlette/_state.py +30 -0
- sqlspec/extensions/starlette/_utils.py +96 -0
- sqlspec/extensions/starlette/extension.py +346 -0
- sqlspec/extensions/starlette/middleware.py +235 -0
- sqlspec/loader.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/loader.py +702 -0
- sqlspec/migrations/__init__.py +36 -0
- sqlspec/migrations/base.py +731 -0
- sqlspec/migrations/commands.py +1232 -0
- sqlspec/migrations/context.py +157 -0
- sqlspec/migrations/fix.py +204 -0
- sqlspec/migrations/loaders.py +443 -0
- sqlspec/migrations/runner.py +1172 -0
- sqlspec/migrations/templates.py +234 -0
- sqlspec/migrations/tracker.py +611 -0
- sqlspec/migrations/utils.py +256 -0
- sqlspec/migrations/validation.py +207 -0
- sqlspec/migrations/version.py +446 -0
- sqlspec/observability/__init__.py +55 -0
- sqlspec/observability/_common.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_common.py +77 -0
- sqlspec/observability/_config.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_config.py +348 -0
- sqlspec/observability/_diagnostics.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_diagnostics.py +74 -0
- sqlspec/observability/_dispatcher.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_dispatcher.py +152 -0
- sqlspec/observability/_formatters/__init__.py +13 -0
- sqlspec/observability/_formatters/_aws.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_aws.py +102 -0
- sqlspec/observability/_formatters/_azure.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_azure.py +96 -0
- sqlspec/observability/_formatters/_base.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_base.py +57 -0
- sqlspec/observability/_formatters/_gcp.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_formatters/_gcp.py +131 -0
- sqlspec/observability/_formatting.py +58 -0
- sqlspec/observability/_observer.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_observer.py +357 -0
- sqlspec/observability/_runtime.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_runtime.py +420 -0
- sqlspec/observability/_sampling.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_sampling.py +188 -0
- sqlspec/observability/_spans.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/observability/_spans.py +161 -0
- sqlspec/protocols.py +916 -0
- sqlspec/py.typed +0 -0
- sqlspec/storage/__init__.py +48 -0
- sqlspec/storage/_utils.py +104 -0
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/base.py +253 -0
- sqlspec/storage/backends/fsspec.py +529 -0
- sqlspec/storage/backends/local.py +441 -0
- sqlspec/storage/backends/obstore.py +916 -0
- sqlspec/storage/errors.py +104 -0
- sqlspec/storage/pipeline.py +582 -0
- sqlspec/storage/registry.py +301 -0
- sqlspec/typing.py +395 -0
- sqlspec/utils/__init__.py +7 -0
- sqlspec/utils/arrow_helpers.py +318 -0
- sqlspec/utils/config_tools.py +332 -0
- sqlspec/utils/correlation.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/correlation.py +134 -0
- sqlspec/utils/deprecation.py +190 -0
- sqlspec/utils/fixtures.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/fixtures.py +258 -0
- sqlspec/utils/logging.py +222 -0
- sqlspec/utils/module_loader.py +306 -0
- sqlspec/utils/portal.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/portal.py +375 -0
- sqlspec/utils/schema.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/schema.py +485 -0
- sqlspec/utils/serializers.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/serializers.py +408 -0
- sqlspec/utils/singleton.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/singleton.py +41 -0
- sqlspec/utils/sync_tools.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/sync_tools.py +311 -0
- sqlspec/utils/text.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/text.py +108 -0
- sqlspec/utils/type_converters.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_converters.py +128 -0
- sqlspec/utils/type_guards.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_guards.py +1360 -0
- sqlspec/utils/uuids.cpython-310-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/uuids.py +225 -0
- sqlspec-0.36.0.dist-info/METADATA +205 -0
- sqlspec-0.36.0.dist-info/RECORD +531 -0
- sqlspec-0.36.0.dist-info/WHEEL +7 -0
- sqlspec-0.36.0.dist-info/entry_points.txt +2 -0
- sqlspec-0.36.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"""PyMySQL MySQL driver implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Final, cast
|
|
4
|
+
|
|
5
|
+
import pymysql
|
|
6
|
+
from pymysql.constants import FIELD_TYPE
|
|
7
|
+
|
|
8
|
+
from sqlspec.adapters.pymysql.core import (
|
|
9
|
+
build_insert_statement,
|
|
10
|
+
collect_rows,
|
|
11
|
+
create_mapped_exception,
|
|
12
|
+
default_statement_config,
|
|
13
|
+
detect_json_columns,
|
|
14
|
+
driver_profile,
|
|
15
|
+
format_identifier,
|
|
16
|
+
normalize_execute_many_parameters,
|
|
17
|
+
normalize_execute_parameters,
|
|
18
|
+
normalize_lastrowid,
|
|
19
|
+
resolve_rowcount,
|
|
20
|
+
)
|
|
21
|
+
from sqlspec.adapters.pymysql.data_dictionary import PyMysqlDataDictionary
|
|
22
|
+
from sqlspec.core import ArrowResult, get_cache_config, register_driver_profile
|
|
23
|
+
from sqlspec.driver import SyncDriverAdapterBase
|
|
24
|
+
from sqlspec.exceptions import SQLSpecError
|
|
25
|
+
from sqlspec.utils.logging import get_logger
|
|
26
|
+
from sqlspec.utils.serializers import from_json
|
|
27
|
+
from sqlspec.utils.type_guards import supports_json_type
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
from collections.abc import Callable
|
|
31
|
+
|
|
32
|
+
from sqlspec.adapters.pymysql._typing import PyMysqlConnection
|
|
33
|
+
from sqlspec.core import SQL, StatementConfig
|
|
34
|
+
from sqlspec.driver import ExecutionResult
|
|
35
|
+
from sqlspec.storage import StorageBridgeJob, StorageDestination, StorageFormat, StorageTelemetry
|
|
36
|
+
|
|
37
|
+
from sqlspec.adapters.pymysql._typing import PyMysqlSessionContext
|
|
38
|
+
|
|
39
|
+
__all__ = ("PyMysqlCursor", "PyMysqlDriver", "PyMysqlExceptionHandler", "PyMysqlSessionContext")
|
|
40
|
+
|
|
41
|
+
logger = get_logger("sqlspec.adapters.pymysql")
|
|
42
|
+
|
|
43
|
+
json_type_value = FIELD_TYPE.JSON if supports_json_type(FIELD_TYPE) else None
|
|
44
|
+
PYMYSQL_JSON_TYPE_CODES: Final[set[int]] = {json_type_value} if json_type_value is not None else set()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PyMysqlCursor:
|
|
48
|
+
"""Context manager for PyMySQL cursor operations."""
|
|
49
|
+
|
|
50
|
+
__slots__ = ("connection", "cursor")
|
|
51
|
+
|
|
52
|
+
def __init__(self, connection: "PyMysqlConnection") -> None:
|
|
53
|
+
self.connection = connection
|
|
54
|
+
self.cursor: Any | None = None
|
|
55
|
+
|
|
56
|
+
def __enter__(self) -> Any:
|
|
57
|
+
self.cursor = self.connection.cursor(pymysql.cursors.DictCursor)
|
|
58
|
+
return self.cursor
|
|
59
|
+
|
|
60
|
+
def __exit__(self, *_: Any) -> None:
|
|
61
|
+
if self.cursor is not None:
|
|
62
|
+
self.cursor.close()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class PyMysqlExceptionHandler:
|
|
66
|
+
"""Context manager for handling PyMySQL exceptions."""
|
|
67
|
+
|
|
68
|
+
__slots__ = ("pending_exception",)
|
|
69
|
+
|
|
70
|
+
def __init__(self) -> None:
|
|
71
|
+
self.pending_exception: Exception | None = None
|
|
72
|
+
|
|
73
|
+
def __enter__(self) -> "PyMysqlExceptionHandler":
|
|
74
|
+
return self
|
|
75
|
+
|
|
76
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> bool:
|
|
77
|
+
if exc_type is None:
|
|
78
|
+
return False
|
|
79
|
+
if issubclass(exc_type, pymysql.MySQLError):
|
|
80
|
+
result = create_mapped_exception(exc_val, logger=logger)
|
|
81
|
+
if result is True:
|
|
82
|
+
return True
|
|
83
|
+
self.pending_exception = cast("Exception", result)
|
|
84
|
+
return True
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class PyMysqlDriver(SyncDriverAdapterBase):
|
|
89
|
+
"""MySQL/MariaDB database driver using PyMySQL."""
|
|
90
|
+
|
|
91
|
+
__slots__ = ("_data_dictionary",)
|
|
92
|
+
dialect = "mysql"
|
|
93
|
+
|
|
94
|
+
def __init__(
|
|
95
|
+
self,
|
|
96
|
+
connection: "PyMysqlConnection",
|
|
97
|
+
statement_config: "StatementConfig | None" = None,
|
|
98
|
+
driver_features: "dict[str, Any] | None" = None,
|
|
99
|
+
) -> None:
|
|
100
|
+
if statement_config is None:
|
|
101
|
+
statement_config = default_statement_config.replace(
|
|
102
|
+
enable_caching=get_cache_config().compiled_cache_enabled
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
|
|
106
|
+
self._data_dictionary: PyMysqlDataDictionary | None = None
|
|
107
|
+
|
|
108
|
+
def dispatch_execute(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
|
|
109
|
+
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
110
|
+
cursor.execute(sql, normalize_execute_parameters(prepared_parameters))
|
|
111
|
+
|
|
112
|
+
if statement.returns_rows():
|
|
113
|
+
fetched_data = cursor.fetchall()
|
|
114
|
+
fetched_rows = list(fetched_data) if fetched_data else None
|
|
115
|
+
description = list(cursor.description) if cursor.description else None
|
|
116
|
+
json_indexes = detect_json_columns(cursor, PYMYSQL_JSON_TYPE_CODES)
|
|
117
|
+
deserializer = cast("Callable[[Any], Any]", self.driver_features.get("json_deserializer", from_json))
|
|
118
|
+
rows, column_names = collect_rows(fetched_rows, description, json_indexes, deserializer, logger=logger)
|
|
119
|
+
|
|
120
|
+
return self.create_execution_result(
|
|
121
|
+
cursor, selected_data=rows, column_names=column_names, data_row_count=len(rows), is_select_result=True
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
affected_rows = resolve_rowcount(cursor)
|
|
125
|
+
last_id = normalize_lastrowid(cursor)
|
|
126
|
+
return self.create_execution_result(cursor, rowcount_override=affected_rows, last_inserted_id=last_id)
|
|
127
|
+
|
|
128
|
+
def dispatch_execute_many(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
|
|
129
|
+
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
130
|
+
|
|
131
|
+
prepared_parameters = normalize_execute_many_parameters(prepared_parameters)
|
|
132
|
+
cursor.executemany(sql, prepared_parameters)
|
|
133
|
+
|
|
134
|
+
affected_rows = len(prepared_parameters)
|
|
135
|
+
return self.create_execution_result(cursor, rowcount_override=affected_rows, is_many_result=True)
|
|
136
|
+
|
|
137
|
+
def dispatch_execute_script(self, cursor: Any, statement: "SQL") -> "ExecutionResult":
|
|
138
|
+
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
139
|
+
statements = self.split_script_statements(sql, statement.statement_config, strip_trailing_semicolon=True)
|
|
140
|
+
|
|
141
|
+
successful_count = 0
|
|
142
|
+
last_cursor = cursor
|
|
143
|
+
|
|
144
|
+
for stmt in statements:
|
|
145
|
+
cursor.execute(stmt, normalize_execute_parameters(prepared_parameters))
|
|
146
|
+
successful_count += 1
|
|
147
|
+
|
|
148
|
+
return self.create_execution_result(
|
|
149
|
+
last_cursor, statement_count=len(statements), successful_statements=successful_count, is_script_result=True
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def begin(self) -> None:
|
|
153
|
+
try:
|
|
154
|
+
with PyMysqlCursor(self.connection) as cursor:
|
|
155
|
+
cursor.execute("BEGIN")
|
|
156
|
+
except pymysql.MySQLError as exc:
|
|
157
|
+
msg = f"Failed to begin MySQL transaction: {exc}"
|
|
158
|
+
raise SQLSpecError(msg) from exc
|
|
159
|
+
|
|
160
|
+
def commit(self) -> None:
|
|
161
|
+
try:
|
|
162
|
+
self.connection.commit()
|
|
163
|
+
except pymysql.MySQLError as exc:
|
|
164
|
+
msg = f"Failed to commit MySQL transaction: {exc}"
|
|
165
|
+
raise SQLSpecError(msg) from exc
|
|
166
|
+
|
|
167
|
+
def rollback(self) -> None:
|
|
168
|
+
try:
|
|
169
|
+
self.connection.rollback()
|
|
170
|
+
except pymysql.MySQLError as exc:
|
|
171
|
+
msg = f"Failed to rollback MySQL transaction: {exc}"
|
|
172
|
+
raise SQLSpecError(msg) from exc
|
|
173
|
+
|
|
174
|
+
def with_cursor(self, connection: "PyMysqlConnection") -> "PyMysqlCursor":
|
|
175
|
+
return PyMysqlCursor(connection)
|
|
176
|
+
|
|
177
|
+
def handle_database_exceptions(self) -> "PyMysqlExceptionHandler":
|
|
178
|
+
return PyMysqlExceptionHandler()
|
|
179
|
+
|
|
180
|
+
def select_to_storage(
|
|
181
|
+
self,
|
|
182
|
+
statement: "SQL | str",
|
|
183
|
+
destination: "StorageDestination",
|
|
184
|
+
/,
|
|
185
|
+
*parameters: Any,
|
|
186
|
+
statement_config: "StatementConfig | None" = None,
|
|
187
|
+
partitioner: "dict[str, object] | None" = None,
|
|
188
|
+
format_hint: "StorageFormat | None" = None,
|
|
189
|
+
telemetry: "StorageTelemetry | None" = None,
|
|
190
|
+
**kwargs: Any,
|
|
191
|
+
) -> "StorageBridgeJob":
|
|
192
|
+
self._require_capability("arrow_export_enabled")
|
|
193
|
+
arrow_result = self.select_to_arrow(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
194
|
+
pipeline = self._storage_pipeline()
|
|
195
|
+
telemetry_payload = self._write_result_to_storage_sync(
|
|
196
|
+
arrow_result, destination, format_hint=format_hint, pipeline=pipeline
|
|
197
|
+
)
|
|
198
|
+
self._attach_partition_telemetry(telemetry_payload, partitioner)
|
|
199
|
+
return self._create_storage_job(telemetry_payload, telemetry)
|
|
200
|
+
|
|
201
|
+
def load_from_arrow(
|
|
202
|
+
self,
|
|
203
|
+
table: str,
|
|
204
|
+
source: "ArrowResult | Any",
|
|
205
|
+
*,
|
|
206
|
+
partitioner: "dict[str, object] | None" = None,
|
|
207
|
+
overwrite: bool = False,
|
|
208
|
+
telemetry: "StorageTelemetry | None" = None,
|
|
209
|
+
) -> "StorageBridgeJob":
|
|
210
|
+
self._require_capability("arrow_import_enabled")
|
|
211
|
+
arrow_table = self._coerce_arrow_table(source)
|
|
212
|
+
if overwrite:
|
|
213
|
+
statement = f"TRUNCATE TABLE {format_identifier(table)}"
|
|
214
|
+
with self.handle_database_exceptions(), self.with_cursor(self.connection) as cursor:
|
|
215
|
+
cursor.execute(statement)
|
|
216
|
+
|
|
217
|
+
columns, records = self._arrow_table_to_rows(arrow_table)
|
|
218
|
+
if records:
|
|
219
|
+
insert_sql = build_insert_statement(table, columns)
|
|
220
|
+
with self.handle_database_exceptions(), self.with_cursor(self.connection) as cursor:
|
|
221
|
+
cursor.executemany(insert_sql, records)
|
|
222
|
+
|
|
223
|
+
telemetry_payload = self._build_ingest_telemetry(arrow_table)
|
|
224
|
+
telemetry_payload["destination"] = table
|
|
225
|
+
self._attach_partition_telemetry(telemetry_payload, partitioner)
|
|
226
|
+
return self._create_storage_job(telemetry_payload, telemetry)
|
|
227
|
+
|
|
228
|
+
def load_from_storage(
|
|
229
|
+
self,
|
|
230
|
+
table: str,
|
|
231
|
+
source: "StorageDestination",
|
|
232
|
+
*,
|
|
233
|
+
file_format: "StorageFormat",
|
|
234
|
+
partitioner: "dict[str, object] | None" = None,
|
|
235
|
+
overwrite: bool = False,
|
|
236
|
+
) -> "StorageBridgeJob":
|
|
237
|
+
arrow_table, inbound = self._read_arrow_from_storage_sync(source, file_format=file_format)
|
|
238
|
+
return self.load_from_arrow(table, arrow_table, partitioner=partitioner, overwrite=overwrite, telemetry=inbound)
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def data_dictionary(self) -> "PyMysqlDataDictionary":
|
|
242
|
+
if self._data_dictionary is None:
|
|
243
|
+
self._data_dictionary = PyMysqlDataDictionary()
|
|
244
|
+
return self._data_dictionary
|
|
245
|
+
|
|
246
|
+
def _connection_in_transaction(self) -> bool:
|
|
247
|
+
get_autocommit = getattr(self.connection, "get_autocommit", None)
|
|
248
|
+
if callable(get_autocommit):
|
|
249
|
+
return not bool(get_autocommit())
|
|
250
|
+
autocommit = getattr(self.connection, "autocommit", None)
|
|
251
|
+
if autocommit is not None:
|
|
252
|
+
try:
|
|
253
|
+
return not bool(autocommit)
|
|
254
|
+
except Exception:
|
|
255
|
+
return False
|
|
256
|
+
return False
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
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)()
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""PyMySQL database configuration with thread-local connections."""
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import threading
|
|
5
|
+
import time
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from typing import TYPE_CHECKING, Any, TypedDict, cast
|
|
8
|
+
|
|
9
|
+
import pymysql
|
|
10
|
+
from typing_extensions import NotRequired
|
|
11
|
+
|
|
12
|
+
from sqlspec.adapters.pymysql._typing import PyMysqlConnection
|
|
13
|
+
from sqlspec.utils.logging import get_logger
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from collections.abc import Generator
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PyMysqlConnectionParams(TypedDict):
|
|
20
|
+
"""PyMySQL connection parameters."""
|
|
21
|
+
|
|
22
|
+
host: NotRequired[str]
|
|
23
|
+
user: NotRequired[str]
|
|
24
|
+
password: NotRequired[str]
|
|
25
|
+
database: NotRequired[str]
|
|
26
|
+
port: NotRequired[int]
|
|
27
|
+
unix_socket: NotRequired[str]
|
|
28
|
+
charset: NotRequired[str]
|
|
29
|
+
connect_timeout: NotRequired[int]
|
|
30
|
+
read_timeout: NotRequired[int]
|
|
31
|
+
write_timeout: NotRequired[int]
|
|
32
|
+
autocommit: NotRequired[bool]
|
|
33
|
+
ssl: NotRequired["dict[str, Any]"]
|
|
34
|
+
client_flag: NotRequired[int]
|
|
35
|
+
cursorclass: NotRequired[type]
|
|
36
|
+
init_command: NotRequired[str]
|
|
37
|
+
sql_mode: NotRequired[str]
|
|
38
|
+
extra: NotRequired["dict[str, Any]"]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
__all__ = ("PyMysqlConnectionPool",)
|
|
42
|
+
|
|
43
|
+
logger = get_logger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class PyMysqlConnectionPool:
|
|
47
|
+
"""Thread-local connection manager for PyMySQL."""
|
|
48
|
+
|
|
49
|
+
__slots__ = ("_connection_parameters", "_health_check_interval", "_recycle_seconds", "_thread_local")
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self, connection_parameters: "dict[str, Any]", recycle_seconds: int = 86400, health_check_interval: float = 30.0
|
|
53
|
+
) -> None:
|
|
54
|
+
self._connection_parameters = connection_parameters
|
|
55
|
+
self._thread_local = threading.local()
|
|
56
|
+
self._recycle_seconds = recycle_seconds
|
|
57
|
+
self._health_check_interval = health_check_interval
|
|
58
|
+
|
|
59
|
+
def _create_connection(self) -> PyMysqlConnection:
|
|
60
|
+
connection = pymysql.connect(**self._connection_parameters)
|
|
61
|
+
return cast("PyMysqlConnection", connection)
|
|
62
|
+
|
|
63
|
+
def _is_connection_alive(self, connection: PyMysqlConnection) -> bool:
|
|
64
|
+
try:
|
|
65
|
+
connection.ping(reconnect=False)
|
|
66
|
+
except Exception:
|
|
67
|
+
return False
|
|
68
|
+
return True
|
|
69
|
+
|
|
70
|
+
def _get_thread_connection(self) -> PyMysqlConnection:
|
|
71
|
+
thread_state = self._thread_local.__dict__
|
|
72
|
+
if "connection" not in thread_state:
|
|
73
|
+
self._thread_local.connection = self._create_connection()
|
|
74
|
+
self._thread_local.created_at = time.time()
|
|
75
|
+
self._thread_local.last_used = time.time()
|
|
76
|
+
return cast("PyMysqlConnection", self._thread_local.connection)
|
|
77
|
+
|
|
78
|
+
if self._recycle_seconds > 0 and time.time() - self._thread_local.created_at > self._recycle_seconds:
|
|
79
|
+
logger.debug("PyMySQL connection exceeded recycle time, recreating")
|
|
80
|
+
with contextlib.suppress(Exception):
|
|
81
|
+
self._thread_local.connection.close()
|
|
82
|
+
self._thread_local.connection = self._create_connection()
|
|
83
|
+
self._thread_local.created_at = time.time()
|
|
84
|
+
self._thread_local.last_used = time.time()
|
|
85
|
+
return cast("PyMysqlConnection", self._thread_local.connection)
|
|
86
|
+
|
|
87
|
+
idle_time = time.time() - thread_state.get("last_used", 0)
|
|
88
|
+
if idle_time > self._health_check_interval and not self._is_connection_alive(self._thread_local.connection):
|
|
89
|
+
logger.debug("PyMySQL connection failed health check after %.1fs idle, recreating", idle_time)
|
|
90
|
+
with contextlib.suppress(Exception):
|
|
91
|
+
self._thread_local.connection.close()
|
|
92
|
+
self._thread_local.connection = self._create_connection()
|
|
93
|
+
self._thread_local.created_at = time.time()
|
|
94
|
+
|
|
95
|
+
self._thread_local.last_used = time.time()
|
|
96
|
+
return cast("PyMysqlConnection", self._thread_local.connection)
|
|
97
|
+
|
|
98
|
+
def _close_thread_connection(self) -> None:
|
|
99
|
+
thread_state = self._thread_local.__dict__
|
|
100
|
+
if "connection" in thread_state:
|
|
101
|
+
with contextlib.suppress(Exception):
|
|
102
|
+
self._thread_local.connection.close()
|
|
103
|
+
del self._thread_local.connection
|
|
104
|
+
if "created_at" in thread_state:
|
|
105
|
+
del self._thread_local.created_at
|
|
106
|
+
if "last_used" in thread_state:
|
|
107
|
+
del self._thread_local.last_used
|
|
108
|
+
|
|
109
|
+
@contextmanager
|
|
110
|
+
def get_connection(self) -> "Generator[PyMysqlConnection, None, None]":
|
|
111
|
+
connection = self._get_thread_connection()
|
|
112
|
+
try:
|
|
113
|
+
yield connection
|
|
114
|
+
finally:
|
|
115
|
+
with contextlib.suppress(Exception):
|
|
116
|
+
if connection.open and connection.get_autocommit() is False:
|
|
117
|
+
connection.commit()
|
|
118
|
+
|
|
119
|
+
def close(self) -> None:
|
|
120
|
+
self._close_thread_connection()
|
|
121
|
+
|
|
122
|
+
def acquire(self) -> PyMysqlConnection:
|
|
123
|
+
return self._get_thread_connection()
|
|
124
|
+
|
|
125
|
+
def release(self, connection: PyMysqlConnection) -> None:
|
|
126
|
+
_ = connection
|
|
127
|
+
|
|
128
|
+
def size(self) -> int:
|
|
129
|
+
try:
|
|
130
|
+
_ = self._thread_local.connection
|
|
131
|
+
except AttributeError:
|
|
132
|
+
return 0
|
|
133
|
+
else:
|
|
134
|
+
return 1
|
|
135
|
+
|
|
136
|
+
def checked_out(self) -> int:
|
|
137
|
+
return 0
|