sqlspec 0.21.0__tar.gz → 0.21.1__tar.gz
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.
Potentially problematic release.
This version of sqlspec might be problematic. Click here for more details.
- {sqlspec-0.21.0 → sqlspec-0.21.1}/PKG-INFO +1 -1
- {sqlspec-0.21.0 → sqlspec-0.21.1}/pyproject.toml +6 -5
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/driver/mixins/_result_tools.py +41 -6
- sqlspec-0.21.1/sqlspec/utils/data_transformation.py +120 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/text.py +27 -19
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/type_guards.py +74 -0
- sqlspec-0.21.1/tests/unit/test_utils/test_data_transformation.py +343 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_text.py +1 -36
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_type_guards.py +105 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/uv.lock +102 -102
- {sqlspec-0.21.0 → sqlspec-0.21.1}/.gitignore +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/.pre-commit-config.yaml +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/CONTRIBUTING.rst +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/LICENSE +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/Makefile +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/NOTICE +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/README.md +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/__main__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/__metadata__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/_serialization.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/_sql.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/_typing.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/adbc/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/adbc/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/adbc/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/adbc/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/aiosqlite/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/aiosqlite/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/aiosqlite/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/aiosqlite/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/aiosqlite/pool.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/asyncmy/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/asyncmy/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/asyncmy/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/asyncmy/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/asyncpg/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/asyncpg/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/asyncpg/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/asyncpg/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/bigquery/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/bigquery/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/bigquery/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/bigquery/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/duckdb/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/duckdb/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/duckdb/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/duckdb/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/duckdb/pool.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/oracledb/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/oracledb/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/oracledb/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/oracledb/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/oracledb/migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/psqlpy/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/psqlpy/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/psqlpy/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/psqlpy/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/psycopg/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/psycopg/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/psycopg/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/psycopg/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/sqlite/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/sqlite/_types.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/sqlite/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/sqlite/driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/adapters/sqlite/pool.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/base.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_base.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_column.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_ddl.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_delete.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_expression_wrappers.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_insert.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_merge.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_parsing_utils.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_select.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/_update.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_cte_and_set_ops.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_delete_operations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_insert_operations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_join_operations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_merge_operations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_order_limit_operations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_pivot_operations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_select_operations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_update_operations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/builder/mixins/_where_clause.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/cli.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/cache.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/compiler.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/filters.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/hashing.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/parameters.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/result.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/splitter.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/core/statement.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/driver/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/driver/_async.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/driver/_common.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/driver/_sync.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/driver/mixins/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/driver/mixins/_sql_translator.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/exceptions.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/aiosql/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/aiosql/adapter.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/litestar/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/litestar/_utils.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/litestar/cli.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/litestar/config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/litestar/handlers.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/litestar/plugin.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/extensions/litestar/providers.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/loader.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/migrations/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/migrations/base.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/migrations/commands.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/migrations/loaders.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/migrations/runner.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/migrations/tracker.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/migrations/utils.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/protocols.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/py.typed +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/storage/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/storage/backends/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/storage/backends/base.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/storage/backends/fsspec.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/storage/backends/obstore.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/storage/capabilities.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/storage/registry.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/typing.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/correlation.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/deprecation.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/fixtures.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/logging.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/module_loader.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/serializers.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/singleton.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/sqlspec/utils/sync_tools.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/asset_maintenance.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/ddls-mysql-collection.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/ddls-postgres-collection.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/example_usage.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/init.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-config.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-data_types.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-database_details.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-engines.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-hostname.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-plugins.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-process_list.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-resource-groups.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-schema_objects.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-table_details.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/collection-users.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/mysql/init.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/oracle.ddl.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-applications.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-aws_extension_dependency.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-aws_oracle_exists.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-bg_writer_stats.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-calculated_metrics.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-data_types.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-database_details.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-extensions.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-index_details.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-pglogical-details.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-privileges.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-replication_slots.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-replication_stats.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-schema_details.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-schema_objects.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-settings.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-source_details.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/collection-table_details.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/extended-collection-all-databases.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/postgres/init.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/readiness-check.sql +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/fixtures/sql_utils.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/test_adbc_arrow_features.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/test_adbc_backends.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/test_adbc_connection.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/test_adbc_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/test_adbc_edge_cases.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/test_adbc_results.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_adbc/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_aiosqlite/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_aiosqlite/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_aiosqlite/test_connection.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_aiosqlite/test_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_aiosqlite/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_aiosqlite/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_aiosqlite/test_pooling.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncmy/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncmy/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncmy/test_asyncmy_features.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncmy/test_config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncmy/test_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncmy/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncmy/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncpg/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncpg/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncpg/test_connection.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncpg/test_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncpg/test_execute_many.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncpg/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_asyncpg/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_bigquery/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_bigquery/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_bigquery/test_bigquery_features.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_bigquery/test_config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_bigquery/test_connection.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_bigquery/test_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/test_connection.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/test_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/test_execute_many.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/test_mixed_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/test_pooling.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_duckdb/utils.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/test_connection.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/test_driver_async.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/test_driver_sync.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/test_execute_many.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/test_oracle_features.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_oracledb/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psqlpy/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psqlpy/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psqlpy/test_connection.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psqlpy/test_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psqlpy/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psqlpy/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psqlpy/test_psqlpy_features.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psycopg/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psycopg/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psycopg/test_async_copy.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psycopg/test_connection.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psycopg/test_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psycopg/test_execute_many.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psycopg/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_psycopg/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_sqlite/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_sqlite/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_sqlite/test_driver.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_sqlite/test_migrations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_sqlite/test_parameter_styles.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_sqlite/test_pooling.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_adapters/test_sqlite/test_query_mixin.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_loader/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_loader/test_file_system_loading.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/integration/test_migrations/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_adapters/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_adapters/conftest.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_adapters/test_adapter_implementations.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_adapters/test_async_adapters.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_adapters/test_sync_adapters.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_base/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_base/test_sql_integration.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_base/test_sqlspec_class.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_builder/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_builder/test_insert_builder.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_builder/test_parameter_naming.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_builder_parameter_naming.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_core/test_cache.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_core/test_compiler.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_core/test_filters.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_core/test_hashing.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_core/test_parameters.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_core/test_result.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_core/test_statement.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_extensions/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_extensions/test_litestar/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_extensions/test_litestar/test_config.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_loader/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_loader/test_cache_integration.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_loader/test_fixtures_directory_loading.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_loader/test_loading_patterns.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_loader/test_sql_file_loader.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_migrations/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_migrations/test_migration.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_migrations/test_migration_commands.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_migrations/test_migration_execution.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_migrations/test_migration_runner.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_parsing_utils.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_sql_factory.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_correlation.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_deprecation.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_fixtures.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_logging.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_module_loader.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_serializers.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_singleton.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tests/unit/test_utils/test_sync_tools.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tools/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tools/build_docs.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tools/local-infra.sh +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tools/pypi_readme.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tools/sphinx_ext/__init__.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tools/sphinx_ext/changelog.py +0 -0
- {sqlspec-0.21.0 → sqlspec-0.21.1}/tools/sphinx_ext/missing_references.py +0 -0
|
@@ -13,7 +13,7 @@ maintainers = [{ name = "Litestar Developers", email = "hello@litestar.dev" }]
|
|
|
13
13
|
name = "sqlspec"
|
|
14
14
|
readme = "README.md"
|
|
15
15
|
requires-python = ">=3.9, <4.0"
|
|
16
|
-
version = "0.21.
|
|
16
|
+
version = "0.21.1"
|
|
17
17
|
|
|
18
18
|
[project.urls]
|
|
19
19
|
Discord = "https://discord.gg/litestar"
|
|
@@ -161,10 +161,11 @@ include = [
|
|
|
161
161
|
"sqlspec/loader.py", # Loader module
|
|
162
162
|
|
|
163
163
|
# === UTILITY MODULES ===
|
|
164
|
-
"sqlspec/utils/text.py",
|
|
165
|
-
"sqlspec/utils/sync_tools.py",
|
|
166
|
-
"sqlspec/utils/type_guards.py",
|
|
167
|
-
"sqlspec/utils/fixtures.py",
|
|
164
|
+
"sqlspec/utils/text.py", # Text utilities
|
|
165
|
+
"sqlspec/utils/sync_tools.py", # Synchronous utility functions
|
|
166
|
+
"sqlspec/utils/type_guards.py", # Type guard utilities
|
|
167
|
+
"sqlspec/utils/fixtures.py", # File fixture loading
|
|
168
|
+
"sqlspec/utils/data_transformation.py", # Data transformation utilities
|
|
168
169
|
]
|
|
169
170
|
mypy-args = [
|
|
170
171
|
"--ignore-missing-imports",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# ruff: noqa: C901
|
|
1
2
|
"""Result handling and schema conversion mixins for database drivers."""
|
|
2
3
|
|
|
3
4
|
import datetime
|
|
@@ -22,7 +23,16 @@ from sqlspec.typing import (
|
|
|
22
23
|
convert,
|
|
23
24
|
get_type_adapter,
|
|
24
25
|
)
|
|
25
|
-
from sqlspec.utils.
|
|
26
|
+
from sqlspec.utils.data_transformation import transform_dict_keys
|
|
27
|
+
from sqlspec.utils.text import camelize, kebabize, pascalize
|
|
28
|
+
from sqlspec.utils.type_guards import (
|
|
29
|
+
get_msgspec_rename_config,
|
|
30
|
+
is_attrs_schema,
|
|
31
|
+
is_dataclass,
|
|
32
|
+
is_dict,
|
|
33
|
+
is_msgspec_struct,
|
|
34
|
+
is_pydantic_model,
|
|
35
|
+
)
|
|
26
36
|
|
|
27
37
|
__all__ = ("_DEFAULT_TYPE_DECODERS", "_default_msgspec_deserializer")
|
|
28
38
|
|
|
@@ -143,21 +153,46 @@ class ToSchemaMixin:
|
|
|
143
153
|
if isinstance(data, list):
|
|
144
154
|
result: list[Any] = []
|
|
145
155
|
for item in data:
|
|
146
|
-
if
|
|
156
|
+
if is_dict(item):
|
|
147
157
|
result.append(schema_type(**dict(item))) # type: ignore[operator]
|
|
148
158
|
else:
|
|
149
159
|
result.append(item)
|
|
150
160
|
return result
|
|
151
|
-
if
|
|
161
|
+
if is_dict(data):
|
|
152
162
|
return schema_type(**dict(data)) # type: ignore[operator]
|
|
153
163
|
if isinstance(data, dict):
|
|
154
164
|
return schema_type(**data) # type: ignore[operator]
|
|
155
165
|
return data
|
|
156
166
|
if is_msgspec_struct(schema_type):
|
|
167
|
+
rename_config = get_msgspec_rename_config(schema_type) # type: ignore[arg-type]
|
|
157
168
|
deserializer = partial(_default_msgspec_deserializer, type_decoders=_DEFAULT_TYPE_DECODERS)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
169
|
+
|
|
170
|
+
# Transform field names if rename configuration exists
|
|
171
|
+
transformed_data = data
|
|
172
|
+
if (rename_config and is_dict(data)) or (isinstance(data, Sequence) and data and is_dict(data[0])):
|
|
173
|
+
try:
|
|
174
|
+
converter = None
|
|
175
|
+
if rename_config == "camel":
|
|
176
|
+
converter = camelize
|
|
177
|
+
elif rename_config == "kebab":
|
|
178
|
+
converter = kebabize
|
|
179
|
+
elif rename_config == "pascal":
|
|
180
|
+
converter = pascalize
|
|
181
|
+
|
|
182
|
+
if converter is not None:
|
|
183
|
+
if isinstance(data, Sequence):
|
|
184
|
+
transformed_data = [
|
|
185
|
+
transform_dict_keys(item, converter) if is_dict(item) else item for item in data
|
|
186
|
+
]
|
|
187
|
+
else:
|
|
188
|
+
transformed_data = transform_dict_keys(data, converter) if is_dict(data) else data
|
|
189
|
+
except Exception as e:
|
|
190
|
+
logger.debug("Field name transformation failed for msgspec schema: %s", e)
|
|
191
|
+
transformed_data = data
|
|
192
|
+
|
|
193
|
+
if not isinstance(transformed_data, Sequence):
|
|
194
|
+
return convert(obj=transformed_data, type=schema_type, from_attributes=True, dec_hook=deserializer)
|
|
195
|
+
return convert(obj=transformed_data, type=list[schema_type], from_attributes=True, dec_hook=deserializer) # type: ignore[valid-type]
|
|
161
196
|
if is_pydantic_model(schema_type):
|
|
162
197
|
if not isinstance(data, Sequence):
|
|
163
198
|
adapter = get_type_adapter(schema_type)
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""Data transformation utilities for SQLSpec.
|
|
2
|
+
|
|
3
|
+
Provides functions for transforming data structures, particularly for
|
|
4
|
+
field name conversion when mapping database results to schema objects.
|
|
5
|
+
Used primarily for msgspec field name conversion with rename configurations.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Callable, Union
|
|
9
|
+
|
|
10
|
+
__all__ = ("transform_dict_keys",)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _safe_convert_key(key: Any, converter: Callable[[str], str]) -> Any:
|
|
14
|
+
"""Safely convert a key using the converter function.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
key: Key to convert (may not be a string).
|
|
18
|
+
converter: Function to convert string keys.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Converted key if conversion succeeds, original key otherwise.
|
|
22
|
+
"""
|
|
23
|
+
if not isinstance(key, str):
|
|
24
|
+
return key
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
return converter(key)
|
|
28
|
+
except (TypeError, ValueError, AttributeError):
|
|
29
|
+
# If conversion fails, return the original key
|
|
30
|
+
return key
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def transform_dict_keys(data: Union[dict, list, Any], converter: Callable[[str], str]) -> Union[dict, list, Any]:
|
|
34
|
+
"""Transform dictionary keys using the provided converter function.
|
|
35
|
+
|
|
36
|
+
Recursively transforms all dictionary keys in a data structure using
|
|
37
|
+
the provided converter function. Handles nested dictionaries, lists
|
|
38
|
+
of dictionaries, and preserves non-dict values unchanged.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
data: The data structure to transform. Can be a dict, list, or any other type.
|
|
42
|
+
converter: Function to convert string keys (e.g., camelize, kebabize).
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The transformed data structure with converted keys. Non-dict values
|
|
46
|
+
are returned unchanged.
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
Transform snake_case keys to camelCase:
|
|
50
|
+
|
|
51
|
+
>>> from sqlspec.utils.text import camelize
|
|
52
|
+
>>> data = {"user_id": 123, "created_at": "2024-01-01"}
|
|
53
|
+
>>> transform_dict_keys(data, camelize)
|
|
54
|
+
{"userId": 123, "createdAt": "2024-01-01"}
|
|
55
|
+
|
|
56
|
+
Transform nested structures:
|
|
57
|
+
|
|
58
|
+
>>> nested = {
|
|
59
|
+
... "user_data": {"first_name": "John", "last_name": "Doe"},
|
|
60
|
+
... "order_items": [
|
|
61
|
+
... {"item_id": 1, "item_name": "Product A"},
|
|
62
|
+
... {"item_id": 2, "item_name": "Product B"},
|
|
63
|
+
... ],
|
|
64
|
+
... }
|
|
65
|
+
>>> transform_dict_keys(nested, camelize)
|
|
66
|
+
{
|
|
67
|
+
"userData": {
|
|
68
|
+
"firstName": "John",
|
|
69
|
+
"lastName": "Doe"
|
|
70
|
+
},
|
|
71
|
+
"orderItems": [
|
|
72
|
+
{"itemId": 1, "itemName": "Product A"},
|
|
73
|
+
{"itemId": 2, "itemName": "Product B"}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
"""
|
|
77
|
+
if isinstance(data, dict):
|
|
78
|
+
return _transform_dict(data, converter)
|
|
79
|
+
if isinstance(data, list):
|
|
80
|
+
return _transform_list(data, converter)
|
|
81
|
+
return data
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _transform_dict(data: dict, converter: Callable[[str], str]) -> dict:
|
|
85
|
+
"""Transform a dictionary's keys recursively.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
data: Dictionary to transform.
|
|
89
|
+
converter: Function to convert string keys.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Dictionary with transformed keys and recursively transformed values.
|
|
93
|
+
"""
|
|
94
|
+
transformed = {}
|
|
95
|
+
|
|
96
|
+
for key, value in data.items():
|
|
97
|
+
# Convert the key using the provided converter function
|
|
98
|
+
# Use safe conversion that handles edge cases without try-except
|
|
99
|
+
converted_key = _safe_convert_key(key, converter)
|
|
100
|
+
|
|
101
|
+
# Recursively transform the value
|
|
102
|
+
transformed_value = transform_dict_keys(value, converter)
|
|
103
|
+
|
|
104
|
+
transformed[converted_key] = transformed_value
|
|
105
|
+
|
|
106
|
+
return transformed
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _transform_list(data: list, converter: Callable[[str], str]) -> list:
|
|
110
|
+
"""Transform a list's elements recursively.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
data: List to transform.
|
|
114
|
+
converter: Function to convert string keys in nested structures.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
List with recursively transformed elements.
|
|
118
|
+
"""
|
|
119
|
+
# Use list comprehension for better performance and avoid try-except in loop
|
|
120
|
+
return [transform_dict_keys(item, converter) for item in data]
|
|
@@ -19,25 +19,7 @@ _SNAKE_CASE_HYPHEN_SPACE = re.compile(r"[.\s@-]+", re.UNICODE)
|
|
|
19
19
|
_SNAKE_CASE_REMOVE_NON_WORD = re.compile(r"[^\w]+", re.UNICODE)
|
|
20
20
|
_SNAKE_CASE_MULTIPLE_UNDERSCORES = re.compile(r"__+", re.UNICODE)
|
|
21
21
|
|
|
22
|
-
__all__ = ("camelize", "
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def check_email(email: str) -> str:
|
|
26
|
-
"""Validate an email address.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
email: The email to validate.
|
|
30
|
-
|
|
31
|
-
Raises:
|
|
32
|
-
ValueError: If the email is invalid.
|
|
33
|
-
|
|
34
|
-
Returns:
|
|
35
|
-
The validated email.
|
|
36
|
-
"""
|
|
37
|
-
if "@" not in email:
|
|
38
|
-
msg = "Invalid email!"
|
|
39
|
-
raise ValueError(msg)
|
|
40
|
-
return email.lower()
|
|
22
|
+
__all__ = ("camelize", "kebabize", "pascalize", "slugify", "snake_case")
|
|
41
23
|
|
|
42
24
|
|
|
43
25
|
def slugify(value: str, allow_unicode: bool = False, separator: Optional[str] = None) -> str:
|
|
@@ -80,6 +62,32 @@ def camelize(string: str) -> str:
|
|
|
80
62
|
return "".join(word if index == 0 else word.capitalize() for index, word in enumerate(string.split("_")))
|
|
81
63
|
|
|
82
64
|
|
|
65
|
+
@lru_cache(maxsize=100)
|
|
66
|
+
def kebabize(string: str) -> str:
|
|
67
|
+
"""Convert a string to kebab-case.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
string: The string to convert.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
The kebab-case version of the string.
|
|
74
|
+
"""
|
|
75
|
+
return "-".join(word.lower() for word in string.split("_") if word)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@lru_cache(maxsize=100)
|
|
79
|
+
def pascalize(string: str) -> str:
|
|
80
|
+
"""Convert a string to PascalCase.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
string: The string to convert.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
The PascalCase version of the string.
|
|
87
|
+
"""
|
|
88
|
+
return "".join(word.capitalize() for word in string.split("_") if word)
|
|
89
|
+
|
|
90
|
+
|
|
83
91
|
@lru_cache(maxsize=100)
|
|
84
92
|
def snake_case(string: str) -> str:
|
|
85
93
|
"""Convert a string to snake_case.
|
|
@@ -6,6 +6,7 @@ understand type narrowing, replacing defensive hasattr() and duck typing pattern
|
|
|
6
6
|
|
|
7
7
|
from collections.abc import Sequence
|
|
8
8
|
from collections.abc import Set as AbstractSet
|
|
9
|
+
from functools import lru_cache
|
|
9
10
|
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
|
10
11
|
|
|
11
12
|
from sqlspec.typing import (
|
|
@@ -59,6 +60,7 @@ __all__ = (
|
|
|
59
60
|
"extract_dataclass_items",
|
|
60
61
|
"get_initial_expression",
|
|
61
62
|
"get_literal_parent",
|
|
63
|
+
"get_msgspec_rename_config",
|
|
62
64
|
"get_node_expressions",
|
|
63
65
|
"get_node_this",
|
|
64
66
|
"get_param_style_and_name",
|
|
@@ -429,6 +431,78 @@ def is_msgspec_struct_without_field(obj: Any, field_name: str) -> "TypeGuard[Str
|
|
|
429
431
|
return False
|
|
430
432
|
|
|
431
433
|
|
|
434
|
+
@lru_cache(maxsize=500)
|
|
435
|
+
def _detect_rename_pattern(field_name: str, encode_name: str) -> "Optional[str]":
|
|
436
|
+
"""Detect the rename pattern by comparing field name transformations.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
field_name: Original field name (e.g., "user_id")
|
|
440
|
+
encode_name: Encoded field name (e.g., "userId")
|
|
441
|
+
|
|
442
|
+
Returns:
|
|
443
|
+
The detected rename pattern ("camel", "kebab", "pascal") or None
|
|
444
|
+
"""
|
|
445
|
+
from sqlspec.utils.text import camelize, kebabize, pascalize
|
|
446
|
+
|
|
447
|
+
# Test camelCase conversion
|
|
448
|
+
if encode_name == camelize(field_name) and encode_name != field_name:
|
|
449
|
+
return "camel"
|
|
450
|
+
|
|
451
|
+
if encode_name == kebabize(field_name) and encode_name != field_name:
|
|
452
|
+
return "kebab"
|
|
453
|
+
|
|
454
|
+
if encode_name == pascalize(field_name) and encode_name != field_name:
|
|
455
|
+
return "pascal"
|
|
456
|
+
return None
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def get_msgspec_rename_config(schema_type: type) -> "Optional[str]":
|
|
460
|
+
"""Extract msgspec rename configuration from a struct type.
|
|
461
|
+
|
|
462
|
+
Analyzes field name transformations to detect the rename pattern used by msgspec.
|
|
463
|
+
Since msgspec doesn't store the original rename parameter directly, we infer it
|
|
464
|
+
by comparing field names with their encode_name values.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
schema_type: The msgspec struct type to inspect.
|
|
468
|
+
|
|
469
|
+
Returns:
|
|
470
|
+
The rename configuration value ("camel", "kebab", "pascal", etc.) if detected,
|
|
471
|
+
None if no rename configuration exists or if not a msgspec struct.
|
|
472
|
+
|
|
473
|
+
Examples:
|
|
474
|
+
>>> class User(msgspec.Struct, rename="camel"):
|
|
475
|
+
... user_id: int
|
|
476
|
+
>>> get_msgspec_rename_config(User)
|
|
477
|
+
"camel"
|
|
478
|
+
|
|
479
|
+
>>> class Product(msgspec.Struct):
|
|
480
|
+
... product_id: int
|
|
481
|
+
>>> get_msgspec_rename_config(Product)
|
|
482
|
+
None
|
|
483
|
+
"""
|
|
484
|
+
if not MSGSPEC_INSTALLED:
|
|
485
|
+
return None
|
|
486
|
+
|
|
487
|
+
if not is_msgspec_struct(schema_type):
|
|
488
|
+
return None
|
|
489
|
+
|
|
490
|
+
from msgspec import structs
|
|
491
|
+
|
|
492
|
+
fields = structs.fields(schema_type) # type: ignore[arg-type]
|
|
493
|
+
if not fields:
|
|
494
|
+
return None
|
|
495
|
+
|
|
496
|
+
# Check if any field name differs from its encode_name
|
|
497
|
+
for field in fields:
|
|
498
|
+
if field.name != field.encode_name:
|
|
499
|
+
# Detect the rename pattern by comparing transformations
|
|
500
|
+
return _detect_rename_pattern(field.name, field.encode_name)
|
|
501
|
+
|
|
502
|
+
# If all field names match their encode_name, no rename is applied
|
|
503
|
+
return None
|
|
504
|
+
|
|
505
|
+
|
|
432
506
|
def is_attrs_instance(obj: Any) -> "TypeGuard[AttrsInstanceStub]":
|
|
433
507
|
"""Check if a value is an attrs class instance.
|
|
434
508
|
|