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,552 @@
|
|
|
1
|
+
"""Psycopg session stores for Litestar integration.
|
|
2
|
+
|
|
3
|
+
Provides both async and sync PostgreSQL session stores using psycopg3.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from datetime import datetime, timedelta, timezone
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from sqlspec.extensions.litestar.store import BaseSQLSpecStore
|
|
10
|
+
from sqlspec.utils.sync_tools import async_
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from sqlspec.adapters.psycopg.config import PsycopgAsyncConfig, PsycopgSyncConfig
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = ("PsycopgAsyncStore", "PsycopgSyncStore")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PsycopgAsyncStore(BaseSQLSpecStore["PsycopgAsyncConfig"]):
|
|
20
|
+
"""PostgreSQL session store using Psycopg async driver.
|
|
21
|
+
|
|
22
|
+
Implements server-side session storage for Litestar using PostgreSQL
|
|
23
|
+
via the Psycopg (psycopg3) async driver. Provides efficient session
|
|
24
|
+
management with:
|
|
25
|
+
- Native async PostgreSQL operations
|
|
26
|
+
- UPSERT support using ON CONFLICT
|
|
27
|
+
- Automatic expiration handling
|
|
28
|
+
- Efficient cleanup of expired sessions
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
config: PsycopgAsyncConfig instance.
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
from sqlspec.adapters.psycopg import PsycopgAsyncConfig
|
|
35
|
+
from sqlspec.adapters.psycopg.litestar.store import PsycopgAsyncStore
|
|
36
|
+
|
|
37
|
+
config = PsycopgAsyncConfig(connection_config={"conninfo": "postgresql://..."})
|
|
38
|
+
store = PsycopgAsyncStore(config)
|
|
39
|
+
await store.create_table()
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
__slots__ = ()
|
|
43
|
+
|
|
44
|
+
def __init__(self, config: "PsycopgAsyncConfig") -> None:
|
|
45
|
+
"""Initialize Psycopg async session store.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
config: PsycopgAsyncConfig instance.
|
|
49
|
+
|
|
50
|
+
Notes:
|
|
51
|
+
Table name is read from config.extension_config["litestar"]["session_table"].
|
|
52
|
+
"""
|
|
53
|
+
super().__init__(config)
|
|
54
|
+
|
|
55
|
+
def _get_create_table_sql(self) -> str:
|
|
56
|
+
"""Get PostgreSQL CREATE TABLE SQL with optimized schema.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
SQL statement to create the sessions table with proper indexes.
|
|
60
|
+
|
|
61
|
+
Notes:
|
|
62
|
+
- Uses TIMESTAMPTZ for timezone-aware expiration timestamps
|
|
63
|
+
- Partial index WHERE expires_at IS NOT NULL reduces index size/maintenance
|
|
64
|
+
- FILLFACTOR 80 leaves space for HOT updates, reducing table bloat
|
|
65
|
+
- Audit columns (created_at, updated_at) help with debugging
|
|
66
|
+
- Table name is internally controlled, not user input (S608 suppressed)
|
|
67
|
+
"""
|
|
68
|
+
return f"""
|
|
69
|
+
CREATE TABLE IF NOT EXISTS {self._table_name} (
|
|
70
|
+
session_id TEXT PRIMARY KEY,
|
|
71
|
+
data BYTEA NOT NULL,
|
|
72
|
+
expires_at TIMESTAMPTZ,
|
|
73
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
74
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
75
|
+
) WITH (fillfactor = 80);
|
|
76
|
+
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_{self._table_name}_expires_at
|
|
78
|
+
ON {self._table_name}(expires_at) WHERE expires_at IS NOT NULL;
|
|
79
|
+
|
|
80
|
+
ALTER TABLE {self._table_name} SET (
|
|
81
|
+
autovacuum_vacuum_scale_factor = 0.05,
|
|
82
|
+
autovacuum_analyze_scale_factor = 0.02
|
|
83
|
+
);
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
def _get_drop_table_sql(self) -> "list[str]":
|
|
87
|
+
"""Get PostgreSQL DROP TABLE SQL statements.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
List of SQL statements to drop indexes and table.
|
|
91
|
+
"""
|
|
92
|
+
return [f"DROP INDEX IF EXISTS idx_{self._table_name}_expires_at", f"DROP TABLE IF EXISTS {self._table_name}"]
|
|
93
|
+
|
|
94
|
+
async def create_table(self) -> None:
|
|
95
|
+
"""Create the session table if it doesn't exist."""
|
|
96
|
+
sql = self._get_create_table_sql()
|
|
97
|
+
async with self._config.provide_session() as driver:
|
|
98
|
+
await driver.execute_script(sql)
|
|
99
|
+
await driver.commit()
|
|
100
|
+
self._log_table_created()
|
|
101
|
+
|
|
102
|
+
async def get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
103
|
+
"""Get a session value by key.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
key: Session ID to retrieve.
|
|
107
|
+
renew_for: If given, renew the expiry time for this duration.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Session data as bytes if found and not expired, None otherwise.
|
|
111
|
+
|
|
112
|
+
Notes:
|
|
113
|
+
Uses CURRENT_TIMESTAMP instead of NOW() for SQL standard compliance.
|
|
114
|
+
The query planner can use the partial index for expires_at > CURRENT_TIMESTAMP.
|
|
115
|
+
"""
|
|
116
|
+
sql = f"""
|
|
117
|
+
SELECT data, expires_at FROM {self._table_name}
|
|
118
|
+
WHERE session_id = %s
|
|
119
|
+
AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
conn_context = self._config.provide_connection()
|
|
123
|
+
async with conn_context as conn:
|
|
124
|
+
async with conn.cursor() as cur:
|
|
125
|
+
await cur.execute(sql.encode(), (key,))
|
|
126
|
+
row = await cur.fetchone()
|
|
127
|
+
|
|
128
|
+
if row is None:
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
if renew_for is not None and row["expires_at"] is not None:
|
|
132
|
+
new_expires_at = self._calculate_expires_at(renew_for)
|
|
133
|
+
if new_expires_at is not None:
|
|
134
|
+
update_sql = f"""
|
|
135
|
+
UPDATE {self._table_name}
|
|
136
|
+
SET expires_at = %s, updated_at = CURRENT_TIMESTAMP
|
|
137
|
+
WHERE session_id = %s
|
|
138
|
+
"""
|
|
139
|
+
await conn.execute(update_sql.encode(), (new_expires_at, key))
|
|
140
|
+
await conn.commit()
|
|
141
|
+
|
|
142
|
+
return bytes(row["data"])
|
|
143
|
+
|
|
144
|
+
async def set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
145
|
+
"""Store a session value.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
key: Session ID.
|
|
149
|
+
value: Session data.
|
|
150
|
+
expires_in: Time until expiration.
|
|
151
|
+
|
|
152
|
+
Notes:
|
|
153
|
+
Uses EXCLUDED to reference the proposed insert values in ON CONFLICT.
|
|
154
|
+
Updates updated_at timestamp on every write for audit trail.
|
|
155
|
+
"""
|
|
156
|
+
data = self._value_to_bytes(value)
|
|
157
|
+
expires_at = self._calculate_expires_at(expires_in)
|
|
158
|
+
|
|
159
|
+
sql = f"""
|
|
160
|
+
INSERT INTO {self._table_name} (session_id, data, expires_at)
|
|
161
|
+
VALUES (%s, %s, %s)
|
|
162
|
+
ON CONFLICT (session_id)
|
|
163
|
+
DO UPDATE SET
|
|
164
|
+
data = EXCLUDED.data,
|
|
165
|
+
expires_at = EXCLUDED.expires_at,
|
|
166
|
+
updated_at = CURRENT_TIMESTAMP
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
conn_context = self._config.provide_connection()
|
|
170
|
+
async with conn_context as conn:
|
|
171
|
+
await conn.execute(sql.encode(), (key, data, expires_at))
|
|
172
|
+
await conn.commit()
|
|
173
|
+
|
|
174
|
+
async def delete(self, key: str) -> None:
|
|
175
|
+
"""Delete a session by key.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
key: Session ID to delete.
|
|
179
|
+
"""
|
|
180
|
+
sql = f"DELETE FROM {self._table_name} WHERE session_id = %s"
|
|
181
|
+
|
|
182
|
+
conn_context = self._config.provide_connection()
|
|
183
|
+
async with conn_context as conn:
|
|
184
|
+
await conn.execute(sql.encode(), (key,))
|
|
185
|
+
await conn.commit()
|
|
186
|
+
|
|
187
|
+
async def delete_all(self) -> None:
|
|
188
|
+
"""Delete all sessions from the store."""
|
|
189
|
+
sql = f"DELETE FROM {self._table_name}"
|
|
190
|
+
|
|
191
|
+
conn_context = self._config.provide_connection()
|
|
192
|
+
async with conn_context as conn:
|
|
193
|
+
await conn.execute(sql.encode())
|
|
194
|
+
await conn.commit()
|
|
195
|
+
self._log_delete_all()
|
|
196
|
+
|
|
197
|
+
async def exists(self, key: str) -> bool:
|
|
198
|
+
"""Check if a session key exists and is not expired.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
key: Session ID to check.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
True if the session exists and is not expired.
|
|
205
|
+
|
|
206
|
+
Notes:
|
|
207
|
+
Uses CURRENT_TIMESTAMP for consistency with get() method.
|
|
208
|
+
"""
|
|
209
|
+
sql = f"""
|
|
210
|
+
SELECT 1 FROM {self._table_name}
|
|
211
|
+
WHERE session_id = %s
|
|
212
|
+
AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
conn_context = self._config.provide_connection()
|
|
216
|
+
async with conn_context as conn, conn.cursor() as cur:
|
|
217
|
+
await cur.execute(sql.encode(), (key,))
|
|
218
|
+
result = await cur.fetchone()
|
|
219
|
+
return result is not None
|
|
220
|
+
|
|
221
|
+
async def expires_in(self, key: str) -> "int | None":
|
|
222
|
+
"""Get the time in seconds until the session expires.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
key: Session ID to check.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
Seconds until expiration, or None if no expiry or key doesn't exist.
|
|
229
|
+
"""
|
|
230
|
+
sql = f"""
|
|
231
|
+
SELECT expires_at FROM {self._table_name}
|
|
232
|
+
WHERE session_id = %s
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
conn_context = self._config.provide_connection()
|
|
236
|
+
async with conn_context as conn:
|
|
237
|
+
async with conn.cursor() as cur:
|
|
238
|
+
await cur.execute(sql.encode(), (key,))
|
|
239
|
+
row = await cur.fetchone()
|
|
240
|
+
|
|
241
|
+
if row is None or row["expires_at"] is None:
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
expires_at = row["expires_at"]
|
|
245
|
+
now = datetime.now(timezone.utc)
|
|
246
|
+
if expires_at <= now:
|
|
247
|
+
return 0
|
|
248
|
+
|
|
249
|
+
delta = expires_at - now
|
|
250
|
+
return int(delta.total_seconds())
|
|
251
|
+
|
|
252
|
+
async def delete_expired(self) -> int:
|
|
253
|
+
"""Delete all expired sessions.
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
Number of sessions deleted.
|
|
257
|
+
|
|
258
|
+
Notes:
|
|
259
|
+
Uses CURRENT_TIMESTAMP for consistency.
|
|
260
|
+
For very large tables (10M+ rows), consider batching deletes
|
|
261
|
+
to avoid holding locks too long.
|
|
262
|
+
"""
|
|
263
|
+
sql = f"DELETE FROM {self._table_name} WHERE expires_at <= CURRENT_TIMESTAMP"
|
|
264
|
+
|
|
265
|
+
conn_context = self._config.provide_connection()
|
|
266
|
+
async with conn_context as conn, conn.cursor() as cur:
|
|
267
|
+
await cur.execute(sql.encode())
|
|
268
|
+
await conn.commit()
|
|
269
|
+
count = cur.rowcount if cur.rowcount and cur.rowcount > 0 else 0
|
|
270
|
+
if count > 0:
|
|
271
|
+
self._log_delete_expired(count)
|
|
272
|
+
return count
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class PsycopgSyncStore(BaseSQLSpecStore["PsycopgSyncConfig"]):
|
|
276
|
+
"""PostgreSQL session store using Psycopg sync driver.
|
|
277
|
+
|
|
278
|
+
Implements server-side session storage for Litestar using PostgreSQL
|
|
279
|
+
via the synchronous Psycopg (psycopg3) driver. Uses Litestar's sync_to_thread
|
|
280
|
+
utility to provide an async interface compatible with the Store protocol.
|
|
281
|
+
|
|
282
|
+
Provides efficient session management with:
|
|
283
|
+
- Sync operations wrapped for async compatibility
|
|
284
|
+
- UPSERT support using ON CONFLICT
|
|
285
|
+
- Automatic expiration handling
|
|
286
|
+
- Efficient cleanup of expired sessions
|
|
287
|
+
|
|
288
|
+
Note:
|
|
289
|
+
For high-concurrency applications, consider using PsycopgAsyncStore instead,
|
|
290
|
+
as it provides native async operations without threading overhead.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
config: PsycopgSyncConfig instance.
|
|
294
|
+
|
|
295
|
+
Example:
|
|
296
|
+
from sqlspec.adapters.psycopg import PsycopgSyncConfig
|
|
297
|
+
from sqlspec.adapters.psycopg.litestar.store import PsycopgSyncStore
|
|
298
|
+
|
|
299
|
+
config = PsycopgSyncConfig(connection_config={"conninfo": "postgresql://..."})
|
|
300
|
+
store = PsycopgSyncStore(config)
|
|
301
|
+
await store.create_table()
|
|
302
|
+
"""
|
|
303
|
+
|
|
304
|
+
__slots__ = ()
|
|
305
|
+
|
|
306
|
+
def __init__(self, config: "PsycopgSyncConfig") -> None:
|
|
307
|
+
"""Initialize Psycopg sync session store.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
config: PsycopgSyncConfig instance.
|
|
311
|
+
|
|
312
|
+
Notes:
|
|
313
|
+
Table name is read from config.extension_config["litestar"]["session_table"].
|
|
314
|
+
"""
|
|
315
|
+
super().__init__(config)
|
|
316
|
+
|
|
317
|
+
def _get_create_table_sql(self) -> str:
|
|
318
|
+
"""Get PostgreSQL CREATE TABLE SQL with optimized schema.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
SQL statement to create the sessions table with proper indexes.
|
|
322
|
+
|
|
323
|
+
Notes:
|
|
324
|
+
- Uses TIMESTAMPTZ for timezone-aware expiration timestamps
|
|
325
|
+
- Partial index WHERE expires_at IS NOT NULL reduces index size/maintenance
|
|
326
|
+
- FILLFACTOR 80 leaves space for HOT updates, reducing table bloat
|
|
327
|
+
- Audit columns (created_at, updated_at) help with debugging
|
|
328
|
+
- Table name is internally controlled, not user input (S608 suppressed)
|
|
329
|
+
"""
|
|
330
|
+
return f"""
|
|
331
|
+
CREATE TABLE IF NOT EXISTS {self._table_name} (
|
|
332
|
+
session_id TEXT PRIMARY KEY,
|
|
333
|
+
data BYTEA NOT NULL,
|
|
334
|
+
expires_at TIMESTAMPTZ,
|
|
335
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
336
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
337
|
+
) WITH (fillfactor = 80);
|
|
338
|
+
|
|
339
|
+
CREATE INDEX IF NOT EXISTS idx_{self._table_name}_expires_at
|
|
340
|
+
ON {self._table_name}(expires_at) WHERE expires_at IS NOT NULL;
|
|
341
|
+
|
|
342
|
+
ALTER TABLE {self._table_name} SET (
|
|
343
|
+
autovacuum_vacuum_scale_factor = 0.05,
|
|
344
|
+
autovacuum_analyze_scale_factor = 0.02
|
|
345
|
+
);
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
def _get_drop_table_sql(self) -> "list[str]":
|
|
349
|
+
"""Get PostgreSQL DROP TABLE SQL statements.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
List of SQL statements to drop indexes and table.
|
|
353
|
+
"""
|
|
354
|
+
return [f"DROP INDEX IF EXISTS idx_{self._table_name}_expires_at", f"DROP TABLE IF EXISTS {self._table_name}"]
|
|
355
|
+
|
|
356
|
+
def _create_table(self) -> None:
|
|
357
|
+
"""Synchronous implementation of create_table."""
|
|
358
|
+
sql = self._get_create_table_sql()
|
|
359
|
+
with self._config.provide_session() as driver:
|
|
360
|
+
driver.execute_script(sql)
|
|
361
|
+
driver.commit()
|
|
362
|
+
self._log_table_created()
|
|
363
|
+
|
|
364
|
+
async def create_table(self) -> None:
|
|
365
|
+
"""Create the session table if it doesn't exist."""
|
|
366
|
+
await async_(self._create_table)()
|
|
367
|
+
|
|
368
|
+
def _get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
369
|
+
"""Synchronous implementation of get.
|
|
370
|
+
|
|
371
|
+
Notes:
|
|
372
|
+
Uses CURRENT_TIMESTAMP for SQL standard compliance.
|
|
373
|
+
"""
|
|
374
|
+
sql = f"""
|
|
375
|
+
SELECT data, expires_at FROM {self._table_name}
|
|
376
|
+
WHERE session_id = %s
|
|
377
|
+
AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
with self._config.provide_connection() as conn:
|
|
381
|
+
with conn.cursor() as cur:
|
|
382
|
+
cur.execute(sql.encode(), (key,))
|
|
383
|
+
row = cur.fetchone()
|
|
384
|
+
|
|
385
|
+
if row is None:
|
|
386
|
+
return None
|
|
387
|
+
|
|
388
|
+
if renew_for is not None and row["expires_at"] is not None:
|
|
389
|
+
new_expires_at = self._calculate_expires_at(renew_for)
|
|
390
|
+
if new_expires_at is not None:
|
|
391
|
+
update_sql = f"""
|
|
392
|
+
UPDATE {self._table_name}
|
|
393
|
+
SET expires_at = %s, updated_at = CURRENT_TIMESTAMP
|
|
394
|
+
WHERE session_id = %s
|
|
395
|
+
"""
|
|
396
|
+
conn.execute(update_sql.encode(), (new_expires_at, key))
|
|
397
|
+
conn.commit()
|
|
398
|
+
|
|
399
|
+
return bytes(row["data"])
|
|
400
|
+
|
|
401
|
+
async def get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
402
|
+
"""Get a session value by key.
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
key: Session ID to retrieve.
|
|
406
|
+
renew_for: If given, renew the expiry time for this duration.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
Session data as bytes if found and not expired, None otherwise.
|
|
410
|
+
"""
|
|
411
|
+
return await async_(self._get)(key, renew_for)
|
|
412
|
+
|
|
413
|
+
def _set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
414
|
+
"""Synchronous implementation of set.
|
|
415
|
+
|
|
416
|
+
Notes:
|
|
417
|
+
Uses EXCLUDED to reference the proposed insert values in ON CONFLICT.
|
|
418
|
+
"""
|
|
419
|
+
data = self._value_to_bytes(value)
|
|
420
|
+
expires_at = self._calculate_expires_at(expires_in)
|
|
421
|
+
|
|
422
|
+
sql = f"""
|
|
423
|
+
INSERT INTO {self._table_name} (session_id, data, expires_at)
|
|
424
|
+
VALUES (%s, %s, %s)
|
|
425
|
+
ON CONFLICT (session_id)
|
|
426
|
+
DO UPDATE SET
|
|
427
|
+
data = EXCLUDED.data,
|
|
428
|
+
expires_at = EXCLUDED.expires_at,
|
|
429
|
+
updated_at = CURRENT_TIMESTAMP
|
|
430
|
+
"""
|
|
431
|
+
|
|
432
|
+
with self._config.provide_connection() as conn:
|
|
433
|
+
conn.execute(sql.encode(), (key, data, expires_at))
|
|
434
|
+
conn.commit()
|
|
435
|
+
|
|
436
|
+
async def set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
437
|
+
"""Store a session value.
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
key: Session ID.
|
|
441
|
+
value: Session data.
|
|
442
|
+
expires_in: Time until expiration.
|
|
443
|
+
"""
|
|
444
|
+
await async_(self._set)(key, value, expires_in)
|
|
445
|
+
|
|
446
|
+
def _delete(self, key: str) -> None:
|
|
447
|
+
"""Synchronous implementation of delete."""
|
|
448
|
+
sql = f"DELETE FROM {self._table_name} WHERE session_id = %s"
|
|
449
|
+
|
|
450
|
+
with self._config.provide_connection() as conn:
|
|
451
|
+
conn.execute(sql.encode(), (key,))
|
|
452
|
+
conn.commit()
|
|
453
|
+
|
|
454
|
+
async def delete(self, key: str) -> None:
|
|
455
|
+
"""Delete a session by key.
|
|
456
|
+
|
|
457
|
+
Args:
|
|
458
|
+
key: Session ID to delete.
|
|
459
|
+
"""
|
|
460
|
+
await async_(self._delete)(key)
|
|
461
|
+
|
|
462
|
+
def _delete_all(self) -> None:
|
|
463
|
+
"""Synchronous implementation of delete_all."""
|
|
464
|
+
sql = f"DELETE FROM {self._table_name}"
|
|
465
|
+
|
|
466
|
+
with self._config.provide_connection() as conn:
|
|
467
|
+
conn.execute(sql.encode())
|
|
468
|
+
conn.commit()
|
|
469
|
+
self._log_delete_all()
|
|
470
|
+
|
|
471
|
+
async def delete_all(self) -> None:
|
|
472
|
+
"""Delete all sessions from the store."""
|
|
473
|
+
await async_(self._delete_all)()
|
|
474
|
+
|
|
475
|
+
def _exists(self, key: str) -> bool:
|
|
476
|
+
"""Synchronous implementation of exists."""
|
|
477
|
+
sql = f"""
|
|
478
|
+
SELECT 1 FROM {self._table_name}
|
|
479
|
+
WHERE session_id = %s
|
|
480
|
+
AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)
|
|
481
|
+
"""
|
|
482
|
+
|
|
483
|
+
with self._config.provide_connection() as conn, conn.cursor() as cur:
|
|
484
|
+
cur.execute(sql.encode(), (key,))
|
|
485
|
+
result = cur.fetchone()
|
|
486
|
+
return result is not None
|
|
487
|
+
|
|
488
|
+
async def exists(self, key: str) -> bool:
|
|
489
|
+
"""Check if a session key exists and is not expired.
|
|
490
|
+
|
|
491
|
+
Args:
|
|
492
|
+
key: Session ID to check.
|
|
493
|
+
|
|
494
|
+
Returns:
|
|
495
|
+
True if the session exists and is not expired.
|
|
496
|
+
"""
|
|
497
|
+
return await async_(self._exists)(key)
|
|
498
|
+
|
|
499
|
+
def _expires_in(self, key: str) -> "int | None":
|
|
500
|
+
"""Synchronous implementation of expires_in."""
|
|
501
|
+
sql = f"""
|
|
502
|
+
SELECT expires_at FROM {self._table_name}
|
|
503
|
+
WHERE session_id = %s
|
|
504
|
+
"""
|
|
505
|
+
|
|
506
|
+
with self._config.provide_connection() as conn:
|
|
507
|
+
with conn.cursor() as cur:
|
|
508
|
+
cur.execute(sql.encode(), (key,))
|
|
509
|
+
row = cur.fetchone()
|
|
510
|
+
|
|
511
|
+
if row is None or row["expires_at"] is None:
|
|
512
|
+
return None
|
|
513
|
+
|
|
514
|
+
expires_at = row["expires_at"]
|
|
515
|
+
now = datetime.now(timezone.utc)
|
|
516
|
+
|
|
517
|
+
if expires_at <= now:
|
|
518
|
+
return 0
|
|
519
|
+
|
|
520
|
+
delta = expires_at - now
|
|
521
|
+
return int(delta.total_seconds())
|
|
522
|
+
|
|
523
|
+
async def expires_in(self, key: str) -> "int | None":
|
|
524
|
+
"""Get the time in seconds until the session expires.
|
|
525
|
+
|
|
526
|
+
Args:
|
|
527
|
+
key: Session ID to check.
|
|
528
|
+
|
|
529
|
+
Returns:
|
|
530
|
+
Seconds until expiration, or None if no expiry or key doesn't exist.
|
|
531
|
+
"""
|
|
532
|
+
return await async_(self._expires_in)(key)
|
|
533
|
+
|
|
534
|
+
def _delete_expired(self) -> int:
|
|
535
|
+
"""Synchronous implementation of delete_expired."""
|
|
536
|
+
sql = f"DELETE FROM {self._table_name} WHERE expires_at <= CURRENT_TIMESTAMP"
|
|
537
|
+
|
|
538
|
+
with self._config.provide_connection() as conn, conn.cursor() as cur:
|
|
539
|
+
cur.execute(sql.encode())
|
|
540
|
+
conn.commit()
|
|
541
|
+
count = cur.rowcount if cur.rowcount and cur.rowcount > 0 else 0
|
|
542
|
+
if count > 0:
|
|
543
|
+
self._log_delete_expired(count)
|
|
544
|
+
return count
|
|
545
|
+
|
|
546
|
+
async def delete_expired(self) -> int:
|
|
547
|
+
"""Delete all expired sessions.
|
|
548
|
+
|
|
549
|
+
Returns:
|
|
550
|
+
Number of sessions deleted.
|
|
551
|
+
"""
|
|
552
|
+
return await async_(self._delete_expired)()
|
|
Binary file
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Psycopg pgvector type handlers for vector data type support.
|
|
2
|
+
|
|
3
|
+
Provides automatic conversion between NumPy arrays and PostgreSQL vector types
|
|
4
|
+
via pgvector-python library. Supports both sync and async connections.
|
|
5
|
+
|
|
6
|
+
All functions are designed for mypyc compilation with imports inside
|
|
7
|
+
functions to avoid module-level optional dependency issues.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import importlib
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
from sqlspec.typing import PGVECTOR_INSTALLED
|
|
14
|
+
from sqlspec.utils.logging import get_logger
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from psycopg import AsyncConnection, Connection
|
|
18
|
+
|
|
19
|
+
__all__ = ("register_pgvector_async", "register_pgvector_sync")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _is_missing_vector_error(error: Exception) -> bool:
|
|
26
|
+
"""Check if error indicates missing vector type in database.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
error: Exception to check.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
True if error indicates vector type not found.
|
|
33
|
+
"""
|
|
34
|
+
from psycopg import errors
|
|
35
|
+
|
|
36
|
+
message = str(error).lower()
|
|
37
|
+
return (
|
|
38
|
+
"vector type not found" in message
|
|
39
|
+
or 'type "vector" does not exist' in message
|
|
40
|
+
or "vector type does not exist" in message
|
|
41
|
+
or isinstance(error, errors.UndefinedObject)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def register_pgvector_sync(connection: "Connection[Any]") -> None:
|
|
46
|
+
"""Register pgvector type handlers on psycopg sync connection.
|
|
47
|
+
|
|
48
|
+
Enables automatic conversion between NumPy arrays and PostgreSQL vector types
|
|
49
|
+
using the pgvector-python library.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
connection: Psycopg sync connection.
|
|
53
|
+
"""
|
|
54
|
+
from psycopg import ProgrammingError
|
|
55
|
+
|
|
56
|
+
if not PGVECTOR_INSTALLED:
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
pgvector_psycopg = importlib.import_module("pgvector.psycopg")
|
|
61
|
+
pgvector_psycopg.register_vector(connection)
|
|
62
|
+
except (ValueError, TypeError, ProgrammingError) as error:
|
|
63
|
+
if _is_missing_vector_error(error):
|
|
64
|
+
return
|
|
65
|
+
logger.warning("Unexpected error during pgvector registration: %s", error)
|
|
66
|
+
except Exception:
|
|
67
|
+
logger.exception("Failed to register pgvector for psycopg sync")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
async def register_pgvector_async(connection: "AsyncConnection[Any]") -> None:
|
|
71
|
+
"""Register pgvector type handlers on psycopg async connection.
|
|
72
|
+
|
|
73
|
+
Enables automatic conversion between NumPy arrays and PostgreSQL vector types
|
|
74
|
+
using the pgvector-python library.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
connection: Psycopg async connection.
|
|
78
|
+
"""
|
|
79
|
+
from psycopg import ProgrammingError
|
|
80
|
+
|
|
81
|
+
if not PGVECTOR_INSTALLED:
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
pgvector_psycopg = importlib.import_module("pgvector.psycopg")
|
|
86
|
+
register_vector_async = pgvector_psycopg.register_vector_async
|
|
87
|
+
await register_vector_async(connection)
|
|
88
|
+
except (ValueError, TypeError, ProgrammingError) as error:
|
|
89
|
+
if _is_missing_vector_error(error):
|
|
90
|
+
return
|
|
91
|
+
logger.warning("Unexpected error during pgvector registration: %s", error)
|
|
92
|
+
except Exception:
|
|
93
|
+
logger.exception("Failed to register pgvector for psycopg async")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from sqlspec.adapters.pymysql._typing import PyMysqlConnection
|
|
2
|
+
from sqlspec.adapters.pymysql.config import (
|
|
3
|
+
PyMysqlConfig,
|
|
4
|
+
PyMysqlConnectionParams,
|
|
5
|
+
PyMysqlDriverFeatures,
|
|
6
|
+
PyMysqlPoolParams,
|
|
7
|
+
)
|
|
8
|
+
from sqlspec.adapters.pymysql.core import default_statement_config
|
|
9
|
+
from sqlspec.adapters.pymysql.driver import PyMysqlCursor, PyMysqlDriver, PyMysqlExceptionHandler
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
"PyMysqlConfig",
|
|
13
|
+
"PyMysqlConnection",
|
|
14
|
+
"PyMysqlConnectionParams",
|
|
15
|
+
"PyMysqlCursor",
|
|
16
|
+
"PyMysqlDriver",
|
|
17
|
+
"PyMysqlDriverFeatures",
|
|
18
|
+
"PyMysqlExceptionHandler",
|
|
19
|
+
"PyMysqlPoolParams",
|
|
20
|
+
"default_statement_config",
|
|
21
|
+
)
|