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,187 @@
|
|
|
1
|
+
"""Spanner event queue store with GoogleSQL-optimized DDL.
|
|
2
|
+
|
|
3
|
+
Spanner requires:
|
|
4
|
+
- STRING instead of VARCHAR
|
|
5
|
+
- INT64 instead of INTEGER
|
|
6
|
+
- No DEFAULT clause for non-computed columns
|
|
7
|
+
- Separate index creation statements (no IF NOT EXISTS)
|
|
8
|
+
- PRIMARY KEY declared inline in CREATE TABLE
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
|
|
13
|
+
from sqlspec.adapters.spanner.config import SpannerSyncConfig
|
|
14
|
+
from sqlspec.extensions.events import BaseEventQueueStore
|
|
15
|
+
from sqlspec.utils.logging import get_logger, log_with_context
|
|
16
|
+
|
|
17
|
+
__all__ = ("SpannerSyncEventQueueStore",)
|
|
18
|
+
|
|
19
|
+
logger = get_logger("sqlspec.adapters.spanner.events.store")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SpannerSyncEventQueueStore(BaseEventQueueStore["SpannerSyncConfig"]):
|
|
23
|
+
"""Spanner-specific event queue store with GoogleSQL DDL.
|
|
24
|
+
|
|
25
|
+
Generates optimized DDL for Google Cloud Spanner using GoogleSQL dialect.
|
|
26
|
+
Spanner does not support IF NOT EXISTS, so statements must be executed
|
|
27
|
+
with proper error handling for existing objects.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
config: SpannerSyncConfig with extension_config["events"] settings.
|
|
31
|
+
|
|
32
|
+
Notes:
|
|
33
|
+
Configuration is read from config.extension_config["events"]:
|
|
34
|
+
- queue_table: Table name (default: "sqlspec_event_queue")
|
|
35
|
+
|
|
36
|
+
Example:
|
|
37
|
+
from sqlspec.adapters.spanner import SpannerSyncConfig
|
|
38
|
+
from sqlspec.adapters.spanner.events import SpannerSyncEventQueueStore
|
|
39
|
+
|
|
40
|
+
config = SpannerSyncConfig(
|
|
41
|
+
connection_config={"project": "my-project", "instance": "my-instance", "database": "my-db"},
|
|
42
|
+
extension_config={"events": {"queue_table": "my_events"}}
|
|
43
|
+
)
|
|
44
|
+
store = SpannerSyncEventQueueStore(config)
|
|
45
|
+
store.create_table()
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
__slots__ = ()
|
|
49
|
+
|
|
50
|
+
def _column_types(self) -> "tuple[str, str, str]":
|
|
51
|
+
"""Return Spanner-specific column types."""
|
|
52
|
+
return "JSON", "JSON", "TIMESTAMP"
|
|
53
|
+
|
|
54
|
+
def _string_type(self, length: int) -> str:
|
|
55
|
+
"""Return Spanner STRING(N) type syntax."""
|
|
56
|
+
return f"STRING({length})"
|
|
57
|
+
|
|
58
|
+
def _integer_type(self) -> str:
|
|
59
|
+
"""Return Spanner INT64 type."""
|
|
60
|
+
return "INT64"
|
|
61
|
+
|
|
62
|
+
def _primary_key_syntax(self) -> str:
|
|
63
|
+
"""Return Spanner inline PRIMARY KEY clause."""
|
|
64
|
+
return " PRIMARY KEY (event_id)"
|
|
65
|
+
|
|
66
|
+
def _build_create_table_sql(self) -> str:
|
|
67
|
+
"""Build Spanner CREATE TABLE with PRIMARY KEY inline.
|
|
68
|
+
|
|
69
|
+
Spanner does not support DEFAULT clauses on non-computed columns,
|
|
70
|
+
so we omit them entirely. Values must be provided at insert time.
|
|
71
|
+
"""
|
|
72
|
+
payload_type, metadata_type, timestamp_type = self._column_types()
|
|
73
|
+
string_64 = self._string_type(64)
|
|
74
|
+
string_128 = self._string_type(128)
|
|
75
|
+
string_32 = self._string_type(32)
|
|
76
|
+
integer_type = self._integer_type()
|
|
77
|
+
pk_inline = self._primary_key_syntax()
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
f"CREATE TABLE {self.table_name} ("
|
|
81
|
+
f"event_id {string_64} NOT NULL,"
|
|
82
|
+
f" channel {string_128} NOT NULL,"
|
|
83
|
+
f" payload_json {payload_type} NOT NULL,"
|
|
84
|
+
f" metadata_json {metadata_type},"
|
|
85
|
+
f" status {string_32} NOT NULL,"
|
|
86
|
+
f" available_at {timestamp_type} NOT NULL,"
|
|
87
|
+
f" lease_expires_at {timestamp_type},"
|
|
88
|
+
f" attempts {integer_type} NOT NULL,"
|
|
89
|
+
f" created_at {timestamp_type} NOT NULL,"
|
|
90
|
+
f" acknowledged_at {timestamp_type}"
|
|
91
|
+
f"){pk_inline}"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def _build_index_sql(self) -> str | None:
|
|
95
|
+
"""Build Spanner secondary index for queue operations."""
|
|
96
|
+
index_name = self._index_name()
|
|
97
|
+
return f"CREATE INDEX {index_name} ON {self.table_name}(channel, status, available_at)"
|
|
98
|
+
|
|
99
|
+
def _wrap_create_statement(self, statement: str, object_type: str) -> str:
|
|
100
|
+
"""Return statement unchanged - Spanner does not support IF NOT EXISTS.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
statement: The DDL statement.
|
|
104
|
+
object_type: Type of object (table, index).
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
The statement unchanged.
|
|
108
|
+
"""
|
|
109
|
+
del object_type
|
|
110
|
+
return statement
|
|
111
|
+
|
|
112
|
+
def _wrap_drop_statement(self, statement: str) -> str:
|
|
113
|
+
"""Return statement unchanged - Spanner does not support IF EXISTS."""
|
|
114
|
+
return statement
|
|
115
|
+
|
|
116
|
+
def create_statements(self) -> "list[str]":
|
|
117
|
+
"""Return separate statements for table and index creation.
|
|
118
|
+
|
|
119
|
+
Spanner requires DDL statements to be executed individually.
|
|
120
|
+
The caller should handle errors for already-existing objects.
|
|
121
|
+
"""
|
|
122
|
+
statements = [self._build_create_table_sql()]
|
|
123
|
+
index_sql = self._build_index_sql()
|
|
124
|
+
if index_sql:
|
|
125
|
+
statements.append(index_sql)
|
|
126
|
+
return statements
|
|
127
|
+
|
|
128
|
+
def drop_statements(self) -> "list[str]":
|
|
129
|
+
"""Return drop statements in reverse dependency order.
|
|
130
|
+
|
|
131
|
+
Spanner requires index to be dropped before the table.
|
|
132
|
+
The caller should handle errors for non-existent objects.
|
|
133
|
+
"""
|
|
134
|
+
index_name = self._index_name()
|
|
135
|
+
return [f"DROP INDEX {index_name}", f"DROP TABLE {self.table_name}"]
|
|
136
|
+
|
|
137
|
+
def create_table(self) -> None:
|
|
138
|
+
"""Create the event queue table and index.
|
|
139
|
+
|
|
140
|
+
Executes DDL statements via database.update_ddl() which is the
|
|
141
|
+
recommended approach for Spanner schema changes.
|
|
142
|
+
|
|
143
|
+
Raises:
|
|
144
|
+
google.api_core.exceptions.AlreadyExists: If table or index exists.
|
|
145
|
+
"""
|
|
146
|
+
config = self._config
|
|
147
|
+
if not isinstance(config, SpannerSyncConfig):
|
|
148
|
+
msg = "create_table requires SpannerSyncConfig"
|
|
149
|
+
raise TypeError(msg)
|
|
150
|
+
|
|
151
|
+
database = config.get_database()
|
|
152
|
+
statements = self.create_statements()
|
|
153
|
+
log_with_context(
|
|
154
|
+
logger,
|
|
155
|
+
logging.DEBUG,
|
|
156
|
+
"events.queue.create",
|
|
157
|
+
adapter_name="spanner",
|
|
158
|
+
table_name=self.table_name,
|
|
159
|
+
statement_count=len(statements),
|
|
160
|
+
)
|
|
161
|
+
database.update_ddl(statements).result() # type: ignore[no-untyped-call]
|
|
162
|
+
|
|
163
|
+
def drop_table(self) -> None:
|
|
164
|
+
"""Drop the event queue table and index.
|
|
165
|
+
|
|
166
|
+
Executes DDL statements via database.update_ddl() which is the
|
|
167
|
+
recommended approach for Spanner schema changes.
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
google.api_core.exceptions.NotFound: If table or index does not exist.
|
|
171
|
+
"""
|
|
172
|
+
config = self._config
|
|
173
|
+
if not isinstance(config, SpannerSyncConfig):
|
|
174
|
+
msg = "drop_table requires SpannerSyncConfig"
|
|
175
|
+
raise TypeError(msg)
|
|
176
|
+
|
|
177
|
+
database = config.get_database()
|
|
178
|
+
statements = self.drop_statements()
|
|
179
|
+
log_with_context(
|
|
180
|
+
logger,
|
|
181
|
+
logging.DEBUG,
|
|
182
|
+
"events.queue.drop",
|
|
183
|
+
adapter_name="spanner",
|
|
184
|
+
table_name=self.table_name,
|
|
185
|
+
statement_count=len(statements),
|
|
186
|
+
)
|
|
187
|
+
database.update_ddl(statements).result() # type: ignore[no-untyped-call]
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""Spanner session store for Litestar integration."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
5
|
+
|
|
6
|
+
from google.cloud.spanner_v1 import param_types
|
|
7
|
+
|
|
8
|
+
from sqlspec.adapters.spanner.type_converter import bytes_to_spanner, spanner_to_bytes
|
|
9
|
+
from sqlspec.extensions.litestar.store import BaseSQLSpecStore
|
|
10
|
+
from sqlspec.utils.sync_tools import async_
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Callable
|
|
14
|
+
from typing import Protocol
|
|
15
|
+
|
|
16
|
+
from google.cloud.spanner_v1.transaction import Transaction
|
|
17
|
+
|
|
18
|
+
from sqlspec.adapters.spanner.config import SpannerSyncConfig
|
|
19
|
+
|
|
20
|
+
class _DatabaseProtocol(Protocol):
|
|
21
|
+
def run_in_transaction(self, func: "Callable[[Transaction], Any]") -> Any: ...
|
|
22
|
+
|
|
23
|
+
def update_ddl(self, ddl_statements: "list[str]") -> Any: ...
|
|
24
|
+
|
|
25
|
+
def list_tables(self) -> Any: ...
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = ("SpannerSyncStore",)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class _SpannerExecuteUpdateJob:
|
|
32
|
+
__slots__ = ("_params", "_sql", "_types")
|
|
33
|
+
|
|
34
|
+
def __init__(self, sql: str, params: "dict[str, Any] | None" = None, types: "dict[str, Any] | None" = None) -> None:
|
|
35
|
+
self._sql = sql
|
|
36
|
+
self._params = params
|
|
37
|
+
self._types = types
|
|
38
|
+
|
|
39
|
+
def __call__(self, transaction: "Transaction") -> None:
|
|
40
|
+
if self._params is None and self._types is None:
|
|
41
|
+
transaction.execute_update(self._sql) # type: ignore[no-untyped-call]
|
|
42
|
+
return
|
|
43
|
+
transaction.execute_update(self._sql, params=self._params or {}, param_types=self._types) # type: ignore[no-untyped-call]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class _SpannerUpsertJob:
|
|
47
|
+
__slots__ = ("_insert_sql", "_params", "_types", "_update_sql")
|
|
48
|
+
|
|
49
|
+
def __init__(self, update_sql: str, insert_sql: str, params: "dict[str, Any]", types: "dict[str, Any]") -> None:
|
|
50
|
+
self._update_sql = update_sql
|
|
51
|
+
self._insert_sql = insert_sql
|
|
52
|
+
self._params = params
|
|
53
|
+
self._types = types
|
|
54
|
+
|
|
55
|
+
def __call__(self, transaction: "Transaction") -> None:
|
|
56
|
+
row_ct = transaction.execute_update(self._update_sql, params=self._params, param_types=self._types) # type: ignore[no-untyped-call]
|
|
57
|
+
if row_ct == 0:
|
|
58
|
+
transaction.execute_update(self._insert_sql, params=self._params, param_types=self._types) # type: ignore[no-untyped-call]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class _SpannerExecuteUpdateCountJob:
|
|
62
|
+
__slots__ = ("_sql",)
|
|
63
|
+
|
|
64
|
+
def __init__(self, sql: str) -> None:
|
|
65
|
+
self._sql = sql
|
|
66
|
+
|
|
67
|
+
def __call__(self, transaction: "Transaction") -> int:
|
|
68
|
+
return int(transaction.execute_update(self._sql)) # type: ignore[no-untyped-call]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class SpannerSyncStore(BaseSQLSpecStore["SpannerSyncConfig"]):
|
|
72
|
+
"""Spanner-backed Litestar session store using sync driver wrapped as async."""
|
|
73
|
+
|
|
74
|
+
__slots__ = ("_index_options", "_shard_count", "_table_options")
|
|
75
|
+
|
|
76
|
+
def __init__(self, config: "SpannerSyncConfig") -> None:
|
|
77
|
+
super().__init__(config)
|
|
78
|
+
litestar_cfg = cast("dict[str, Any]", config.extension_config.get("litestar", {}))
|
|
79
|
+
self._shard_count: int = int(litestar_cfg.get("shard_count", 0)) if litestar_cfg.get("shard_count") else 0
|
|
80
|
+
self._table_options: str | None = litestar_cfg.get("table_options")
|
|
81
|
+
self._index_options: str | None = litestar_cfg.get("index_options")
|
|
82
|
+
|
|
83
|
+
def _database(self) -> "_DatabaseProtocol":
|
|
84
|
+
return cast("_DatabaseProtocol", self._config.get_database())
|
|
85
|
+
|
|
86
|
+
def _datetime_to_timestamp(self, dt: "datetime | None") -> "datetime | None":
|
|
87
|
+
if dt is None:
|
|
88
|
+
return None
|
|
89
|
+
if dt.tzinfo is None:
|
|
90
|
+
return dt.replace(tzinfo=timezone.utc)
|
|
91
|
+
return dt
|
|
92
|
+
|
|
93
|
+
def _timestamp_to_datetime(self, ts: "datetime | None") -> "datetime | None":
|
|
94
|
+
if ts is None:
|
|
95
|
+
return None
|
|
96
|
+
if ts.tzinfo is None:
|
|
97
|
+
return ts.replace(tzinfo=timezone.utc)
|
|
98
|
+
return ts
|
|
99
|
+
|
|
100
|
+
def _build_params(
|
|
101
|
+
self, key: str, expires_at: "datetime | None" = None, data: "bytes | None" = None
|
|
102
|
+
) -> "dict[str, Any]":
|
|
103
|
+
return {
|
|
104
|
+
"session_id": key,
|
|
105
|
+
"data": bytes_to_spanner(data),
|
|
106
|
+
"expires_at": self._datetime_to_timestamp(expires_at),
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
def _get_param_types(
|
|
110
|
+
self, session_id: bool = True, expires_at: bool = False, data: bool = False
|
|
111
|
+
) -> "dict[str, Any]":
|
|
112
|
+
types: dict[str, Any] = {}
|
|
113
|
+
if session_id:
|
|
114
|
+
types["session_id"] = param_types.STRING
|
|
115
|
+
if expires_at:
|
|
116
|
+
types["expires_at"] = param_types.TIMESTAMP
|
|
117
|
+
if data:
|
|
118
|
+
types["data"] = param_types.BYTES
|
|
119
|
+
return types
|
|
120
|
+
|
|
121
|
+
async def get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
122
|
+
return await async_(self._get)(key, renew_for)
|
|
123
|
+
|
|
124
|
+
def _get(self, key: str, renew_for: "int | timedelta | None" = None) -> "bytes | None":
|
|
125
|
+
sql = f"""
|
|
126
|
+
SELECT data, expires_at
|
|
127
|
+
FROM {self._table_name}
|
|
128
|
+
WHERE session_id = @session_id
|
|
129
|
+
AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP())
|
|
130
|
+
"""
|
|
131
|
+
if self._shard_count > 1:
|
|
132
|
+
sql = f"""
|
|
133
|
+
SELECT data, expires_at
|
|
134
|
+
FROM {self._table_name}
|
|
135
|
+
WHERE shard_id = MOD(FARM_FINGERPRINT(@session_id), {self._shard_count})
|
|
136
|
+
AND session_id = @session_id
|
|
137
|
+
AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP())
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
with self._config.provide_session() as driver:
|
|
141
|
+
result = driver.select_one_or_none(sql, {"session_id": key})
|
|
142
|
+
|
|
143
|
+
if result is None:
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
data = result.get("data")
|
|
147
|
+
expires_at = self._timestamp_to_datetime(result.get("expires_at"))
|
|
148
|
+
|
|
149
|
+
if renew_for is not None and expires_at is not None:
|
|
150
|
+
new_expires = self._calculate_expires_at(renew_for)
|
|
151
|
+
update_sql = f"""
|
|
152
|
+
UPDATE {self._table_name}
|
|
153
|
+
SET expires_at = @expires_at, updated_at = PENDING_COMMIT_TIMESTAMP()
|
|
154
|
+
WHERE session_id = @session_id
|
|
155
|
+
"""
|
|
156
|
+
if self._shard_count > 1:
|
|
157
|
+
update_sql = f"{update_sql} AND shard_id = MOD(FARM_FINGERPRINT(@session_id), {self._shard_count})"
|
|
158
|
+
params = self._build_params(key, new_expires)
|
|
159
|
+
types = self._get_param_types(expires_at=True)
|
|
160
|
+
self._database().run_in_transaction(_SpannerExecuteUpdateJob(update_sql, params, types))
|
|
161
|
+
|
|
162
|
+
return spanner_to_bytes(data)
|
|
163
|
+
|
|
164
|
+
async def set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
165
|
+
await async_(self._set)(key, value, expires_in)
|
|
166
|
+
|
|
167
|
+
def _set(self, key: str, value: "str | bytes", expires_in: "int | timedelta | None" = None) -> None:
|
|
168
|
+
data = self._value_to_bytes(value)
|
|
169
|
+
expires_at = self._calculate_expires_at(expires_in)
|
|
170
|
+
params = self._build_params(key, expires_at, data)
|
|
171
|
+
types = self._get_param_types(session_id=True, expires_at=True, data=True)
|
|
172
|
+
|
|
173
|
+
update_sql = f"""
|
|
174
|
+
UPDATE {self._table_name}
|
|
175
|
+
SET data = @data,
|
|
176
|
+
expires_at = @expires_at,
|
|
177
|
+
updated_at = PENDING_COMMIT_TIMESTAMP()
|
|
178
|
+
WHERE session_id = @session_id
|
|
179
|
+
"""
|
|
180
|
+
if self._shard_count > 1:
|
|
181
|
+
update_sql = f"{update_sql} AND shard_id = MOD(FARM_FINGERPRINT(@session_id), {self._shard_count})"
|
|
182
|
+
insert_sql = f"""
|
|
183
|
+
INSERT {self._table_name} (session_id, data, expires_at, created_at, updated_at)
|
|
184
|
+
VALUES (@session_id, @data, @expires_at, PENDING_COMMIT_TIMESTAMP(), PENDING_COMMIT_TIMESTAMP())
|
|
185
|
+
"""
|
|
186
|
+
self._database().run_in_transaction(_SpannerUpsertJob(update_sql, insert_sql, params, types))
|
|
187
|
+
|
|
188
|
+
async def delete(self, key: str) -> None:
|
|
189
|
+
await async_(self._delete)(key)
|
|
190
|
+
|
|
191
|
+
def _delete(self, key: str) -> None:
|
|
192
|
+
sql = f"DELETE FROM {self._table_name} WHERE session_id = @session_id"
|
|
193
|
+
if self._shard_count > 1:
|
|
194
|
+
sql = f"{sql} AND shard_id = MOD(FARM_FINGERPRINT(@session_id), {self._shard_count})"
|
|
195
|
+
params = {"session_id": key}
|
|
196
|
+
types = self._get_param_types(session_id=True)
|
|
197
|
+
self._database().run_in_transaction(_SpannerExecuteUpdateJob(sql, params, types))
|
|
198
|
+
|
|
199
|
+
async def delete_all(self) -> None:
|
|
200
|
+
await async_(self._delete_all)()
|
|
201
|
+
|
|
202
|
+
def _delete_all(self) -> None:
|
|
203
|
+
sql = f"DELETE FROM {self._table_name} WHERE TRUE"
|
|
204
|
+
self._database().run_in_transaction(_SpannerExecuteUpdateJob(sql))
|
|
205
|
+
|
|
206
|
+
async def exists(self, key: str) -> bool:
|
|
207
|
+
return await async_(self._exists)(key)
|
|
208
|
+
|
|
209
|
+
def _exists(self, key: str) -> bool:
|
|
210
|
+
sql = f"""
|
|
211
|
+
SELECT 1 FROM {self._table_name}
|
|
212
|
+
WHERE session_id = @session_id
|
|
213
|
+
AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP())
|
|
214
|
+
LIMIT 1
|
|
215
|
+
"""
|
|
216
|
+
with self._config.provide_session() as driver:
|
|
217
|
+
row = driver.select_one_or_none(sql, {"session_id": key})
|
|
218
|
+
return row is not None
|
|
219
|
+
|
|
220
|
+
async def expires_in(self, key: str) -> "int | None":
|
|
221
|
+
return await async_(self._expires_in)(key)
|
|
222
|
+
|
|
223
|
+
def _expires_in(self, key: str) -> "int | None":
|
|
224
|
+
sql = f"""
|
|
225
|
+
SELECT expires_at FROM {self._table_name}
|
|
226
|
+
WHERE session_id = @session_id
|
|
227
|
+
"""
|
|
228
|
+
if self._shard_count > 1:
|
|
229
|
+
sql = f"{sql} AND shard_id = MOD(FARM_FINGERPRINT(@session_id), {self._shard_count})"
|
|
230
|
+
with self._config.provide_session() as driver:
|
|
231
|
+
row = driver.select_one_or_none(sql, {"session_id": key})
|
|
232
|
+
if row is None:
|
|
233
|
+
return None
|
|
234
|
+
expires_at = self._timestamp_to_datetime(row.get("expires_at"))
|
|
235
|
+
if expires_at is None:
|
|
236
|
+
return None
|
|
237
|
+
delta = expires_at - datetime.now(timezone.utc)
|
|
238
|
+
return max(int(delta.total_seconds()), 0)
|
|
239
|
+
|
|
240
|
+
async def delete_expired(self) -> int:
|
|
241
|
+
return await async_(self._delete_expired)()
|
|
242
|
+
|
|
243
|
+
def _delete_expired(self) -> int:
|
|
244
|
+
sql = f"""
|
|
245
|
+
DELETE FROM {self._table_name}
|
|
246
|
+
WHERE expires_at IS NOT NULL AND expires_at <= CURRENT_TIMESTAMP()
|
|
247
|
+
"""
|
|
248
|
+
result = self._database().run_in_transaction(_SpannerExecuteUpdateCountJob(sql))
|
|
249
|
+
return cast("int", result)
|
|
250
|
+
|
|
251
|
+
async def create_table(self) -> None:
|
|
252
|
+
await async_(self._create_table)()
|
|
253
|
+
|
|
254
|
+
def _create_table(self) -> None:
|
|
255
|
+
database = self._config.get_database()
|
|
256
|
+
existing_tables = {t.table_id for t in database.list_tables()} # type: ignore[no-untyped-call]
|
|
257
|
+
|
|
258
|
+
if self._table_name not in existing_tables:
|
|
259
|
+
ddl_statements = [self._get_create_table_sql(), self._get_create_index_sql()]
|
|
260
|
+
database.update_ddl(ddl_statements).result(300) # type: ignore[no-untyped-call]
|
|
261
|
+
|
|
262
|
+
def _get_create_table_sql(self) -> str:
|
|
263
|
+
shard_column = ""
|
|
264
|
+
pk = "PRIMARY KEY (session_id)"
|
|
265
|
+
if self._shard_count > 1:
|
|
266
|
+
shard_column = f",\n shard_id INT64 AS (MOD(FARM_FINGERPRINT(session_id), {self._shard_count})) STORED"
|
|
267
|
+
pk = "PRIMARY KEY (shard_id, session_id)"
|
|
268
|
+
options = ""
|
|
269
|
+
if self._table_options:
|
|
270
|
+
options = f"\nOPTIONS ({self._table_options})"
|
|
271
|
+
return f"""
|
|
272
|
+
CREATE TABLE {self._table_name} (
|
|
273
|
+
session_id STRING(128) NOT NULL,
|
|
274
|
+
data BYTES(MAX) NOT NULL,
|
|
275
|
+
expires_at TIMESTAMP,
|
|
276
|
+
created_at TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
|
|
277
|
+
updated_at TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true){shard_column}
|
|
278
|
+
) {pk}{options}
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
def _get_create_index_sql(self) -> str:
|
|
282
|
+
leading = "expires_at"
|
|
283
|
+
if self._shard_count > 1:
|
|
284
|
+
leading = "shard_id, expires_at"
|
|
285
|
+
opts = ""
|
|
286
|
+
if self._index_options:
|
|
287
|
+
opts = f" OPTIONS ({self._index_options})"
|
|
288
|
+
return f"CREATE INDEX idx_{self._table_name}_expires_at ON {self._table_name}({leading}){opts}"
|
|
289
|
+
|
|
290
|
+
def _get_drop_table_sql(self) -> "list[str]":
|
|
291
|
+
return [f"DROP INDEX idx_{self._table_name}_expires_at", f"DROP TABLE {self._table_name}"]
|
|
Binary file
|