dblift 3.3.2__tar.gz → 3.3.4__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.3.2 → dblift-3.3.4}/PKG-INFO +3 -3
- {dblift-3.3.2 → dblift-3.3.4}/README.md +2 -2
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/_formatters.py +47 -38
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/jsonformatter.py +2 -34
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cockroachdb/__init__.py +8 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cockroachdb/plugin.py +5 -1
- dblift-3.3.4/db/plugins/cockroachdb/sqlalchemy_dialect.py +124 -0
- dblift-3.3.4/db/plugins/cockroachdb/sqlalchemy_url.py +93 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/provider.py +169 -1
- {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/PKG-INFO +3 -3
- {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/SOURCES.txt +2 -0
- {dblift-3.3.2 → dblift-3.3.4}/pyproject.toml +1 -1
- {dblift-3.3.2 → dblift-3.3.4}/LICENSE +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/_cli_support.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/_client_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/_client_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/_engine_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/async_client.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/client.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/events.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/migrations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/api/py.typed +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/_command_handlers.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/_config_helpers.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/_constants.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/_output.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/_parser_setup.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/commands/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/commands/config_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/db_utils.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/extensions.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/_shared.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/baseline.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/clean.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/import_flyway.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/info.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/migrate.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/repair.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/undo.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/handlers/validate.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/main.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/cli/premium_manifest.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/_credential_masking.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/_subclasses/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/_subclasses/dummy_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/_url_builder_mixin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/config_builder.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/database_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/dblift_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/errors.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/property_registry.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/secrets/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_cache.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_provider_base.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_registry.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_resolver.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/config/secrets/_secrets_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/constants.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/dialect_boundary.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/exceptions.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_column_enricher.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_partition_enricher.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_schema_orchestrator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_utils.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/_vendor_property_applier.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/base_introspector.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/base_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/column_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/constraint_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/index_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/misc_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/procedure_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/sequence_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/table_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/trigger_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/extractors/view_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/introspector_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/result.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/schema_introspector.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/vendor_queries_base.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/vendor_queries_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/vendor_queries_protocols.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/introspection/version_detector.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/_base.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/_levels.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/_multi.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/_null.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/console.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/_formatter_impl.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/formatter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/formatters/htmlformatter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/log.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/results.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/templates/oldreport.html +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/logger/templates/report.html +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/_type_match.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/clean_summary.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/_script_events.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/base_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/baseline_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/clean_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/import_flyway_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/info_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/migrate_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/repair_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/undo_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/commands/validate_command.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/encoding.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/execution_engine.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/migration_executor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/migration_helpers.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/placeholder_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executor/transaction_policy.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/base_executor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/executor_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/python_executor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/executors/sql_executor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/formats/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/formats/format_detector.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/formats/migration_format.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/history/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/history/migration_history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/journals/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/journals/migration_journal.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/migration.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/placeholders/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/placeholders/placeholder_service.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/rules/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/rules/migration_rules.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/migration_script_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_ddl_reversers.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_dml_reversers.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_extractors.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_generator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_helpers.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_models.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/scripting/undo_script_generator/_reversers.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/execution_statement.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/sql_analyzer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/sql_execution_service.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/sql/statement_splitter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_data_service.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_display_state.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_formatter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_state.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_state_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/state/migration_state_service.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/data_collector.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/display_formatters.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/migration_analyzer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/migration_ui.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/ui/table_renderer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/migration/version_utils.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/normalization/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/normalization/dependency_resolver.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/normalization/identifier_normalizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/normalization/object_orderer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/normalization/type_constants.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/normalization/type_mapper.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/normalization/type_mappings.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/normalization/type_normalizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/capabilities.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/client_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/event_listeners.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/feature_loading.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/introspection.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/license_info.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/runtime_checks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/sql_generators.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/seams/tier_resolver.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/alter/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/alter/alter_generator_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/alter/base_alter_generator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/alter_generator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/base_generator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/basic_table_ddl_generator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/dependency_analyzer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/diff_converters/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/diff_converters/base_converter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/formatter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/generator_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/options.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/script_organizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/sql_generator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/sql_statement.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_generator/table_ddl_render.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_parse_result.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_sql_column.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_sql_constraint.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_sql_object.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/_base_sql_statement.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/base.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/constraint_validator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/database_link.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/dialect.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/event.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/extension.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/feature_gates.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/foreign_data_wrapper.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/foreign_server.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/index.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/linked_server.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/module.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/package.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/partition.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/procedure.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/sequence.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/server_info.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/synonym.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/table.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/table_canonicalizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/table_options.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/trigger.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/user_defined_type.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/view.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_model/view_options.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/_partition_handler.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/_sqlglot_builders.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/base_statement_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/base_tokenizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/common/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/common/base_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/dialects/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/dialects/base_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/enhanced_regex_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/hybrid_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/parser_context.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/parser_factory.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/parser_interface.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/sqlglot_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/tokens.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_parser/unified_regex_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_checksum_validator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_flyway_compatibility.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_migration_filter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_sql_syntax_validator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/_strict_mode_validator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/sql_validator/migration_validator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/state/sql_script_formatter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/state/sql_statement.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/utils/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/utils/database_url_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/utils/metadata_helpers.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/utils/row_access.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/utils/string_utils.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/core/utils/url_masking.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/base_provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/base_quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/constants.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/dml_analysis.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/error.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/error_handler.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/exceptions.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/feature_gate.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/native_connection_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/object_naming.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/_pg_compatible.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/alloydb/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/alloydb/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/aurora_postgresql/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/aurora_postgresql/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_locking_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_query_executor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_schema_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_snapshot_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/base_undo_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/citus/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/citus/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cockroachdb/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cockroachdb/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/_sdk.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/connection_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/locking_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/query_executor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/cosmosdb/schema_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/introspection/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/cosmosdb/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/db2/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/db2/history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/db2/locking_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/db2/schema_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/introspection/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/parser/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/parser/db2_regex_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/parser/parser_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/db2/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/parser/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/parser/duckdb_regex_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/parser/parser_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/duckdb/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mariadb/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mariadb/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mariadb/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mariadb/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/introspection/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/mysql/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/mysql/history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/mysql/locking_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/mysql/schema_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/mysql_regex_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/mysql_statement_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/mysql_tokenizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/parser/parser_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/mysql/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/neon/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/neon/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/nosql_base/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/nosql_base/history.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/nosql_base/introspection.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/nosql_base/locking.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/introspection/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/introspection/oracle_utils.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/dbms_output.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/locking_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/oracle/schema_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_comments.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_object_extractor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_plsql_block.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_sqlplus.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/_statement_splitter.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/oracle_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/oracle_statement_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/oracle_tokenizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/parser_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/parser/sqlplus_context.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/oracle/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/_provider_query_executor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/introspection/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/parser_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/postgresql_regex_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/postgresql_statement_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/parser/postgresql_tokenizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/postgresql/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/postgresql/history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/postgresql/locking_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/postgresql/schema_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/postgresql/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/redshift/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/snowflake/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/introspection/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/parser/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/parser/parser_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/parser/sqlite_regex_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/connection_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/locking_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/query_executor.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlite/sqlite/schema_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/introspection/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/parser_config.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/sqlserver_regex_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/sqlserver_statement_parser.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/sqlserver_tokenizer.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/parser/tsql_batch_separator.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/quirks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlalchemy_url.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlserver/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlserver/history_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlserver/locking_manager.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/sqlserver/sqlserver/schema_operations.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/supabase/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/supabase/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/timescaledb/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/timescaledb/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/yugabytedb/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/plugins/yugabytedb/plugin.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/provider_capabilities.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/provider_interfaces.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/provider_registry.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/sqlalchemy_provider.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/db/value_utils.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/dependency_links.txt +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/entry_points.txt +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/requires.txt +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/dblift.egg-info/top_level.txt +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/_client.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/_engine.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/apps.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/checks.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/commands/__init__.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/commands/dblift_info.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/commands/dblift_migrate.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/django/management/commands/dblift_validate.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/fastapi.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/flask.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/integrations/opentelemetry.py +0 -0
- {dblift-3.3.2 → dblift-3.3.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dblift
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.4
|
|
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
|
|
@@ -115,8 +115,8 @@ Dynamic: license-file
|
|
|
115
115
|
|
|
116
116
|

|
|
117
117
|

|
|
118
|
-
[](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml)
|
|
119
|
+
[](https://codecov.io/gh/dblift/dblift)
|
|
120
120
|
[](SECURITY.md)
|
|
121
121
|
|
|
122
122
|
Application code usually has tests, CI pipelines, and pull request review. Database changes often skip one or more of those stages. DBLift is a Python-native migration toolkit that shows you exactly what SQL will run before it runs — and keeps the full migration lifecycle inside your Python workflow. No JVM required.
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|

|
|
9
|
-
[](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml)
|
|
10
|
+
[](https://codecov.io/gh/dblift/dblift)
|
|
11
11
|
[](SECURITY.md)
|
|
12
12
|
|
|
13
13
|
Application code usually has tests, CI pipelines, and pull request review. Database changes often skip one or more of those stages. DBLift is a Python-native migration toolkit that shows you exactly what SQL will run before it runs — and keeps the full migration lifecycle inside your Python workflow. No JVM required.
|
|
@@ -6,6 +6,7 @@ from ``core.logger.log`` for back-compat. JSON / HTML formatters live in
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import logging
|
|
9
|
+
import sys
|
|
9
10
|
from datetime import datetime
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any, Dict, Optional
|
|
@@ -15,6 +16,51 @@ from core.logger._levels import LogEvent, LogLevel
|
|
|
15
16
|
_logger = logging.getLogger(__name__)
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
def resolve_dblift_package_version() -> Optional[str]:
|
|
20
|
+
"""Return the installed ``dblift`` distribution version for log banners.
|
|
21
|
+
|
|
22
|
+
Prefer ``importlib.metadata`` (correct for wheels and frozen binaries).
|
|
23
|
+
Avoid walking the filesystem first: under PyInstaller ``Path(__file__)``
|
|
24
|
+
can resolve to a unrelated ``__init__.py`` and print a stale version.
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
28
|
+
except ImportError: # pragma: no cover - Python <3.8
|
|
29
|
+
from importlib_metadata import PackageNotFoundError, version # type: ignore
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
return version("dblift")
|
|
33
|
+
except PackageNotFoundError:
|
|
34
|
+
pass
|
|
35
|
+
except Exception as e:
|
|
36
|
+
_logger.debug(f"Could not get dblift version from importlib.metadata: {e}")
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
import dblift # type: ignore[import-untyped]
|
|
40
|
+
|
|
41
|
+
ver = getattr(dblift, "__version__", None)
|
|
42
|
+
if ver:
|
|
43
|
+
return str(ver)
|
|
44
|
+
except (ImportError, AttributeError):
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
# Dev checkouts only (skip when frozen — MEIPASS layout is not a git tree)
|
|
48
|
+
if not getattr(sys, "frozen", False):
|
|
49
|
+
try:
|
|
50
|
+
init_file = Path(__file__).parent.parent.parent / "__init__.py"
|
|
51
|
+
if init_file.exists():
|
|
52
|
+
with open(init_file, "r", encoding="utf-8") as f:
|
|
53
|
+
for line in f:
|
|
54
|
+
if line.startswith("__version__"):
|
|
55
|
+
parts = line.split("=", 1)
|
|
56
|
+
if len(parts) == 2:
|
|
57
|
+
return parts[1].strip().strip('"').strip("'")
|
|
58
|
+
except Exception as e:
|
|
59
|
+
_logger.debug(f"Could not read version from __init__.py: {e}")
|
|
60
|
+
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
|
|
18
64
|
class LogFormatter:
|
|
19
65
|
"""Base class for all log formatters."""
|
|
20
66
|
|
|
@@ -74,44 +120,7 @@ class TextFormatter(LogFormatter):
|
|
|
74
120
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
75
121
|
lines.append(f"Timestamp: {current_time}")
|
|
76
122
|
|
|
77
|
-
|
|
78
|
-
# Try multiple methods to get the version, prioritizing source code
|
|
79
|
-
version = None
|
|
80
|
-
|
|
81
|
-
# Method 1: Try to read from source __init__.py file (most reliable for development)
|
|
82
|
-
try:
|
|
83
|
-
# Path from core/logger/_formatters.py to root __init__.py: up 3 levels
|
|
84
|
-
init_file = Path(__file__).parent.parent.parent / "__init__.py"
|
|
85
|
-
if init_file.exists():
|
|
86
|
-
with open(init_file, "r", encoding="utf-8") as f:
|
|
87
|
-
for line in f:
|
|
88
|
-
if line.startswith("__version__"):
|
|
89
|
-
# Extract version from: __version__ = "x.y.z"
|
|
90
|
-
parts = line.split("=", 1)
|
|
91
|
-
if len(parts) == 2:
|
|
92
|
-
version = parts[1].strip().strip('"').strip("'")
|
|
93
|
-
break
|
|
94
|
-
except Exception as e:
|
|
95
|
-
_logger.debug(f"Could not read version from __init__.py: {e}")
|
|
96
|
-
|
|
97
|
-
# Method 2: Try to import directly from package (if source is in path)
|
|
98
|
-
if not version:
|
|
99
|
-
try:
|
|
100
|
-
import dblift # type: ignore[import-untyped]
|
|
101
|
-
|
|
102
|
-
version = getattr(dblift, "__version__", None)
|
|
103
|
-
except (ImportError, AttributeError):
|
|
104
|
-
pass
|
|
105
|
-
|
|
106
|
-
# Method 3: Fallback to pkg_resources (for installed packages)
|
|
107
|
-
if not version:
|
|
108
|
-
try:
|
|
109
|
-
import pkg_resources # type: ignore[import-untyped]
|
|
110
|
-
|
|
111
|
-
version = pkg_resources.get_distribution("dblift").version
|
|
112
|
-
except Exception as e:
|
|
113
|
-
_logger.debug(f"Could not get version from pkg_resources: {e}")
|
|
114
|
-
|
|
123
|
+
version = resolve_dblift_package_version()
|
|
115
124
|
if version:
|
|
116
125
|
lines.append(f"Dblift version: {version}")
|
|
117
126
|
|
|
@@ -128,43 +128,11 @@ class JsonFormatter:
|
|
|
128
128
|
|
|
129
129
|
def _get_version_info(self) -> Dict[str, Any]:
|
|
130
130
|
"""Return a dict with log_format_version and dblift_version."""
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
# Method 1: Try to read from source __init__.py file (most reliable for development)
|
|
134
|
-
try:
|
|
135
|
-
init_file = Path(__file__).parent.parent.parent.parent / "__init__.py"
|
|
136
|
-
if init_file.exists():
|
|
137
|
-
with open(init_file, "r", encoding="utf-8") as f:
|
|
138
|
-
for line in f:
|
|
139
|
-
if line.startswith("__version__"):
|
|
140
|
-
parts = line.split("=", 1)
|
|
141
|
-
if len(parts) == 2:
|
|
142
|
-
dblift_version = parts[1].strip().strip('"').strip("'")
|
|
143
|
-
break
|
|
144
|
-
except Exception as e:
|
|
145
|
-
_logger.debug(f"Could not read version from __init__.py: {e}")
|
|
146
|
-
|
|
147
|
-
# Method 2: Try to import directly from package (if source is in path)
|
|
148
|
-
if not dblift_version:
|
|
149
|
-
try:
|
|
150
|
-
import dblift # type: ignore[import-untyped]
|
|
151
|
-
|
|
152
|
-
dblift_version = getattr(dblift, "__version__", None)
|
|
153
|
-
except (ImportError, AttributeError):
|
|
154
|
-
pass
|
|
155
|
-
|
|
156
|
-
# Method 3: Fallback to pkg_resources (for installed packages)
|
|
157
|
-
if not dblift_version:
|
|
158
|
-
try:
|
|
159
|
-
import pkg_resources # type: ignore[import-untyped]
|
|
160
|
-
|
|
161
|
-
dblift_version = pkg_resources.get_distribution("dblift").version
|
|
162
|
-
except Exception as e:
|
|
163
|
-
_logger.debug(f"Could not get version from pkg_resources: {e}")
|
|
131
|
+
from core.logger._formatters import resolve_dblift_package_version
|
|
164
132
|
|
|
165
133
|
return {
|
|
166
134
|
"log_format_version": "1.0",
|
|
167
|
-
"dblift_version":
|
|
135
|
+
"dblift_version": resolve_dblift_package_version(),
|
|
168
136
|
}
|
|
169
137
|
|
|
170
138
|
def _build_time_metadata(self, result: OperationResult) -> Dict[str, Any]:
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
"""CockroachDB database provider plugin (PostgreSQL-compatible)."""
|
|
2
2
|
|
|
3
|
+
# Side-effect import: register the SQLAlchemy dialect so create_engine can
|
|
4
|
+
# resolve cockroachdb+psycopg even if plugin.py was not loaded yet.
|
|
5
|
+
from db.plugins.cockroachdb.sqlalchemy_dialect import ( # noqa: F401
|
|
6
|
+
register_cockroach_dialect,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
register_cockroach_dialect()
|
|
10
|
+
|
|
3
11
|
__plugin_name__ = "cockroachdb"
|
|
4
12
|
__plugin_version__ = "1.0.0"
|
|
5
13
|
__plugin_description__ = "CockroachDB database provider"
|
|
@@ -11,9 +11,13 @@ from __future__ import annotations
|
|
|
11
11
|
|
|
12
12
|
from db.plugins.cockroachdb.provider import CockroachdbProvider
|
|
13
13
|
from db.plugins.cockroachdb.quirks import CockroachdbQuirks
|
|
14
|
-
from db.plugins.
|
|
14
|
+
from db.plugins.cockroachdb.sqlalchemy_dialect import register_cockroach_dialect
|
|
15
|
+
from db.plugins.cockroachdb.sqlalchemy_url import build_sqlalchemy_url
|
|
15
16
|
from db.provider_registry import PluginInfo
|
|
16
17
|
|
|
18
|
+
# Register before any create_engine call can race plugin discovery.
|
|
19
|
+
register_cockroach_dialect()
|
|
20
|
+
|
|
17
21
|
PLUGIN: PluginInfo = PluginInfo(
|
|
18
22
|
name="cockroachdb",
|
|
19
23
|
version="1.0.0",
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""SQLAlchemy dialect for CockroachDB (PostgreSQL wire, CRDB version banner).
|
|
2
|
+
|
|
3
|
+
SQLAlchemy's stock PostgreSQL dialect requires a ``PostgreSQL X.Y`` (or
|
|
4
|
+
``EnterpriseDB``) prefix from ``select version()``. CockroachDB returns banners
|
|
5
|
+
like::
|
|
6
|
+
|
|
7
|
+
CockroachDB CCL v24.3.18 (x86_64-pc-linux-gnu, built 2025/08/07 22:44:01, go1.22.8 ...)
|
|
8
|
+
|
|
9
|
+
which raise ``AssertionError: Could not determine version from string`` on every
|
|
10
|
+
``create_engine`` connect. This dialect reuses the psycopg PostgreSQL dialect
|
|
11
|
+
and only overrides server-version parsing so the product version ``vX.Y.Z`` is
|
|
12
|
+
used — never the trailing ``go1.x.y`` fragment.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import re
|
|
18
|
+
from typing import Any, Optional, Tuple
|
|
19
|
+
|
|
20
|
+
from sqlalchemy.dialects.postgresql.psycopg import PGDialect_psycopg
|
|
21
|
+
|
|
22
|
+
# Prefer an explicit product "vMAJOR.MINOR[.PATCH]" token (CRDB's usual form).
|
|
23
|
+
_CRDB_V_TOKEN = re.compile(r"\bv(\d+)\.(\d+)(?:\.(\d+))?\b", re.IGNORECASE)
|
|
24
|
+
# Fallback when the banner omits the leading ``v`` (older strings).
|
|
25
|
+
_CRDB_DOTTED = re.compile(
|
|
26
|
+
r"CockroachDB(?:\s+CCL)?\s+(\d+)\.(\d+)(?:\.(\d+))?",
|
|
27
|
+
re.IGNORECASE,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
_registered = False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def parse_cockroach_server_version(banner: str) -> Tuple[int, ...]:
|
|
34
|
+
"""Return ``(major, minor[, patch])`` from a CockroachDB ``version()`` banner.
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
AssertionError: when no product version can be extracted (same shape as
|
|
38
|
+
SQLAlchemy's PostgreSQL dialect failure).
|
|
39
|
+
"""
|
|
40
|
+
text = banner or ""
|
|
41
|
+
match = _CRDB_V_TOKEN.search(text)
|
|
42
|
+
if match is None:
|
|
43
|
+
match = _CRDB_DOTTED.search(text)
|
|
44
|
+
if match is None:
|
|
45
|
+
raise AssertionError(f"Could not determine version from string '{banner}'")
|
|
46
|
+
major = int(match.group(1))
|
|
47
|
+
minor = int(match.group(2))
|
|
48
|
+
patch = match.group(3)
|
|
49
|
+
if patch is not None:
|
|
50
|
+
return (major, minor, int(patch))
|
|
51
|
+
return (major, minor)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class CockroachDBDialect_psycopg(PGDialect_psycopg):
|
|
55
|
+
"""PostgreSQL+psycopg dialect that accepts CockroachDB version banners."""
|
|
56
|
+
|
|
57
|
+
name = "cockroachdb"
|
|
58
|
+
driver = "psycopg"
|
|
59
|
+
# Inherit PG caching semantics; SQLAlchemy warns if a subclass omits this.
|
|
60
|
+
supports_statement_cache = True
|
|
61
|
+
|
|
62
|
+
def _get_server_version_info(self, connection: Any) -> Tuple[int, ...]:
|
|
63
|
+
raw = connection.exec_driver_sql("select version()").scalar()
|
|
64
|
+
return parse_cockroach_server_version(str(raw) if raw is not None else "")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def register_cockroach_dialect() -> None:
|
|
68
|
+
"""Register ``cockroachdb`` / ``cockroachdb.psycopg`` with SQLAlchemy once."""
|
|
69
|
+
global _registered
|
|
70
|
+
if _registered:
|
|
71
|
+
return
|
|
72
|
+
from sqlalchemy.dialects import registry
|
|
73
|
+
|
|
74
|
+
registry.register(
|
|
75
|
+
"cockroachdb",
|
|
76
|
+
"db.plugins.cockroachdb.sqlalchemy_dialect",
|
|
77
|
+
"CockroachDBDialect_psycopg",
|
|
78
|
+
)
|
|
79
|
+
registry.register(
|
|
80
|
+
"cockroachdb.psycopg",
|
|
81
|
+
"db.plugins.cockroachdb.sqlalchemy_dialect",
|
|
82
|
+
"CockroachDBDialect_psycopg",
|
|
83
|
+
)
|
|
84
|
+
_registered = True
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def ensure_cockroach_drivername(drivername: str) -> str:
|
|
88
|
+
"""Map a PostgreSQL-family drivername onto ``cockroachdb+psycopg``.
|
|
89
|
+
|
|
90
|
+
Only the ``psycopg`` DBAPI is registered for CockroachDB. Bare
|
|
91
|
+
``postgresql`` / ``postgres`` / ``cockroachdb`` names and ``+psycopg``
|
|
92
|
+
variants rewrite cleanly; any other driver suffix (e.g. ``asyncpg``)
|
|
93
|
+
raises so ``create_engine`` does not fail later with an unloadable dialect.
|
|
94
|
+
"""
|
|
95
|
+
if drivername in (
|
|
96
|
+
"cockroachdb",
|
|
97
|
+
"cockroachdb+psycopg",
|
|
98
|
+
"postgresql",
|
|
99
|
+
"postgres",
|
|
100
|
+
"postgresql+psycopg",
|
|
101
|
+
"postgres+psycopg",
|
|
102
|
+
):
|
|
103
|
+
return "cockroachdb+psycopg"
|
|
104
|
+
if drivername.startswith(("postgresql+", "postgres+", "cockroachdb+")):
|
|
105
|
+
suffix = drivername.split("+", 1)[1]
|
|
106
|
+
if suffix != "psycopg":
|
|
107
|
+
raise ValueError(
|
|
108
|
+
"CockroachDB native connections require the psycopg driver "
|
|
109
|
+
f"(got {drivername!r}); use cockroachdb+psycopg or "
|
|
110
|
+
"postgresql+psycopg"
|
|
111
|
+
)
|
|
112
|
+
return "cockroachdb+psycopg"
|
|
113
|
+
raise ValueError(
|
|
114
|
+
"CockroachDB native connections require a PostgreSQL/CockroachDB "
|
|
115
|
+
f"SQLAlchemy URL (got drivername {drivername!r})"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
__all__ = [
|
|
120
|
+
"CockroachDBDialect_psycopg",
|
|
121
|
+
"ensure_cockroach_drivername",
|
|
122
|
+
"parse_cockroach_server_version",
|
|
123
|
+
"register_cockroach_dialect",
|
|
124
|
+
]
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""SQLAlchemy URL construction for CockroachDB.
|
|
2
|
+
|
|
3
|
+
Reuses the PostgreSQL URL shape (host/user/sslmode/search_path) but forces the
|
|
4
|
+
``cockroachdb+psycopg`` drivername so SQLAlchemy loads
|
|
5
|
+
:class:`CockroachDBDialect_psycopg` instead of the stock PostgreSQL dialect
|
|
6
|
+
that cannot parse CockroachDB ``version()`` banners.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Any, Dict
|
|
12
|
+
|
|
13
|
+
from sqlalchemy.engine import URL, make_url
|
|
14
|
+
|
|
15
|
+
from db.plugins.cockroachdb.sqlalchemy_dialect import (
|
|
16
|
+
ensure_cockroach_drivername,
|
|
17
|
+
register_cockroach_dialect,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _string_mapping(values: Any) -> Dict[str, str]:
|
|
22
|
+
if not isinstance(values, dict):
|
|
23
|
+
return {}
|
|
24
|
+
return {str(key): str(value) for key, value in values.items()}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _query_mapping(database_config: Any, base_query: Any = None) -> Dict[str, str]:
|
|
28
|
+
query = _string_mapping(base_query)
|
|
29
|
+
query.update(_string_mapping(getattr(database_config, "extra_params", None)))
|
|
30
|
+
query.update(_string_mapping(getattr(database_config, "options", None)))
|
|
31
|
+
|
|
32
|
+
connection_timeout = getattr(database_config, "connection_timeout", None)
|
|
33
|
+
if connection_timeout:
|
|
34
|
+
query["connect_timeout"] = str(connection_timeout)
|
|
35
|
+
|
|
36
|
+
ssl_mode = getattr(database_config, "ssl_mode", None)
|
|
37
|
+
if ssl_mode:
|
|
38
|
+
query["sslmode"] = str(ssl_mode)
|
|
39
|
+
|
|
40
|
+
schema = getattr(database_config, "schema", None)
|
|
41
|
+
if schema:
|
|
42
|
+
schema_option = f"-csearch_path={schema}"
|
|
43
|
+
query["options"] = (
|
|
44
|
+
f"{query['options']} {schema_option}" if query.get("options") else schema_option
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
return query
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def build_sqlalchemy_url(database_config: Any) -> str:
|
|
51
|
+
"""Build a CockroachDB SQLAlchemy URL (psycopg driver, CRDB dialect)."""
|
|
52
|
+
register_cockroach_dialect()
|
|
53
|
+
|
|
54
|
+
raw_url = getattr(database_config, "url", None)
|
|
55
|
+
if isinstance(raw_url, str) and raw_url:
|
|
56
|
+
# Same scheme gate as the PostgreSQL builder, plus cockroachdb:// so a
|
|
57
|
+
# pre-rewritten URL still validates. Other schemes raise immediately.
|
|
58
|
+
if not raw_url.startswith(
|
|
59
|
+
(
|
|
60
|
+
"postgresql://",
|
|
61
|
+
"postgresql+",
|
|
62
|
+
"postgres://",
|
|
63
|
+
"postgres+",
|
|
64
|
+
"cockroachdb://",
|
|
65
|
+
"cockroachdb+",
|
|
66
|
+
)
|
|
67
|
+
):
|
|
68
|
+
raise ValueError(
|
|
69
|
+
"CockroachDB native connections require a PostgreSQL/CockroachDB SQLAlchemy URL"
|
|
70
|
+
)
|
|
71
|
+
url = make_url(raw_url)
|
|
72
|
+
url = url.set(drivername=ensure_cockroach_drivername(url.drivername))
|
|
73
|
+
username = getattr(database_config, "username", None) or url.username or None
|
|
74
|
+
password = getattr(database_config, "password", None) or url.password or None
|
|
75
|
+
if username != url.username or password != url.password:
|
|
76
|
+
url = url.set(username=username, password=password)
|
|
77
|
+
query = _query_mapping(database_config, url.query)
|
|
78
|
+
if query != dict(url.query):
|
|
79
|
+
url = url.set(query=query)
|
|
80
|
+
return url.render_as_string(hide_password=False)
|
|
81
|
+
|
|
82
|
+
return URL.create(
|
|
83
|
+
"cockroachdb+psycopg",
|
|
84
|
+
username=getattr(database_config, "username", None) or None,
|
|
85
|
+
password=getattr(database_config, "password", None) or None,
|
|
86
|
+
host=getattr(database_config, "host", None) or "localhost",
|
|
87
|
+
port=getattr(database_config, "port", None),
|
|
88
|
+
database=getattr(database_config, "database", None),
|
|
89
|
+
query=_query_mapping(database_config),
|
|
90
|
+
).render_as_string(hide_password=False)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
__all__ = ["build_sqlalchemy_url"]
|
|
@@ -27,12 +27,180 @@ class DuckDBProvider(SqlAlchemyProvider):
|
|
|
27
27
|
def execute_statement(
|
|
28
28
|
self, sql: str, schema: Optional[str] = None, params: Optional[List[Any]] = None
|
|
29
29
|
) -> int:
|
|
30
|
-
"""Execute a SQL statement, optionally preparing the schema first.
|
|
30
|
+
"""Execute a SQL statement, optionally preparing the schema first.
|
|
31
|
+
|
|
32
|
+
DuckDB/SQLAlchemy often reports ``rowcount == -1`` for DML. For single
|
|
33
|
+
INSERT/UPDATE/DELETE statements without parameters, append
|
|
34
|
+
``RETURNING 1`` so callers (e.g. data corrections ``expect=N``) get a
|
|
35
|
+
real affected-row count.
|
|
36
|
+
"""
|
|
31
37
|
if schema:
|
|
32
38
|
self.create_schema_if_not_exists(schema)
|
|
33
39
|
self.set_current_schema(schema)
|
|
40
|
+
|
|
41
|
+
if params is None:
|
|
42
|
+
counted = self._try_dml_rowcount_via_returning(sql)
|
|
43
|
+
if counted is not None:
|
|
44
|
+
return counted
|
|
34
45
|
return super().execute_statement(sql, schema=schema, params=params)
|
|
35
46
|
|
|
47
|
+
def _try_dml_rowcount_via_returning(self, sql: str) -> Optional[int]:
|
|
48
|
+
"""Return affected-row count using RETURNING, or None if not applicable.
|
|
49
|
+
|
|
50
|
+
Returns None only when the statement is not rewritten (caller falls back
|
|
51
|
+
to the default path). Once execution is attempted, errors propagate —
|
|
52
|
+
do not re-run a failed statement via super() (that masks the root cause
|
|
53
|
+
as a follow-on \"transaction is aborted\" error).
|
|
54
|
+
"""
|
|
55
|
+
stripped = self._strip_sql_comments(sql.strip()).rstrip(";").strip()
|
|
56
|
+
if not stripped:
|
|
57
|
+
return None
|
|
58
|
+
# Already has a top-level RETURNING clause — do not double-append
|
|
59
|
+
if self._has_top_level_keyword(stripped, "RETURNING"):
|
|
60
|
+
return None
|
|
61
|
+
# Normalize whitespace for statement-type checks only
|
|
62
|
+
upper = " ".join(stripped.upper().split())
|
|
63
|
+
if not (
|
|
64
|
+
upper.startswith("INSERT ")
|
|
65
|
+
or upper.startswith("UPDATE ")
|
|
66
|
+
or upper.startswith("DELETE ")
|
|
67
|
+
):
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
# Multi-statement scripts: leave to super (no silent rewrite)
|
|
71
|
+
if self._has_top_level_semicolon(stripped):
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
rewritten = f"{stripped} RETURNING 1"
|
|
75
|
+
conn = self._ensure_connection()
|
|
76
|
+
driver_sql = self._escape_driver_percent_literals(rewritten, conn.dialect.paramstyle)
|
|
77
|
+
result = conn.exec_driver_sql(driver_sql)
|
|
78
|
+
rows = result.fetchall()
|
|
79
|
+
if self._tx is None and not getattr(self, "_external_connection", False):
|
|
80
|
+
conn.commit()
|
|
81
|
+
return len(rows)
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def _strip_sql_comments(sql: str) -> str:
|
|
85
|
+
"""Remove ``--`` / ``/* */`` comments (and blank lines).
|
|
86
|
+
|
|
87
|
+
Strips leading directives, full-line mid-statement comments, and
|
|
88
|
+
trailing *inline* ``--`` on DML lines so an appended ``RETURNING 1``
|
|
89
|
+
is not commented out and keyword detection is not confused by the
|
|
90
|
+
word ``returning`` inside comments.
|
|
91
|
+
"""
|
|
92
|
+
s = sql.lstrip()
|
|
93
|
+
# Leading block comments only (line comments handled per-line below)
|
|
94
|
+
while s.startswith("/*"):
|
|
95
|
+
end = s.find("*/")
|
|
96
|
+
if end < 0:
|
|
97
|
+
return ""
|
|
98
|
+
s = s[end + 2 :].lstrip()
|
|
99
|
+
|
|
100
|
+
kept: List[str] = []
|
|
101
|
+
for raw in s.splitlines():
|
|
102
|
+
line = DuckDBProvider._strip_inline_trailing_comment(raw)
|
|
103
|
+
if not line or line.lstrip().startswith("--"):
|
|
104
|
+
continue
|
|
105
|
+
# Drop leftover full-line block comments
|
|
106
|
+
if line.lstrip().startswith("/*") and line.rstrip().endswith("*/"):
|
|
107
|
+
continue
|
|
108
|
+
kept.append(line)
|
|
109
|
+
return "\n".join(kept).strip()
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def _strip_inline_trailing_comment(line: str) -> str:
|
|
113
|
+
"""Strip trailing ``--`` or ``/* … */`` outside string/identifier quotes."""
|
|
114
|
+
in_single = in_double = False
|
|
115
|
+
i = 0
|
|
116
|
+
n = len(line)
|
|
117
|
+
cut: Optional[int] = None
|
|
118
|
+
while i < n:
|
|
119
|
+
ch = line[i]
|
|
120
|
+
if ch == "'" and not in_double:
|
|
121
|
+
if in_single and i + 1 < n and line[i + 1] == "'":
|
|
122
|
+
i += 2
|
|
123
|
+
continue
|
|
124
|
+
in_single = not in_single
|
|
125
|
+
elif ch == '"' and not in_single:
|
|
126
|
+
if in_double and i + 1 < n and line[i + 1] == '"':
|
|
127
|
+
i += 2
|
|
128
|
+
continue
|
|
129
|
+
in_double = not in_double
|
|
130
|
+
elif not in_single and not in_double:
|
|
131
|
+
if ch == "-" and i + 1 < n and line[i + 1] == "-":
|
|
132
|
+
cut = i
|
|
133
|
+
break
|
|
134
|
+
if ch == "/" and i + 1 < n and line[i + 1] == "*":
|
|
135
|
+
# Only treat as trailing comment if it runs to end of line
|
|
136
|
+
close = line.find("*/", i + 2)
|
|
137
|
+
if close >= 0 and line[close + 2 :].strip() == "":
|
|
138
|
+
cut = i
|
|
139
|
+
break
|
|
140
|
+
i += 1
|
|
141
|
+
if cut is not None:
|
|
142
|
+
return line[:cut].rstrip()
|
|
143
|
+
return line.rstrip()
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def _has_top_level_semicolon(sql: str) -> bool:
|
|
147
|
+
"""True if ``sql`` contains a semicolon outside string/identifier quotes."""
|
|
148
|
+
in_single = in_double = False
|
|
149
|
+
i = 0
|
|
150
|
+
n = len(sql)
|
|
151
|
+
while i < n:
|
|
152
|
+
ch = sql[i]
|
|
153
|
+
if ch == "'" and not in_double:
|
|
154
|
+
# SQL escaped single quote ''
|
|
155
|
+
if in_single and i + 1 < n and sql[i + 1] == "'":
|
|
156
|
+
i += 2
|
|
157
|
+
continue
|
|
158
|
+
in_single = not in_single
|
|
159
|
+
elif ch == '"' and not in_single:
|
|
160
|
+
if in_double and i + 1 < n and sql[i + 1] == '"':
|
|
161
|
+
i += 2
|
|
162
|
+
continue
|
|
163
|
+
in_double = not in_double
|
|
164
|
+
elif ch == ";" and not in_single and not in_double:
|
|
165
|
+
return True
|
|
166
|
+
i += 1
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def _has_top_level_keyword(sql: str, keyword: str) -> bool:
|
|
171
|
+
"""True if ``keyword`` appears as a top-level token outside quotes.
|
|
172
|
+
|
|
173
|
+
Used instead of a raw substring search so values like
|
|
174
|
+
``SET note = ' returning '`` or mid-line comments mentioning
|
|
175
|
+
``returning`` do not skip the RETURNING rewrite.
|
|
176
|
+
"""
|
|
177
|
+
kw = keyword.upper()
|
|
178
|
+
kw_len = len(kw)
|
|
179
|
+
in_single = in_double = False
|
|
180
|
+
i = 0
|
|
181
|
+
n = len(sql)
|
|
182
|
+
while i < n:
|
|
183
|
+
ch = sql[i]
|
|
184
|
+
if ch == "'" and not in_double:
|
|
185
|
+
if in_single and i + 1 < n and sql[i + 1] == "'":
|
|
186
|
+
i += 2
|
|
187
|
+
continue
|
|
188
|
+
in_single = not in_single
|
|
189
|
+
elif ch == '"' and not in_single:
|
|
190
|
+
if in_double and i + 1 < n and sql[i + 1] == '"':
|
|
191
|
+
i += 2
|
|
192
|
+
continue
|
|
193
|
+
in_double = not in_double
|
|
194
|
+
elif not in_single and not in_double:
|
|
195
|
+
if sql[i : i + kw_len].upper() == kw:
|
|
196
|
+
before_ok = i == 0 or not (sql[i - 1].isalnum() or sql[i - 1] == "_")
|
|
197
|
+
after = i + kw_len
|
|
198
|
+
after_ok = after >= n or not (sql[after].isalnum() or sql[after] == "_")
|
|
199
|
+
if before_ok and after_ok:
|
|
200
|
+
return True
|
|
201
|
+
i += 1
|
|
202
|
+
return False
|
|
203
|
+
|
|
36
204
|
def create_schema_if_not_exists(self, schema: str) -> None:
|
|
37
205
|
"""Create a DuckDB schema if it is missing."""
|
|
38
206
|
rows = self.execute_query(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dblift
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.4
|
|
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
|
|
@@ -115,8 +115,8 @@ Dynamic: license-file
|
|
|
115
115
|
|
|
116
116
|

|
|
117
117
|

|
|
118
|
-
[](https://github.com/dblift/dblift/actions/workflows/unit-tests.yml)
|
|
119
|
+
[](https://codecov.io/gh/dblift/dblift)
|
|
120
120
|
[](SECURITY.md)
|
|
121
121
|
|
|
122
122
|
Application code usually has tests, CI pipelines, and pull request review. Database changes often skip one or more of those stages. DBLift is a Python-native migration toolkit that shows you exactly what SQL will run before it runs — and keeps the full migration lifecycle inside your Python workflow. No JVM required.
|
|
@@ -295,6 +295,8 @@ db/plugins/cockroachdb/__init__.py
|
|
|
295
295
|
db/plugins/cockroachdb/plugin.py
|
|
296
296
|
db/plugins/cockroachdb/provider.py
|
|
297
297
|
db/plugins/cockroachdb/quirks.py
|
|
298
|
+
db/plugins/cockroachdb/sqlalchemy_dialect.py
|
|
299
|
+
db/plugins/cockroachdb/sqlalchemy_url.py
|
|
298
300
|
db/plugins/cosmosdb/__init__.py
|
|
299
301
|
db/plugins/cosmosdb/config.py
|
|
300
302
|
db/plugins/cosmosdb/plugin.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dblift"
|
|
7
|
-
version = "3.3.
|
|
7
|
+
version = "3.3.4"
|
|
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"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|