sqlspec 0.16.0__tar.gz → 0.16.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.16.0 → sqlspec-0.16.1}/PKG-INFO +1 -1
- {sqlspec-0.16.0 → sqlspec-0.16.1}/pyproject.toml +1 -1
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/_sql.py +448 -15
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_base.py +77 -44
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_column.py +0 -4
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_ddl.py +15 -52
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_ddl_utils.py +0 -1
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_delete.py +4 -5
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_insert.py +59 -44
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_merge.py +17 -2
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_parsing_utils.py +11 -11
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_select.py +29 -33
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_update.py +4 -2
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_cte_and_set_ops.py +47 -20
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_delete_operations.py +6 -1
- sqlspec-0.16.1/sqlspec/builder/mixins/_insert_operations.py +244 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_join_operations.py +11 -4
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_merge_operations.py +81 -21
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_order_limit_operations.py +15 -3
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_pivot_operations.py +11 -2
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_select_operations.py +12 -8
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_update_operations.py +37 -14
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_where_clause.py +55 -43
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/cache.py +26 -28
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/compiler.py +58 -37
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/parameters.py +80 -52
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/result.py +30 -17
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/statement.py +31 -21
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/_async.py +76 -46
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/_common.py +25 -6
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/_sync.py +73 -43
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/mixins/_result_tools.py +51 -22
- sqlspec-0.16.1/sqlspec/driver/mixins/_sql_translator.py +86 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/protocols.py +7 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/type_guards.py +7 -3
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_builder_parameter_naming.py +11 -20
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_filters.py +97 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_sql_factory.py +402 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/uv.lock +91 -87
- sqlspec-0.16.0/sqlspec/builder/mixins/_insert_operations.py +0 -152
- sqlspec-0.16.0/sqlspec/driver/mixins/_sql_translator.py +0 -36
- {sqlspec-0.16.0 → sqlspec-0.16.1}/.gitignore +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/.pre-commit-config.yaml +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/CONTRIBUTING.rst +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/LICENSE +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/Makefile +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/NOTICE +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/README.md +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/__main__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/__metadata__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/_serialization.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/_typing.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/adbc/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/adbc/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/adbc/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/adbc/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/aiosqlite/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/aiosqlite/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/aiosqlite/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/aiosqlite/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncmy/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncmy/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncmy/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncmy/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncpg/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncpg/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncpg/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncpg/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/bigquery/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/bigquery/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/bigquery/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/bigquery/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/duckdb/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/duckdb/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/duckdb/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/duckdb/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/oracledb/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/oracledb/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/oracledb/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/oracledb/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psqlpy/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psqlpy/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psqlpy/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psqlpy/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psycopg/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psycopg/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psycopg/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psycopg/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/sqlite/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/sqlite/_types.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/sqlite/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/sqlite/driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/base.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/cli.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/filters.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/hashing.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/splitter.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/mixins/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/exceptions.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/aiosql/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/aiosql/adapter.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/_utils.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/cli.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/handlers.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/plugin.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/providers.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/loader.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/base.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/commands.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/loaders.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/runner.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/tracker.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/utils.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/py.typed +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/backends/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/backends/base.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/backends/fsspec.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/backends/obstore.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/capabilities.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/registry.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/typing.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/correlation.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/deprecation.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/fixtures.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/logging.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/module_loader.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/serializers.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/singleton.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/sync_tools.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/text.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/ddls-mysql-collection.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/ddls-postgres-collection.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/example_usage.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/init.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-config.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-data_types.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-database_details.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-engines.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-hostname.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-plugins.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-process_list.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-resource-groups.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-schema_objects.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-table_details.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-users.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/init.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/oracle.ddl.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-applications.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-aws_extension_dependency.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-aws_oracle_exists.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-bg_writer_stats.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-calculated_metrics.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-data_types.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-database_details.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-extensions.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-index_details.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-pglogical-details.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-privileges.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-replication_slots.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-replication_stats.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-schema_details.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-schema_objects.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-settings.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-source_details.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-table_details.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/extended-collection-all-databases.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/init.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/readiness-check.sql +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/sql_utils.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_arrow_features.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_backends.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_connection.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_edge_cases.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_results.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/test_connection.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/test_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/test_pooling.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/test_asyncmy_features.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/test_config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/test_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/test_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/test_connection.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/test_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/test_execute_many.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/test_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_bigquery_features.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_config.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_connection.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_connection.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_execute_many.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_mixed_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_pooling.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/utils.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_connection.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_driver_async.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_driver_sync.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_execute_many.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_oracle_features.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/test_connection.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/test_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/test_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/test_psqlpy_features.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_async_copy.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_connection.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_execute_many.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/test_driver.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/test_parameter_styles.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/test_pooling.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/test_query_mixin.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_loader/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_loader/test_file_system_loading.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_migrations/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_migrations/test_migration_execution.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/conftest.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/test_adapter_implementations.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/test_async_adapters.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/test_sync_adapters.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_base/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_base/test_sqlspec_class.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_builder/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_builder/test_parameter_naming.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_cache.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_compiler.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_hashing.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_parameters.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_result.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_statement.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_loader/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_loader/test_cache_integration.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_loader/test_loading_patterns.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_loader/test_sql_file_loader.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_migrations/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_migrations/test_migration.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_migrations/test_migration_execution.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_migrations/test_migration_runner.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_correlation.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_deprecation.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_fixtures.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_logging.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_module_loader.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_serializers.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_singleton.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_sync_tools.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_text.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_type_guards.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/build_docs.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/local-infra.sh +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/pypi_readme.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/sphinx_ext/__init__.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/sphinx_ext/changelog.py +0 -0
- {sqlspec-0.16.0 → sqlspec-0.16.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.16.
|
|
16
|
+
version = "0.16.1"
|
|
17
17
|
|
|
18
18
|
[project.urls]
|
|
19
19
|
Discord = "https://discord.gg/litestar"
|
|
@@ -4,9 +4,10 @@ Provides both statement builders (select, insert, update, etc.) and column expre
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
|
8
8
|
|
|
9
9
|
import sqlglot
|
|
10
|
+
from mypy_extensions import trait
|
|
10
11
|
from sqlglot import exp
|
|
11
12
|
from sqlglot.dialects.dialect import DialectType
|
|
12
13
|
from sqlglot.errors import ParseError as SQLGlotParseError
|
|
@@ -36,6 +37,7 @@ from sqlspec.builder import (
|
|
|
36
37
|
from sqlspec.exceptions import SQLBuilderError
|
|
37
38
|
|
|
38
39
|
if TYPE_CHECKING:
|
|
40
|
+
from sqlspec.builder._column import ColumnExpression
|
|
39
41
|
from sqlspec.core.statement import SQL
|
|
40
42
|
|
|
41
43
|
__all__ = (
|
|
@@ -61,6 +63,7 @@ __all__ = (
|
|
|
61
63
|
"Select",
|
|
62
64
|
"Truncate",
|
|
63
65
|
"Update",
|
|
66
|
+
"WindowFunctionBuilder",
|
|
64
67
|
"sql",
|
|
65
68
|
)
|
|
66
69
|
|
|
@@ -188,12 +191,8 @@ class SQLFactory:
|
|
|
188
191
|
)
|
|
189
192
|
raise SQLBuilderError(msg)
|
|
190
193
|
select_builder = Select(dialect=builder_dialect)
|
|
191
|
-
if select_builder._expression is None:
|
|
192
|
-
select_builder.__post_init__()
|
|
193
194
|
return self._populate_select_from_sql(select_builder, sql_candidate)
|
|
194
195
|
select_builder = Select(dialect=builder_dialect)
|
|
195
|
-
if select_builder._expression is None:
|
|
196
|
-
select_builder.__post_init__()
|
|
197
196
|
if columns_or_sql:
|
|
198
197
|
select_builder.select(*columns_or_sql)
|
|
199
198
|
return select_builder
|
|
@@ -201,8 +200,6 @@ class SQLFactory:
|
|
|
201
200
|
def insert(self, table_or_sql: Optional[str] = None, dialect: DialectType = None) -> "Insert":
|
|
202
201
|
builder_dialect = dialect or self.dialect
|
|
203
202
|
builder = Insert(dialect=builder_dialect)
|
|
204
|
-
if builder._expression is None:
|
|
205
|
-
builder.__post_init__()
|
|
206
203
|
if table_or_sql:
|
|
207
204
|
if self._looks_like_sql(table_or_sql):
|
|
208
205
|
detected = self.detect_sql_type(table_or_sql, dialect=builder_dialect)
|
|
@@ -220,8 +217,6 @@ class SQLFactory:
|
|
|
220
217
|
def update(self, table_or_sql: Optional[str] = None, dialect: DialectType = None) -> "Update":
|
|
221
218
|
builder_dialect = dialect or self.dialect
|
|
222
219
|
builder = Update(dialect=builder_dialect)
|
|
223
|
-
if builder._expression is None:
|
|
224
|
-
builder.__post_init__()
|
|
225
220
|
if table_or_sql:
|
|
226
221
|
if self._looks_like_sql(table_or_sql):
|
|
227
222
|
detected = self.detect_sql_type(table_or_sql, dialect=builder_dialect)
|
|
@@ -235,8 +230,6 @@ class SQLFactory:
|
|
|
235
230
|
def delete(self, table_or_sql: Optional[str] = None, dialect: DialectType = None) -> "Delete":
|
|
236
231
|
builder_dialect = dialect or self.dialect
|
|
237
232
|
builder = Delete(dialect=builder_dialect)
|
|
238
|
-
if builder._expression is None:
|
|
239
|
-
builder.__post_init__()
|
|
240
233
|
if table_or_sql and self._looks_like_sql(table_or_sql):
|
|
241
234
|
detected = self.detect_sql_type(table_or_sql, dialect=builder_dialect)
|
|
242
235
|
if detected != "DELETE":
|
|
@@ -248,8 +241,6 @@ class SQLFactory:
|
|
|
248
241
|
def merge(self, table_or_sql: Optional[str] = None, dialect: DialectType = None) -> "Merge":
|
|
249
242
|
builder_dialect = dialect or self.dialect
|
|
250
243
|
builder = Merge(dialect=builder_dialect)
|
|
251
|
-
if builder._expression is None:
|
|
252
|
-
builder.__post_init__()
|
|
253
244
|
if table_or_sql:
|
|
254
245
|
if self._looks_like_sql(table_or_sql):
|
|
255
246
|
detected = self.detect_sql_type(table_or_sql, dialect=builder_dialect)
|
|
@@ -563,14 +554,112 @@ class SQLFactory:
|
|
|
563
554
|
"""
|
|
564
555
|
return Column(name, table)
|
|
565
556
|
|
|
566
|
-
|
|
557
|
+
@property
|
|
558
|
+
def case_(self) -> "Case":
|
|
559
|
+
"""Create a CASE expression builder with improved syntax.
|
|
560
|
+
|
|
561
|
+
Returns:
|
|
562
|
+
Case builder instance for fluent CASE expression building.
|
|
563
|
+
|
|
564
|
+
Example:
|
|
565
|
+
```python
|
|
566
|
+
case_expr = (
|
|
567
|
+
sql.case_.when("x = 1", "one")
|
|
568
|
+
.when("x = 2", "two")
|
|
569
|
+
.else_("other")
|
|
570
|
+
.end()
|
|
571
|
+
)
|
|
572
|
+
aliased_case = (
|
|
573
|
+
sql.case_.when("status = 'active'", 1)
|
|
574
|
+
.else_(0)
|
|
575
|
+
.as_("is_active")
|
|
576
|
+
)
|
|
577
|
+
```
|
|
578
|
+
"""
|
|
579
|
+
return Case()
|
|
580
|
+
|
|
581
|
+
@property
|
|
582
|
+
def row_number_(self) -> "WindowFunctionBuilder":
|
|
583
|
+
"""Create a ROW_NUMBER() window function builder."""
|
|
584
|
+
return WindowFunctionBuilder("row_number")
|
|
585
|
+
|
|
586
|
+
@property
|
|
587
|
+
def rank_(self) -> "WindowFunctionBuilder":
|
|
588
|
+
"""Create a RANK() window function builder."""
|
|
589
|
+
return WindowFunctionBuilder("rank")
|
|
590
|
+
|
|
591
|
+
@property
|
|
592
|
+
def dense_rank_(self) -> "WindowFunctionBuilder":
|
|
593
|
+
"""Create a DENSE_RANK() window function builder."""
|
|
594
|
+
return WindowFunctionBuilder("dense_rank")
|
|
595
|
+
|
|
596
|
+
@property
|
|
597
|
+
def lag_(self) -> "WindowFunctionBuilder":
|
|
598
|
+
"""Create a LAG() window function builder."""
|
|
599
|
+
return WindowFunctionBuilder("lag")
|
|
600
|
+
|
|
601
|
+
@property
|
|
602
|
+
def lead_(self) -> "WindowFunctionBuilder":
|
|
603
|
+
"""Create a LEAD() window function builder."""
|
|
604
|
+
return WindowFunctionBuilder("lead")
|
|
605
|
+
|
|
606
|
+
@property
|
|
607
|
+
def exists_(self) -> "SubqueryBuilder":
|
|
608
|
+
"""Create an EXISTS subquery builder."""
|
|
609
|
+
return SubqueryBuilder("exists")
|
|
610
|
+
|
|
611
|
+
@property
|
|
612
|
+
def in_(self) -> "SubqueryBuilder":
|
|
613
|
+
"""Create an IN subquery builder."""
|
|
614
|
+
return SubqueryBuilder("in")
|
|
615
|
+
|
|
616
|
+
@property
|
|
617
|
+
def any_(self) -> "SubqueryBuilder":
|
|
618
|
+
"""Create an ANY subquery builder."""
|
|
619
|
+
return SubqueryBuilder("any")
|
|
620
|
+
|
|
621
|
+
@property
|
|
622
|
+
def all_(self) -> "SubqueryBuilder":
|
|
623
|
+
"""Create an ALL subquery builder."""
|
|
624
|
+
return SubqueryBuilder("all")
|
|
625
|
+
|
|
626
|
+
@property
|
|
627
|
+
def inner_join_(self) -> "JoinBuilder":
|
|
628
|
+
"""Create an INNER JOIN builder."""
|
|
629
|
+
return JoinBuilder("inner join")
|
|
630
|
+
|
|
631
|
+
@property
|
|
632
|
+
def left_join_(self) -> "JoinBuilder":
|
|
633
|
+
"""Create a LEFT JOIN builder."""
|
|
634
|
+
return JoinBuilder("left join")
|
|
635
|
+
|
|
636
|
+
@property
|
|
637
|
+
def right_join_(self) -> "JoinBuilder":
|
|
638
|
+
"""Create a RIGHT JOIN builder."""
|
|
639
|
+
return JoinBuilder("right join")
|
|
640
|
+
|
|
641
|
+
@property
|
|
642
|
+
def full_join_(self) -> "JoinBuilder":
|
|
643
|
+
"""Create a FULL OUTER JOIN builder."""
|
|
644
|
+
return JoinBuilder("full join")
|
|
645
|
+
|
|
646
|
+
@property
|
|
647
|
+
def cross_join_(self) -> "JoinBuilder":
|
|
648
|
+
"""Create a CROSS JOIN builder."""
|
|
649
|
+
return JoinBuilder("cross join")
|
|
650
|
+
|
|
651
|
+
def __getattr__(self, name: str) -> "Column":
|
|
567
652
|
"""Dynamically create column references.
|
|
568
653
|
|
|
569
654
|
Args:
|
|
570
655
|
name: Column name.
|
|
571
656
|
|
|
572
657
|
Returns:
|
|
573
|
-
Column object
|
|
658
|
+
Column object for the given name.
|
|
659
|
+
|
|
660
|
+
Note:
|
|
661
|
+
Special SQL constructs like case_, row_number_, etc. are now
|
|
662
|
+
handled as properties for better type safety.
|
|
574
663
|
"""
|
|
575
664
|
return Column(name)
|
|
576
665
|
|
|
@@ -1282,6 +1371,7 @@ class SQLFactory:
|
|
|
1282
1371
|
return exp.Window(this=func_expr, **over_args)
|
|
1283
1372
|
|
|
1284
1373
|
|
|
1374
|
+
@trait
|
|
1285
1375
|
class Case:
|
|
1286
1376
|
"""Builder for CASE expressions using the SQL factory.
|
|
1287
1377
|
|
|
@@ -1304,6 +1394,19 @@ class Case:
|
|
|
1304
1394
|
self._conditions: list[exp.If] = []
|
|
1305
1395
|
self._default: Optional[exp.Expression] = None
|
|
1306
1396
|
|
|
1397
|
+
def __eq__(self, other: object) -> "ColumnExpression": # type: ignore[override]
|
|
1398
|
+
"""Equal to (==) - convert to expression then compare."""
|
|
1399
|
+
from sqlspec.builder._column import ColumnExpression
|
|
1400
|
+
|
|
1401
|
+
case_expr = exp.Case(ifs=self._conditions, default=self._default)
|
|
1402
|
+
if other is None:
|
|
1403
|
+
return ColumnExpression(exp.Is(this=case_expr, expression=exp.Null()))
|
|
1404
|
+
return ColumnExpression(exp.EQ(this=case_expr, expression=exp.convert(other)))
|
|
1405
|
+
|
|
1406
|
+
def __hash__(self) -> int:
|
|
1407
|
+
"""Make Case hashable."""
|
|
1408
|
+
return hash(id(self))
|
|
1409
|
+
|
|
1307
1410
|
def when(self, condition: Union[str, exp.Expression], value: Union[str, exp.Expression, Any]) -> "Case":
|
|
1308
1411
|
"""Add a WHEN clause.
|
|
1309
1412
|
|
|
@@ -1342,6 +1445,336 @@ class Case:
|
|
|
1342
1445
|
"""
|
|
1343
1446
|
return exp.Case(ifs=self._conditions, default=self._default)
|
|
1344
1447
|
|
|
1448
|
+
def as_(self, alias: str) -> exp.Alias:
|
|
1449
|
+
"""Complete the CASE expression with an alias.
|
|
1450
|
+
|
|
1451
|
+
Args:
|
|
1452
|
+
alias: Alias name for the CASE expression.
|
|
1453
|
+
|
|
1454
|
+
Returns:
|
|
1455
|
+
Aliased CASE expression.
|
|
1456
|
+
"""
|
|
1457
|
+
case_expr = exp.Case(ifs=self._conditions, default=self._default)
|
|
1458
|
+
return cast("exp.Alias", exp.alias_(case_expr, alias))
|
|
1459
|
+
|
|
1460
|
+
|
|
1461
|
+
@trait
|
|
1462
|
+
class WindowFunctionBuilder:
|
|
1463
|
+
"""Builder for window functions with fluent syntax.
|
|
1464
|
+
|
|
1465
|
+
Example:
|
|
1466
|
+
```python
|
|
1467
|
+
from sqlspec import sql
|
|
1468
|
+
|
|
1469
|
+
# sql.row_number_.partition_by("department").order_by("salary")
|
|
1470
|
+
window_func = (
|
|
1471
|
+
sql.row_number_.partition_by("department")
|
|
1472
|
+
.order_by("salary")
|
|
1473
|
+
.as_("row_num")
|
|
1474
|
+
)
|
|
1475
|
+
```
|
|
1476
|
+
"""
|
|
1477
|
+
|
|
1478
|
+
def __init__(self, function_name: str) -> None:
|
|
1479
|
+
"""Initialize the window function builder.
|
|
1480
|
+
|
|
1481
|
+
Args:
|
|
1482
|
+
function_name: Name of the window function (row_number, rank, etc.)
|
|
1483
|
+
"""
|
|
1484
|
+
self._function_name = function_name
|
|
1485
|
+
self._partition_by_cols: list[exp.Expression] = []
|
|
1486
|
+
self._order_by_cols: list[exp.Expression] = []
|
|
1487
|
+
self._alias: Optional[str] = None
|
|
1488
|
+
|
|
1489
|
+
def __eq__(self, other: object) -> "ColumnExpression": # type: ignore[override]
|
|
1490
|
+
"""Equal to (==) - convert to expression then compare."""
|
|
1491
|
+
from sqlspec.builder._column import ColumnExpression
|
|
1492
|
+
|
|
1493
|
+
window_expr = self._build_expression()
|
|
1494
|
+
if other is None:
|
|
1495
|
+
return ColumnExpression(exp.Is(this=window_expr, expression=exp.Null()))
|
|
1496
|
+
return ColumnExpression(exp.EQ(this=window_expr, expression=exp.convert(other)))
|
|
1497
|
+
|
|
1498
|
+
def __hash__(self) -> int:
|
|
1499
|
+
"""Make WindowFunctionBuilder hashable."""
|
|
1500
|
+
return hash(id(self))
|
|
1501
|
+
|
|
1502
|
+
def partition_by(self, *columns: Union[str, exp.Expression]) -> "WindowFunctionBuilder":
|
|
1503
|
+
"""Add PARTITION BY clause.
|
|
1504
|
+
|
|
1505
|
+
Args:
|
|
1506
|
+
*columns: Columns to partition by.
|
|
1507
|
+
|
|
1508
|
+
Returns:
|
|
1509
|
+
Self for method chaining.
|
|
1510
|
+
"""
|
|
1511
|
+
for col in columns:
|
|
1512
|
+
col_expr = exp.column(col) if isinstance(col, str) else col
|
|
1513
|
+
self._partition_by_cols.append(col_expr)
|
|
1514
|
+
return self
|
|
1515
|
+
|
|
1516
|
+
def order_by(self, *columns: Union[str, exp.Expression]) -> "WindowFunctionBuilder":
|
|
1517
|
+
"""Add ORDER BY clause.
|
|
1518
|
+
|
|
1519
|
+
Args:
|
|
1520
|
+
*columns: Columns to order by.
|
|
1521
|
+
|
|
1522
|
+
Returns:
|
|
1523
|
+
Self for method chaining.
|
|
1524
|
+
"""
|
|
1525
|
+
for col in columns:
|
|
1526
|
+
if isinstance(col, str):
|
|
1527
|
+
col_expr = exp.column(col).asc()
|
|
1528
|
+
self._order_by_cols.append(col_expr)
|
|
1529
|
+
else:
|
|
1530
|
+
# Convert to ordered expression
|
|
1531
|
+
self._order_by_cols.append(exp.Ordered(this=col, desc=False))
|
|
1532
|
+
return self
|
|
1533
|
+
|
|
1534
|
+
def as_(self, alias: str) -> exp.Expression:
|
|
1535
|
+
"""Complete the window function with an alias.
|
|
1536
|
+
|
|
1537
|
+
Args:
|
|
1538
|
+
alias: Alias name for the window function.
|
|
1539
|
+
|
|
1540
|
+
Returns:
|
|
1541
|
+
Aliased window function expression.
|
|
1542
|
+
"""
|
|
1543
|
+
window_expr = self._build_expression()
|
|
1544
|
+
return cast("exp.Alias", exp.alias_(window_expr, alias))
|
|
1545
|
+
|
|
1546
|
+
def build(self) -> exp.Expression:
|
|
1547
|
+
"""Complete the window function without an alias.
|
|
1548
|
+
|
|
1549
|
+
Returns:
|
|
1550
|
+
Window function expression.
|
|
1551
|
+
"""
|
|
1552
|
+
return self._build_expression()
|
|
1553
|
+
|
|
1554
|
+
def _build_expression(self) -> exp.Expression:
|
|
1555
|
+
"""Build the complete window function expression."""
|
|
1556
|
+
# Create the function expression
|
|
1557
|
+
func_expr = exp.Anonymous(this=self._function_name.upper(), expressions=[])
|
|
1558
|
+
|
|
1559
|
+
# Build the OVER clause arguments
|
|
1560
|
+
over_args: dict[str, Any] = {}
|
|
1561
|
+
|
|
1562
|
+
if self._partition_by_cols:
|
|
1563
|
+
over_args["partition_by"] = self._partition_by_cols
|
|
1564
|
+
|
|
1565
|
+
if self._order_by_cols:
|
|
1566
|
+
over_args["order"] = exp.Order(expressions=self._order_by_cols)
|
|
1567
|
+
|
|
1568
|
+
return exp.Window(this=func_expr, **over_args)
|
|
1569
|
+
|
|
1570
|
+
|
|
1571
|
+
@trait
|
|
1572
|
+
class SubqueryBuilder:
|
|
1573
|
+
"""Builder for subquery operations with fluent syntax.
|
|
1574
|
+
|
|
1575
|
+
Example:
|
|
1576
|
+
```python
|
|
1577
|
+
from sqlspec import sql
|
|
1578
|
+
|
|
1579
|
+
# sql.exists_(subquery)
|
|
1580
|
+
exists_check = sql.exists_(
|
|
1581
|
+
sql.select("1")
|
|
1582
|
+
.from_("orders")
|
|
1583
|
+
.where_eq("user_id", sql.users.id)
|
|
1584
|
+
)
|
|
1585
|
+
|
|
1586
|
+
# sql.in_(subquery)
|
|
1587
|
+
in_check = sql.in_(
|
|
1588
|
+
sql.select("category_id")
|
|
1589
|
+
.from_("categories")
|
|
1590
|
+
.where_eq("active", True)
|
|
1591
|
+
)
|
|
1592
|
+
```
|
|
1593
|
+
"""
|
|
1594
|
+
|
|
1595
|
+
def __init__(self, operation: str) -> None:
|
|
1596
|
+
"""Initialize the subquery builder.
|
|
1597
|
+
|
|
1598
|
+
Args:
|
|
1599
|
+
operation: Type of subquery operation (exists, in, any, all)
|
|
1600
|
+
"""
|
|
1601
|
+
self._operation = operation
|
|
1602
|
+
|
|
1603
|
+
def __eq__(self, other: object) -> "ColumnExpression": # type: ignore[override]
|
|
1604
|
+
"""Equal to (==) - not typically used but needed for type consistency."""
|
|
1605
|
+
from sqlspec.builder._column import ColumnExpression
|
|
1606
|
+
|
|
1607
|
+
# SubqueryBuilder doesn't have a direct expression, so this is a placeholder
|
|
1608
|
+
# In practice, this shouldn't be called as subqueries are used differently
|
|
1609
|
+
placeholder_expr = exp.Literal.string(f"subquery_{self._operation}")
|
|
1610
|
+
if other is None:
|
|
1611
|
+
return ColumnExpression(exp.Is(this=placeholder_expr, expression=exp.Null()))
|
|
1612
|
+
return ColumnExpression(exp.EQ(this=placeholder_expr, expression=exp.convert(other)))
|
|
1613
|
+
|
|
1614
|
+
def __hash__(self) -> int:
|
|
1615
|
+
"""Make SubqueryBuilder hashable."""
|
|
1616
|
+
return hash(id(self))
|
|
1617
|
+
|
|
1618
|
+
def __call__(self, subquery: Union[str, exp.Expression, Any]) -> exp.Expression:
|
|
1619
|
+
"""Build the subquery expression.
|
|
1620
|
+
|
|
1621
|
+
Args:
|
|
1622
|
+
subquery: The subquery - can be a SQL string, SelectBuilder, or expression
|
|
1623
|
+
|
|
1624
|
+
Returns:
|
|
1625
|
+
The subquery expression (EXISTS, IN, ANY, ALL, etc.)
|
|
1626
|
+
"""
|
|
1627
|
+
subquery_expr: exp.Expression
|
|
1628
|
+
if isinstance(subquery, str):
|
|
1629
|
+
# Parse as SQL
|
|
1630
|
+
parsed: Optional[exp.Expression] = exp.maybe_parse(subquery)
|
|
1631
|
+
if not parsed:
|
|
1632
|
+
msg = f"Could not parse subquery SQL: {subquery}"
|
|
1633
|
+
raise SQLBuilderError(msg)
|
|
1634
|
+
subquery_expr = parsed
|
|
1635
|
+
elif hasattr(subquery, "build") and callable(getattr(subquery, "build", None)):
|
|
1636
|
+
# It's a query builder - build it to get the SQL and parse
|
|
1637
|
+
built_query = subquery.build() # pyright: ignore[reportAttributeAccessIssue]
|
|
1638
|
+
subquery_expr = exp.maybe_parse(built_query.sql)
|
|
1639
|
+
if not subquery_expr:
|
|
1640
|
+
msg = f"Could not parse built query: {built_query.sql}"
|
|
1641
|
+
raise SQLBuilderError(msg)
|
|
1642
|
+
elif isinstance(subquery, exp.Expression):
|
|
1643
|
+
subquery_expr = subquery
|
|
1644
|
+
else:
|
|
1645
|
+
# Try to convert to expression
|
|
1646
|
+
parsed = exp.maybe_parse(str(subquery))
|
|
1647
|
+
if not parsed:
|
|
1648
|
+
msg = f"Could not convert subquery to expression: {subquery}"
|
|
1649
|
+
raise SQLBuilderError(msg)
|
|
1650
|
+
subquery_expr = parsed
|
|
1651
|
+
|
|
1652
|
+
# Build the appropriate expression based on operation
|
|
1653
|
+
if self._operation == "exists":
|
|
1654
|
+
return exp.Exists(this=subquery_expr)
|
|
1655
|
+
if self._operation == "in":
|
|
1656
|
+
# For IN, we create a subquery that can be used with WHERE column IN (subquery)
|
|
1657
|
+
return exp.In(expressions=[subquery_expr])
|
|
1658
|
+
if self._operation == "any":
|
|
1659
|
+
return exp.Any(this=subquery_expr)
|
|
1660
|
+
if self._operation == "all":
|
|
1661
|
+
return exp.All(this=subquery_expr)
|
|
1662
|
+
msg = f"Unknown subquery operation: {self._operation}"
|
|
1663
|
+
raise SQLBuilderError(msg)
|
|
1664
|
+
|
|
1665
|
+
|
|
1666
|
+
@trait
|
|
1667
|
+
class JoinBuilder:
|
|
1668
|
+
"""Builder for JOIN operations with fluent syntax.
|
|
1669
|
+
|
|
1670
|
+
Example:
|
|
1671
|
+
```python
|
|
1672
|
+
from sqlspec import sql
|
|
1673
|
+
|
|
1674
|
+
# sql.left_join_("posts").on("users.id = posts.user_id")
|
|
1675
|
+
join_clause = sql.left_join_("posts").on(
|
|
1676
|
+
"users.id = posts.user_id"
|
|
1677
|
+
)
|
|
1678
|
+
|
|
1679
|
+
# Or with query builder
|
|
1680
|
+
query = (
|
|
1681
|
+
sql.select("users.name", "posts.title")
|
|
1682
|
+
.from_("users")
|
|
1683
|
+
.join(
|
|
1684
|
+
sql.left_join_("posts").on(
|
|
1685
|
+
"users.id = posts.user_id"
|
|
1686
|
+
)
|
|
1687
|
+
)
|
|
1688
|
+
)
|
|
1689
|
+
```
|
|
1690
|
+
"""
|
|
1691
|
+
|
|
1692
|
+
def __init__(self, join_type: str) -> None:
|
|
1693
|
+
"""Initialize the join builder.
|
|
1694
|
+
|
|
1695
|
+
Args:
|
|
1696
|
+
join_type: Type of join (inner, left, right, full, cross)
|
|
1697
|
+
"""
|
|
1698
|
+
self._join_type = join_type.upper()
|
|
1699
|
+
self._table: Optional[Union[str, exp.Expression]] = None
|
|
1700
|
+
self._condition: Optional[exp.Expression] = None
|
|
1701
|
+
self._alias: Optional[str] = None
|
|
1702
|
+
|
|
1703
|
+
def __eq__(self, other: object) -> "ColumnExpression": # type: ignore[override]
|
|
1704
|
+
"""Equal to (==) - not typically used but needed for type consistency."""
|
|
1705
|
+
from sqlspec.builder._column import ColumnExpression
|
|
1706
|
+
|
|
1707
|
+
# JoinBuilder doesn't have a direct expression, so this is a placeholder
|
|
1708
|
+
# In practice, this shouldn't be called as joins are used differently
|
|
1709
|
+
placeholder_expr = exp.Literal.string(f"join_{self._join_type.lower()}")
|
|
1710
|
+
if other is None:
|
|
1711
|
+
return ColumnExpression(exp.Is(this=placeholder_expr, expression=exp.Null()))
|
|
1712
|
+
return ColumnExpression(exp.EQ(this=placeholder_expr, expression=exp.convert(other)))
|
|
1713
|
+
|
|
1714
|
+
def __hash__(self) -> int:
|
|
1715
|
+
"""Make JoinBuilder hashable."""
|
|
1716
|
+
return hash(id(self))
|
|
1717
|
+
|
|
1718
|
+
def __call__(self, table: Union[str, exp.Expression], alias: Optional[str] = None) -> "JoinBuilder":
|
|
1719
|
+
"""Set the table to join.
|
|
1720
|
+
|
|
1721
|
+
Args:
|
|
1722
|
+
table: Table name or expression to join
|
|
1723
|
+
alias: Optional alias for the table
|
|
1724
|
+
|
|
1725
|
+
Returns:
|
|
1726
|
+
Self for method chaining
|
|
1727
|
+
"""
|
|
1728
|
+
self._table = table
|
|
1729
|
+
self._alias = alias
|
|
1730
|
+
return self
|
|
1731
|
+
|
|
1732
|
+
def on(self, condition: Union[str, exp.Expression]) -> exp.Expression:
|
|
1733
|
+
"""Set the join condition and build the JOIN expression.
|
|
1734
|
+
|
|
1735
|
+
Args:
|
|
1736
|
+
condition: JOIN condition (e.g., "users.id = posts.user_id")
|
|
1737
|
+
|
|
1738
|
+
Returns:
|
|
1739
|
+
Complete JOIN expression
|
|
1740
|
+
"""
|
|
1741
|
+
if not self._table:
|
|
1742
|
+
msg = "Table must be set before calling .on()"
|
|
1743
|
+
raise SQLBuilderError(msg)
|
|
1744
|
+
|
|
1745
|
+
# Parse the condition
|
|
1746
|
+
condition_expr: exp.Expression
|
|
1747
|
+
if isinstance(condition, str):
|
|
1748
|
+
parsed: Optional[exp.Expression] = exp.maybe_parse(condition)
|
|
1749
|
+
condition_expr = parsed or exp.condition(condition)
|
|
1750
|
+
else:
|
|
1751
|
+
condition_expr = condition
|
|
1752
|
+
|
|
1753
|
+
# Build table expression
|
|
1754
|
+
table_expr: exp.Expression
|
|
1755
|
+
if isinstance(self._table, str):
|
|
1756
|
+
table_expr = exp.to_table(self._table)
|
|
1757
|
+
if self._alias:
|
|
1758
|
+
table_expr = cast("exp.Expression", exp.alias_(table_expr, self._alias))
|
|
1759
|
+
else:
|
|
1760
|
+
table_expr = self._table
|
|
1761
|
+
if self._alias:
|
|
1762
|
+
table_expr = cast("exp.Expression", exp.alias_(table_expr, self._alias))
|
|
1763
|
+
|
|
1764
|
+
# Create the appropriate join type using same pattern as existing JoinClauseMixin
|
|
1765
|
+
if self._join_type == "INNER JOIN":
|
|
1766
|
+
return exp.Join(this=table_expr, on=condition_expr)
|
|
1767
|
+
if self._join_type == "LEFT JOIN":
|
|
1768
|
+
return exp.Join(this=table_expr, on=condition_expr, side="LEFT")
|
|
1769
|
+
if self._join_type == "RIGHT JOIN":
|
|
1770
|
+
return exp.Join(this=table_expr, on=condition_expr, side="RIGHT")
|
|
1771
|
+
if self._join_type == "FULL JOIN":
|
|
1772
|
+
return exp.Join(this=table_expr, on=condition_expr, side="FULL", kind="OUTER")
|
|
1773
|
+
if self._join_type == "CROSS JOIN":
|
|
1774
|
+
# CROSS JOIN doesn't use ON condition
|
|
1775
|
+
return exp.Join(this=table_expr, kind="CROSS")
|
|
1776
|
+
return exp.Join(this=table_expr, on=condition_expr)
|
|
1777
|
+
|
|
1345
1778
|
|
|
1346
1779
|
# Create a default SQL factory instance
|
|
1347
1780
|
sql = SQLFactory()
|