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,420 @@
|
|
|
1
|
+
"""Runtime helpers that bundle lifecycle, observer, and span orchestration."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
5
|
+
|
|
6
|
+
from sqlspec.observability._common import compute_sql_hash, get_trace_context, resolve_db_system
|
|
7
|
+
from sqlspec.observability._config import LoggingConfig, ObservabilityConfig
|
|
8
|
+
from sqlspec.observability._dispatcher import LifecycleDispatcher, LifecycleHook
|
|
9
|
+
from sqlspec.observability._observer import StatementObserver, create_event, create_statement_observer
|
|
10
|
+
from sqlspec.observability._spans import SpanManager
|
|
11
|
+
from sqlspec.utils.correlation import CorrelationContext
|
|
12
|
+
from sqlspec.utils.type_guards import has_span_attribute
|
|
13
|
+
|
|
14
|
+
_LITERAL_PATTERN = re.compile(r"'(?:''|[^'])*'")
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from collections.abc import Iterable
|
|
18
|
+
|
|
19
|
+
from sqlspec.storage import StorageTelemetry
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ObservabilityRuntime:
|
|
23
|
+
"""Aggregates dispatchers, observers, spans, and custom metrics."""
|
|
24
|
+
|
|
25
|
+
__slots__ = (
|
|
26
|
+
"_metrics",
|
|
27
|
+
"_redaction",
|
|
28
|
+
"_statement_observers",
|
|
29
|
+
"bind_key",
|
|
30
|
+
"config",
|
|
31
|
+
"config_name",
|
|
32
|
+
"lifecycle",
|
|
33
|
+
"span_manager",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Allow test injection with fake span managers (mypyc strict typing workaround)
|
|
37
|
+
span_manager: "Any"
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self, config: ObservabilityConfig | None = None, *, bind_key: str | None = None, config_name: str | None = None
|
|
41
|
+
) -> None:
|
|
42
|
+
config = config.copy() if config else ObservabilityConfig()
|
|
43
|
+
if config.logging is None:
|
|
44
|
+
config.logging = LoggingConfig()
|
|
45
|
+
self.config = config
|
|
46
|
+
self.bind_key = bind_key
|
|
47
|
+
self.config_name = config_name or "SQLSpecConfig"
|
|
48
|
+
lifecycle_config = cast("dict[str, Iterable[LifecycleHook]] | None", config.lifecycle)
|
|
49
|
+
self.lifecycle = LifecycleDispatcher(lifecycle_config)
|
|
50
|
+
self.span_manager = SpanManager(config.telemetry)
|
|
51
|
+
observers: list[StatementObserver] = []
|
|
52
|
+
if config.statement_observers:
|
|
53
|
+
observers.extend(config.statement_observers)
|
|
54
|
+
if config.print_sql:
|
|
55
|
+
observers.append(create_statement_observer(config.logging))
|
|
56
|
+
self._statement_observers = tuple(observers)
|
|
57
|
+
self._redaction = config.redaction.copy() if config.redaction else None
|
|
58
|
+
self._metrics: dict[str, float] = {}
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def has_statement_observers(self) -> bool:
|
|
62
|
+
"""Return True when any observers are registered."""
|
|
63
|
+
|
|
64
|
+
return bool(self._statement_observers)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def diagnostics_key(self) -> str:
|
|
68
|
+
"""Derive diagnostics key from bind key or configuration name."""
|
|
69
|
+
|
|
70
|
+
if self.bind_key:
|
|
71
|
+
return self.bind_key
|
|
72
|
+
return self.config_name
|
|
73
|
+
|
|
74
|
+
def base_context(self) -> dict[str, Any]:
|
|
75
|
+
"""Return the base payload for lifecycle events."""
|
|
76
|
+
|
|
77
|
+
context = {"config": self.config_name}
|
|
78
|
+
if self.bind_key:
|
|
79
|
+
context["bind_key"] = self.bind_key
|
|
80
|
+
correlation_id = CorrelationContext.get()
|
|
81
|
+
if correlation_id:
|
|
82
|
+
context["correlation_id"] = correlation_id
|
|
83
|
+
return context
|
|
84
|
+
|
|
85
|
+
def _build_context(self, **extras: Any) -> dict[str, Any]:
|
|
86
|
+
context = self.base_context()
|
|
87
|
+
context.update({key: value for key, value in extras.items() if value is not None})
|
|
88
|
+
return context
|
|
89
|
+
|
|
90
|
+
def lifecycle_snapshot(self) -> dict[str, int]:
|
|
91
|
+
"""Return lifecycle counters keyed under the diagnostics prefix."""
|
|
92
|
+
|
|
93
|
+
return self.lifecycle.snapshot(prefix=self.diagnostics_key)
|
|
94
|
+
|
|
95
|
+
def metrics_snapshot(self) -> dict[str, float]:
|
|
96
|
+
"""Return accumulated custom metrics with diagnostics prefix."""
|
|
97
|
+
|
|
98
|
+
if not self._metrics:
|
|
99
|
+
return {}
|
|
100
|
+
prefix = self.diagnostics_key
|
|
101
|
+
return {f"{prefix}.{name}": value for name, value in self._metrics.items()}
|
|
102
|
+
|
|
103
|
+
def increment_metric(self, name: str, amount: float = 1.0) -> None:
|
|
104
|
+
"""Increment a custom metric counter."""
|
|
105
|
+
|
|
106
|
+
self._metrics[name] = self._metrics.get(name, 0.0) + amount
|
|
107
|
+
|
|
108
|
+
def record_metric(self, name: str, value: float) -> None:
|
|
109
|
+
"""Set a custom metric to an explicit value."""
|
|
110
|
+
|
|
111
|
+
self._metrics[name] = value
|
|
112
|
+
|
|
113
|
+
def start_migration_span(
|
|
114
|
+
self, event: str, *, version: "str | None" = None, metadata: "dict[str, Any] | None" = None
|
|
115
|
+
) -> Any:
|
|
116
|
+
"""Start a migration span when telemetry is enabled."""
|
|
117
|
+
|
|
118
|
+
if not self.span_manager.is_enabled:
|
|
119
|
+
return None
|
|
120
|
+
attributes: dict[str, Any] = {"sqlspec.migration.event": event, "sqlspec.config": self.config_name}
|
|
121
|
+
if self.bind_key:
|
|
122
|
+
attributes["sqlspec.bind_key"] = self.bind_key
|
|
123
|
+
correlation_id = CorrelationContext.get()
|
|
124
|
+
if correlation_id:
|
|
125
|
+
attributes["sqlspec.correlation_id"] = correlation_id
|
|
126
|
+
if version:
|
|
127
|
+
attributes["sqlspec.migration.version"] = version
|
|
128
|
+
if metadata:
|
|
129
|
+
for key, value in metadata.items():
|
|
130
|
+
if value is not None:
|
|
131
|
+
attributes[f"sqlspec.migration.{key}"] = value
|
|
132
|
+
return self.span_manager.start_span(f"sqlspec.migration.{event}", attributes)
|
|
133
|
+
|
|
134
|
+
def end_migration_span(
|
|
135
|
+
self, span: Any, *, duration_ms: "int | None" = None, error: "Exception | None" = None
|
|
136
|
+
) -> None:
|
|
137
|
+
"""Finish a migration span, attaching optional duration metadata."""
|
|
138
|
+
|
|
139
|
+
if span is None:
|
|
140
|
+
return
|
|
141
|
+
if duration_ms is not None and has_span_attribute(span):
|
|
142
|
+
span.set_attribute("sqlspec.migration.duration_ms", duration_ms)
|
|
143
|
+
self.span_manager.end_span(span, error=error)
|
|
144
|
+
|
|
145
|
+
def emit_pool_create(self, pool: Any) -> None:
|
|
146
|
+
span = self._start_lifecycle_span("pool.create", subject=pool)
|
|
147
|
+
try:
|
|
148
|
+
if self.lifecycle.has_pool_create:
|
|
149
|
+
self.lifecycle.emit_pool_create(self._build_context(pool=pool))
|
|
150
|
+
finally:
|
|
151
|
+
self.span_manager.end_span(span)
|
|
152
|
+
|
|
153
|
+
def emit_pool_destroy(self, pool: Any) -> None:
|
|
154
|
+
span = self._start_lifecycle_span("pool.destroy", subject=pool)
|
|
155
|
+
try:
|
|
156
|
+
if self.lifecycle.has_pool_destroy:
|
|
157
|
+
self.lifecycle.emit_pool_destroy(self._build_context(pool=pool))
|
|
158
|
+
finally:
|
|
159
|
+
self.span_manager.end_span(span)
|
|
160
|
+
|
|
161
|
+
def emit_connection_create(self, connection: Any) -> None:
|
|
162
|
+
span = self._start_lifecycle_span("connection.create", subject=connection)
|
|
163
|
+
try:
|
|
164
|
+
if self.lifecycle.has_connection_create:
|
|
165
|
+
self.lifecycle.emit_connection_create(self._build_context(connection=connection))
|
|
166
|
+
finally:
|
|
167
|
+
self.span_manager.end_span(span)
|
|
168
|
+
|
|
169
|
+
def emit_connection_destroy(self, connection: Any) -> None:
|
|
170
|
+
span = self._start_lifecycle_span("connection.destroy", subject=connection)
|
|
171
|
+
try:
|
|
172
|
+
if self.lifecycle.has_connection_destroy:
|
|
173
|
+
self.lifecycle.emit_connection_destroy(self._build_context(connection=connection))
|
|
174
|
+
finally:
|
|
175
|
+
self.span_manager.end_span(span)
|
|
176
|
+
|
|
177
|
+
def emit_session_start(self, session: Any) -> None:
|
|
178
|
+
span = self._start_lifecycle_span("session.start", subject=session)
|
|
179
|
+
try:
|
|
180
|
+
if self.lifecycle.has_session_start:
|
|
181
|
+
self.lifecycle.emit_session_start(self._build_context(session=session))
|
|
182
|
+
finally:
|
|
183
|
+
self.span_manager.end_span(span)
|
|
184
|
+
|
|
185
|
+
def emit_session_end(self, session: Any) -> None:
|
|
186
|
+
span = self._start_lifecycle_span("session.end", subject=session)
|
|
187
|
+
try:
|
|
188
|
+
if self.lifecycle.has_session_end:
|
|
189
|
+
self.lifecycle.emit_session_end(self._build_context(session=session))
|
|
190
|
+
finally:
|
|
191
|
+
self.span_manager.end_span(span)
|
|
192
|
+
|
|
193
|
+
def emit_query_start(self, **extras: Any) -> None:
|
|
194
|
+
if self.lifecycle.has_query_start:
|
|
195
|
+
self.lifecycle.emit_query_start(self._build_context(**extras))
|
|
196
|
+
|
|
197
|
+
def emit_query_complete(self, **extras: Any) -> None:
|
|
198
|
+
if self.lifecycle.has_query_complete:
|
|
199
|
+
self.lifecycle.emit_query_complete(self._build_context(**extras))
|
|
200
|
+
|
|
201
|
+
def emit_error(self, exception: Exception, **extras: Any) -> None:
|
|
202
|
+
if self.lifecycle.has_error:
|
|
203
|
+
payload = self._build_context(exception=exception)
|
|
204
|
+
payload.update({key: value for key, value in extras.items() if value is not None})
|
|
205
|
+
self.lifecycle.emit_error(payload)
|
|
206
|
+
self.increment_metric("errors", 1.0)
|
|
207
|
+
|
|
208
|
+
def emit_statement_event(
|
|
209
|
+
self,
|
|
210
|
+
*,
|
|
211
|
+
sql: str,
|
|
212
|
+
parameters: Any,
|
|
213
|
+
driver: str,
|
|
214
|
+
operation: str,
|
|
215
|
+
execution_mode: str | None,
|
|
216
|
+
is_many: bool,
|
|
217
|
+
is_script: bool,
|
|
218
|
+
rows_affected: int | None,
|
|
219
|
+
duration_s: float,
|
|
220
|
+
storage_backend: str | None,
|
|
221
|
+
started_at: float | None = None,
|
|
222
|
+
) -> None:
|
|
223
|
+
"""Emit a statement event to all registered observers."""
|
|
224
|
+
|
|
225
|
+
if not self._statement_observers:
|
|
226
|
+
return
|
|
227
|
+
sanitized_sql = self._redact_sql(sql)
|
|
228
|
+
sanitized_params = self._redact_parameters(parameters)
|
|
229
|
+
correlation_id = CorrelationContext.get()
|
|
230
|
+
logging_config = self.config.logging
|
|
231
|
+
db_system = resolve_db_system(self.config_name)
|
|
232
|
+
sql_hash = None
|
|
233
|
+
if logging_config and logging_config.include_sql_hash:
|
|
234
|
+
sql_hash = compute_sql_hash(sanitized_sql)
|
|
235
|
+
sql_truncation_length = logging_config.sql_truncation_length if logging_config else 2000
|
|
236
|
+
sql_original_length = len(sanitized_sql)
|
|
237
|
+
sql_truncated = sql_original_length > sql_truncation_length
|
|
238
|
+
trace_id = None
|
|
239
|
+
span_id = None
|
|
240
|
+
if logging_config and logging_config.include_trace_context:
|
|
241
|
+
trace_id, span_id = get_trace_context()
|
|
242
|
+
event = create_event(
|
|
243
|
+
sql=sanitized_sql,
|
|
244
|
+
parameters=sanitized_params,
|
|
245
|
+
driver=driver,
|
|
246
|
+
adapter=self.config_name,
|
|
247
|
+
bind_key=self.bind_key,
|
|
248
|
+
db_system=db_system,
|
|
249
|
+
operation=operation,
|
|
250
|
+
execution_mode=execution_mode,
|
|
251
|
+
is_many=is_many,
|
|
252
|
+
is_script=is_script,
|
|
253
|
+
rows_affected=rows_affected,
|
|
254
|
+
duration_s=duration_s,
|
|
255
|
+
correlation_id=correlation_id,
|
|
256
|
+
storage_backend=storage_backend,
|
|
257
|
+
started_at=started_at,
|
|
258
|
+
sql_hash=sql_hash,
|
|
259
|
+
sql_truncated=sql_truncated,
|
|
260
|
+
sql_original_length=sql_original_length,
|
|
261
|
+
trace_id=trace_id,
|
|
262
|
+
span_id=span_id,
|
|
263
|
+
)
|
|
264
|
+
for observer in self._statement_observers:
|
|
265
|
+
observer(event)
|
|
266
|
+
|
|
267
|
+
def start_query_span(self, sql: str, operation: str, driver: str) -> Any:
|
|
268
|
+
"""Start a query span with runtime metadata."""
|
|
269
|
+
|
|
270
|
+
sql_hash = compute_sql_hash(sql)
|
|
271
|
+
connection_info = {"sqlspec.statement.hash": sql_hash, "sqlspec.statement.length": len(sql)}
|
|
272
|
+
sql_payload = ""
|
|
273
|
+
if self.config.print_sql:
|
|
274
|
+
sql_payload = self._redact_sql(sql)
|
|
275
|
+
sql_payload, truncated = _truncate_text(sql_payload, max_chars=4096)
|
|
276
|
+
if truncated:
|
|
277
|
+
connection_info["sqlspec.statement.truncated"] = True
|
|
278
|
+
|
|
279
|
+
correlation_id = CorrelationContext.get()
|
|
280
|
+
return self.span_manager.start_query_span(
|
|
281
|
+
driver=driver,
|
|
282
|
+
adapter=self.config_name,
|
|
283
|
+
bind_key=self.bind_key,
|
|
284
|
+
sql=sql_payload,
|
|
285
|
+
operation=operation,
|
|
286
|
+
connection_info=connection_info,
|
|
287
|
+
correlation_id=correlation_id,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
def start_storage_span(
|
|
291
|
+
self, operation: str, *, destination: str | None = None, format_label: str | None = None
|
|
292
|
+
) -> Any:
|
|
293
|
+
"""Start a storage bridge span for read/write operations."""
|
|
294
|
+
|
|
295
|
+
if not self.span_manager.is_enabled:
|
|
296
|
+
return None
|
|
297
|
+
attributes: dict[str, Any] = {"sqlspec.storage.operation": operation, "sqlspec.config": self.config_name}
|
|
298
|
+
if self.bind_key:
|
|
299
|
+
attributes["sqlspec.bind_key"] = self.bind_key
|
|
300
|
+
correlation_id = CorrelationContext.get()
|
|
301
|
+
if correlation_id:
|
|
302
|
+
attributes["sqlspec.correlation_id"] = correlation_id
|
|
303
|
+
if destination:
|
|
304
|
+
attributes["sqlspec.storage.destination"] = destination
|
|
305
|
+
if format_label:
|
|
306
|
+
attributes["sqlspec.storage.format"] = format_label
|
|
307
|
+
return self.span_manager.start_span(f"sqlspec.storage.{operation}", attributes)
|
|
308
|
+
|
|
309
|
+
def start_span(self, name: str, *, attributes: dict[str, Any] | None = None) -> Any:
|
|
310
|
+
"""Start a custom span enriched with configuration context."""
|
|
311
|
+
|
|
312
|
+
if not self.span_manager.is_enabled:
|
|
313
|
+
return None
|
|
314
|
+
merged: dict[str, Any] = attributes.copy() if attributes else {}
|
|
315
|
+
merged.setdefault("sqlspec.config", self.config_name)
|
|
316
|
+
if self.bind_key:
|
|
317
|
+
merged.setdefault("sqlspec.bind_key", self.bind_key)
|
|
318
|
+
correlation_id = CorrelationContext.get()
|
|
319
|
+
if correlation_id:
|
|
320
|
+
merged.setdefault("sqlspec.correlation_id", correlation_id)
|
|
321
|
+
return self.span_manager.start_span(name, merged)
|
|
322
|
+
|
|
323
|
+
def end_span(self, span: Any, *, error: Exception | None = None) -> None:
|
|
324
|
+
"""Finish a custom span."""
|
|
325
|
+
|
|
326
|
+
self.span_manager.end_span(span, error=error)
|
|
327
|
+
|
|
328
|
+
def end_storage_span(
|
|
329
|
+
self, span: Any, *, telemetry: "StorageTelemetry | None" = None, error: Exception | None = None
|
|
330
|
+
) -> None:
|
|
331
|
+
"""Finish a storage span, attaching telemetry metadata when available."""
|
|
332
|
+
|
|
333
|
+
if span is None:
|
|
334
|
+
return
|
|
335
|
+
if telemetry:
|
|
336
|
+
telemetry = self.annotate_storage_telemetry(telemetry)
|
|
337
|
+
self._attach_storage_telemetry(span, telemetry)
|
|
338
|
+
self.span_manager.end_span(span, error=error)
|
|
339
|
+
|
|
340
|
+
def annotate_storage_telemetry(self, telemetry: "StorageTelemetry") -> "StorageTelemetry":
|
|
341
|
+
"""Add bind key / config / correlation metadata to telemetry payloads."""
|
|
342
|
+
|
|
343
|
+
annotated = telemetry
|
|
344
|
+
base = self.base_context()
|
|
345
|
+
correlation_id = base.get("correlation_id")
|
|
346
|
+
if correlation_id and not annotated.get("correlation_id"):
|
|
347
|
+
annotated["correlation_id"] = correlation_id
|
|
348
|
+
annotated.setdefault("config", self.config_name)
|
|
349
|
+
if self.bind_key and not annotated.get("bind_key"):
|
|
350
|
+
annotated["bind_key"] = self.bind_key
|
|
351
|
+
return annotated
|
|
352
|
+
|
|
353
|
+
def _start_lifecycle_span(self, event: str, subject: Any | None = None) -> Any:
|
|
354
|
+
if not self.span_manager.is_enabled:
|
|
355
|
+
return None
|
|
356
|
+
attributes: dict[str, Any] = {"sqlspec.lifecycle.event": event, "sqlspec.config": self.config_name}
|
|
357
|
+
if self.bind_key:
|
|
358
|
+
attributes["sqlspec.bind_key"] = self.bind_key
|
|
359
|
+
correlation_id = CorrelationContext.get()
|
|
360
|
+
if correlation_id:
|
|
361
|
+
attributes["sqlspec.correlation_id"] = correlation_id
|
|
362
|
+
if subject is not None:
|
|
363
|
+
attributes["sqlspec.lifecycle.subject_type"] = type(subject).__name__
|
|
364
|
+
return self.span_manager.start_span(f"sqlspec.lifecycle.{event}", attributes)
|
|
365
|
+
|
|
366
|
+
def _attach_storage_telemetry(self, span: Any, telemetry: "StorageTelemetry") -> None:
|
|
367
|
+
if not has_span_attribute(span):
|
|
368
|
+
return
|
|
369
|
+
if "backend" in telemetry and telemetry["backend"] is not None:
|
|
370
|
+
span.set_attribute("sqlspec.storage.backend", telemetry["backend"])
|
|
371
|
+
if "bytes_processed" in telemetry and telemetry["bytes_processed"] is not None:
|
|
372
|
+
span.set_attribute("sqlspec.storage.bytes_processed", telemetry["bytes_processed"])
|
|
373
|
+
if "rows_processed" in telemetry and telemetry["rows_processed"] is not None:
|
|
374
|
+
span.set_attribute("sqlspec.storage.rows_processed", telemetry["rows_processed"])
|
|
375
|
+
if "destination" in telemetry and telemetry["destination"] is not None:
|
|
376
|
+
span.set_attribute("sqlspec.storage.destination", telemetry["destination"])
|
|
377
|
+
if "format" in telemetry and telemetry["format"] is not None:
|
|
378
|
+
span.set_attribute("sqlspec.storage.format", telemetry["format"])
|
|
379
|
+
if "duration_s" in telemetry and telemetry["duration_s"] is not None:
|
|
380
|
+
span.set_attribute("sqlspec.storage.duration_s", telemetry["duration_s"])
|
|
381
|
+
if "correlation_id" in telemetry and telemetry["correlation_id"] is not None:
|
|
382
|
+
span.set_attribute("sqlspec.correlation_id", telemetry["correlation_id"])
|
|
383
|
+
|
|
384
|
+
def _redact_sql(self, sql: str) -> str:
|
|
385
|
+
config = self._redaction
|
|
386
|
+
if config is None or not config.mask_literals:
|
|
387
|
+
return sql
|
|
388
|
+
return _LITERAL_PATTERN.sub("'***'", sql)
|
|
389
|
+
|
|
390
|
+
def _redact_parameters(self, parameters: Any) -> Any:
|
|
391
|
+
config = self._redaction
|
|
392
|
+
if config is None or not config.mask_parameters:
|
|
393
|
+
return parameters
|
|
394
|
+
allow_list = set(config.parameter_allow_list or ())
|
|
395
|
+
return _mask_parameters(parameters, allow_list)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _mask_parameters(value: Any, allow_list: set[str]) -> Any:
|
|
399
|
+
if isinstance(value, dict):
|
|
400
|
+
masked: dict[str, Any] = {}
|
|
401
|
+
for key, item in value.items():
|
|
402
|
+
if allow_list and key in allow_list:
|
|
403
|
+
masked[key] = _mask_parameters(item, allow_list)
|
|
404
|
+
else:
|
|
405
|
+
masked[key] = "***"
|
|
406
|
+
return masked
|
|
407
|
+
if isinstance(value, list):
|
|
408
|
+
return [_mask_parameters(item, allow_list) for item in value]
|
|
409
|
+
if isinstance(value, tuple):
|
|
410
|
+
return tuple(_mask_parameters(item, allow_list) for item in value)
|
|
411
|
+
return "***"
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def _truncate_text(value: str, *, max_chars: int) -> tuple[str, bool]:
|
|
415
|
+
if len(value) <= max_chars:
|
|
416
|
+
return value, False
|
|
417
|
+
return value[:max_chars], True
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
__all__ = ("ObservabilityRuntime",)
|
|
Binary file
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Sampling configuration for observability data.
|
|
2
|
+
|
|
3
|
+
This module provides sampling configuration to control the volume of
|
|
4
|
+
logs, metrics, and traces emitted by the observability system.
|
|
5
|
+
Sampling can significantly reduce cloud logging costs while maintaining
|
|
6
|
+
visibility into errors and slow queries.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import random
|
|
10
|
+
from typing import ClassVar
|
|
11
|
+
|
|
12
|
+
__all__ = ("SamplingConfig",)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SamplingConfig:
|
|
16
|
+
"""Configuration for log and metric sampling.
|
|
17
|
+
|
|
18
|
+
Controls when observability data (logs, spans, metrics) is emitted.
|
|
19
|
+
Supports both random and deterministic sampling modes, with
|
|
20
|
+
force-sample conditions for errors and slow queries.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
sample_rate: Probability of sampling (0.0 to 1.0). 1.0 means always sample.
|
|
24
|
+
force_sample_on_error: If True, always sample when an error occurs.
|
|
25
|
+
force_sample_slow_queries_ms: If set, always sample queries slower than this threshold.
|
|
26
|
+
deterministic: If True, use hash-based sampling for consistency across distributed systems.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
```python
|
|
30
|
+
# Sample 10% of requests, but always sample errors and slow queries
|
|
31
|
+
config = SamplingConfig(
|
|
32
|
+
sample_rate=0.1,
|
|
33
|
+
force_sample_on_error=True,
|
|
34
|
+
force_sample_slow_queries_ms=100.0,
|
|
35
|
+
deterministic=True,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Check if a request should be sampled
|
|
39
|
+
if config.should_sample(
|
|
40
|
+
correlation_id="abc-123",
|
|
41
|
+
is_error=False,
|
|
42
|
+
duration_ms=50.0,
|
|
43
|
+
):
|
|
44
|
+
emit_logs()
|
|
45
|
+
```
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
__slots__ = ("deterministic", "force_sample_on_error", "force_sample_slow_queries_ms", "sample_rate")
|
|
49
|
+
|
|
50
|
+
DEFAULT_SAMPLE_RATE: ClassVar[float] = 1.0
|
|
51
|
+
"""Default sample rate (100% - sample everything)."""
|
|
52
|
+
|
|
53
|
+
DEFAULT_SLOW_QUERY_THRESHOLD_MS: ClassVar[float] = 100.0
|
|
54
|
+
"""Default threshold in milliseconds for slow query detection."""
|
|
55
|
+
|
|
56
|
+
HASH_MODULUS: ClassVar[int] = 10000
|
|
57
|
+
"""Modulus for deterministic hash-based sampling."""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
*,
|
|
62
|
+
sample_rate: float = 1.0,
|
|
63
|
+
force_sample_on_error: bool = True,
|
|
64
|
+
force_sample_slow_queries_ms: float | None = 100.0,
|
|
65
|
+
deterministic: bool = True,
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Initialize sampling configuration.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
sample_rate: Probability of sampling (0.0 to 1.0). Values outside
|
|
71
|
+
this range are clamped. Defaults to 1.0 (always sample).
|
|
72
|
+
force_sample_on_error: If True, always sample when an error occurs.
|
|
73
|
+
Defaults to True.
|
|
74
|
+
force_sample_slow_queries_ms: If set, always sample queries that take
|
|
75
|
+
longer than this threshold in milliseconds. Defaults to 100.0ms.
|
|
76
|
+
Set to None to disable.
|
|
77
|
+
deterministic: If True, use hash-based sampling that produces consistent
|
|
78
|
+
results for the same correlation ID across distributed systems.
|
|
79
|
+
If False, use random sampling. Defaults to True.
|
|
80
|
+
"""
|
|
81
|
+
self.sample_rate = max(0.0, min(1.0, sample_rate))
|
|
82
|
+
self.force_sample_on_error = force_sample_on_error
|
|
83
|
+
self.force_sample_slow_queries_ms = force_sample_slow_queries_ms
|
|
84
|
+
self.deterministic = deterministic
|
|
85
|
+
|
|
86
|
+
def should_sample(
|
|
87
|
+
self,
|
|
88
|
+
correlation_id: str | None = None,
|
|
89
|
+
*,
|
|
90
|
+
is_error: bool = False,
|
|
91
|
+
duration_ms: float | None = None,
|
|
92
|
+
force: bool = False,
|
|
93
|
+
) -> bool:
|
|
94
|
+
"""Determine if this request should be sampled.
|
|
95
|
+
|
|
96
|
+
Evaluates force-sample conditions first (errors, slow queries, explicit force),
|
|
97
|
+
then falls back to rate-based sampling.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
correlation_id: The correlation ID for deterministic sampling.
|
|
101
|
+
If None and deterministic=True, falls back to random sampling.
|
|
102
|
+
is_error: Whether this request resulted in an error.
|
|
103
|
+
duration_ms: Query duration in milliseconds, if known.
|
|
104
|
+
force: Explicit force-sample flag from application code.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
True if the request should be sampled, False otherwise.
|
|
108
|
+
|
|
109
|
+
Example:
|
|
110
|
+
```python
|
|
111
|
+
# Always sampled due to error
|
|
112
|
+
config.should_sample(is_error=True) # True
|
|
113
|
+
|
|
114
|
+
# Always sampled due to slow query (>100ms default)
|
|
115
|
+
config.should_sample(duration_ms=150.0) # True
|
|
116
|
+
|
|
117
|
+
# Rate-based sampling
|
|
118
|
+
config.should_sample(
|
|
119
|
+
correlation_id="abc-123"
|
|
120
|
+
) # depends on rate
|
|
121
|
+
```
|
|
122
|
+
"""
|
|
123
|
+
# Force sample conditions take precedence
|
|
124
|
+
if force:
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
if is_error and self.force_sample_on_error:
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
if (
|
|
131
|
+
duration_ms is not None
|
|
132
|
+
and self.force_sample_slow_queries_ms is not None
|
|
133
|
+
and duration_ms >= self.force_sample_slow_queries_ms
|
|
134
|
+
):
|
|
135
|
+
return True
|
|
136
|
+
|
|
137
|
+
# Rate-based sampling
|
|
138
|
+
if self.sample_rate >= 1.0:
|
|
139
|
+
return True
|
|
140
|
+
|
|
141
|
+
if self.sample_rate <= 0.0:
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
# Deterministic or random sampling
|
|
145
|
+
if self.deterministic and correlation_id:
|
|
146
|
+
# Hash-based sampling for consistency across distributed systems
|
|
147
|
+
hash_value = hash(correlation_id) % self.HASH_MODULUS
|
|
148
|
+
threshold = int(self.sample_rate * self.HASH_MODULUS)
|
|
149
|
+
return hash_value < threshold
|
|
150
|
+
|
|
151
|
+
# Fall back to random sampling
|
|
152
|
+
return random.random() < self.sample_rate # noqa: S311
|
|
153
|
+
|
|
154
|
+
def copy(self) -> "SamplingConfig":
|
|
155
|
+
"""Return a copy of the sampling configuration.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
A new SamplingConfig instance with the same values.
|
|
159
|
+
"""
|
|
160
|
+
return SamplingConfig(
|
|
161
|
+
sample_rate=self.sample_rate,
|
|
162
|
+
force_sample_on_error=self.force_sample_on_error,
|
|
163
|
+
force_sample_slow_queries_ms=self.force_sample_slow_queries_ms,
|
|
164
|
+
deterministic=self.deterministic,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def __repr__(self) -> str:
|
|
168
|
+
return (
|
|
169
|
+
f"SamplingConfig(sample_rate={self.sample_rate!r}, "
|
|
170
|
+
f"force_sample_on_error={self.force_sample_on_error!r}, "
|
|
171
|
+
f"force_sample_slow_queries_ms={self.force_sample_slow_queries_ms!r}, "
|
|
172
|
+
f"deterministic={self.deterministic!r})"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
def __eq__(self, other: object) -> bool:
|
|
176
|
+
if not isinstance(other, SamplingConfig):
|
|
177
|
+
return NotImplemented
|
|
178
|
+
return (
|
|
179
|
+
self.sample_rate == other.sample_rate
|
|
180
|
+
and self.force_sample_on_error == other.force_sample_on_error
|
|
181
|
+
and self.force_sample_slow_queries_ms == other.force_sample_slow_queries_ms
|
|
182
|
+
and self.deterministic == other.deterministic
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
def __hash__(self) -> int:
|
|
186
|
+
# SamplingConfig is mutable, so it should not be hashable
|
|
187
|
+
msg = "SamplingConfig objects are mutable and unhashable"
|
|
188
|
+
raise TypeError(msg)
|
|
Binary file
|