dblift 3.2.1__tar.gz → 3.3.0__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.
- {dblift-3.2.1 → dblift-3.3.0}/PKG-INFO +1 -1
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/_column_enricher.py +91 -8
- dblift-3.3.0/core/seams/feature_loading.py +109 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/alter/alter_generator_factory.py +10 -2
- {dblift-3.2.1 → dblift-3.3.0}/db/base_quirks.py +19 -9
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/cosmosdb/query_executor.py +56 -5
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/provider.py +22 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/quirks.py +4 -2
- {dblift-3.2.1 → dblift-3.3.0}/dblift.egg-info/PKG-INFO +1 -1
- {dblift-3.2.1 → dblift-3.3.0}/pyproject.toml +1 -1
- dblift-3.2.1/core/seams/feature_loading.py +0 -66
- {dblift-3.2.1 → dblift-3.3.0}/LICENSE +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/README.md +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/_cli_support.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/_client_factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/_client_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/_engine_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/async_client.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/client.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/events.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/migrations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/api/py.typed +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/_command_handlers.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/_config_helpers.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/_constants.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/_output.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/_parser_setup.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/commands/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/commands/config_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/db_utils.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/extensions.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/_shared.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/baseline.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/clean.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/import_flyway.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/info.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/migrate.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/repair.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/undo.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/handlers/validate.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/main.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/cli/premium_manifest.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/_credential_masking.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/_subclasses/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/_subclasses/dummy_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/_url_builder_mixin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/config_builder.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/database_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/dblift_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/errors.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/property_registry.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/secrets/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/secrets/_cache.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/secrets/_provider_base.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/secrets/_registry.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/secrets/_resolver.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/config/secrets/_secrets_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/constants.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/dialect_boundary.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/exceptions.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/_partition_enricher.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/_schema_orchestrator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/_utils.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/_vendor_property_applier.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/base_introspector.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/base_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/column_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/constraint_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/index_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/misc_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/procedure_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/sequence_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/table_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/trigger_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/extractors/view_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/introspector_factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/result.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/schema_introspector.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/vendor_queries_base.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/vendor_queries_factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/vendor_queries_protocols.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/introspection/version_detector.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/_base.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/_factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/_formatters.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/_levels.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/_multi.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/_null.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/console.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/formatters/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/formatters/_formatter_impl.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/formatters/factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/formatters/formatter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/formatters/htmlformatter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/formatters/jsonformatter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/log.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/results.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/templates/oldreport.html +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/logger/templates/report.html +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/_type_match.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/clean_summary.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/_script_events.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/base_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/baseline_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/clean_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/import_flyway_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/info_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/migrate_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/repair_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/undo_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/commands/validate_command.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/encoding.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executor/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executor/execution_engine.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executor/migration_executor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executor/migration_helpers.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executor/placeholder_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executor/transaction_policy.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executors/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executors/base_executor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executors/executor_factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executors/python_executor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/executors/sql_executor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/formats/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/formats/format_detector.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/formats/migration_format.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/history/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/history/migration_history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/journals/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/journals/migration_journal.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/migration.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/placeholders/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/placeholders/placeholder_service.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/rules/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/rules/migration_rules.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/migration_script_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/undo_script_generator/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/undo_script_generator/_ddl_reversers.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/undo_script_generator/_dml_reversers.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/undo_script_generator/_extractors.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/undo_script_generator/_generator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/undo_script_generator/_helpers.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/undo_script_generator/_models.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/scripting/undo_script_generator/_reversers.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/sql/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/sql/execution_statement.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/sql/sql_analyzer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/sql/sql_execution_service.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/sql/statement_splitter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/state/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/state/migration_data_service.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/state/migration_display_state.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/state/migration_formatter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/state/migration_state.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/state/migration_state_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/state/migration_state_service.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/ui/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/ui/data_collector.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/ui/display_formatters.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/ui/migration_analyzer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/ui/migration_ui.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/ui/table_renderer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/migration/version_utils.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/normalization/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/normalization/dependency_resolver.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/normalization/identifier_normalizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/normalization/object_orderer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/normalization/type_constants.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/normalization/type_mapper.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/normalization/type_mappings.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/normalization/type_normalizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/capabilities.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/client_factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/event_listeners.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/introspection.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/license_info.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/runtime_checks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/sql_generators.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/seams/tier_resolver.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/alter/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/alter/base_alter_generator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/alter_generator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/base_generator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/basic_table_ddl_generator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/dependency_analyzer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/diff_converters/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/diff_converters/base_converter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/formatter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/generator_factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/options.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/script_organizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/sql_generator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/sql_statement.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_generator/table_ddl_render.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/_base_parse_result.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/_base_sql_column.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/_base_sql_constraint.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/_base_sql_object.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/_base_sql_statement.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/base.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/constraint_validator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/database_link.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/dialect.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/event.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/extension.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/feature_gates.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/foreign_data_wrapper.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/foreign_server.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/index.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/linked_server.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/module.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/package.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/partition.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/procedure.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/sequence.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/server_info.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/synonym.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/table.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/table_canonicalizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/table_options.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/trigger.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/user_defined_type.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/view.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_model/view_options.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/_partition_handler.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/_sqlglot_builders.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/base_statement_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/base_tokenizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/common/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/common/base_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/dialects/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/dialects/base_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/enhanced_regex_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/hybrid_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/parser_context.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/parser_factory.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/parser_interface.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/sqlglot_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/tokens.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_parser/unified_regex_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_validator/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_validator/_checksum_validator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_validator/_flyway_compatibility.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_validator/_migration_filter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_validator/_sql_syntax_validator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_validator/_strict_mode_validator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/sql_validator/migration_validator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/state/sql_script_formatter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/state/sql_statement.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/utils/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/utils/database_url_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/utils/metadata_helpers.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/utils/row_access.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/utils/string_utils.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/core/utils/url_masking.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/base_provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/constants.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/dml_analysis.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/error.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/error_handler.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/exceptions.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/feature_gate.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/native_connection_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/object_naming.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/_pg_compatible.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/alloydb/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/alloydb/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/aurora_postgresql/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/aurora_postgresql/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/base_history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/base_locking_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/base_query_executor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/base_schema_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/base_snapshot_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/base_undo_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/citus/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/citus/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cockroachdb/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cockroachdb/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cockroachdb/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cockroachdb/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/cosmosdb/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/cosmosdb/_sdk.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/cosmosdb/connection_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/cosmosdb/history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/cosmosdb/locking_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/cosmosdb/schema_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/introspection/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/cosmosdb/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/db2/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/db2/history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/db2/locking_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/db2/schema_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/introspection/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/parser/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/parser/db2_regex_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/parser/parser_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/db2/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/parser/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/parser/duckdb_regex_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/parser/parser_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/duckdb/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mariadb/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mariadb/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mariadb/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mariadb/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/introspection/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/mysql/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/mysql/history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/mysql/locking_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/mysql/schema_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/parser/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/parser/mysql_regex_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/parser/mysql_statement_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/parser/mysql_tokenizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/parser/parser_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/mysql/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/neon/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/neon/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/nosql_base/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/nosql_base/history.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/nosql_base/introspection.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/nosql_base/locking.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/introspection/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/introspection/oracle_utils.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/oracle/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/oracle/dbms_output.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/oracle/history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/oracle/locking_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/oracle/schema_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/_comments.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/_object_extractor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/_plsql_block.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/_sqlplus.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/_statement_splitter.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/oracle_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/oracle_statement_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/oracle_tokenizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/parser_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/parser/sqlplus_context.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/oracle/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/_provider_query_executor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/introspection/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/parser/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/parser/parser_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/parser/postgresql_regex_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/parser/postgresql_statement_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/parser/postgresql_tokenizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/postgresql/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/postgresql/history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/postgresql/locking_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/postgresql/schema_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/postgresql/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/redshift/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/redshift/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/redshift/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/redshift/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/redshift/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/snowflake/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/snowflake/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/snowflake/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/snowflake/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/snowflake/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/snowflake/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/introspection/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/parser/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/parser/parser_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/parser/sqlite_regex_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/sqlite/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/sqlite/connection_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/sqlite/history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/sqlite/locking_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/sqlite/query_executor.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlite/sqlite/schema_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/introspection/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/parser/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/parser/parser_config.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/parser/sqlserver_regex_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/parser/sqlserver_statement_parser.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/parser/sqlserver_tokenizer.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/parser/tsql_batch_separator.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/quirks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/sqlalchemy_url.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/sqlserver/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/sqlserver/history_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/sqlserver/locking_manager.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/sqlserver/sqlserver/schema_operations.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/supabase/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/supabase/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/timescaledb/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/timescaledb/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/yugabytedb/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/plugins/yugabytedb/plugin.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/provider_capabilities.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/provider_interfaces.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/provider_registry.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/sqlalchemy_provider.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/db/value_utils.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/dblift.egg-info/SOURCES.txt +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/dblift.egg-info/dependency_links.txt +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/dblift.egg-info/entry_points.txt +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/dblift.egg-info/requires.txt +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/dblift.egg-info/top_level.txt +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/_client.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/_engine.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/apps.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/checks.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/management/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/management/commands/__init__.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/management/commands/dblift_info.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/management/commands/dblift_migrate.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/django/management/commands/dblift_validate.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/fastapi.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/flask.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/integrations/opentelemetry.py +0 -0
- {dblift-3.2.1 → dblift-3.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dblift
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: A database migration tool that supports multiple databases with native Python drivers
|
|
5
5
|
Classifier: Development Status :: 5 - Production/Stable
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -16,7 +16,7 @@ The two helpers take the introspector instance as their first parameter
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
18
|
import traceback
|
|
19
|
-
from typing import TYPE_CHECKING, List
|
|
19
|
+
from typing import TYPE_CHECKING, Any, List
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
22
|
from core.introspection.schema_introspector import SchemaIntrospector
|
|
@@ -253,18 +253,101 @@ def enrich_columns_with_identity(
|
|
|
253
253
|
),
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
# sql_variant columns (e.g. SQL Server's
|
|
257
|
+
# sys.identity_columns.seed_value/increment_value/last_value) can
|
|
258
|
+
# arrive via pymssql/FreeTDS as raw on-wire bytes rather than an int
|
|
259
|
+
# (e.g. the int 1 as b'\x01\x00\x00\x00'). Normalize those to a plain
|
|
260
|
+
# int here so every downstream consumer -- regardless of which
|
|
261
|
+
# dialect's driver quirks produced the raw value -- can rely on
|
|
262
|
+
# identity_seed/identity_increment/identity_last_value already being
|
|
263
|
+
# an int. Non-bytes values (str, int, None) pass through unchanged,
|
|
264
|
+
# exactly as before.
|
|
265
|
+
#
|
|
266
|
+
# Bytes are only decoded when their length matches a standard
|
|
267
|
+
# two's-complement integer width (1, 2, 4, or 8 bytes --
|
|
268
|
+
# tinyint/smallint/int/bigint). SQL Server also permits IDENTITY on
|
|
269
|
+
# decimal/numeric columns, whose sql_variant wire shape is a sign
|
|
270
|
+
# byte plus an *unsigned* magnitude -- not a plain two's-complement
|
|
271
|
+
# integer -- so decoding those the same way would silently produce a
|
|
272
|
+
# plausible-looking but wrong value. For any other byte length,
|
|
273
|
+
# refuse to guess and raise instead; the outer try/except around
|
|
274
|
+
# this whole enrichment pass logs a warning for it.
|
|
275
|
+
def _decode_sql_variant_int(column_name: str, field_name: str, value: Any) -> Any:
|
|
276
|
+
if not isinstance(value, bytes):
|
|
277
|
+
return value
|
|
278
|
+
if len(value) not in (1, 2, 4, 8):
|
|
279
|
+
raise ValueError(
|
|
280
|
+
f"Column {column_name!r}: {field_name} arrived as "
|
|
281
|
+
f"{len(value)} raw bytes, which is not a standard "
|
|
282
|
+
f"two's-complement integer width (1, 2, 4, or 8 bytes). "
|
|
283
|
+
f"This looks like a non-integer sql_variant encoding "
|
|
284
|
+
f"(e.g. decimal/numeric IDENTITY) that isn't supported yet."
|
|
285
|
+
)
|
|
286
|
+
return int.from_bytes(value, byteorder="little", signed=True)
|
|
287
|
+
|
|
256
288
|
# Enrich matching columns with detailed metadata
|
|
257
289
|
for column in columns:
|
|
258
290
|
identity_data = identity_map.get(column.name.upper())
|
|
259
291
|
if identity_data:
|
|
260
|
-
# Mark as identity (may already be marked from the column
|
|
292
|
+
# Mark as identity (may already be marked from the column
|
|
293
|
+
# query) for now -- the except block below reverts this if
|
|
294
|
+
# decoding seed OR increment fails, since a column whose real
|
|
295
|
+
# identity parameters we can't decode must not still claim
|
|
296
|
+
# is_identity (see that block for why). last_value is decoded
|
|
297
|
+
# separately below and its failure does NOT revert this: it
|
|
298
|
+
# has no downstream DDL consumer, so losing it carries none
|
|
299
|
+
# of the "silently wrong seed/increment" risk the reset here
|
|
300
|
+
# exists to guard against.
|
|
261
301
|
column.is_identity = True
|
|
262
|
-
#
|
|
263
|
-
column
|
|
264
|
-
column
|
|
265
|
-
#
|
|
266
|
-
|
|
267
|
-
|
|
302
|
+
# A decode failure (see _decode_sql_variant_int above) is
|
|
303
|
+
# isolated to THIS column, not the whole table: without this,
|
|
304
|
+
# one decimal/numeric-typed IDENTITY column sitting alongside
|
|
305
|
+
# ordinary int-typed ones would raise past this loop into the
|
|
306
|
+
# table-level except below, silently losing seed/increment/
|
|
307
|
+
# last_value for every column processed after it too -- a
|
|
308
|
+
# wider blast radius than the single bad column the raise is
|
|
309
|
+
# actually about.
|
|
310
|
+
try:
|
|
311
|
+
# Add detailed metadata
|
|
312
|
+
column.identity_seed = _decode_sql_variant_int(
|
|
313
|
+
column.name, "seed_value", identity_data["seed_value"]
|
|
314
|
+
)
|
|
315
|
+
column.identity_increment = _decode_sql_variant_int(
|
|
316
|
+
column.name, "increment_value", identity_data["increment_value"]
|
|
317
|
+
)
|
|
318
|
+
except ValueError as decode_error:
|
|
319
|
+
si.log.warning(
|
|
320
|
+
f"Could not decode identity metadata for column "
|
|
321
|
+
f"{column.name!r} in {schema}.{table}: {decode_error}"
|
|
322
|
+
)
|
|
323
|
+
# A decode failure means we cannot reliably tell "seed
|
|
324
|
+
# decoded fine, increment failed" apart from "failed
|
|
325
|
+
# immediately" -- either way, downstream DDL rendering
|
|
326
|
+
# must not mistake a leftover None for "never asked, use
|
|
327
|
+
# SQL Server's own default". Reset is_identity and the
|
|
328
|
+
# two fields render_identity_clause reads so the column
|
|
329
|
+
# falls out of identity handling entirely rather than
|
|
330
|
+
# rendering a guessed IDENTITY(1,1).
|
|
331
|
+
column.is_identity = False
|
|
332
|
+
column.identity_seed = None
|
|
333
|
+
column.identity_increment = None
|
|
334
|
+
else:
|
|
335
|
+
# seed/increment decoded fine -- only now attempt
|
|
336
|
+
# last_value, in its own try/except so that a
|
|
337
|
+
# last_value-only decode failure (e.g. a non-standard
|
|
338
|
+
# byte width) doesn't discard the good seed/increment we
|
|
339
|
+
# just stored. Note: last_value is not part of SQL Model,
|
|
340
|
+
# store as custom attribute if needed.
|
|
341
|
+
if identity_data["last_value"] is not None:
|
|
342
|
+
try:
|
|
343
|
+
column.identity_last_value = _decode_sql_variant_int( # type: ignore[attr-defined]
|
|
344
|
+
column.name, "last_value", identity_data["last_value"]
|
|
345
|
+
)
|
|
346
|
+
except ValueError as decode_error:
|
|
347
|
+
si.log.warning(
|
|
348
|
+
f"Could not decode identity metadata for column "
|
|
349
|
+
f"{column.name!r} in {schema}.{table}: {decode_error}"
|
|
350
|
+
)
|
|
268
351
|
|
|
269
352
|
if identity_map:
|
|
270
353
|
si.log.debug(
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Load ``dblift.features`` entry points (tier feature registration).
|
|
2
|
+
|
|
3
|
+
Each ``dblift.features`` entry point resolves to a no-arg callable that
|
|
4
|
+
performs registrations against the neutral seams
|
|
5
|
+
(:mod:`core.seams.runtime_checks`, :mod:`core.seams.tier_resolver`, ...).
|
|
6
|
+
OSS ships none; installed higher tiers register their runtime checks and
|
|
7
|
+
tier resolver here.
|
|
8
|
+
|
|
9
|
+
Loading is idempotent via a module-level once-flag: entry points do not
|
|
10
|
+
change at runtime, and both CLI startup and API-client construction invoke
|
|
11
|
+
:func:`load_feature_extensions`, so double-loading is expected and cheap. An
|
|
12
|
+
empty entry-point result latches immediately unless a known tier
|
|
13
|
+
distribution (``dblift-pro``/``dblift-enterprise``) is installed but its
|
|
14
|
+
entry point hasn't reached this process's metadata view yet, in which case
|
|
15
|
+
it is retried on a later call instead of latched.
|
|
16
|
+
|
|
17
|
+
``DBLIFT_DISABLE_CLI_EXTENSIONS=1`` skips feature loading entirely. This is
|
|
18
|
+
an accepted, explicit operator opt-out: with higher-tier packages installed
|
|
19
|
+
it also disables their registered runtime checks and tier resolution for
|
|
20
|
+
API usage in the same process.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import logging
|
|
26
|
+
import os
|
|
27
|
+
from collections.abc import Callable
|
|
28
|
+
from importlib.metadata import PackageNotFoundError, entry_points, version
|
|
29
|
+
from typing import Protocol
|
|
30
|
+
|
|
31
|
+
_log = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
FEATURE_ENTRY_POINT_GROUP = "dblift.features"
|
|
34
|
+
|
|
35
|
+
# Feature registrations load in tier order (pro before enterprise, unknown
|
|
36
|
+
# third parties in between, name as the tie-breaker) — the same ordering
|
|
37
|
+
# contract as cli/extensions.py's command-extension loaders.
|
|
38
|
+
_TIER_LOAD_ORDER = {"pro": 0, "enterprise": 2}
|
|
39
|
+
_DEFAULT_TIER_LOAD_ORDER = 1
|
|
40
|
+
|
|
41
|
+
_features_loaded = False
|
|
42
|
+
|
|
43
|
+
# Must be updated if a tier package's distribution name changes in the
|
|
44
|
+
# monorepo, or a new tier is added under a different name -- an unlisted
|
|
45
|
+
# distribution is indistinguishable here from "not installed", so
|
|
46
|
+
# _any_tier_distribution_installed silently reverts to the pre-fix
|
|
47
|
+
# never-retries behavior for it.
|
|
48
|
+
_KNOWN_TIER_DISTRIBUTIONS = ("dblift-pro", "dblift-enterprise")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _any_tier_distribution_installed() -> bool:
|
|
52
|
+
"""Whether a known paid-tier package is installed as a distribution.
|
|
53
|
+
|
|
54
|
+
Checked independently of whether its ``dblift.features`` entry point has
|
|
55
|
+
become visible yet in this process's ``importlib.metadata`` view -- this
|
|
56
|
+
is what distinguishes "no dblift.features entry point will ever exist"
|
|
57
|
+
(pure OSS, no tier package installed at all -- the ordinary case) from
|
|
58
|
+
"one exists but hasn't reached this process's view of the metadata yet"
|
|
59
|
+
(the documented race an empty ``entry_points()`` result alone can't
|
|
60
|
+
rule out).
|
|
61
|
+
"""
|
|
62
|
+
for name in _KNOWN_TIER_DISTRIBUTIONS:
|
|
63
|
+
try:
|
|
64
|
+
version(name)
|
|
65
|
+
except PackageNotFoundError:
|
|
66
|
+
continue
|
|
67
|
+
except Exception as exc: # a broken distribution must not break startup
|
|
68
|
+
_log.warning("Could not check whether %r is installed: %s", name, exc)
|
|
69
|
+
continue
|
|
70
|
+
return True
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class _FeatureEntryPoint(Protocol):
|
|
75
|
+
name: str
|
|
76
|
+
|
|
77
|
+
def load(self) -> Callable[[], object]:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def load_feature_extensions() -> None:
|
|
82
|
+
"""Load every ``dblift.features`` entry point (idempotent, best-effort)."""
|
|
83
|
+
global _features_loaded
|
|
84
|
+
if _features_loaded or os.environ.get("DBLIFT_DISABLE_CLI_EXTENSIONS") == "1":
|
|
85
|
+
return
|
|
86
|
+
discovered_by_name: dict[str, _FeatureEntryPoint] = {
|
|
87
|
+
entry_point.name: entry_point
|
|
88
|
+
for entry_point in entry_points(group=FEATURE_ENTRY_POINT_GROUP)
|
|
89
|
+
}
|
|
90
|
+
ordered = sorted(
|
|
91
|
+
discovered_by_name.values(),
|
|
92
|
+
key=lambda ep: (_TIER_LOAD_ORDER.get(ep.name, _DEFAULT_TIER_LOAD_ORDER), ep.name),
|
|
93
|
+
)
|
|
94
|
+
for entry_point in ordered:
|
|
95
|
+
try:
|
|
96
|
+
register = entry_point.load()
|
|
97
|
+
register()
|
|
98
|
+
except Exception as exc: # a bad plugin must not break startup
|
|
99
|
+
_log.warning("dblift.features '%s' failed to load: %s", entry_point.name, exc)
|
|
100
|
+
# Latch when something was actually found, OR when nothing was found but
|
|
101
|
+
# no tier package is installed at all -- an empty result is only the
|
|
102
|
+
# documented race (a paid package's dblift.features entry point not yet
|
|
103
|
+
# reaching this process's importlib.metadata view, needing a retry on a
|
|
104
|
+
# later call, exactly like the identical latch bug fixed in
|
|
105
|
+
# AlterGeneratorFactory._ensure_populated) when a tier distribution is
|
|
106
|
+
# actually installed. In pure OSS, with no tier package installed,
|
|
107
|
+
# OSS's own pyproject.toml declares the entry-points group empty, so an
|
|
108
|
+
# empty result is permanent and must latch immediately.
|
|
109
|
+
_features_loaded = bool(ordered) or not _any_tier_distribution_installed()
|
|
@@ -46,7 +46,8 @@ class AlterGeneratorFactory:
|
|
|
46
46
|
load_feature_extensions()
|
|
47
47
|
attach_registered_sql_generators()
|
|
48
48
|
ProviderRegistry.discover_plugins()
|
|
49
|
-
|
|
49
|
+
plugin_list = ProviderRegistry.list_plugins()
|
|
50
|
+
for plugin_info in plugin_list:
|
|
50
51
|
# Per-plugin fault isolation: a broken plugin must not
|
|
51
52
|
# prevent the others from registering. (PR #241 Bugbot.)
|
|
52
53
|
try:
|
|
@@ -62,7 +63,14 @@ class AlterGeneratorFactory:
|
|
|
62
63
|
plugin_info.name,
|
|
63
64
|
exc,
|
|
64
65
|
)
|
|
65
|
-
|
|
66
|
+
# Latch only when plugin discovery itself found something. An empty
|
|
67
|
+
# ``plugin_list`` is the documented race (entry points not yet wired
|
|
68
|
+
# up in this process) and must be retried on a later call. A
|
|
69
|
+
# non-empty ``plugin_list`` means discovery genuinely completed --
|
|
70
|
+
# even if every plugin's quirks raised or returned no ALTER
|
|
71
|
+
# generator class, that is a real, stable outcome and should latch
|
|
72
|
+
# rather than re-running full discovery on every subsequent call.
|
|
73
|
+
cls._populated = bool(plugin_list)
|
|
66
74
|
|
|
67
75
|
@classmethod
|
|
68
76
|
def create_generator(cls, dialect: str) -> BaseAlterGenerator:
|
|
@@ -435,9 +435,15 @@ class BaseQuirks:
|
|
|
435
435
|
#: Oracle requires ``FROM DUAL``.
|
|
436
436
|
connection_probe_sql: str = "SELECT 1"
|
|
437
437
|
#: ``SELECT … LIMIT N`` syntax is supported. PostgreSQL, MySQL and
|
|
438
|
-
#: SQLite accept ``LIMIT``; Oracle (``FETCH FIRST N ROWS ONLY``)
|
|
439
|
-
#:
|
|
440
|
-
#:
|
|
438
|
+
#: SQLite accept ``LIMIT``; Oracle (``FETCH FIRST N ROWS ONLY``) does
|
|
439
|
+
#: not; SQL Server uses ``TOP N`` instead. DB2's *preferred* rendering
|
|
440
|
+
#: is also ``FETCH FIRST N ROWS ONLY`` (see :attr:`row_limit_style`),
|
|
441
|
+
#: but DB2 additionally accepts a bare trailing ``LIMIT`` clause —
|
|
442
|
+
#: verified against a live db2 12.01.0500 server via the
|
|
443
|
+
#: capability-probe integration test
|
|
444
|
+
#: (``tests/integration/capabilities/test_engine_capabilities.py``) —
|
|
445
|
+
#: so it sets this True even though its declared ``row_limit_style``
|
|
446
|
+
#: is not ``"limit"``. When False, post-commit verification queries
|
|
441
447
|
#: and similar probes omit the ``LIMIT`` clause.
|
|
442
448
|
select_supports_limit: bool = True
|
|
443
449
|
#: How a SELECT is bounded to N rows. One of:
|
|
@@ -461,12 +467,16 @@ class BaseQuirks:
|
|
|
461
467
|
#: Read through :meth:`row_limit_clauses`, which renders the triple
|
|
462
468
|
#: rather than making each caller re-derive the syntax. Distinct from
|
|
463
469
|
#: :attr:`select_supports_limit`, which answers the coarser "may I
|
|
464
|
-
#: append ``LIMIT`` at all" question for optional probes —
|
|
465
|
-
#:
|
|
466
|
-
#: ``row_limit_style
|
|
467
|
-
#:
|
|
468
|
-
#:
|
|
469
|
-
#:
|
|
470
|
+
#: append ``LIMIT`` at all" question for optional probes — the two
|
|
471
|
+
#: usually correlate (SQL Server and Oracle, which set a non-default
|
|
472
|
+
#: ``row_limit_style``, also set ``select_supports_limit = False``,
|
|
473
|
+
#: since neither accepts a bare trailing ``LIMIT``) but they are NOT
|
|
474
|
+
#: guaranteed to: DB2 is a documented exception — it declares
|
|
475
|
+
#: ``row_limit_style = "fetch_first"`` as its preferred rendering yet
|
|
476
|
+
#: sets ``select_supports_limit = True`` because the live engine also
|
|
477
|
+
#: accepts a bare trailing ``LIMIT`` (verified via the capability-probe
|
|
478
|
+
#: integration test). Nothing in the framework enforces that the two
|
|
479
|
+
#: stay consistent, so a new dialect could set one without the other;
|
|
470
480
|
#: see the invariant test in ``tests/unit/db/test_dialect_capability_quirks.py``.
|
|
471
481
|
row_limit_style: str = "limit"
|
|
472
482
|
#: How an "insert or update on primary-key conflict" is expressed.
|
|
@@ -3,12 +3,15 @@ Cosmos DB query execution using the SQL API.
|
|
|
3
3
|
|
|
4
4
|
The Cosmos DB SQL API is a read-only query language: this module runs
|
|
5
5
|
``SELECT`` against containers. Everything that changes state — containers,
|
|
6
|
-
documents, throughput, indexing policy, TTL — is an Azure SDK call
|
|
7
|
-
|
|
6
|
+
documents, throughput, indexing policy, TTL — is an Azure SDK call, not SQL
|
|
7
|
+
routed through a translator. That SDK call is made either from a
|
|
8
|
+
user-authored Python migration (via ``context.db`` / ``context.raw_client``)
|
|
9
|
+
or, for internal callers that are not a migration, through a native escape
|
|
10
|
+
hatch exposed here (e.g. ``upsert_native_item``).
|
|
8
11
|
"""
|
|
9
12
|
|
|
10
13
|
import re
|
|
11
|
-
from typing import Any, Dict, List, Optional
|
|
14
|
+
from typing import Any, Dict, List, Optional, cast
|
|
12
15
|
|
|
13
16
|
from core.exceptions import NoSqlWriteNotSupportedError
|
|
14
17
|
from core.logger import Log, NullLog
|
|
@@ -63,8 +66,11 @@ class CosmosDbQueryExecutor(BaseQueryExecutor):
|
|
|
63
66
|
The Cosmos DB SQL API reads; it does not write. Containers and
|
|
64
67
|
documents are changed through the Azure SDK, so a write statement
|
|
65
68
|
reaching here is a mistake to surface rather than something to
|
|
66
|
-
translate. Python migrations get to the SDK through
|
|
67
|
-
``context.db`` / ``context.raw_client
|
|
69
|
+
translate. User-authored Python migrations get to the SDK through
|
|
70
|
+
``context.db`` / ``context.raw_client``; internal, non-migration
|
|
71
|
+
callers that need to write a single document use
|
|
72
|
+
:meth:`upsert_native_item` instead of building SQL for this method
|
|
73
|
+
to reject.
|
|
68
74
|
|
|
69
75
|
Returns the number of rows a read produced (``0`` for the scalar
|
|
70
76
|
liveness probe).
|
|
@@ -168,6 +174,51 @@ class CosmosDbQueryExecutor(BaseQueryExecutor):
|
|
|
168
174
|
self.log.error(error_msg)
|
|
169
175
|
raise
|
|
170
176
|
|
|
177
|
+
def upsert_native_item(self, container_name: str, document: Dict[str, Any]) -> Dict[str, Any]:
|
|
178
|
+
"""Upsert a document directly through the Azure SDK, bypassing SQL.
|
|
179
|
+
|
|
180
|
+
``execute_statement`` only accepts ``SELECT`` — the Cosmos DB SQL API
|
|
181
|
+
is read-only, and pretending otherwise (the pseudo-SQL emulator this
|
|
182
|
+
module used to have) was actively wrong, which is why the ADR
|
|
183
|
+
removing pseudo-SQL deleted it. Container *creation* was ported to a
|
|
184
|
+
native SDK call at the time (see
|
|
185
|
+
``CosmosDbProvider.create_snapshot_table_if_not_exists``, which calls
|
|
186
|
+
``CosmosDbSchemaOperations.create_container_if_not_exists`` instead of
|
|
187
|
+
rendering ``CREATE TABLE``), but the matching write for a single
|
|
188
|
+
document was missed: an internal caller such as the schema-snapshot
|
|
189
|
+
repository still built a plain SQL ``INSERT`` and routed it through
|
|
190
|
+
``execute_statement``, which now raises
|
|
191
|
+
``NoSqlWriteNotSupportedError`` for anything but a ``SELECT``. That
|
|
192
|
+
exception is swallowed by a best-effort event listener, so
|
|
193
|
+
``migrate`` reports success while the snapshot document silently
|
|
194
|
+
never lands.
|
|
195
|
+
|
|
196
|
+
This method provides the native, non-SQL escape hatch a caller needs
|
|
197
|
+
to close that gap: it calls ``azure.cosmos.ContainerProxy.upsert_item``
|
|
198
|
+
directly instead of rendering anything this executor — or its
|
|
199
|
+
SELECT-only ``execute_statement`` — would have to parse as SQL. It is
|
|
200
|
+
meant for internal dblift callers that hold a provider/query-executor
|
|
201
|
+
reference and are not a user-authored migration; migrations already
|
|
202
|
+
reach the SDK through ``context.db`` / ``context.raw_client`` (see
|
|
203
|
+
``execute_statement``'s docstring). This change adds the primitive
|
|
204
|
+
only — the schema-snapshot repository still needs to be updated, in
|
|
205
|
+
the sibling monorepo where it lives, to call this instead of
|
|
206
|
+
building an ``INSERT``; until that happens the gap above is not yet
|
|
207
|
+
closed end-to-end.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
container_name: Name of the Cosmos DB container to upsert into.
|
|
211
|
+
document: The full document body to upsert. Must include
|
|
212
|
+
whatever field the container's partition key path points at.
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
The document as returned by the SDK (typically the input body
|
|
216
|
+
plus Cosmos-assigned system properties such as ``_etag``,
|
|
217
|
+
``_ts``, ``_self``).
|
|
218
|
+
"""
|
|
219
|
+
container_client = self.connection_manager.get_container_client(container_name)
|
|
220
|
+
return cast(Dict[str, Any], container_client.upsert_item(body=document))
|
|
221
|
+
|
|
171
222
|
def _normalize_cosmos_sql(self, sql: str, container_name: str) -> str:
|
|
172
223
|
"""Normalize Cosmos DB SQL query to use proper container alias.
|
|
173
224
|
|
|
@@ -75,6 +75,28 @@ class CosmosDbProvider(NativeProvider):
|
|
|
75
75
|
connection = self._get_connection_or_raise()
|
|
76
76
|
return self.query_executor.execute_query(connection, sql, params)
|
|
77
77
|
|
|
78
|
+
def upsert_native_item(self, container_name: str, document: Dict[str, Any]) -> Dict[str, Any]:
|
|
79
|
+
"""Upsert a document straight through the Azure SDK, bypassing SQL.
|
|
80
|
+
|
|
81
|
+
Thin forward to :meth:`CosmosDbQueryExecutor.upsert_native_item` —
|
|
82
|
+
the same shape as :meth:`execute_statement` and :meth:`execute_query`
|
|
83
|
+
above, which forward to the query executor's SQL-shaped methods. This
|
|
84
|
+
one exists for callers (e.g. the schema-snapshot repository) that
|
|
85
|
+
need to write a single document and hold a provider reference rather
|
|
86
|
+
than a query-executor one; see
|
|
87
|
+
:meth:`CosmosDbQueryExecutor.upsert_native_item` for why a native
|
|
88
|
+
write path exists instead of routing an ``INSERT`` through
|
|
89
|
+
``execute_statement``.
|
|
90
|
+
|
|
91
|
+
No connection guard here (unlike ``execute_statement`` /
|
|
92
|
+
``execute_query``): the query executor reaches the container through
|
|
93
|
+
``connection_manager.get_container_client`` rather than the
|
|
94
|
+
``connection`` object, the same reason
|
|
95
|
+
``create_snapshot_table_if_not_exists`` below calls into
|
|
96
|
+
``schema_operations`` directly without fetching one.
|
|
97
|
+
"""
|
|
98
|
+
return self.query_executor.upsert_native_item(container_name, document)
|
|
99
|
+
|
|
78
100
|
def create_schema_if_not_exists(self, schema: str) -> None:
|
|
79
101
|
"""Create schema if it doesn't exist (Cosmos DB doesn't have schemas)."""
|
|
80
102
|
connection = self._get_connection_or_raise()
|
|
@@ -72,8 +72,10 @@ class Db2Quirks(BaseQuirks):
|
|
|
72
72
|
return self.is_data_history_table_already_exists_error(error_message)
|
|
73
73
|
|
|
74
74
|
connection_probe_sql = "SELECT 1 FROM SYSIBM.SYSDUMMY1"
|
|
75
|
-
select_supports_limit =
|
|
76
|
-
#
|
|
75
|
+
select_supports_limit = True
|
|
76
|
+
# Canonical rendering is trailing ``FETCH FIRST n ROWS ONLY``, but DB2
|
|
77
|
+
# also accepts a bare trailing ``LIMIT n`` (verified against a live
|
|
78
|
+
# db2 12.01.0500 server via the capability-probe integration test).
|
|
77
79
|
row_limit_style = "fetch_first"
|
|
78
80
|
unquoted_identifier_case = "uppercase"
|
|
79
81
|
connection_identifier_attrs = ("url", "host", "database")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dblift
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: A database migration tool that supports multiple databases with native Python drivers
|
|
5
5
|
Classifier: Development Status :: 5 - Production/Stable
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dblift"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.3.0"
|
|
8
8
|
description = "A database migration tool that supports multiple databases with native Python drivers"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
"""Load ``dblift.features`` entry points (tier feature registration).
|
|
2
|
-
|
|
3
|
-
Each ``dblift.features`` entry point resolves to a no-arg callable that
|
|
4
|
-
performs registrations against the neutral seams
|
|
5
|
-
(:mod:`core.seams.runtime_checks`, :mod:`core.seams.tier_resolver`, ...).
|
|
6
|
-
OSS ships none; installed higher tiers register their runtime checks and
|
|
7
|
-
tier resolver here.
|
|
8
|
-
|
|
9
|
-
Loading is idempotent via a module-level once-flag: entry points do not
|
|
10
|
-
change at runtime, and both CLI startup and API-client construction invoke
|
|
11
|
-
:func:`load_feature_extensions`, so double-loading is expected and cheap.
|
|
12
|
-
|
|
13
|
-
``DBLIFT_DISABLE_CLI_EXTENSIONS=1`` skips feature loading entirely. This is
|
|
14
|
-
an accepted, explicit operator opt-out: with higher-tier packages installed
|
|
15
|
-
it also disables their registered runtime checks and tier resolution for
|
|
16
|
-
API usage in the same process.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from __future__ import annotations
|
|
20
|
-
|
|
21
|
-
import logging
|
|
22
|
-
import os
|
|
23
|
-
from collections.abc import Callable
|
|
24
|
-
from importlib.metadata import entry_points
|
|
25
|
-
from typing import Protocol
|
|
26
|
-
|
|
27
|
-
_log = logging.getLogger(__name__)
|
|
28
|
-
|
|
29
|
-
FEATURE_ENTRY_POINT_GROUP = "dblift.features"
|
|
30
|
-
|
|
31
|
-
# Feature registrations load in tier order (pro before enterprise, unknown
|
|
32
|
-
# third parties in between, name as the tie-breaker) — the same ordering
|
|
33
|
-
# contract as cli/extensions.py's command-extension loaders.
|
|
34
|
-
_TIER_LOAD_ORDER = {"pro": 0, "enterprise": 2}
|
|
35
|
-
_DEFAULT_TIER_LOAD_ORDER = 1
|
|
36
|
-
|
|
37
|
-
_features_loaded = False
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class _FeatureEntryPoint(Protocol):
|
|
41
|
-
name: str
|
|
42
|
-
|
|
43
|
-
def load(self) -> Callable[[], object]:
|
|
44
|
-
pass
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def load_feature_extensions() -> None:
|
|
48
|
-
"""Load every ``dblift.features`` entry point (idempotent, best-effort)."""
|
|
49
|
-
global _features_loaded
|
|
50
|
-
if _features_loaded or os.environ.get("DBLIFT_DISABLE_CLI_EXTENSIONS") == "1":
|
|
51
|
-
return
|
|
52
|
-
discovered_by_name: dict[str, _FeatureEntryPoint] = {
|
|
53
|
-
entry_point.name: entry_point
|
|
54
|
-
for entry_point in entry_points(group=FEATURE_ENTRY_POINT_GROUP)
|
|
55
|
-
}
|
|
56
|
-
ordered = sorted(
|
|
57
|
-
discovered_by_name.values(),
|
|
58
|
-
key=lambda ep: (_TIER_LOAD_ORDER.get(ep.name, _DEFAULT_TIER_LOAD_ORDER), ep.name),
|
|
59
|
-
)
|
|
60
|
-
for entry_point in ordered:
|
|
61
|
-
try:
|
|
62
|
-
register = entry_point.load()
|
|
63
|
-
register()
|
|
64
|
-
except Exception as exc: # a bad plugin must not break startup
|
|
65
|
-
_log.warning("dblift.features '%s' failed to load: %s", entry_point.name, exc)
|
|
66
|
-
_features_loaded = True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|