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,20 @@
|
|
|
1
|
+
"""Events helpers for the psycopg adapter."""
|
|
2
|
+
|
|
3
|
+
from sqlspec.adapters.psycopg.events.backend import (
|
|
4
|
+
PsycopgAsyncEventsBackend,
|
|
5
|
+
PsycopgAsyncHybridEventsBackend,
|
|
6
|
+
PsycopgSyncEventsBackend,
|
|
7
|
+
PsycopgSyncHybridEventsBackend,
|
|
8
|
+
create_event_backend,
|
|
9
|
+
)
|
|
10
|
+
from sqlspec.adapters.psycopg.events.store import PsycopgAsyncEventQueueStore, PsycopgSyncEventQueueStore
|
|
11
|
+
|
|
12
|
+
__all__ = (
|
|
13
|
+
"PsycopgAsyncEventQueueStore",
|
|
14
|
+
"PsycopgAsyncEventsBackend",
|
|
15
|
+
"PsycopgAsyncHybridEventsBackend",
|
|
16
|
+
"PsycopgSyncEventQueueStore",
|
|
17
|
+
"PsycopgSyncEventsBackend",
|
|
18
|
+
"PsycopgSyncHybridEventsBackend",
|
|
19
|
+
"create_event_backend",
|
|
20
|
+
)
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
# pyright: reportPrivateUsage=false
|
|
2
|
+
"""Psycopg LISTEN/NOTIFY and hybrid event backends."""
|
|
3
|
+
|
|
4
|
+
import contextlib
|
|
5
|
+
import logging
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
8
|
+
|
|
9
|
+
from sqlspec.core import SQL
|
|
10
|
+
from sqlspec.exceptions import ImproperConfigurationError
|
|
11
|
+
from sqlspec.extensions.events import (
|
|
12
|
+
AsyncTableEventQueue,
|
|
13
|
+
EventMessage,
|
|
14
|
+
SyncTableEventQueue,
|
|
15
|
+
build_queue_backend,
|
|
16
|
+
decode_notify_payload,
|
|
17
|
+
encode_notify_payload,
|
|
18
|
+
normalize_event_channel_name,
|
|
19
|
+
)
|
|
20
|
+
from sqlspec.utils.logging import get_logger, log_with_context
|
|
21
|
+
from sqlspec.utils.serializers import from_json, to_json
|
|
22
|
+
from sqlspec.utils.uuids import uuid4
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from sqlspec.adapters.psycopg.config import PsycopgAsyncConfig, PsycopgSyncConfig
|
|
26
|
+
|
|
27
|
+
logger = get_logger("sqlspec.events.psycopg")
|
|
28
|
+
|
|
29
|
+
__all__ = (
|
|
30
|
+
"PsycopgAsyncEventsBackend",
|
|
31
|
+
"PsycopgAsyncHybridEventsBackend",
|
|
32
|
+
"PsycopgSyncEventsBackend",
|
|
33
|
+
"PsycopgSyncHybridEventsBackend",
|
|
34
|
+
"create_event_backend",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _extract_event_id(payload: str | None) -> "str | None":
|
|
39
|
+
if not payload:
|
|
40
|
+
return None
|
|
41
|
+
raw = from_json(payload)
|
|
42
|
+
if isinstance(raw, dict):
|
|
43
|
+
event_id = raw.get("event_id")
|
|
44
|
+
return event_id if isinstance(event_id, str) else None
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PsycopgSyncEventsBackend:
|
|
49
|
+
"""Native LISTEN/NOTIFY backend for sync psycopg adapters."""
|
|
50
|
+
|
|
51
|
+
__slots__ = ("_config", "_listen_connection", "_listen_connection_cm", "_runtime")
|
|
52
|
+
|
|
53
|
+
supports_sync = True
|
|
54
|
+
supports_async = False
|
|
55
|
+
backend_name = "listen_notify"
|
|
56
|
+
|
|
57
|
+
def __init__(self, config: "PsycopgSyncConfig") -> None:
|
|
58
|
+
if "psycopg" not in type(config).__module__:
|
|
59
|
+
msg = "Psycopg events backend requires a Psycopg adapter"
|
|
60
|
+
raise ImproperConfigurationError(msg)
|
|
61
|
+
if config.is_async:
|
|
62
|
+
msg = "PsycopgSyncEventsBackend requires a sync adapter"
|
|
63
|
+
raise ImproperConfigurationError(msg)
|
|
64
|
+
self._config = config
|
|
65
|
+
self._runtime = config.get_observability_runtime()
|
|
66
|
+
self._listen_connection: Any | None = None
|
|
67
|
+
self._listen_connection_cm: Any | None = None
|
|
68
|
+
log_with_context(
|
|
69
|
+
logger,
|
|
70
|
+
logging.DEBUG,
|
|
71
|
+
"event.listen",
|
|
72
|
+
adapter_name="psycopg",
|
|
73
|
+
backend_name=self.backend_name,
|
|
74
|
+
mode="async",
|
|
75
|
+
status="backend_ready",
|
|
76
|
+
)
|
|
77
|
+
log_with_context(
|
|
78
|
+
logger,
|
|
79
|
+
logging.DEBUG,
|
|
80
|
+
"event.listen",
|
|
81
|
+
adapter_name="psycopg",
|
|
82
|
+
backend_name=self.backend_name,
|
|
83
|
+
mode="sync",
|
|
84
|
+
status="backend_ready",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def publish(self, channel: str, payload: "dict[str, Any]", metadata: "dict[str, Any] | None" = None) -> str:
|
|
88
|
+
event_id = uuid4().hex
|
|
89
|
+
session_cm = self._config.provide_session()
|
|
90
|
+
with session_cm as driver:
|
|
91
|
+
driver.execute(
|
|
92
|
+
SQL(
|
|
93
|
+
"SELECT pg_notify(:channel, :payload)",
|
|
94
|
+
{"channel": channel, "payload": encode_notify_payload(event_id, payload, metadata)},
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
driver.commit()
|
|
98
|
+
self._runtime.increment_metric("events.publish.native")
|
|
99
|
+
return event_id
|
|
100
|
+
|
|
101
|
+
def dequeue(self, channel: str, poll_interval: float) -> EventMessage | None:
|
|
102
|
+
connection = self._ensure_listener(channel)
|
|
103
|
+
notify_iter = connection.notifies(timeout=poll_interval, stop_after=1)
|
|
104
|
+
with contextlib.suppress(StopIteration):
|
|
105
|
+
notify = next(notify_iter)
|
|
106
|
+
if notify.channel == channel:
|
|
107
|
+
return decode_notify_payload(channel, notify.payload)
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
def ack(self, _event_id: str) -> None:
|
|
111
|
+
self._runtime.increment_metric("events.ack")
|
|
112
|
+
|
|
113
|
+
def nack(self, _event_id: str) -> None:
|
|
114
|
+
"""Return an event to the queue (no-op for native LISTEN/NOTIFY)."""
|
|
115
|
+
|
|
116
|
+
def shutdown(self) -> None:
|
|
117
|
+
"""Shutdown the listener and release resources."""
|
|
118
|
+
if self._listen_connection_cm is not None:
|
|
119
|
+
with contextlib.suppress(Exception):
|
|
120
|
+
self._listen_connection_cm.__exit__(None, None, None)
|
|
121
|
+
self._listen_connection = None
|
|
122
|
+
self._listen_connection_cm = None
|
|
123
|
+
|
|
124
|
+
def _ensure_listener(self, channel: str) -> Any:
|
|
125
|
+
"""Ensure listener connection is established for the channel."""
|
|
126
|
+
if self._listen_connection is None:
|
|
127
|
+
validated_channel = normalize_event_channel_name(channel)
|
|
128
|
+
self._listen_connection_cm = self._config.provide_connection()
|
|
129
|
+
self._listen_connection = self._listen_connection_cm.__enter__()
|
|
130
|
+
if self._listen_connection is not None:
|
|
131
|
+
self._listen_connection.autocommit = True
|
|
132
|
+
self._listen_connection.execute(f"LISTEN {validated_channel}")
|
|
133
|
+
return self._listen_connection
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class PsycopgAsyncEventsBackend:
|
|
137
|
+
"""Native LISTEN/NOTIFY backend for async psycopg adapters."""
|
|
138
|
+
|
|
139
|
+
__slots__ = ("_config", "_listen_connection", "_listen_connection_cm", "_runtime")
|
|
140
|
+
|
|
141
|
+
supports_sync = False
|
|
142
|
+
supports_async = True
|
|
143
|
+
backend_name = "listen_notify"
|
|
144
|
+
|
|
145
|
+
def __init__(self, config: "PsycopgAsyncConfig") -> None:
|
|
146
|
+
if "psycopg" not in type(config).__module__:
|
|
147
|
+
msg = "Psycopg events backend requires a Psycopg adapter"
|
|
148
|
+
raise ImproperConfigurationError(msg)
|
|
149
|
+
if not config.is_async:
|
|
150
|
+
msg = "PsycopgAsyncEventsBackend requires an async adapter"
|
|
151
|
+
raise ImproperConfigurationError(msg)
|
|
152
|
+
self._config = config
|
|
153
|
+
self._runtime = config.get_observability_runtime()
|
|
154
|
+
self._listen_connection: Any | None = None
|
|
155
|
+
self._listen_connection_cm: Any | None = None
|
|
156
|
+
|
|
157
|
+
async def publish(self, channel: str, payload: "dict[str, Any]", metadata: "dict[str, Any] | None" = None) -> str:
|
|
158
|
+
event_id = uuid4().hex
|
|
159
|
+
session_cm = self._config.provide_session()
|
|
160
|
+
async with session_cm as driver:
|
|
161
|
+
await driver.execute(
|
|
162
|
+
SQL(
|
|
163
|
+
"SELECT pg_notify(:channel, :payload)",
|
|
164
|
+
{"channel": channel, "payload": encode_notify_payload(event_id, payload, metadata)},
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
await driver.commit()
|
|
168
|
+
self._runtime.increment_metric("events.publish.native")
|
|
169
|
+
return event_id
|
|
170
|
+
|
|
171
|
+
async def dequeue(self, channel: str, poll_interval: float) -> EventMessage | None:
|
|
172
|
+
connection = await self._ensure_listener(channel)
|
|
173
|
+
async for notify in connection.notifies(timeout=poll_interval, stop_after=1):
|
|
174
|
+
if notify.channel == channel:
|
|
175
|
+
return decode_notify_payload(channel, notify.payload)
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
async def ack(self, _event_id: str) -> None:
|
|
179
|
+
self._runtime.increment_metric("events.ack")
|
|
180
|
+
|
|
181
|
+
async def nack(self, _event_id: str) -> None:
|
|
182
|
+
"""Return an event to the queue (no-op for native LISTEN/NOTIFY)."""
|
|
183
|
+
|
|
184
|
+
async def shutdown(self) -> None:
|
|
185
|
+
"""Shutdown the listener and release resources."""
|
|
186
|
+
if self._listen_connection_cm is not None:
|
|
187
|
+
with contextlib.suppress(Exception):
|
|
188
|
+
await self._listen_connection_cm.__aexit__(None, None, None)
|
|
189
|
+
self._listen_connection = None
|
|
190
|
+
self._listen_connection_cm = None
|
|
191
|
+
|
|
192
|
+
async def _ensure_listener(self, channel: str) -> Any:
|
|
193
|
+
"""Ensure listener connection is established for the channel."""
|
|
194
|
+
if self._listen_connection is None:
|
|
195
|
+
validated_channel = normalize_event_channel_name(channel)
|
|
196
|
+
self._listen_connection_cm = self._config.provide_connection()
|
|
197
|
+
self._listen_connection = await self._listen_connection_cm.__aenter__()
|
|
198
|
+
if self._listen_connection is not None:
|
|
199
|
+
await self._listen_connection.set_autocommit(True)
|
|
200
|
+
await self._listen_connection.execute(f"LISTEN {validated_channel}")
|
|
201
|
+
return self._listen_connection
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class PsycopgSyncHybridEventsBackend:
|
|
205
|
+
"""Durable hybrid backend for sync psycopg adapters."""
|
|
206
|
+
|
|
207
|
+
__slots__ = ("_config", "_listen_connection", "_listen_connection_cm", "_queue", "_runtime")
|
|
208
|
+
|
|
209
|
+
supports_sync = True
|
|
210
|
+
supports_async = False
|
|
211
|
+
backend_name = "listen_notify_durable"
|
|
212
|
+
|
|
213
|
+
def __init__(self, config: "PsycopgSyncConfig", queue: "SyncTableEventQueue") -> None:
|
|
214
|
+
if "psycopg" not in type(config).__module__:
|
|
215
|
+
msg = "Psycopg hybrid backend requires a Psycopg adapter"
|
|
216
|
+
raise ImproperConfigurationError(msg)
|
|
217
|
+
if config.is_async:
|
|
218
|
+
msg = "PsycopgSyncHybridEventsBackend requires a sync adapter"
|
|
219
|
+
raise ImproperConfigurationError(msg)
|
|
220
|
+
self._config = config
|
|
221
|
+
self._queue = queue
|
|
222
|
+
self._runtime = config.get_observability_runtime()
|
|
223
|
+
self._listen_connection: Any | None = None
|
|
224
|
+
self._listen_connection_cm: Any | None = None
|
|
225
|
+
log_with_context(
|
|
226
|
+
logger,
|
|
227
|
+
logging.DEBUG,
|
|
228
|
+
"event.listen",
|
|
229
|
+
adapter_name="psycopg",
|
|
230
|
+
backend_name=self.backend_name,
|
|
231
|
+
mode="async",
|
|
232
|
+
status="backend_ready",
|
|
233
|
+
)
|
|
234
|
+
log_with_context(
|
|
235
|
+
logger,
|
|
236
|
+
logging.DEBUG,
|
|
237
|
+
"event.listen",
|
|
238
|
+
adapter_name="psycopg",
|
|
239
|
+
backend_name=self.backend_name,
|
|
240
|
+
mode="sync",
|
|
241
|
+
status="backend_ready",
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
def publish(self, channel: str, payload: "dict[str, Any]", metadata: "dict[str, Any] | None" = None) -> str:
|
|
245
|
+
event_id = uuid4().hex
|
|
246
|
+
self._publish_durable(channel, event_id, payload, metadata)
|
|
247
|
+
self._runtime.increment_metric("events.publish.native")
|
|
248
|
+
return event_id
|
|
249
|
+
|
|
250
|
+
def dequeue(self, channel: str, poll_interval: float) -> EventMessage | None:
|
|
251
|
+
connection = self._ensure_listener(channel)
|
|
252
|
+
notify_iter = connection.notifies(timeout=poll_interval, stop_after=1)
|
|
253
|
+
with contextlib.suppress(StopIteration):
|
|
254
|
+
notify = next(notify_iter)
|
|
255
|
+
event_id = _extract_event_id(notify.payload)
|
|
256
|
+
if event_id:
|
|
257
|
+
event = self._queue.dequeue_by_event_id(event_id)
|
|
258
|
+
if event is not None:
|
|
259
|
+
return event
|
|
260
|
+
return self._queue.dequeue(channel, poll_interval)
|
|
261
|
+
|
|
262
|
+
def ack(self, event_id: str) -> None:
|
|
263
|
+
self._queue.ack(event_id)
|
|
264
|
+
self._runtime.increment_metric("events.ack")
|
|
265
|
+
|
|
266
|
+
def nack(self, event_id: str) -> None:
|
|
267
|
+
self._queue.nack(event_id)
|
|
268
|
+
self._runtime.increment_metric("events.nack")
|
|
269
|
+
|
|
270
|
+
def shutdown(self) -> None:
|
|
271
|
+
"""Shutdown the listener and release resources."""
|
|
272
|
+
if self._listen_connection_cm is not None:
|
|
273
|
+
with contextlib.suppress(Exception):
|
|
274
|
+
self._listen_connection_cm.__exit__(None, None, None)
|
|
275
|
+
self._listen_connection = None
|
|
276
|
+
self._listen_connection_cm = None
|
|
277
|
+
|
|
278
|
+
def _ensure_listener(self, channel: str) -> Any:
|
|
279
|
+
"""Ensure listener connection is established for the channel."""
|
|
280
|
+
if self._listen_connection is None:
|
|
281
|
+
validated_channel = normalize_event_channel_name(channel)
|
|
282
|
+
self._listen_connection_cm = self._config.provide_connection()
|
|
283
|
+
self._listen_connection = self._listen_connection_cm.__enter__()
|
|
284
|
+
if self._listen_connection is not None:
|
|
285
|
+
self._listen_connection.autocommit = True
|
|
286
|
+
self._listen_connection.execute(f"LISTEN {validated_channel}")
|
|
287
|
+
return self._listen_connection
|
|
288
|
+
|
|
289
|
+
def _publish_durable(
|
|
290
|
+
self, channel: str, event_id: str, payload: "dict[str, Any]", metadata: "dict[str, Any] | None"
|
|
291
|
+
) -> None:
|
|
292
|
+
"""Publish event to durable queue and send NOTIFY."""
|
|
293
|
+
now = datetime.now(timezone.utc)
|
|
294
|
+
with self._config.provide_session() as driver:
|
|
295
|
+
driver.execute(
|
|
296
|
+
SQL(
|
|
297
|
+
self._queue._upsert_sql,
|
|
298
|
+
{
|
|
299
|
+
"event_id": event_id,
|
|
300
|
+
"channel": channel,
|
|
301
|
+
"payload_json": to_json(payload),
|
|
302
|
+
"metadata_json": to_json(metadata) if metadata else None,
|
|
303
|
+
"status": "pending",
|
|
304
|
+
"available_at": now,
|
|
305
|
+
"lease_expires_at": None,
|
|
306
|
+
"attempts": 0,
|
|
307
|
+
"created_at": now,
|
|
308
|
+
},
|
|
309
|
+
statement_config=self._queue._statement_config,
|
|
310
|
+
)
|
|
311
|
+
)
|
|
312
|
+
driver.execute(
|
|
313
|
+
SQL(
|
|
314
|
+
"SELECT pg_notify(:channel, :payload)",
|
|
315
|
+
{"channel": channel, "payload": to_json({"event_id": event_id})},
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
driver.commit()
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class PsycopgAsyncHybridEventsBackend:
|
|
322
|
+
"""Durable hybrid backend for async psycopg adapters."""
|
|
323
|
+
|
|
324
|
+
__slots__ = ("_config", "_listen_connection", "_listen_connection_cm", "_queue", "_runtime")
|
|
325
|
+
|
|
326
|
+
supports_sync = False
|
|
327
|
+
supports_async = True
|
|
328
|
+
backend_name = "listen_notify_durable"
|
|
329
|
+
|
|
330
|
+
def __init__(self, config: "PsycopgAsyncConfig", queue: "AsyncTableEventQueue") -> None:
|
|
331
|
+
if "psycopg" not in type(config).__module__:
|
|
332
|
+
msg = "Psycopg hybrid backend requires a Psycopg adapter"
|
|
333
|
+
raise ImproperConfigurationError(msg)
|
|
334
|
+
if not config.is_async:
|
|
335
|
+
msg = "PsycopgAsyncHybridEventsBackend requires an async adapter"
|
|
336
|
+
raise ImproperConfigurationError(msg)
|
|
337
|
+
self._config = config
|
|
338
|
+
self._queue = queue
|
|
339
|
+
self._runtime = config.get_observability_runtime()
|
|
340
|
+
self._listen_connection: Any | None = None
|
|
341
|
+
self._listen_connection_cm: Any | None = None
|
|
342
|
+
|
|
343
|
+
async def publish(self, channel: str, payload: "dict[str, Any]", metadata: "dict[str, Any] | None" = None) -> str:
|
|
344
|
+
event_id = uuid4().hex
|
|
345
|
+
await self._publish_durable(channel, event_id, payload, metadata)
|
|
346
|
+
self._runtime.increment_metric("events.publish.native")
|
|
347
|
+
return event_id
|
|
348
|
+
|
|
349
|
+
async def dequeue(self, channel: str, poll_interval: float) -> EventMessage | None:
|
|
350
|
+
connection = await self._ensure_listener(channel)
|
|
351
|
+
async for notify in connection.notifies(timeout=poll_interval, stop_after=1):
|
|
352
|
+
event_id = _extract_event_id(notify.payload)
|
|
353
|
+
if event_id:
|
|
354
|
+
event = await self._queue.dequeue_by_event_id(event_id)
|
|
355
|
+
if event is not None:
|
|
356
|
+
return event
|
|
357
|
+
break
|
|
358
|
+
return await self._queue.dequeue(channel, poll_interval)
|
|
359
|
+
|
|
360
|
+
async def ack(self, event_id: str) -> None:
|
|
361
|
+
await self._queue.ack(event_id)
|
|
362
|
+
self._runtime.increment_metric("events.ack")
|
|
363
|
+
|
|
364
|
+
async def nack(self, event_id: str) -> None:
|
|
365
|
+
await self._queue.nack(event_id)
|
|
366
|
+
self._runtime.increment_metric("events.nack")
|
|
367
|
+
|
|
368
|
+
async def shutdown(self) -> None:
|
|
369
|
+
"""Shutdown the listener and release resources."""
|
|
370
|
+
if self._listen_connection_cm is not None:
|
|
371
|
+
with contextlib.suppress(Exception):
|
|
372
|
+
await self._listen_connection_cm.__aexit__(None, None, None)
|
|
373
|
+
self._listen_connection = None
|
|
374
|
+
self._listen_connection_cm = None
|
|
375
|
+
|
|
376
|
+
async def _ensure_listener(self, channel: str) -> Any:
|
|
377
|
+
"""Ensure listener connection is established for the channel."""
|
|
378
|
+
if self._listen_connection is None:
|
|
379
|
+
validated_channel = normalize_event_channel_name(channel)
|
|
380
|
+
self._listen_connection_cm = self._config.provide_connection()
|
|
381
|
+
self._listen_connection = await self._listen_connection_cm.__aenter__()
|
|
382
|
+
if self._listen_connection is not None:
|
|
383
|
+
await self._listen_connection.set_autocommit(True)
|
|
384
|
+
await self._listen_connection.execute(f"LISTEN {validated_channel}")
|
|
385
|
+
return self._listen_connection
|
|
386
|
+
|
|
387
|
+
async def _publish_durable(
|
|
388
|
+
self, channel: str, event_id: str, payload: "dict[str, Any]", metadata: "dict[str, Any] | None"
|
|
389
|
+
) -> None:
|
|
390
|
+
"""Publish event to durable queue and send NOTIFY."""
|
|
391
|
+
now = datetime.now(timezone.utc)
|
|
392
|
+
async with self._config.provide_session() as driver:
|
|
393
|
+
await driver.execute(
|
|
394
|
+
SQL(
|
|
395
|
+
self._queue._upsert_sql,
|
|
396
|
+
{
|
|
397
|
+
"event_id": event_id,
|
|
398
|
+
"channel": channel,
|
|
399
|
+
"payload_json": to_json(payload),
|
|
400
|
+
"metadata_json": to_json(metadata) if metadata else None,
|
|
401
|
+
"status": "pending",
|
|
402
|
+
"available_at": now,
|
|
403
|
+
"lease_expires_at": None,
|
|
404
|
+
"attempts": 0,
|
|
405
|
+
"created_at": now,
|
|
406
|
+
},
|
|
407
|
+
statement_config=self._queue._statement_config,
|
|
408
|
+
)
|
|
409
|
+
)
|
|
410
|
+
await driver.execute(
|
|
411
|
+
SQL(
|
|
412
|
+
"SELECT pg_notify(:channel, :payload)",
|
|
413
|
+
{"channel": channel, "payload": to_json({"event_id": event_id})},
|
|
414
|
+
)
|
|
415
|
+
)
|
|
416
|
+
await driver.commit()
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def create_event_backend(
|
|
420
|
+
config: "PsycopgAsyncConfig | PsycopgSyncConfig", backend_name: str, extension_settings: "dict[str, Any]"
|
|
421
|
+
) -> (
|
|
422
|
+
PsycopgSyncEventsBackend
|
|
423
|
+
| PsycopgAsyncEventsBackend
|
|
424
|
+
| PsycopgSyncHybridEventsBackend
|
|
425
|
+
| PsycopgAsyncHybridEventsBackend
|
|
426
|
+
| None
|
|
427
|
+
):
|
|
428
|
+
"""Factory used by EventChannel to create the native psycopg backend."""
|
|
429
|
+
is_async = config.is_async
|
|
430
|
+
match (backend_name, is_async):
|
|
431
|
+
case ("listen_notify", False):
|
|
432
|
+
try:
|
|
433
|
+
return PsycopgSyncEventsBackend(config) # type: ignore[arg-type]
|
|
434
|
+
except ImproperConfigurationError:
|
|
435
|
+
return None
|
|
436
|
+
case ("listen_notify", True):
|
|
437
|
+
try:
|
|
438
|
+
return PsycopgAsyncEventsBackend(config) # type: ignore[arg-type]
|
|
439
|
+
except ImproperConfigurationError:
|
|
440
|
+
return None
|
|
441
|
+
case ("listen_notify_durable", False):
|
|
442
|
+
sync_queue = cast(
|
|
443
|
+
"SyncTableEventQueue", build_queue_backend(config, extension_settings, adapter_name="psycopg")
|
|
444
|
+
)
|
|
445
|
+
try:
|
|
446
|
+
return PsycopgSyncHybridEventsBackend(config, sync_queue) # type: ignore[arg-type]
|
|
447
|
+
except ImproperConfigurationError:
|
|
448
|
+
return None
|
|
449
|
+
case ("listen_notify_durable", True):
|
|
450
|
+
async_queue = cast(
|
|
451
|
+
"AsyncTableEventQueue", build_queue_backend(config, extension_settings, adapter_name="psycopg")
|
|
452
|
+
)
|
|
453
|
+
try:
|
|
454
|
+
return PsycopgAsyncHybridEventsBackend(config, async_queue) # type: ignore[arg-type]
|
|
455
|
+
except ImproperConfigurationError:
|
|
456
|
+
return None
|
|
457
|
+
case _:
|
|
458
|
+
return None
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Psycopg event queue stores for sync and async drivers."""
|
|
2
|
+
|
|
3
|
+
from sqlspec.adapters.psycopg.config import PsycopgAsyncConfig, PsycopgSyncConfig
|
|
4
|
+
from sqlspec.extensions.events import BaseEventQueueStore
|
|
5
|
+
|
|
6
|
+
__all__ = ("PsycopgAsyncEventQueueStore", "PsycopgSyncEventQueueStore")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PsycopgSyncEventQueueStore(BaseEventQueueStore[PsycopgSyncConfig]):
|
|
10
|
+
"""Queue DDL for psycopg synchronous configs.
|
|
11
|
+
|
|
12
|
+
PostgreSQL uses JSONB for efficient binary JSON storage with indexing support,
|
|
13
|
+
and TIMESTAMPTZ for timezone-aware timestamps.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
__slots__ = ()
|
|
17
|
+
|
|
18
|
+
def _column_types(self) -> "tuple[str, str, str]":
|
|
19
|
+
"""Return PostgreSQL-optimized column types for the event queue.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Tuple of (payload_type, metadata_type, timestamp_type).
|
|
23
|
+
"""
|
|
24
|
+
return "JSONB", "JSONB", "TIMESTAMPTZ"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PsycopgAsyncEventQueueStore(BaseEventQueueStore[PsycopgAsyncConfig]):
|
|
28
|
+
"""Queue DDL for psycopg async configs.
|
|
29
|
+
|
|
30
|
+
PostgreSQL uses JSONB for efficient binary JSON storage with indexing support,
|
|
31
|
+
and TIMESTAMPTZ for timezone-aware timestamps.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
__slots__ = ()
|
|
35
|
+
|
|
36
|
+
def _column_types(self) -> "tuple[str, str, str]":
|
|
37
|
+
"""Return PostgreSQL-optimized column types for the event queue.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Tuple of (payload_type, metadata_type, timestamp_type).
|
|
41
|
+
"""
|
|
42
|
+
return "JSONB", "JSONB", "TIMESTAMPTZ"
|