sqlspec 0.47.0__cp314-cp314-win_amd64.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.
- f68e0789eb443ecb1c2c__mypyc.cp314-win_amd64.pyd +0 -0
- sqlspec/__init__.py +167 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_typing.py +714 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +13 -0
- sqlspec/adapters/adbc/_typing.py +106 -0
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +1280 -0
- sqlspec/adapters/adbc/config.py +378 -0
- sqlspec/adapters/adbc/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/adbc/core.py +922 -0
- sqlspec/adapters/adbc/data_dictionary.py +339 -0
- sqlspec/adapters/adbc/driver.py +534 -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 +534 -0
- sqlspec/adapters/adbc/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/adbc/type_converter.py +142 -0
- sqlspec/adapters/aiomysql/__init__.py +21 -0
- sqlspec/adapters/aiomysql/_typing.py +137 -0
- sqlspec/adapters/aiomysql/adk/__init__.py +5 -0
- sqlspec/adapters/aiomysql/adk/store.py +678 -0
- sqlspec/adapters/aiomysql/config.py +305 -0
- sqlspec/adapters/aiomysql/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiomysql/core.py +536 -0
- sqlspec/adapters/aiomysql/data_dictionary.py +121 -0
- sqlspec/adapters/aiomysql/driver.py +386 -0
- sqlspec/adapters/aiomysql/events/__init__.py +5 -0
- sqlspec/adapters/aiomysql/events/store.py +104 -0
- sqlspec/adapters/aiomysql/litestar/__init__.py +5 -0
- sqlspec/adapters/aiomysql/litestar/store.py +314 -0
- sqlspec/adapters/aiosqlite/__init__.py +26 -0
- sqlspec/adapters/aiosqlite/_typing.py +109 -0
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +829 -0
- sqlspec/adapters/aiosqlite/config.py +315 -0
- sqlspec/adapters/aiosqlite/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiosqlite/core.py +315 -0
- sqlspec/adapters/aiosqlite/data_dictionary.py +202 -0
- sqlspec/adapters/aiosqlite/driver.py +311 -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.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/aiosqlite/pool.py +734 -0
- sqlspec/adapters/asyncmy/__init__.py +21 -0
- sqlspec/adapters/asyncmy/_typing.py +113 -0
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +644 -0
- sqlspec/adapters/asyncmy/config.py +307 -0
- sqlspec/adapters/asyncmy/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/asyncmy/core.py +538 -0
- sqlspec/adapters/asyncmy/data_dictionary.py +122 -0
- sqlspec/adapters/asyncmy/driver.py +391 -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 +26 -0
- sqlspec/adapters/asyncpg/_typing.py +103 -0
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +483 -0
- sqlspec/adapters/asyncpg/config.py +575 -0
- sqlspec/adapters/asyncpg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/asyncpg/core.py +480 -0
- sqlspec/adapters/asyncpg/data_dictionary.py +157 -0
- sqlspec/adapters/asyncpg/driver.py +487 -0
- sqlspec/adapters/asyncpg/events/__init__.py +6 -0
- sqlspec/adapters/asyncpg/events/_hub.py +181 -0
- sqlspec/adapters/asyncpg/events/backend.py +210 -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 +15 -0
- sqlspec/adapters/bigquery/_typing.py +108 -0
- sqlspec/adapters/bigquery/config.py +362 -0
- sqlspec/adapters/bigquery/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/bigquery/core.py +768 -0
- sqlspec/adapters/bigquery/data_dictionary.py +120 -0
- sqlspec/adapters/bigquery/driver.py +542 -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.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/bigquery/type_converter.py +107 -0
- sqlspec/adapters/cockroach_asyncpg/__init__.py +26 -0
- sqlspec/adapters/cockroach_asyncpg/_typing.py +73 -0
- sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
- sqlspec/adapters/cockroach_asyncpg/adk/store.py +465 -0
- sqlspec/adapters/cockroach_asyncpg/config.py +248 -0
- sqlspec/adapters/cockroach_asyncpg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
- sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +110 -0
- sqlspec/adapters/cockroach_asyncpg/driver.py +142 -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 +39 -0
- sqlspec/adapters/cockroach_psycopg/_typing.py +137 -0
- sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
- sqlspec/adapters/cockroach_psycopg/adk/store.py +1039 -0
- sqlspec/adapters/cockroach_psycopg/config.py +511 -0
- sqlspec/adapters/cockroach_psycopg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/cockroach_psycopg/core.py +63 -0
- sqlspec/adapters/cockroach_psycopg/data_dictionary.py +220 -0
- sqlspec/adapters/cockroach_psycopg/driver.py +273 -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 +327 -0
- sqlspec/adapters/duckdb/__init__.py +29 -0
- sqlspec/adapters/duckdb/_typing.py +104 -0
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +935 -0
- sqlspec/adapters/duckdb/config.py +386 -0
- sqlspec/adapters/duckdb/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/core.py +332 -0
- sqlspec/adapters/duckdb/data_dictionary.py +140 -0
- sqlspec/adapters/duckdb/driver.py +426 -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.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/pool.py +350 -0
- sqlspec/adapters/duckdb/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/duckdb/type_converter.py +118 -0
- sqlspec/adapters/mysqlconnector/__init__.py +39 -0
- sqlspec/adapters/mysqlconnector/_typing.py +186 -0
- sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
- sqlspec/adapters/mysqlconnector/adk/store.py +1183 -0
- sqlspec/adapters/mysqlconnector/config.py +421 -0
- sqlspec/adapters/mysqlconnector/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/mysqlconnector/core.py +472 -0
- sqlspec/adapters/mysqlconnector/data_dictionary.py +230 -0
- sqlspec/adapters/mysqlconnector/driver.py +516 -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 +39 -0
- sqlspec/adapters/oracledb/_json_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_json_handlers.py +196 -0
- sqlspec/adapters/oracledb/_param_types.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_param_types.py +46 -0
- sqlspec/adapters/oracledb/_typing.py +258 -0
- sqlspec/adapters/oracledb/_uuid_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_uuid_handlers.py +163 -0
- sqlspec/adapters/oracledb/_vector_handlers.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/_vector_handlers.py +228 -0
- sqlspec/adapters/oracledb/adk/__init__.py +21 -0
- sqlspec/adapters/oracledb/adk/store.py +2453 -0
- sqlspec/adapters/oracledb/config.py +575 -0
- sqlspec/adapters/oracledb/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/core.py +820 -0
- sqlspec/adapters/oracledb/data_dictionary.py +404 -0
- sqlspec/adapters/oracledb/driver.py +1277 -0
- sqlspec/adapters/oracledb/events/__init__.py +16 -0
- sqlspec/adapters/oracledb/events/_hub.py +345 -0
- sqlspec/adapters/oracledb/events/backend.py +300 -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 +539 -0
- sqlspec/adapters/oracledb/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/oracledb/type_converter.py +211 -0
- sqlspec/adapters/psqlpy/__init__.py +18 -0
- sqlspec/adapters/psqlpy/_typing.py +121 -0
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +591 -0
- sqlspec/adapters/psqlpy/config.py +376 -0
- sqlspec/adapters/psqlpy/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psqlpy/core.py +694 -0
- sqlspec/adapters/psqlpy/data_dictionary.py +121 -0
- sqlspec/adapters/psqlpy/driver.py +411 -0
- sqlspec/adapters/psqlpy/events/__init__.py +6 -0
- sqlspec/adapters/psqlpy/events/_hub.py +204 -0
- sqlspec/adapters/psqlpy/events/backend.py +210 -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.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psqlpy/type_converter.py +113 -0
- sqlspec/adapters/psycopg/__init__.py +38 -0
- sqlspec/adapters/psycopg/_typing.py +218 -0
- sqlspec/adapters/psycopg/adk/__init__.py +10 -0
- sqlspec/adapters/psycopg/adk/store.py +1106 -0
- sqlspec/adapters/psycopg/config.py +695 -0
- sqlspec/adapters/psycopg/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psycopg/core.py +520 -0
- sqlspec/adapters/psycopg/data_dictionary.py +278 -0
- sqlspec/adapters/psycopg/driver.py +1033 -0
- sqlspec/adapters/psycopg/events/__init__.py +20 -0
- sqlspec/adapters/psycopg/events/_hub.py +388 -0
- sqlspec/adapters/psycopg/events/backend.py +398 -0
- sqlspec/adapters/psycopg/events/store.py +42 -0
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +554 -0
- sqlspec/adapters/psycopg/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/psycopg/type_converter.py +93 -0
- sqlspec/adapters/pymysql/__init__.py +21 -0
- sqlspec/adapters/pymysql/_typing.py +92 -0
- sqlspec/adapters/pymysql/adk/__init__.py +5 -0
- sqlspec/adapters/pymysql/adk/store.py +657 -0
- sqlspec/adapters/pymysql/config.py +176 -0
- sqlspec/adapters/pymysql/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/pymysql/core.py +469 -0
- sqlspec/adapters/pymysql/data_dictionary.py +120 -0
- sqlspec/adapters/pymysql/driver.py +271 -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.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/pymysql/pool.py +184 -0
- sqlspec/adapters/spanner/__init__.py +33 -0
- sqlspec/adapters/spanner/_typing.py +102 -0
- sqlspec/adapters/spanner/adk/__init__.py +5 -0
- sqlspec/adapters/spanner/adk/store.py +758 -0
- sqlspec/adapters/spanner/config.py +355 -0
- sqlspec/adapters/spanner/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/spanner/core.py +263 -0
- sqlspec/adapters/spanner/data_dictionary.py +120 -0
- sqlspec/adapters/spanner/driver.py +407 -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.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/spanner/type_converter.py +342 -0
- sqlspec/adapters/sqlite/__init__.py +19 -0
- sqlspec/adapters/sqlite/_typing.py +123 -0
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +992 -0
- sqlspec/adapters/sqlite/config.py +240 -0
- sqlspec/adapters/sqlite/core.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/core.py +357 -0
- sqlspec/adapters/sqlite/data_dictionary.py +198 -0
- sqlspec/adapters/sqlite/driver.py +527 -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.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/pool.py +237 -0
- sqlspec/adapters/sqlite/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/adapters/sqlite/type_converter.py +114 -0
- sqlspec/base.py +832 -0
- sqlspec/builder/__init__.py +181 -0
- sqlspec/builder/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_base.py +1071 -0
- sqlspec/builder/_column.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_column.py +521 -0
- sqlspec/builder/_ddl.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_ddl.py +1691 -0
- sqlspec/builder/_delete.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_delete.py +95 -0
- sqlspec/builder/_dml.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_dml.py +386 -0
- sqlspec/builder/_explain.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_explain.py +579 -0
- sqlspec/builder/_expression_wrappers.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_expression_wrappers.py +46 -0
- sqlspec/builder/_factory.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_factory.py +1884 -0
- sqlspec/builder/_insert.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_insert.py +405 -0
- sqlspec/builder/_join.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_join.py +489 -0
- sqlspec/builder/_merge.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_merge.py +823 -0
- sqlspec/builder/_parsing_utils.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_parsing_utils.py +295 -0
- sqlspec/builder/_select.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_select.py +1666 -0
- sqlspec/builder/_temporal.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_temporal.py +167 -0
- sqlspec/builder/_update.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_update.py +173 -0
- sqlspec/builder/_vector_distance.cp314-win_amd64.pyd +0 -0
- sqlspec/builder/_vector_distance.py +330 -0
- sqlspec/cli.py +1095 -0
- sqlspec/config.py +2383 -0
- sqlspec/core/__init__.py +372 -0
- sqlspec/core/_correlation.cp314-win_amd64.pyd +0 -0
- sqlspec/core/_correlation.py +176 -0
- sqlspec/core/_pagination.py +42 -0
- sqlspec/core/_pool.cp314-win_amd64.pyd +0 -0
- sqlspec/core/_pool.py +76 -0
- sqlspec/core/cache.cp314-win_amd64.pyd +0 -0
- sqlspec/core/cache.py +1085 -0
- sqlspec/core/compiler.cp314-win_amd64.pyd +0 -0
- sqlspec/core/compiler.py +1090 -0
- sqlspec/core/config_runtime.cp314-win_amd64.pyd +0 -0
- sqlspec/core/config_runtime.py +174 -0
- sqlspec/core/explain.cp314-win_amd64.pyd +0 -0
- sqlspec/core/explain.py +275 -0
- sqlspec/core/filters.cp314-win_amd64.pyd +0 -0
- sqlspec/core/filters.py +969 -0
- sqlspec/core/hashing.cp314-win_amd64.pyd +0 -0
- sqlspec/core/hashing.py +266 -0
- sqlspec/core/metrics.cp314-win_amd64.pyd +0 -0
- sqlspec/core/metrics.py +83 -0
- sqlspec/core/parameters/__init__.py +72 -0
- sqlspec/core/parameters/_alignment.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_alignment.py +283 -0
- sqlspec/core/parameters/_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_converter.py +554 -0
- sqlspec/core/parameters/_processor.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_processor.py +1182 -0
- sqlspec/core/parameters/_registry.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_registry.py +206 -0
- sqlspec/core/parameters/_transformers.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_transformers.py +324 -0
- sqlspec/core/parameters/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_types.py +536 -0
- sqlspec/core/parameters/_validator.cp314-win_amd64.pyd +0 -0
- sqlspec/core/parameters/_validator.py +171 -0
- sqlspec/core/pipeline.cp314-win_amd64.pyd +0 -0
- sqlspec/core/pipeline.py +333 -0
- sqlspec/core/query_modifiers.cp314-win_amd64.pyd +0 -0
- sqlspec/core/query_modifiers.py +508 -0
- sqlspec/core/result/__init__.py +25 -0
- sqlspec/core/result/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/core/result/_base.py +1232 -0
- sqlspec/core/result/_io.cp314-win_amd64.pyd +0 -0
- sqlspec/core/result/_io.py +28 -0
- sqlspec/core/splitter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/splitter.py +1021 -0
- sqlspec/core/sqlcommenter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/sqlcommenter.py +249 -0
- sqlspec/core/stack.cp314-win_amd64.pyd +0 -0
- sqlspec/core/stack.py +163 -0
- sqlspec/core/statement.cp314-win_amd64.pyd +0 -0
- sqlspec/core/statement.py +1865 -0
- sqlspec/core/type_converter.cp314-win_amd64.pyd +0 -0
- sqlspec/core/type_converter.py +340 -0
- sqlspec/data_dictionary/__init__.py +22 -0
- sqlspec/data_dictionary/_loader.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_loader.py +138 -0
- sqlspec/data_dictionary/_registry.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_registry.py +74 -0
- sqlspec/data_dictionary/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/_types.py +121 -0
- sqlspec/data_dictionary/dialects/__init__.py +21 -0
- sqlspec/data_dictionary/dialects/bigquery.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/bigquery.py +81 -0
- sqlspec/data_dictionary/dialects/cockroachdb.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/cockroachdb.py +54 -0
- sqlspec/data_dictionary/dialects/duckdb.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/duckdb.py +47 -0
- sqlspec/data_dictionary/dialects/mysql.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/mysql.py +53 -0
- sqlspec/data_dictionary/dialects/oracle.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/oracle.py +197 -0
- sqlspec/data_dictionary/dialects/postgres.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/postgres.py +69 -0
- sqlspec/data_dictionary/dialects/spanner.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/spanner.py +37 -0
- sqlspec/data_dictionary/dialects/sqlite.cp314-win_amd64.pyd +0 -0
- sqlspec/data_dictionary/dialects/sqlite.py +59 -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/dialects/__init__.py +22 -0
- sqlspec/dialects/_compat.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/_compat.py +14 -0
- sqlspec/dialects/postgres/__init__.py +9 -0
- sqlspec/dialects/postgres/_generators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/postgres/_generators.py +57 -0
- sqlspec/dialects/postgres/_operators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/postgres/_operators.py +81 -0
- sqlspec/dialects/postgres/_paradedb.py +50 -0
- sqlspec/dialects/postgres/_pgvector.py +36 -0
- sqlspec/dialects/spanner/__init__.py +6 -0
- sqlspec/dialects/spanner/_generators.cp314-win_amd64.pyd +0 -0
- sqlspec/dialects/spanner/_generators.py +206 -0
- sqlspec/dialects/spanner/_spangres.py +77 -0
- sqlspec/dialects/spanner/_spanner.py +179 -0
- sqlspec/driver/__init__.py +49 -0
- sqlspec/driver/_async.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_async.py +1830 -0
- sqlspec/driver/_common.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_common.py +2292 -0
- sqlspec/driver/_exception_handler.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_exception_handler.py +108 -0
- sqlspec/driver/_query_cache.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_query_cache.py +96 -0
- sqlspec/driver/_sql_helpers.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_sql_helpers.py +139 -0
- sqlspec/driver/_storage_helpers.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_storage_helpers.py +153 -0
- sqlspec/driver/_sync.cp314-win_amd64.pyd +0 -0
- sqlspec/driver/_sync.py +1817 -0
- sqlspec/exceptions.cp314-win_amd64.pyd +0 -0
- sqlspec/exceptions.py +480 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/adk/__init__.py +84 -0
- sqlspec/extensions/adk/_config_utils.py +199 -0
- sqlspec/extensions/adk/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/_types.py +41 -0
- sqlspec/extensions/adk/artifact/__init__.py +57 -0
- sqlspec/extensions/adk/artifact/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/artifact/_types.py +32 -0
- sqlspec/extensions/adk/artifact/service.py +508 -0
- sqlspec/extensions/adk/artifact/store.py +361 -0
- sqlspec/extensions/adk/converters.py +212 -0
- sqlspec/extensions/adk/memory/__init__.py +69 -0
- sqlspec/extensions/adk/memory/_types.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/adk/memory/_types.py +30 -0
- sqlspec/extensions/adk/memory/converters.py +225 -0
- sqlspec/extensions/adk/memory/service.py +316 -0
- sqlspec/extensions/adk/memory/store.py +525 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +184 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +279 -0
- sqlspec/extensions/adk/store.py +590 -0
- sqlspec/extensions/events/__init__.py +51 -0
- sqlspec/extensions/events/_channel.py +703 -0
- sqlspec/extensions/events/_hints.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/events/_hints.py +45 -0
- sqlspec/extensions/events/_models.py +23 -0
- sqlspec/extensions/events/_payload.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/events/_payload.py +69 -0
- sqlspec/extensions/events/_protocols.py +134 -0
- sqlspec/extensions/events/_queue.py +462 -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 +22 -0
- sqlspec/extensions/fastapi/extension.py +391 -0
- sqlspec/extensions/fastapi/providers.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/fastapi/providers.py +712 -0
- sqlspec/extensions/flask/__init__.py +38 -0
- sqlspec/extensions/flask/_state.py +87 -0
- sqlspec/extensions/flask/_utils.py +71 -0
- sqlspec/extensions/flask/extension.py +539 -0
- sqlspec/extensions/litestar/__init__.py +31 -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 +1066 -0
- sqlspec/extensions/litestar/providers.cp314-win_amd64.pyd +0 -0
- sqlspec/extensions/litestar/providers.py +784 -0
- sqlspec/extensions/litestar/store.py +298 -0
- sqlspec/extensions/otel/__init__.py +58 -0
- sqlspec/extensions/prometheus/__init__.py +113 -0
- sqlspec/extensions/sanic/__init__.py +19 -0
- sqlspec/extensions/sanic/_state.py +43 -0
- sqlspec/extensions/sanic/_utils.py +127 -0
- sqlspec/extensions/sanic/extension.py +647 -0
- sqlspec/extensions/starlette/__init__.py +22 -0
- sqlspec/extensions/starlette/_state.py +42 -0
- sqlspec/extensions/starlette/_utils.py +96 -0
- sqlspec/extensions/starlette/extension.py +374 -0
- sqlspec/extensions/starlette/middleware.py +281 -0
- sqlspec/loader.cp314-win_amd64.pyd +0 -0
- sqlspec/loader.py +727 -0
- sqlspec/migrations/__init__.py +39 -0
- sqlspec/migrations/base.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/base.py +862 -0
- sqlspec/migrations/commands.py +2151 -0
- sqlspec/migrations/context.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/context.py +157 -0
- sqlspec/migrations/fix.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/fix.py +204 -0
- sqlspec/migrations/loaders.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/loaders.py +443 -0
- sqlspec/migrations/runner.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/runner.py +1195 -0
- sqlspec/migrations/squash.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/squash.py +490 -0
- sqlspec/migrations/templates.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/templates.py +234 -0
- sqlspec/migrations/tracker.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/tracker.py +792 -0
- sqlspec/migrations/utils.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/utils.py +256 -0
- sqlspec/migrations/validation.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/validation.py +359 -0
- sqlspec/migrations/version.cp314-win_amd64.pyd +0 -0
- sqlspec/migrations/version.py +446 -0
- sqlspec/observability/__init__.py +57 -0
- sqlspec/observability/_common.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_common.py +77 -0
- sqlspec/observability/_config.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_config.py +364 -0
- sqlspec/observability/_diagnostics.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_diagnostics.py +74 -0
- sqlspec/observability/_dispatcher.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_dispatcher.py +200 -0
- sqlspec/observability/_formatters/__init__.py +13 -0
- sqlspec/observability/_formatters/_aws.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_aws.py +102 -0
- sqlspec/observability/_formatters/_azure.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_azure.py +96 -0
- sqlspec/observability/_formatters/_base.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_base.py +57 -0
- sqlspec/observability/_formatters/_gcp.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_formatters/_gcp.py +131 -0
- sqlspec/observability/_formatting.py +58 -0
- sqlspec/observability/_observer.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_observer.py +361 -0
- sqlspec/observability/_runtime.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_runtime.py +461 -0
- sqlspec/observability/_sampling.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_sampling.py +188 -0
- sqlspec/observability/_spans.cp314-win_amd64.pyd +0 -0
- sqlspec/observability/_spans.py +161 -0
- sqlspec/protocols.py +955 -0
- sqlspec/py.typed +0 -0
- sqlspec/service.py +433 -0
- sqlspec/storage/__init__.py +48 -0
- sqlspec/storage/_arrow_payload.py +68 -0
- sqlspec/storage/_paths.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/_paths.py +58 -0
- sqlspec/storage/_utils.py +46 -0
- sqlspec/storage/backends/__init__.py +1 -0
- sqlspec/storage/backends/base.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/backends/base.py +374 -0
- sqlspec/storage/backends/fsspec.py +574 -0
- sqlspec/storage/backends/local.py +468 -0
- sqlspec/storage/backends/obstore.py +956 -0
- sqlspec/storage/errors.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/errors.py +102 -0
- sqlspec/storage/pipeline.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/pipeline.py +628 -0
- sqlspec/storage/registry.cp314-win_amd64.pyd +0 -0
- sqlspec/storage/registry.py +329 -0
- sqlspec/typing.py +405 -0
- sqlspec/utils/__init__.py +7 -0
- sqlspec/utils/arrow_helpers.py +384 -0
- sqlspec/utils/config_tools.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/config_tools.py +314 -0
- sqlspec/utils/correlation.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/correlation.py +134 -0
- sqlspec/utils/deprecation.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/deprecation.py +157 -0
- sqlspec/utils/dispatch.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/dispatch.py +101 -0
- sqlspec/utils/fixtures.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/fixtures.py +260 -0
- sqlspec/utils/logging.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/logging.py +251 -0
- sqlspec/utils/module_loader.py +306 -0
- sqlspec/utils/portal.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/portal.py +377 -0
- sqlspec/utils/schema.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/schema.py +1040 -0
- sqlspec/utils/serializers/__init__.py +30 -0
- sqlspec/utils/serializers/_json.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_json.py +415 -0
- sqlspec/utils/serializers/_numpy.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_numpy.py +65 -0
- sqlspec/utils/serializers/_schema.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/serializers/_schema.py +285 -0
- sqlspec/utils/singleton.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/singleton.py +41 -0
- sqlspec/utils/sync_tools.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/sync_tools.py +316 -0
- sqlspec/utils/text.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/text.py +109 -0
- sqlspec/utils/type_converters.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/type_converters.py +216 -0
- sqlspec/utils/type_guards.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/type_guards.py +1508 -0
- sqlspec/utils/uuids.cp314-win_amd64.pyd +0 -0
- sqlspec/utils/uuids.py +241 -0
- sqlspec-0.47.0.dist-info/METADATA +202 -0
- sqlspec-0.47.0.dist-info/RECORD +621 -0
- sqlspec-0.47.0.dist-info/WHEEL +4 -0
- sqlspec-0.47.0.dist-info/entry_points.txt +6 -0
- sqlspec-0.47.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,694 @@
|
|
|
1
|
+
"""psqlpy adapter compiled helpers."""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
import decimal
|
|
5
|
+
import io
|
|
6
|
+
import re
|
|
7
|
+
import uuid
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Final, cast
|
|
9
|
+
|
|
10
|
+
from sqlspec.core import DriverParameterProfile, ParameterStyle, StatementConfig, build_statement_config_from_profile
|
|
11
|
+
from sqlspec.core.config_runtime import (
|
|
12
|
+
build_postgres_extension_probe_names,
|
|
13
|
+
resolve_postgres_extension_state,
|
|
14
|
+
resolve_runtime_statement_config,
|
|
15
|
+
)
|
|
16
|
+
from sqlspec.exceptions import (
|
|
17
|
+
CheckViolationError,
|
|
18
|
+
ConnectionTimeoutError,
|
|
19
|
+
DatabaseConnectionError,
|
|
20
|
+
DeadlockError,
|
|
21
|
+
ForeignKeyViolationError,
|
|
22
|
+
IntegrityError,
|
|
23
|
+
NotNullViolationError,
|
|
24
|
+
PermissionDeniedError,
|
|
25
|
+
QueryTimeoutError,
|
|
26
|
+
SerializationConflictError,
|
|
27
|
+
SQLParsingError,
|
|
28
|
+
SQLSpecError,
|
|
29
|
+
UniqueViolationError,
|
|
30
|
+
)
|
|
31
|
+
from sqlspec.typing import PGVECTOR_INSTALLED, Empty
|
|
32
|
+
from sqlspec.utils.dispatch import TypeDispatcher
|
|
33
|
+
from sqlspec.utils.logging import get_logger
|
|
34
|
+
from sqlspec.utils.serializers import from_json, to_json
|
|
35
|
+
from sqlspec.utils.type_converters import build_nested_decimal_normalizer, build_uuid_coercions
|
|
36
|
+
from sqlspec.utils.type_guards import has_query_result_metadata
|
|
37
|
+
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from collections.abc import Callable, Mapping
|
|
40
|
+
|
|
41
|
+
from sqlspec.core import SQL, ParameterStyleConfig, StatementConfig
|
|
42
|
+
|
|
43
|
+
__all__ = (
|
|
44
|
+
"apply_driver_features",
|
|
45
|
+
"build_connection_config",
|
|
46
|
+
"build_insert_statement",
|
|
47
|
+
"build_postgres_extension_probe_names",
|
|
48
|
+
"build_profile",
|
|
49
|
+
"build_statement_config",
|
|
50
|
+
"coerce_numeric_for_write",
|
|
51
|
+
"coerce_records_for_execute_many",
|
|
52
|
+
"collect_rows",
|
|
53
|
+
"create_mapped_exception",
|
|
54
|
+
"default_statement_config",
|
|
55
|
+
"driver_profile",
|
|
56
|
+
"encode_records_for_binary_copy",
|
|
57
|
+
"extract_rows_affected",
|
|
58
|
+
"format_execute_many_parameters",
|
|
59
|
+
"format_table_identifier",
|
|
60
|
+
"get_parameter_casts",
|
|
61
|
+
"normalize_scalar_parameter",
|
|
62
|
+
"prepare_parameters_with_casts",
|
|
63
|
+
"resolve_postgres_extension_state",
|
|
64
|
+
"resolve_runtime_statement_config",
|
|
65
|
+
"split_schema_and_table",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
_JSON_CASTS: Final[frozenset[str]] = frozenset({"JSON", "JSONB"})
|
|
70
|
+
_TIMESTAMP_CASTS: Final[frozenset[str]] = frozenset({
|
|
71
|
+
"TIMESTAMP",
|
|
72
|
+
"TIMESTAMPTZ",
|
|
73
|
+
"TIMESTAMP WITH TIME ZONE",
|
|
74
|
+
"TIMESTAMP WITHOUT TIME ZONE",
|
|
75
|
+
})
|
|
76
|
+
_UUID_CASTS: Final[frozenset[str]] = frozenset({"UUID"})
|
|
77
|
+
_DECIMAL_NORMALIZER = build_nested_decimal_normalizer(mode="float")
|
|
78
|
+
_JSONB_TYPE: "type[Any] | None" = None
|
|
79
|
+
_JSONB_RESOLVED: bool = False
|
|
80
|
+
_TYPE_COERCION_DISPATCHERS: "dict[tuple[tuple[type, Callable[[Any], Any]], ...], TypeDispatcher[Callable[[Any], Any]]]" = {}
|
|
81
|
+
PSQLPY_STATUS_REGEX: "re.Pattern[str]" = re.compile(r"^([A-Z]+)(?:\s+(\d+))?\s+(\d+)$", re.IGNORECASE)
|
|
82
|
+
|
|
83
|
+
logger = get_logger("sqlspec.adapters.psqlpy.core")
|
|
84
|
+
_NUMERIC_COERCE_TYPES: "tuple[type[Any], ...]" = (float, decimal.Decimal, list, tuple, dict)
|
|
85
|
+
_STRING_WRITER_TYPE: "type[Any] | None" = None
|
|
86
|
+
_STRING_WRITER_RESOLVED = False
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _get_librt_string_writer() -> "type[Any] | None":
|
|
90
|
+
"""Return librt's StringWriter when the optional performance helper exists."""
|
|
91
|
+
global _STRING_WRITER_RESOLVED, _STRING_WRITER_TYPE
|
|
92
|
+
if _STRING_WRITER_RESOLVED:
|
|
93
|
+
return _STRING_WRITER_TYPE
|
|
94
|
+
try:
|
|
95
|
+
from librt.strings import StringWriter
|
|
96
|
+
except ImportError:
|
|
97
|
+
_STRING_WRITER_TYPE = None
|
|
98
|
+
else:
|
|
99
|
+
_STRING_WRITER_TYPE = StringWriter
|
|
100
|
+
_STRING_WRITER_RESOLVED = True
|
|
101
|
+
return _STRING_WRITER_TYPE
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _get_jsonb_type() -> "type[Any] | None":
|
|
105
|
+
global _JSONB_TYPE, _JSONB_RESOLVED
|
|
106
|
+
if _JSONB_RESOLVED:
|
|
107
|
+
return _JSONB_TYPE
|
|
108
|
+
try:
|
|
109
|
+
from psqlpy.extra_types import JSONB
|
|
110
|
+
except ImportError:
|
|
111
|
+
_JSONB_TYPE = None
|
|
112
|
+
else:
|
|
113
|
+
_JSONB_TYPE = JSONB
|
|
114
|
+
_JSONB_RESOLVED = True
|
|
115
|
+
return _JSONB_TYPE
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _coerce_json_parameter(value: Any, cast_type: str, serializer: "Callable[[Any], str]") -> Any:
|
|
119
|
+
"""Serialize JSON parameters according to the detected cast type."""
|
|
120
|
+
|
|
121
|
+
if value is None:
|
|
122
|
+
return None
|
|
123
|
+
jsonb_type = _get_jsonb_type()
|
|
124
|
+
if cast_type == "JSONB":
|
|
125
|
+
if jsonb_type is not None and isinstance(value, jsonb_type):
|
|
126
|
+
return value
|
|
127
|
+
if jsonb_type is not None:
|
|
128
|
+
if isinstance(value, dict):
|
|
129
|
+
return jsonb_type(value)
|
|
130
|
+
if isinstance(value, (list, tuple)):
|
|
131
|
+
return jsonb_type(list(value))
|
|
132
|
+
if isinstance(value, tuple):
|
|
133
|
+
return list(value)
|
|
134
|
+
if jsonb_type is not None and isinstance(value, jsonb_type):
|
|
135
|
+
return value
|
|
136
|
+
if isinstance(value, (dict, list, str)):
|
|
137
|
+
return value
|
|
138
|
+
try:
|
|
139
|
+
serialized_value = serializer(value)
|
|
140
|
+
except Exception as error:
|
|
141
|
+
msg = "Failed to serialize JSON parameter for psqlpy."
|
|
142
|
+
raise SQLSpecError(msg) from error
|
|
143
|
+
return serialized_value
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _coerce_uuid_parameter(value: Any) -> Any:
|
|
147
|
+
"""Convert UUID-compatible parameters to ``uuid.UUID`` instances."""
|
|
148
|
+
|
|
149
|
+
if isinstance(value, uuid.UUID):
|
|
150
|
+
return value
|
|
151
|
+
if isinstance(value, str):
|
|
152
|
+
try:
|
|
153
|
+
return uuid.UUID(value)
|
|
154
|
+
except ValueError as error:
|
|
155
|
+
msg = "Invalid UUID parameter for psqlpy."
|
|
156
|
+
raise SQLSpecError(msg) from error
|
|
157
|
+
return value
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _coerce_timestamp_parameter(value: Any) -> Any:
|
|
161
|
+
"""Convert ISO-formatted timestamp strings to ``datetime.datetime``."""
|
|
162
|
+
|
|
163
|
+
if isinstance(value, datetime.datetime):
|
|
164
|
+
return value
|
|
165
|
+
if isinstance(value, str):
|
|
166
|
+
normalized_value = value[:-1] + "+00:00" if value.endswith("Z") else value
|
|
167
|
+
try:
|
|
168
|
+
return datetime.datetime.fromisoformat(normalized_value)
|
|
169
|
+
except ValueError as error:
|
|
170
|
+
msg = "Invalid ISO timestamp parameter for psqlpy."
|
|
171
|
+
raise SQLSpecError(msg) from error
|
|
172
|
+
return value
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _coerce_parameter_for_cast(value: Any, cast_type: str, serializer: "Callable[[Any], str]") -> Any:
|
|
176
|
+
"""Apply cast-aware coercion for psqlpy parameters."""
|
|
177
|
+
|
|
178
|
+
upper_cast = cast_type.upper()
|
|
179
|
+
if upper_cast in _JSON_CASTS:
|
|
180
|
+
return _coerce_json_parameter(value, upper_cast, serializer)
|
|
181
|
+
if upper_cast in _UUID_CASTS:
|
|
182
|
+
return _coerce_uuid_parameter(value)
|
|
183
|
+
if upper_cast in _TIMESTAMP_CASTS:
|
|
184
|
+
return _coerce_timestamp_parameter(value)
|
|
185
|
+
return value
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _prepare_dict_parameter(value: "dict[str, Any]") -> "dict[str, Any]":
|
|
189
|
+
normalized = _DECIMAL_NORMALIZER(value)
|
|
190
|
+
return normalized if isinstance(normalized, dict) else value
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _prepare_list_parameter(value: "list[Any]") -> "list[Any]":
|
|
194
|
+
return [_DECIMAL_NORMALIZER(item) for item in value]
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _prepare_tuple_parameter(value: "tuple[Any, ...]") -> "tuple[Any, ...]":
|
|
198
|
+
return tuple(_DECIMAL_NORMALIZER(item) for item in value)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def build_profile() -> "DriverParameterProfile":
|
|
202
|
+
"""Create the psqlpy driver parameter profile."""
|
|
203
|
+
coercions: dict[type, Callable[[Any], Any]] = {decimal.Decimal: float, **build_uuid_coercions(native=True)}
|
|
204
|
+
return DriverParameterProfile(
|
|
205
|
+
name="Psqlpy",
|
|
206
|
+
default_style=ParameterStyle.NUMERIC,
|
|
207
|
+
supported_styles={ParameterStyle.NUMERIC, ParameterStyle.NAMED_DOLLAR, ParameterStyle.QMARK},
|
|
208
|
+
default_execution_style=ParameterStyle.NUMERIC,
|
|
209
|
+
supported_execution_styles={ParameterStyle.NUMERIC},
|
|
210
|
+
has_native_list_expansion=False,
|
|
211
|
+
preserve_parameter_format=True,
|
|
212
|
+
needs_static_script_compilation=False,
|
|
213
|
+
allow_mixed_parameter_styles=False,
|
|
214
|
+
preserve_original_params_for_many=False,
|
|
215
|
+
json_serializer_strategy="helper",
|
|
216
|
+
custom_type_coercions=coercions,
|
|
217
|
+
default_dialect="postgres",
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
driver_profile = build_profile()
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _build_psqlpy_parameter_config(
|
|
225
|
+
profile: "DriverParameterProfile", serializer: "Callable[[Any], str]"
|
|
226
|
+
) -> "ParameterStyleConfig":
|
|
227
|
+
"""Construct parameter configuration for psqlpy.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
profile: Driver parameter profile to extend.
|
|
231
|
+
serializer: JSON serializer for parameter coercion.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
ParameterStyleConfig with updated type coercions.
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
base_config = build_statement_config_from_profile(profile, json_serializer=serializer).parameter_config
|
|
238
|
+
|
|
239
|
+
updated_type_map = dict(base_config.type_coercion_map)
|
|
240
|
+
updated_type_map[dict] = _prepare_dict_parameter
|
|
241
|
+
updated_type_map[list] = _prepare_list_parameter
|
|
242
|
+
updated_type_map[tuple] = _prepare_tuple_parameter
|
|
243
|
+
|
|
244
|
+
return base_config.replace(type_coercion_map=updated_type_map)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def build_statement_config(*, json_serializer: "Callable[[Any], str] | None" = None) -> "StatementConfig":
|
|
248
|
+
"""Construct the psqlpy statement configuration with optional JSON codecs."""
|
|
249
|
+
serializer = json_serializer or to_json
|
|
250
|
+
profile = driver_profile
|
|
251
|
+
parameter_config = _build_psqlpy_parameter_config(profile, serializer)
|
|
252
|
+
base_config = build_statement_config_from_profile(profile, json_serializer=serializer)
|
|
253
|
+
return base_config.replace(parameter_config=parameter_config)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
default_statement_config = build_statement_config()
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def build_connection_config(connection_config: "Mapping[str, Any]") -> "dict[str, Any]":
|
|
260
|
+
"""Build connection configuration with non-null values only.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
connection_config: Raw connection configuration mapping.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
Dictionary with connection parameters.
|
|
267
|
+
"""
|
|
268
|
+
return {key: value for key, value in connection_config.items() if value is not None}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def apply_driver_features(
|
|
272
|
+
statement_config: "StatementConfig", driver_features: "Mapping[str, Any] | None"
|
|
273
|
+
) -> "tuple[StatementConfig, dict[str, Any]]":
|
|
274
|
+
"""Apply psqlpy driver feature defaults to statement config."""
|
|
275
|
+
features: dict[str, Any] = dict(driver_features) if driver_features else {}
|
|
276
|
+
serializer = features.get("json_serializer", to_json)
|
|
277
|
+
features.setdefault("json_serializer", serializer)
|
|
278
|
+
features.setdefault("enable_pgvector", PGVECTOR_INSTALLED)
|
|
279
|
+
features.setdefault("enable_paradedb", True)
|
|
280
|
+
|
|
281
|
+
parameter_config = _build_psqlpy_parameter_config(driver_profile, serializer)
|
|
282
|
+
statement_config = statement_config.replace(parameter_config=parameter_config)
|
|
283
|
+
|
|
284
|
+
return statement_config, features
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def collect_rows(query_result: Any | None) -> "tuple[list[dict[str, Any]], list[str]]":
|
|
288
|
+
"""Collect psqlpy rows and column names.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
query_result: Result returned from cursor.fetch().
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
Tuple of (rows, column_names).
|
|
295
|
+
"""
|
|
296
|
+
if not query_result:
|
|
297
|
+
return [], []
|
|
298
|
+
|
|
299
|
+
dict_rows = cast("list[dict[str, Any]]", query_result if isinstance(query_result, list) else query_result.result())
|
|
300
|
+
if not dict_rows:
|
|
301
|
+
return [], []
|
|
302
|
+
return dict_rows, list(dict_rows[0])
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def normalize_scalar_parameter(value: Any) -> Any:
|
|
306
|
+
return value
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def coerce_numeric_for_write(value: Any) -> Any:
|
|
310
|
+
if isinstance(value, float):
|
|
311
|
+
return decimal.Decimal(str(value))
|
|
312
|
+
if isinstance(value, decimal.Decimal):
|
|
313
|
+
return value
|
|
314
|
+
if isinstance(value, list):
|
|
315
|
+
coerced_list: list[Any] | None = None
|
|
316
|
+
for index, item in enumerate(value):
|
|
317
|
+
coerced_item = coerce_numeric_for_write(item)
|
|
318
|
+
if coerced_list is None:
|
|
319
|
+
if coerced_item is item:
|
|
320
|
+
continue
|
|
321
|
+
coerced_list = list(value[:index])
|
|
322
|
+
coerced_list.append(coerced_item)
|
|
323
|
+
return value if coerced_list is None else coerced_list
|
|
324
|
+
if isinstance(value, tuple):
|
|
325
|
+
coerced_tuple: list[Any] | None = None
|
|
326
|
+
for index, item in enumerate(value):
|
|
327
|
+
coerced_item = coerce_numeric_for_write(item)
|
|
328
|
+
if coerced_tuple is None:
|
|
329
|
+
if coerced_item is item:
|
|
330
|
+
continue
|
|
331
|
+
coerced_tuple = list(value[:index])
|
|
332
|
+
coerced_tuple.append(coerced_item)
|
|
333
|
+
return value if coerced_tuple is None else tuple(coerced_tuple)
|
|
334
|
+
if isinstance(value, dict):
|
|
335
|
+
coerced_dict: dict[Any, Any] | None = None
|
|
336
|
+
for key, item in value.items():
|
|
337
|
+
coerced_item = coerce_numeric_for_write(item)
|
|
338
|
+
if coerced_dict is None:
|
|
339
|
+
if coerced_item is item:
|
|
340
|
+
continue
|
|
341
|
+
coerced_dict = dict(value)
|
|
342
|
+
coerced_dict[key] = coerced_item
|
|
343
|
+
return value if coerced_dict is None else coerced_dict
|
|
344
|
+
return value
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _escape_copy_text(value: str) -> str:
|
|
348
|
+
return value.replace("\\", "\\\\").replace("\t", "\\t").replace("\n", "\\n").replace("\r", "\\r")
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def _format_copy_value(value: Any) -> str:
|
|
352
|
+
if value is None:
|
|
353
|
+
return r"\N"
|
|
354
|
+
if isinstance(value, bool):
|
|
355
|
+
return "t" if value else "f"
|
|
356
|
+
if isinstance(value, (datetime.date, datetime.datetime, datetime.time)):
|
|
357
|
+
return value.isoformat()
|
|
358
|
+
if isinstance(value, (list, tuple, dict)):
|
|
359
|
+
return to_json(value)
|
|
360
|
+
if isinstance(value, (bytes, bytearray)):
|
|
361
|
+
return value.decode("utf-8")
|
|
362
|
+
return str(coerce_numeric_for_write(value))
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def encode_records_for_binary_copy(records: "list[tuple[Any, ...]]") -> bytes:
|
|
366
|
+
"""Encode row tuples into a bytes payload compatible with binary_copy_to_table."""
|
|
367
|
+
|
|
368
|
+
string_writer_type = _get_librt_string_writer()
|
|
369
|
+
if string_writer_type is not None:
|
|
370
|
+
writer = string_writer_type()
|
|
371
|
+
for record in records:
|
|
372
|
+
first = True
|
|
373
|
+
for value in record:
|
|
374
|
+
if first:
|
|
375
|
+
first = False
|
|
376
|
+
else:
|
|
377
|
+
writer.write("\t")
|
|
378
|
+
writer.write(_escape_copy_text(_format_copy_value(value)))
|
|
379
|
+
writer.write("\n")
|
|
380
|
+
return cast("str", writer.getvalue()).encode("utf-8")
|
|
381
|
+
|
|
382
|
+
buffer = io.StringIO()
|
|
383
|
+
for record in records:
|
|
384
|
+
encoded_columns = [_escape_copy_text(_format_copy_value(value)) for value in record]
|
|
385
|
+
buffer.write("\t".join(encoded_columns))
|
|
386
|
+
buffer.write("\n")
|
|
387
|
+
return buffer.getvalue().encode("utf-8")
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def split_schema_and_table(identifier: str) -> "tuple[str | None, str]":
|
|
391
|
+
cleaned = identifier.strip()
|
|
392
|
+
if not cleaned:
|
|
393
|
+
msg = "Table name must not be empty"
|
|
394
|
+
raise SQLSpecError(msg)
|
|
395
|
+
if "." not in cleaned:
|
|
396
|
+
return None, cleaned.strip('"')
|
|
397
|
+
parts = [part for part in cleaned.split(".") if part]
|
|
398
|
+
if len(parts) == 1:
|
|
399
|
+
return None, parts[0].strip('"')
|
|
400
|
+
schema_name = ".".join(parts[:-1]).strip('"')
|
|
401
|
+
table_name = parts[-1].strip('"')
|
|
402
|
+
if not table_name:
|
|
403
|
+
msg = "Table name must not be empty"
|
|
404
|
+
raise SQLSpecError(msg)
|
|
405
|
+
return schema_name or None, table_name
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _parse_psqlpy_command_tag(tag: str) -> int:
|
|
409
|
+
"""Parse PostgreSQL command tag to extract rows affected.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
tag: PostgreSQL command tag string.
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
Number of rows affected, -1 if unable to parse.
|
|
416
|
+
"""
|
|
417
|
+
if not tag:
|
|
418
|
+
return -1
|
|
419
|
+
|
|
420
|
+
match = PSQLPY_STATUS_REGEX.match(tag.strip())
|
|
421
|
+
if match:
|
|
422
|
+
command = match.group(1).upper()
|
|
423
|
+
if command == "INSERT" and match.group(3):
|
|
424
|
+
return int(match.group(3))
|
|
425
|
+
if command in {"UPDATE", "DELETE"} and match.group(3):
|
|
426
|
+
return int(match.group(3))
|
|
427
|
+
return -1
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def extract_rows_affected(result: Any) -> int:
|
|
431
|
+
"""Extract rows affected from psqlpy results."""
|
|
432
|
+
try:
|
|
433
|
+
if has_query_result_metadata(result):
|
|
434
|
+
if result.tag:
|
|
435
|
+
return _parse_psqlpy_command_tag(result.tag)
|
|
436
|
+
if result.status:
|
|
437
|
+
return _parse_psqlpy_command_tag(result.status)
|
|
438
|
+
if isinstance(result, str):
|
|
439
|
+
return _parse_psqlpy_command_tag(result)
|
|
440
|
+
except Exception as error:
|
|
441
|
+
logger.debug("Failed to parse psqlpy command tag: %s", error)
|
|
442
|
+
return -1
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def get_parameter_casts(statement: "SQL") -> "dict[int, str]":
|
|
446
|
+
"""Get parameter cast metadata from compiled statements."""
|
|
447
|
+
processed_state = statement.get_processed_state()
|
|
448
|
+
if processed_state is not Empty:
|
|
449
|
+
return processed_state.parameter_casts or {}
|
|
450
|
+
return {}
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def _get_type_coercion_dispatcher(
|
|
454
|
+
type_map: "dict[type, Callable[[Any], Any]]",
|
|
455
|
+
) -> "TypeDispatcher[Callable[[Any], Any]]":
|
|
456
|
+
fallback_items = tuple(type_map.items())
|
|
457
|
+
dispatcher = _TYPE_COERCION_DISPATCHERS.get(fallback_items)
|
|
458
|
+
if dispatcher is not None:
|
|
459
|
+
return dispatcher
|
|
460
|
+
|
|
461
|
+
dispatcher = TypeDispatcher["Callable[[Any], Any]"]()
|
|
462
|
+
dispatcher.register_all(fallback_items)
|
|
463
|
+
_TYPE_COERCION_DISPATCHERS[fallback_items] = dispatcher
|
|
464
|
+
return dispatcher
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def prepare_parameters_with_casts(
|
|
468
|
+
parameters: Any, parameter_casts: "dict[int, str]", statement_config: "StatementConfig"
|
|
469
|
+
) -> Any:
|
|
470
|
+
"""Prepare parameters with cast-aware type coercion."""
|
|
471
|
+
if isinstance(parameters, (list, tuple)):
|
|
472
|
+
result: list[Any] = []
|
|
473
|
+
serializer = statement_config.parameter_config.json_serializer or to_json
|
|
474
|
+
type_map = statement_config.parameter_config.type_coercion_map
|
|
475
|
+
dispatcher = _get_type_coercion_dispatcher(type_map) if type_map else None
|
|
476
|
+
for idx, param in enumerate(parameters, start=1):
|
|
477
|
+
cast_type = parameter_casts.get(idx, "")
|
|
478
|
+
prepared_value = param
|
|
479
|
+
if type_map and dispatcher is not None:
|
|
480
|
+
exact_converter = type_map.get(type(prepared_value))
|
|
481
|
+
if exact_converter is not None:
|
|
482
|
+
prepared_value = exact_converter(prepared_value)
|
|
483
|
+
else:
|
|
484
|
+
fallback_converter = dispatcher.get(prepared_value)
|
|
485
|
+
if fallback_converter is not None:
|
|
486
|
+
prepared_value = fallback_converter(prepared_value)
|
|
487
|
+
if cast_type:
|
|
488
|
+
prepared_value = _coerce_parameter_for_cast(prepared_value, cast_type, serializer)
|
|
489
|
+
result.append(prepared_value)
|
|
490
|
+
return tuple(result) if isinstance(parameters, tuple) else result
|
|
491
|
+
return parameters
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
def _create_postgres_error(error: Any, error_class: type[SQLSpecError], description: str) -> SQLSpecError:
|
|
495
|
+
"""Create a SQLSpec exception from a psqlpy error.
|
|
496
|
+
|
|
497
|
+
Args:
|
|
498
|
+
error: The original psqlpy exception
|
|
499
|
+
error_class: The SQLSpec exception class to instantiate
|
|
500
|
+
description: Human-readable description of the error type
|
|
501
|
+
|
|
502
|
+
Returns:
|
|
503
|
+
A new SQLSpec exception instance with the original as its cause
|
|
504
|
+
"""
|
|
505
|
+
msg = f"PostgreSQL {description}: {error}"
|
|
506
|
+
exc = error_class(msg)
|
|
507
|
+
exc.__cause__ = error
|
|
508
|
+
return exc
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def create_mapped_exception(error: Any) -> SQLSpecError:
|
|
512
|
+
"""Map psqlpy exceptions to SQLSpec exceptions.
|
|
513
|
+
|
|
514
|
+
This is a factory function that returns an exception instance rather than
|
|
515
|
+
raising. This pattern is more robust for use in __exit__ handlers and
|
|
516
|
+
avoids issues with exception control flow in different Python versions.
|
|
517
|
+
|
|
518
|
+
psqlpy doesn't expose SQLSTATE codes directly, so we rely on message-based
|
|
519
|
+
pattern matching for exception classification.
|
|
520
|
+
|
|
521
|
+
Args:
|
|
522
|
+
error: The psqlpy exception to map
|
|
523
|
+
|
|
524
|
+
Returns:
|
|
525
|
+
A SQLSpec exception that wraps the original error
|
|
526
|
+
"""
|
|
527
|
+
error_msg = str(error).lower()
|
|
528
|
+
|
|
529
|
+
# Integrity constraint violations (most specific first)
|
|
530
|
+
if "unique" in error_msg or "duplicate key" in error_msg:
|
|
531
|
+
return _create_postgres_error(error, UniqueViolationError, "unique constraint violation")
|
|
532
|
+
if "foreign key" in error_msg or "violates foreign key" in error_msg:
|
|
533
|
+
return _create_postgres_error(error, ForeignKeyViolationError, "foreign key constraint violation")
|
|
534
|
+
if "not null" in error_msg or ("null value" in error_msg and "violates not-null" in error_msg):
|
|
535
|
+
return _create_postgres_error(error, NotNullViolationError, "not-null constraint violation")
|
|
536
|
+
if "check constraint" in error_msg or "violates check constraint" in error_msg:
|
|
537
|
+
return _create_postgres_error(error, CheckViolationError, "check constraint violation")
|
|
538
|
+
if "constraint" in error_msg:
|
|
539
|
+
return _create_postgres_error(error, IntegrityError, "integrity constraint violation")
|
|
540
|
+
|
|
541
|
+
# Transaction and serialization errors (deadlock before serialization)
|
|
542
|
+
if "deadlock" in error_msg:
|
|
543
|
+
return _create_postgres_error(error, DeadlockError, "deadlock detected")
|
|
544
|
+
if "serialization failure" in error_msg or "could not serialize" in error_msg:
|
|
545
|
+
return _create_postgres_error(error, SerializationConflictError, "serialization failure")
|
|
546
|
+
|
|
547
|
+
# Query timeout/cancellation
|
|
548
|
+
if "cancel" in error_msg or "timeout" in error_msg or "statement timeout" in error_msg:
|
|
549
|
+
return _create_postgres_error(error, QueryTimeoutError, "query canceled or timed out")
|
|
550
|
+
|
|
551
|
+
# Permission/authentication errors
|
|
552
|
+
if "permission denied" in error_msg or "insufficient privilege" in error_msg:
|
|
553
|
+
return _create_postgres_error(error, PermissionDeniedError, "permission denied")
|
|
554
|
+
if "authentication failed" in error_msg or "password" in error_msg:
|
|
555
|
+
return _create_postgres_error(error, PermissionDeniedError, "authentication error")
|
|
556
|
+
|
|
557
|
+
# Connection errors
|
|
558
|
+
if "connection" in error_msg or "could not connect" in error_msg:
|
|
559
|
+
if "timeout" in error_msg:
|
|
560
|
+
return _create_postgres_error(error, ConnectionTimeoutError, "connection timeout")
|
|
561
|
+
return _create_postgres_error(error, DatabaseConnectionError, "connection error")
|
|
562
|
+
|
|
563
|
+
# SQL syntax errors
|
|
564
|
+
if "syntax error" in error_msg or "parse" in error_msg:
|
|
565
|
+
return _create_postgres_error(error, SQLParsingError, "SQL syntax error")
|
|
566
|
+
|
|
567
|
+
return _create_postgres_error(error, SQLSpecError, "database error")
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def _quote_identifier(identifier: str) -> str:
|
|
571
|
+
normalized = identifier.replace('"', '""')
|
|
572
|
+
return f'"{normalized}"'
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def format_table_identifier(identifier: str) -> str:
|
|
576
|
+
schema_name, table_name = split_schema_and_table(identifier)
|
|
577
|
+
if schema_name:
|
|
578
|
+
return f"{_quote_identifier(schema_name)}.{_quote_identifier(table_name)}"
|
|
579
|
+
return _quote_identifier(table_name)
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def build_insert_statement(table: str, columns: "list[str]") -> str:
|
|
583
|
+
column_clause = ", ".join(_quote_identifier(column) for column in columns)
|
|
584
|
+
placeholders = ", ".join(f"${index}" for index in range(1, len(columns) + 1))
|
|
585
|
+
return f"INSERT INTO {format_table_identifier(table)} ({column_clause}) VALUES ({placeholders})"
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def _sequence_needs_numeric_coercion(values: "list[Any] | tuple[Any, ...]") -> bool:
|
|
589
|
+
"""Return True when any value in a parameter sequence needs numeric coercion."""
|
|
590
|
+
return any(type(value) in _NUMERIC_COERCE_TYPES for value in values)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def _format_execute_many_param_set(param_set: Any, *, coerce_numeric: bool) -> "list[Any]":
|
|
594
|
+
"""Normalize a single execute_many parameter set to list form."""
|
|
595
|
+
if isinstance(param_set, list):
|
|
596
|
+
if not coerce_numeric or not _sequence_needs_numeric_coercion(param_set):
|
|
597
|
+
return param_set
|
|
598
|
+
coerced = coerce_numeric_for_write(param_set)
|
|
599
|
+
if isinstance(coerced, list):
|
|
600
|
+
return coerced
|
|
601
|
+
if isinstance(coerced, tuple):
|
|
602
|
+
return list(coerced)
|
|
603
|
+
return [coerced]
|
|
604
|
+
|
|
605
|
+
if isinstance(param_set, tuple):
|
|
606
|
+
if not coerce_numeric or not _sequence_needs_numeric_coercion(param_set):
|
|
607
|
+
return list(param_set)
|
|
608
|
+
coerced = coerce_numeric_for_write(param_set)
|
|
609
|
+
if isinstance(coerced, tuple):
|
|
610
|
+
return list(coerced)
|
|
611
|
+
if isinstance(coerced, list):
|
|
612
|
+
return coerced
|
|
613
|
+
return [coerced]
|
|
614
|
+
|
|
615
|
+
if coerce_numeric:
|
|
616
|
+
coerced = coerce_numeric_for_write(param_set)
|
|
617
|
+
if isinstance(coerced, list):
|
|
618
|
+
return coerced
|
|
619
|
+
if isinstance(coerced, tuple):
|
|
620
|
+
return list(coerced)
|
|
621
|
+
return [coerced]
|
|
622
|
+
|
|
623
|
+
return [param_set]
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
def format_execute_many_parameters(parameters: Any, *, coerce_numeric: bool) -> "list[list[Any]]":
|
|
627
|
+
"""Normalize execute_many parameters for psqlpy.
|
|
628
|
+
|
|
629
|
+
Args:
|
|
630
|
+
parameters: Prepared parameter payload.
|
|
631
|
+
coerce_numeric: Whether numeric write coercion should be applied.
|
|
632
|
+
|
|
633
|
+
Returns:
|
|
634
|
+
Parameter payload normalized to ``list[list[Any]]``.
|
|
635
|
+
"""
|
|
636
|
+
if not parameters:
|
|
637
|
+
return []
|
|
638
|
+
|
|
639
|
+
if (
|
|
640
|
+
isinstance(parameters, list)
|
|
641
|
+
and not coerce_numeric
|
|
642
|
+
and all(isinstance(param_set, list) for param_set in parameters)
|
|
643
|
+
):
|
|
644
|
+
return cast("list[list[Any]]", parameters)
|
|
645
|
+
|
|
646
|
+
if isinstance(parameters, (list, tuple)):
|
|
647
|
+
formatted: list[list[Any]] = []
|
|
648
|
+
append = formatted.append
|
|
649
|
+
for param_set in parameters:
|
|
650
|
+
append(_format_execute_many_param_set(param_set, coerce_numeric=coerce_numeric))
|
|
651
|
+
return formatted
|
|
652
|
+
|
|
653
|
+
return [_format_execute_many_param_set(parameters, coerce_numeric=coerce_numeric)]
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def _coerce_json_text_for_execute_many(value: Any) -> Any:
|
|
657
|
+
if not isinstance(value, str):
|
|
658
|
+
return value
|
|
659
|
+
stripped = value.lstrip()
|
|
660
|
+
if not stripped or stripped[0] not in "{[":
|
|
661
|
+
return value
|
|
662
|
+
try:
|
|
663
|
+
decoded = from_json(value)
|
|
664
|
+
except Exception:
|
|
665
|
+
return value
|
|
666
|
+
return decoded if isinstance(decoded, (dict, list, tuple)) else value
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
def _coerce_json_text_rows(rows: "list[list[Any]]") -> "list[list[Any]]":
|
|
670
|
+
coerced_rows: list[list[Any]] | None = None
|
|
671
|
+
for row_index, row in enumerate(rows):
|
|
672
|
+
coerced_row: list[Any] | None = None
|
|
673
|
+
for value_index, value in enumerate(row):
|
|
674
|
+
coerced_value = _coerce_json_text_for_execute_many(value)
|
|
675
|
+
if coerced_row is None:
|
|
676
|
+
if coerced_value is value:
|
|
677
|
+
continue
|
|
678
|
+
coerced_row = list(row)
|
|
679
|
+
coerced_row[value_index] = coerced_value
|
|
680
|
+
if coerced_row is None:
|
|
681
|
+
if coerced_rows is not None:
|
|
682
|
+
coerced_rows.append(row)
|
|
683
|
+
continue
|
|
684
|
+
if coerced_rows is None:
|
|
685
|
+
coerced_rows = list(rows[:row_index])
|
|
686
|
+
coerced_rows.append(coerced_row)
|
|
687
|
+
return rows if coerced_rows is None else coerced_rows
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
def coerce_records_for_execute_many(
|
|
691
|
+
records: "list[tuple[Any, ...]]", *, parse_json_text: bool = False
|
|
692
|
+
) -> "list[list[Any]]":
|
|
693
|
+
formatted = format_execute_many_parameters(records, coerce_numeric=True)
|
|
694
|
+
return _coerce_json_text_rows(formatted) if parse_json_text else formatted
|