dblift 2.2.2__tar.gz → 2.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-2.2.2 → dblift-2.3.0}/PKG-INFO +5 -2
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/repair_command.py +17 -1
- dblift-2.3.0/db/plugins/duckdb/__init__.py +12 -0
- dblift-2.3.0/db/plugins/duckdb/config.py +81 -0
- dblift-2.3.0/db/plugins/duckdb/parser/__init__.py +5 -0
- dblift-2.3.0/db/plugins/duckdb/parser/duckdb_regex_parser.py +180 -0
- dblift-2.3.0/db/plugins/duckdb/parser/parser_config.py +203 -0
- dblift-2.3.0/db/plugins/duckdb/plugin.py +22 -0
- dblift-2.3.0/db/plugins/duckdb/provider.py +368 -0
- dblift-2.3.0/db/plugins/duckdb/quirks.py +96 -0
- dblift-2.3.0/db/plugins/duckdb/sqlalchemy_url.py +30 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/sqlalchemy_provider.py +6 -0
- {dblift-2.2.2 → dblift-2.3.0}/dblift.egg-info/PKG-INFO +5 -2
- {dblift-2.2.2 → dblift-2.3.0}/dblift.egg-info/SOURCES.txt +9 -0
- {dblift-2.2.2 → dblift-2.3.0}/dblift.egg-info/entry_points.txt +1 -0
- {dblift-2.2.2 → dblift-2.3.0}/dblift.egg-info/requires.txt +5 -1
- {dblift-2.2.2 → dblift-2.3.0}/pyproject.toml +4 -2
- {dblift-2.2.2 → dblift-2.3.0}/LICENSE +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/README.md +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/_cli_support.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/_client_factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/_client_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/_engine_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/async_client.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/client.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/events.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/migrations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/api/py.typed +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/_command_handlers.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/_config_helpers.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/_constants.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/_output.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/_parser_setup.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/commands/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/commands/config_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/db_utils.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/extensions.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/_shared.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/baseline.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/clean.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/import_flyway.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/info.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/migrate.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/repair.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/undo.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/handlers/validate.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/cli/main.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/_credential_masking.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/_subclasses/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/_subclasses/dummy_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/_url_builder_mixin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/config_builder.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/database_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/dblift_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/errors.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/property_registry.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/secrets/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/secrets/_cache.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/secrets/_provider_base.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/secrets/_registry.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/secrets/_resolver.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/config/secrets/_secrets_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/constants.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/dialect_boundary.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/exceptions.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/_column_enricher.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/_partition_enricher.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/_schema_orchestrator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/_utils.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/_vendor_property_applier.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/base_introspector.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/base_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/column_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/constraint_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/index_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/misc_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/procedure_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/sequence_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/table_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/trigger_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/extractors/view_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/introspector_factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/result.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/schema_introspector.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/vendor_queries_base.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/vendor_queries_factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/vendor_queries_protocols.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/introspection/version_detector.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/_base.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/_factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/_formatters.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/_levels.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/_multi.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/_null.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/console.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/formatters/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/formatters/_formatter_impl.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/formatters/factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/formatters/formatter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/formatters/htmlformatter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/formatters/jsonformatter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/log.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/results.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/templates/oldreport.html +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/logger/templates/report.html +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/_type_match.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/clean_summary.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/_script_events.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/base_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/baseline_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/clean_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/import_flyway_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/info_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/migrate_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/undo_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/commands/validate_command.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/encoding.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executor/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executor/execution_engine.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executor/migration_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executor/migration_helpers.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executor/placeholder_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executor/transaction_policy.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executors/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executors/base_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executors/executor_factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executors/python_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/executors/sql_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/formats/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/formats/format_detector.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/formats/migration_format.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/history/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/history/migration_history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/journals/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/journals/migration_journal.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/migration.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/placeholders/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/placeholders/placeholder_service.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/rules/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/rules/migration_rules.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/migration_script_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/undo_script_generator/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/undo_script_generator/_ddl_reversers.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/undo_script_generator/_dml_reversers.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/undo_script_generator/_extractors.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/undo_script_generator/_generator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/undo_script_generator/_helpers.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/undo_script_generator/_models.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/scripting/undo_script_generator/_reversers.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/sql/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/sql/execution_statement.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/sql/sql_analyzer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/sql/sql_execution_service.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/sql/statement_splitter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/state/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/state/migration_data_service.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/state/migration_display_state.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/state/migration_formatter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/state/migration_state.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/state/migration_state_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/state/migration_state_service.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/ui/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/ui/data_collector.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/ui/display_formatters.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/ui/migration_analyzer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/ui/migration_ui.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/ui/table_renderer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/migration/version_utils.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/normalization/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/normalization/dependency_resolver.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/normalization/identifier_normalizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/normalization/object_orderer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/normalization/type_constants.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/normalization/type_mapper.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/normalization/type_mappings.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/normalization/type_normalizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/capabilities.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/event_listeners.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/feature_loading.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/introspection.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/license_info.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/runtime_checks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/sql_generators.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/seams/tier_resolver.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/alter/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/alter/alter_generator_factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/alter/base_alter_generator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/alter_generator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/base_generator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/basic_table_ddl_generator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/dependency_analyzer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/diff_converters/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/diff_converters/base_converter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/formatter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/generator_factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/options.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/script_organizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/sql_generator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/sql_statement.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_generator/table_ddl_render.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/_base_parse_result.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/_base_sql_column.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/_base_sql_constraint.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/_base_sql_object.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/_base_sql_statement.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/base.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/constraint_validator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/database_link.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/dialect.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/event.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/extension.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/foreign_data_wrapper.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/foreign_server.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/index.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/linked_server.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/module.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/package.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/partition.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/procedure.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/sequence.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/synonym.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/table.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/table_canonicalizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/table_options.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/trigger.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/user_defined_type.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/view.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_model/view_options.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/_partition_handler.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/_sqlglot_builders.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/base_statement_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/base_tokenizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/common/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/common/base_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/dialects/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/dialects/base_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/enhanced_regex_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/hybrid_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/parser_context.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/parser_factory.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/parser_interface.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/sqlglot_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/tokens.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_parser/unified_regex_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_validator/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_validator/_checksum_validator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_validator/_flyway_compatibility.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_validator/_migration_filter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_validator/_sql_syntax_validator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_validator/_strict_mode_validator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/sql_validator/migration_validator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/state/sql_script_formatter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/state/sql_statement.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/utils/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/utils/database_url_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/utils/metadata_helpers.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/utils/row_access.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/utils/string_utils.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/core/utils/url_masking.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/base_provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/base_quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/constants.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/dml_analysis.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/error.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/error_handler.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/exceptions.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/native_connection_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/object_naming.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/base_history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/base_locking_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/base_query_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/base_schema_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/base_snapshot_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/base_undo_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/cosmosdb/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/cosmosdb/_sdk.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/cosmosdb/connection_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/cosmosdb/history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/cosmosdb/locking_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/cosmosdb/query_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/cosmosdb/schema_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/introspection/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/parser/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/parser/cosmosdb_regex_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/plugin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/sdk_translator/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/sdk_translator/_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/sdk_translator/_executors.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/sdk_translator/_parsing.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/sdk_translator/_script_generation.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/sdk_translator/_translator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/cosmosdb/sdk_translator/_translators.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/db2/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/db2/history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/db2/locking_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/db2/schema_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/introspection/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/parser/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/parser/db2_regex_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/parser/parser_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/plugin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/db2/sqlalchemy_url.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mariadb/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mariadb/plugin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mariadb/provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mariadb/quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/introspection/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/mysql/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/mysql/history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/mysql/locking_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/mysql/schema_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/parser/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/parser/mysql_regex_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/parser/mysql_statement_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/parser/mysql_tokenizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/parser/parser_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/plugin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/mysql/sqlalchemy_url.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/introspection/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/introspection/oracle_utils.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/oracle/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/oracle/dbms_output.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/oracle/history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/oracle/locking_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/oracle/schema_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/_comments.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/_object_extractor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/_plsql_block.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/_sqlplus.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/_statement_splitter.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/oracle_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/oracle_statement_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/oracle_tokenizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/parser_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/parser/sqlplus_context.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/plugin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/oracle/sqlalchemy_url.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/_provider_query_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/introspection/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/parser/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/parser/parser_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/parser/postgresql_regex_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/parser/postgresql_statement_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/parser/postgresql_tokenizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/plugin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/postgresql/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/postgresql/history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/postgresql/locking_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/postgresql/schema_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/postgresql/sqlalchemy_url.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/introspection/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/parser/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/parser/parser_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/parser/sqlite_regex_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/plugin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/sqlalchemy_url.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/sqlite/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/sqlite/connection_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/sqlite/history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/sqlite/locking_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/sqlite/query_executor.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlite/sqlite/schema_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/introspection/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/parser/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/parser/parser_config.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/parser/sqlserver_regex_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/parser/sqlserver_statement_parser.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/parser/sqlserver_tokenizer.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/parser/tsql_batch_separator.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/plugin.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/provider.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/quirks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/sqlalchemy_url.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/sqlserver/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/sqlserver/history_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/sqlserver/locking_manager.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/plugins/sqlserver/sqlserver/schema_operations.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/provider_capabilities.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/provider_interfaces.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/provider_registry.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/db/value_utils.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/dblift.egg-info/dependency_links.txt +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/dblift.egg-info/top_level.txt +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/_client.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/_engine.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/apps.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/checks.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/management/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/management/commands/__init__.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/management/commands/dblift_info.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/management/commands/dblift_migrate.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/django/management/commands/dblift_validate.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/fastapi.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/flask.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/integrations/opentelemetry.py +0 -0
- {dblift-2.2.2 → dblift-2.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dblift
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.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
|
|
@@ -66,6 +66,9 @@ Requires-Dist: pymssql>=2.3; extra == "sqlserver"
|
|
|
66
66
|
Provides-Extra: db2
|
|
67
67
|
Requires-Dist: ibm_db>=3.2; extra == "db2"
|
|
68
68
|
Requires-Dist: ibm_db_sa>=0.4; extra == "db2"
|
|
69
|
+
Provides-Extra: duckdb
|
|
70
|
+
Requires-Dist: duckdb>=1.0; extra == "duckdb"
|
|
71
|
+
Requires-Dist: duckdb_engine>=0.13; extra == "duckdb"
|
|
69
72
|
Provides-Extra: fastapi
|
|
70
73
|
Requires-Dist: fastapi>=0.100; extra == "fastapi"
|
|
71
74
|
Provides-Extra: flask
|
|
@@ -75,7 +78,7 @@ Requires-Dist: Django>=4.2; extra == "django"
|
|
|
75
78
|
Provides-Extra: otel
|
|
76
79
|
Requires-Dist: opentelemetry-api>=1.20; extra == "otel"
|
|
77
80
|
Provides-Extra: all
|
|
78
|
-
Requires-Dist: dblift[db2,mariadb,mysql,oracle,postgresql,sqlserver]; extra == "all"
|
|
81
|
+
Requires-Dist: dblift[db2,duckdb,mariadb,mysql,oracle,postgresql,sqlserver]; extra == "all"
|
|
79
82
|
Dynamic: license-file
|
|
80
83
|
|
|
81
84
|
# DBLift — Database release safety for Python teams
|
|
@@ -498,7 +498,23 @@ class RepairCommand(BaseCommand):
|
|
|
498
498
|
params=[script_name],
|
|
499
499
|
)
|
|
500
500
|
|
|
501
|
-
|
|
501
|
+
row_removed = rows_affected > 0
|
|
502
|
+
if (
|
|
503
|
+
rows_affected < 0
|
|
504
|
+
and not is_non_transactional
|
|
505
|
+
and hasattr(self.provider, "execute_query")
|
|
506
|
+
):
|
|
507
|
+
# Some DBAPIs report an "unknown" rowcount of -1 for DML
|
|
508
|
+
# (e.g. duckdb_engine), so ``rows_affected > 0`` would wrongly
|
|
509
|
+
# read as "nothing removed". Verify the failed row is gone.
|
|
510
|
+
remaining = self.provider.execute_query(
|
|
511
|
+
f"SELECT 1 FROM {qualified_table} "
|
|
512
|
+
f"WHERE script = ? AND success = {false_literal}",
|
|
513
|
+
[script_name],
|
|
514
|
+
)
|
|
515
|
+
row_removed = not remaining
|
|
516
|
+
|
|
517
|
+
if row_removed:
|
|
502
518
|
result.failed_migrations_removed = (
|
|
503
519
|
getattr(result, "failed_migrations_removed", 0) + 1
|
|
504
520
|
)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""DuckDB database provider plugin."""
|
|
2
|
+
|
|
3
|
+
__plugin_name__ = "duckdb"
|
|
4
|
+
__plugin_version__ = "1.0.0"
|
|
5
|
+
__plugin_description__ = "DuckDB database provider (SQLAlchemy via duckdb_engine)"
|
|
6
|
+
__plugin_dialects__ = ["duckdb"]
|
|
7
|
+
__plugin_transport__ = "native"
|
|
8
|
+
__plugin_class__ = "DuckDBProvider"
|
|
9
|
+
|
|
10
|
+
from .provider import DuckDBProvider
|
|
11
|
+
|
|
12
|
+
__all__ = ["DuckDBProvider"]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""DuckDB-specific ``BaseDatabaseConfig`` subclass."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
|
|
6
|
+
from config.database_config import BaseDatabaseConfig, register_database_type
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# lint: allow-dialect-string: config type registration
|
|
10
|
+
@register_database_type("duckdb")
|
|
11
|
+
@dataclass
|
|
12
|
+
class DuckDBConfig(BaseDatabaseConfig):
|
|
13
|
+
"""Configuration for DuckDB connections.
|
|
14
|
+
|
|
15
|
+
DuckDB is embedded/file-based (like SQLite): no server, no
|
|
16
|
+
credentials, ``"main"`` default schema. Connections resolve to a
|
|
17
|
+
file path (or ``:memory:``) rather than a host/port.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# DuckDB specific fields
|
|
21
|
+
path: Optional[str] = None # Path to the DuckDB file (or :memory: for in-memory)
|
|
22
|
+
|
|
23
|
+
def __post_init__(self) -> None:
|
|
24
|
+
"""Resolve the file path from path/url/database and apply defaults."""
|
|
25
|
+
super().__post_init__()
|
|
26
|
+
|
|
27
|
+
if not self.path:
|
|
28
|
+
if self.url:
|
|
29
|
+
url = self.url
|
|
30
|
+
if url.startswith("duckdb://"):
|
|
31
|
+
# Match duckdb_engine's URL convention:
|
|
32
|
+
# duckdb:///rel.db (3 slashes) -> relative "rel.db"
|
|
33
|
+
# duckdb:////abs.db (4 slashes) -> absolute "/abs.db"
|
|
34
|
+
# duckdb:///:memory: -> ":memory:"
|
|
35
|
+
self.path = url[len("duckdb://") :]
|
|
36
|
+
if self.path in ("/:memory:", ":memory:"):
|
|
37
|
+
self.path = ":memory:"
|
|
38
|
+
elif self.path.startswith("//"):
|
|
39
|
+
self.path = "/" + self.path.lstrip("/")
|
|
40
|
+
elif self.path.startswith("/"):
|
|
41
|
+
self.path = self.path[1:]
|
|
42
|
+
else:
|
|
43
|
+
self.path = url
|
|
44
|
+
elif self.database:
|
|
45
|
+
self.path = self.database
|
|
46
|
+
|
|
47
|
+
if not self.path:
|
|
48
|
+
raise ValueError(
|
|
49
|
+
"Database path is required for DuckDB (use 'path' or 'database' field)"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# DuckDB's default schema is 'main'; no credentials required.
|
|
53
|
+
if not self.schema:
|
|
54
|
+
self.schema = "main"
|
|
55
|
+
if not self.username:
|
|
56
|
+
self.username = ""
|
|
57
|
+
if not self.password:
|
|
58
|
+
self.password = ""
|
|
59
|
+
|
|
60
|
+
def build_connection_string(self) -> str:
|
|
61
|
+
"""Build a DuckDB connection string (file path)."""
|
|
62
|
+
return self.path or ""
|
|
63
|
+
|
|
64
|
+
def build_database_url(self) -> str:
|
|
65
|
+
"""Build the DuckDB plugin-owned SQLAlchemy URL."""
|
|
66
|
+
from db.provider_registry import ProviderRegistry
|
|
67
|
+
|
|
68
|
+
return ProviderRegistry.build_sqlalchemy_url(self)
|
|
69
|
+
|
|
70
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
71
|
+
"""Convert to dictionary with DuckDB specific parameters."""
|
|
72
|
+
result = super().to_dict()
|
|
73
|
+
result["path"] = self.path
|
|
74
|
+
return result
|
|
75
|
+
|
|
76
|
+
def get_connection_props(self) -> Dict[str, str]:
|
|
77
|
+
"""Get connection properties for DuckDB connection."""
|
|
78
|
+
props: Dict[str, str] = {}
|
|
79
|
+
if self.path:
|
|
80
|
+
props["path"] = self.path
|
|
81
|
+
return props
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""DuckDB-specific regex-based SQL parser.
|
|
2
|
+
|
|
3
|
+
DuckDB has a non-procedural DDL surface (no stored procedures/PL blocks),
|
|
4
|
+
so statement splitting only needs to respect string literals and comments
|
|
5
|
+
around the ``;`` separator.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
from core.sql_model.base import SqlObject, SqlObjectType
|
|
11
|
+
from core.sql_parser.enhanced_regex_parser import EnhancedRegexParser
|
|
12
|
+
from db.plugins.duckdb.parser.parser_config import DuckDBParserConfig
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DuckDBRegexParser(EnhancedRegexParser):
|
|
16
|
+
"""DuckDB-specific regex-based SQL parser."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, config: Optional[DuckDBParserConfig] = None):
|
|
19
|
+
"""Initialize the DuckDB regex parser."""
|
|
20
|
+
duckdb_config = config or DuckDBParserConfig()
|
|
21
|
+
self.config = duckdb_config # type: ignore[assignment]
|
|
22
|
+
super().__init__(self.config)
|
|
23
|
+
|
|
24
|
+
def split_statements(self, sql_content: str, strict_tokenizer: bool = False) -> List[str]:
|
|
25
|
+
"""Split SQL into statements, honouring string literals and comments."""
|
|
26
|
+
if not sql_content or not sql_content.strip():
|
|
27
|
+
return []
|
|
28
|
+
|
|
29
|
+
statements: List[str] = []
|
|
30
|
+
current: List[str] = []
|
|
31
|
+
in_string = False
|
|
32
|
+
in_ident = False # inside a "double-quoted" identifier
|
|
33
|
+
in_block_comment = False
|
|
34
|
+
in_line_comment = False
|
|
35
|
+
|
|
36
|
+
i = 0
|
|
37
|
+
content = sql_content
|
|
38
|
+
length = len(content)
|
|
39
|
+
while i < length:
|
|
40
|
+
char = content[i]
|
|
41
|
+
nxt = content[i + 1] if i + 1 < length else ""
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
not in_string
|
|
45
|
+
and not in_ident
|
|
46
|
+
and not in_line_comment
|
|
47
|
+
and char == "/"
|
|
48
|
+
and nxt == "*"
|
|
49
|
+
):
|
|
50
|
+
in_block_comment = True
|
|
51
|
+
current.append(char)
|
|
52
|
+
current.append(nxt)
|
|
53
|
+
i += 2
|
|
54
|
+
continue
|
|
55
|
+
if in_block_comment:
|
|
56
|
+
current.append(char)
|
|
57
|
+
if char == "*" and nxt == "/":
|
|
58
|
+
current.append(nxt)
|
|
59
|
+
in_block_comment = False
|
|
60
|
+
i += 2
|
|
61
|
+
continue
|
|
62
|
+
i += 1
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
if not in_string and not in_ident and char == "-" and nxt == "-":
|
|
66
|
+
in_line_comment = True
|
|
67
|
+
current.append(char)
|
|
68
|
+
i += 1
|
|
69
|
+
continue
|
|
70
|
+
if in_line_comment:
|
|
71
|
+
current.append(char)
|
|
72
|
+
if char in "\r\n":
|
|
73
|
+
in_line_comment = False
|
|
74
|
+
i += 1
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
# Double-quoted identifiers may contain ; and comment markers.
|
|
78
|
+
if char == '"' and not in_string and not in_ident:
|
|
79
|
+
in_ident = True
|
|
80
|
+
current.append(char)
|
|
81
|
+
i += 1
|
|
82
|
+
continue
|
|
83
|
+
if in_ident:
|
|
84
|
+
current.append(char)
|
|
85
|
+
if char == '"':
|
|
86
|
+
if nxt == '"': # escaped quote inside identifier
|
|
87
|
+
current.append(nxt)
|
|
88
|
+
i += 2
|
|
89
|
+
continue
|
|
90
|
+
in_ident = False
|
|
91
|
+
i += 1
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
if char == "'" and not in_string:
|
|
95
|
+
in_string = True
|
|
96
|
+
current.append(char)
|
|
97
|
+
i += 1
|
|
98
|
+
continue
|
|
99
|
+
if in_string:
|
|
100
|
+
current.append(char)
|
|
101
|
+
if char == "'":
|
|
102
|
+
if nxt == "'": # escaped quote
|
|
103
|
+
current.append(nxt)
|
|
104
|
+
i += 2
|
|
105
|
+
continue
|
|
106
|
+
in_string = False
|
|
107
|
+
i += 1
|
|
108
|
+
continue
|
|
109
|
+
|
|
110
|
+
if char == ";":
|
|
111
|
+
current.append(char)
|
|
112
|
+
stmt = "".join(current).strip()
|
|
113
|
+
if stmt:
|
|
114
|
+
statements.append(stmt)
|
|
115
|
+
current = []
|
|
116
|
+
i += 1
|
|
117
|
+
continue
|
|
118
|
+
|
|
119
|
+
current.append(char)
|
|
120
|
+
i += 1
|
|
121
|
+
|
|
122
|
+
final = "".join(current).strip()
|
|
123
|
+
if final:
|
|
124
|
+
statements.append(final)
|
|
125
|
+
return statements
|
|
126
|
+
|
|
127
|
+
def classify_statement(self, statement: str) -> str:
|
|
128
|
+
"""Classify a SQL statement as DDL / DML / QUERY / TCL / UNKNOWN."""
|
|
129
|
+
if not statement:
|
|
130
|
+
return "UNKNOWN"
|
|
131
|
+
statement = statement.strip()
|
|
132
|
+
cfg = self.config
|
|
133
|
+
if cfg.is_ddl_statement(statement): # type: ignore[attr-defined]
|
|
134
|
+
return "DDL"
|
|
135
|
+
if cfg.is_dml_statement(statement): # type: ignore[attr-defined]
|
|
136
|
+
return "DML"
|
|
137
|
+
if cfg.is_query_statement(statement): # type: ignore[attr-defined]
|
|
138
|
+
return "QUERY"
|
|
139
|
+
if statement.upper().startswith(("BEGIN", "COMMIT", "ROLLBACK", "ABORT", "START")):
|
|
140
|
+
return "TCL"
|
|
141
|
+
return "UNKNOWN"
|
|
142
|
+
|
|
143
|
+
def extract_objects(
|
|
144
|
+
self, sql_content: str, default_schema: Optional[str] = None
|
|
145
|
+
) -> List[SqlObject]:
|
|
146
|
+
"""Extract database objects from a statement via config object patterns."""
|
|
147
|
+
if not sql_content:
|
|
148
|
+
return []
|
|
149
|
+
objects: List[SqlObject] = []
|
|
150
|
+
statement = sql_content.strip()
|
|
151
|
+
for pattern_name, pattern in self.config.object_patterns.items():
|
|
152
|
+
match = pattern.search(statement)
|
|
153
|
+
if not match:
|
|
154
|
+
continue
|
|
155
|
+
non_none = [g for g in match.groups() if g is not None]
|
|
156
|
+
if not non_none:
|
|
157
|
+
continue
|
|
158
|
+
name = non_none[-1].strip('"')
|
|
159
|
+
schema = non_none[-2].strip('"') if len(non_none) >= 2 else None
|
|
160
|
+
objects.append(
|
|
161
|
+
SqlObject(
|
|
162
|
+
name=name,
|
|
163
|
+
object_type=self._object_type(pattern_name),
|
|
164
|
+
schema=schema or default_schema,
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
break
|
|
168
|
+
return objects
|
|
169
|
+
|
|
170
|
+
@staticmethod
|
|
171
|
+
def _object_type(pattern_name: str) -> SqlObjectType:
|
|
172
|
+
mapping: Dict[str, SqlObjectType] = {
|
|
173
|
+
"create_table": SqlObjectType.TABLE,
|
|
174
|
+
"create_view": SqlObjectType.VIEW,
|
|
175
|
+
"create_index": SqlObjectType.INDEX,
|
|
176
|
+
"create_sequence": SqlObjectType.SEQUENCE,
|
|
177
|
+
"alter_table": SqlObjectType.TABLE,
|
|
178
|
+
"drop_table": SqlObjectType.TABLE,
|
|
179
|
+
}
|
|
180
|
+
return mapping.get(pattern_name, SqlObjectType.UNKNOWN)
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""DuckDB dialect configuration for regex-based parsing.
|
|
2
|
+
|
|
3
|
+
DuckDB SQL is PostgreSQL-like but with a small, non-procedural surface:
|
|
4
|
+
- No stored procedures / no PL blocks (user code lives outside the DB)
|
|
5
|
+
- Real schemas and sequences
|
|
6
|
+
- Double-quoted identifiers (no square brackets)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from typing import Dict, List, Pattern, Set
|
|
11
|
+
|
|
12
|
+
from core.sql_parser.dialects.base_config import DialectConfig
|
|
13
|
+
|
|
14
|
+
_IDENT = r'(?:"[^"]*"|[a-zA-Z_][a-zA-Z0-9_]*)'
|
|
15
|
+
_QUALIFIED = rf"(?:{_IDENT}\.)?{_IDENT}"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DuckDBParserConfig(DialectConfig):
|
|
19
|
+
"""DuckDB dialect configuration for the regex parser framework."""
|
|
20
|
+
|
|
21
|
+
def __init__(self) -> None:
|
|
22
|
+
"""Initialize DuckDB dialect configuration."""
|
|
23
|
+
super().__init__() # type: ignore[no-untyped-call]
|
|
24
|
+
|
|
25
|
+
self.identifier_quote_char = '"'
|
|
26
|
+
self.string_quote_char = "'"
|
|
27
|
+
self.supports_bracket_identifiers = False
|
|
28
|
+
self.statement_separator = ";"
|
|
29
|
+
self.line_comment_prefix = "--"
|
|
30
|
+
self.block_comment_start = "/*"
|
|
31
|
+
self.block_comment_end = "*/"
|
|
32
|
+
|
|
33
|
+
self.supports_dollar_quoting = False
|
|
34
|
+
self.supports_copy_statements = True # DuckDB COPY
|
|
35
|
+
self.supports_plpgsql_blocks = False
|
|
36
|
+
self.supports_cte_with_recursive = True
|
|
37
|
+
self.supports_on_conflict = True
|
|
38
|
+
self.supports_returning = True
|
|
39
|
+
|
|
40
|
+
self._compile_patterns()
|
|
41
|
+
|
|
42
|
+
def _compile_patterns(self) -> None:
|
|
43
|
+
def _create(kind: str) -> Pattern[str]:
|
|
44
|
+
return re.compile(
|
|
45
|
+
rf"\s*CREATE\s+(?:OR\s+REPLACE\s+)?{kind}\s+(?:IF\s+NOT\s+EXISTS\s+)?",
|
|
46
|
+
re.IGNORECASE,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def _drop(kind: str) -> Pattern[str]:
|
|
50
|
+
return re.compile(rf"\s*DROP\s+{kind}\s+(?:IF\s+EXISTS\s+)?", re.IGNORECASE)
|
|
51
|
+
|
|
52
|
+
self._ddl_patterns = {
|
|
53
|
+
"create_table": _create(r"(?:TEMP(?:ORARY)?\s+)?TABLE"),
|
|
54
|
+
"create_view": _create(r"(?:TEMP(?:ORARY)?\s+)?VIEW"),
|
|
55
|
+
"create_index": re.compile(
|
|
56
|
+
r"\s*CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?", re.IGNORECASE
|
|
57
|
+
),
|
|
58
|
+
"create_sequence": _create(r"(?:TEMP(?:ORARY)?\s+)?SEQUENCE"),
|
|
59
|
+
"create_schema": _create(r"SCHEMA"),
|
|
60
|
+
"create_type": _create(r"TYPE"),
|
|
61
|
+
"create_macro": _create(r"(?:TEMP(?:ORARY)?\s+)?MACRO"),
|
|
62
|
+
"alter_table": re.compile(r"\s*ALTER\s+TABLE\s+", re.IGNORECASE),
|
|
63
|
+
"drop_table": _drop("TABLE"),
|
|
64
|
+
"drop_view": _drop("VIEW"),
|
|
65
|
+
"drop_index": _drop("INDEX"),
|
|
66
|
+
"drop_sequence": _drop("SEQUENCE"),
|
|
67
|
+
"drop_schema": _drop("SCHEMA"),
|
|
68
|
+
"drop_type": _drop("TYPE"),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
self._dml_patterns = {
|
|
72
|
+
"insert": re.compile(
|
|
73
|
+
r"\s*INSERT\s+(?:OR\s+(?:REPLACE|IGNORE)\s+)?INTO\s+", re.IGNORECASE
|
|
74
|
+
),
|
|
75
|
+
"update": re.compile(r"\s*UPDATE\s+", re.IGNORECASE),
|
|
76
|
+
"delete": re.compile(r"\s*DELETE\s+FROM\s+", re.IGNORECASE),
|
|
77
|
+
"copy": re.compile(r"\s*COPY\s+", re.IGNORECASE),
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
self._query_patterns = {
|
|
81
|
+
"select": re.compile(r"\s*SELECT\s+", re.IGNORECASE),
|
|
82
|
+
"with": re.compile(r"\s*WITH\s+(?:RECURSIVE\s+)?", re.IGNORECASE),
|
|
83
|
+
"values": re.compile(r"\s*VALUES\s+", re.IGNORECASE),
|
|
84
|
+
"explain": re.compile(r"\s*EXPLAIN\s+", re.IGNORECASE),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
def get_ddl_keywords(self) -> Set[str]:
|
|
88
|
+
return {"CREATE", "ALTER", "DROP", "ATTACH", "DETACH", "PRAGMA"}
|
|
89
|
+
|
|
90
|
+
def get_dml_keywords(self) -> Set[str]:
|
|
91
|
+
return {"INSERT", "UPDATE", "DELETE", "COPY"}
|
|
92
|
+
|
|
93
|
+
def get_query_keywords(self) -> Set[str]:
|
|
94
|
+
return {"SELECT", "WITH", "VALUES", "EXPLAIN"}
|
|
95
|
+
|
|
96
|
+
def get_transaction_keywords(self) -> Set[str]:
|
|
97
|
+
return {"BEGIN", "COMMIT", "ROLLBACK", "ABORT", "TRANSACTION", "START"}
|
|
98
|
+
|
|
99
|
+
def get_identifier_pattern(self) -> re.Pattern[str]:
|
|
100
|
+
return re.compile(_IDENT, re.IGNORECASE)
|
|
101
|
+
|
|
102
|
+
def get_qualified_identifier_pattern(self) -> re.Pattern[str]:
|
|
103
|
+
return re.compile(_QUALIFIED, re.IGNORECASE)
|
|
104
|
+
|
|
105
|
+
def get_string_literal_pattern(self) -> re.Pattern[str]:
|
|
106
|
+
return re.compile(r"'(?:[^']|'')*'", re.IGNORECASE)
|
|
107
|
+
|
|
108
|
+
def get_comment_pattern(self) -> re.Pattern[str]:
|
|
109
|
+
return re.compile(r"(?:--[^\r\n]*|/\*.*?\*/)", re.DOTALL)
|
|
110
|
+
|
|
111
|
+
def get_statement_separator_pattern(self) -> re.Pattern[str]:
|
|
112
|
+
return re.compile(r";")
|
|
113
|
+
|
|
114
|
+
def _matches_any(self, patterns: Dict[str, Pattern[str]], statement: str) -> bool:
|
|
115
|
+
statement = statement.strip()
|
|
116
|
+
return bool(statement) and any(p.match(statement) for p in patterns.values())
|
|
117
|
+
|
|
118
|
+
def is_ddl_statement(self, statement: str) -> bool:
|
|
119
|
+
return self._matches_any(self._ddl_patterns, statement)
|
|
120
|
+
|
|
121
|
+
def is_dml_statement(self, statement: str) -> bool:
|
|
122
|
+
return self._matches_any(self._dml_patterns, statement)
|
|
123
|
+
|
|
124
|
+
def is_query_statement(self, statement: str) -> bool:
|
|
125
|
+
return self._matches_any(self._query_patterns, statement)
|
|
126
|
+
|
|
127
|
+
def get_batch_separator(self) -> str:
|
|
128
|
+
return ";"
|
|
129
|
+
|
|
130
|
+
def supports_block_comments(self) -> bool:
|
|
131
|
+
return True
|
|
132
|
+
|
|
133
|
+
def supports_line_comments(self) -> bool:
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
def get_block_keywords_for_splitting(self) -> Set[str]:
|
|
137
|
+
# DuckDB DDL is non-procedural; only transaction control uses BEGIN/END.
|
|
138
|
+
return set()
|
|
139
|
+
|
|
140
|
+
def normalize_identifier(self, identifier: str, is_quoted: bool = False) -> str:
|
|
141
|
+
if not identifier:
|
|
142
|
+
return identifier
|
|
143
|
+
if identifier.startswith('"') and identifier.endswith('"'):
|
|
144
|
+
return identifier[1:-1]
|
|
145
|
+
return identifier
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def name(self) -> str:
|
|
149
|
+
return "duckdb" # lint: allow-dialect-string: dialect dispatch
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def batch_separators(self) -> List[Pattern[str]]:
|
|
153
|
+
return [re.compile(r";")]
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def quoted_identifiers(self) -> List[Pattern[str]]:
|
|
157
|
+
return [re.compile(r'"[^"]*"')]
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def comment_patterns(self) -> List[Pattern[str]]:
|
|
161
|
+
return [re.compile(r"--[^\r\n]*"), re.compile(r"/\*.*?\*/", re.DOTALL)]
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def block_keywords(self) -> List[str]:
|
|
165
|
+
return ["CREATE", "ALTER", "DROP"]
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def ddl_patterns(self) -> Dict[str, Pattern[str]]:
|
|
169
|
+
return self._ddl_patterns
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def dml_patterns(self) -> Dict[str, Pattern[str]]:
|
|
173
|
+
return self._dml_patterns
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def query_patterns(self) -> Dict[str, Pattern[str]]:
|
|
177
|
+
return self._query_patterns
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def object_patterns(self) -> Dict[str, Pattern[str]]:
|
|
181
|
+
def _obj(kind: str) -> Pattern[str]:
|
|
182
|
+
return re.compile(
|
|
183
|
+
rf"CREATE\s+(?:OR\s+REPLACE\s+)?{kind}\s+(?:IF\s+NOT\s+EXISTS\s+)?"
|
|
184
|
+
rf"(?:({_IDENT})\.)?({_IDENT})",
|
|
185
|
+
re.IGNORECASE,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
"create_table": _obj(r"(?:TEMP(?:ORARY)?\s+)?TABLE"),
|
|
190
|
+
"create_view": _obj(r"(?:TEMP(?:ORARY)?\s+)?VIEW"),
|
|
191
|
+
"create_index": re.compile(
|
|
192
|
+
rf"CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?"
|
|
193
|
+
rf"(?:({_IDENT})\.)?({_IDENT})",
|
|
194
|
+
re.IGNORECASE,
|
|
195
|
+
),
|
|
196
|
+
"create_sequence": _obj(r"(?:TEMP(?:ORARY)?\s+)?SEQUENCE"),
|
|
197
|
+
"alter_table": re.compile(
|
|
198
|
+
rf"ALTER\s+TABLE\s+(?:({_IDENT})\.)?({_IDENT})", re.IGNORECASE
|
|
199
|
+
),
|
|
200
|
+
"drop_table": re.compile(
|
|
201
|
+
rf"DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?(?:({_IDENT})\.)?({_IDENT})", re.IGNORECASE
|
|
202
|
+
),
|
|
203
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Entry-point declaration for the DuckDB plugin."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from db.plugins.duckdb.config import DuckDBConfig
|
|
6
|
+
from db.plugins.duckdb.provider import DuckDBProvider
|
|
7
|
+
from db.plugins.duckdb.quirks import DuckDBQuirks
|
|
8
|
+
from db.plugins.duckdb.sqlalchemy_url import build_sqlalchemy_url
|
|
9
|
+
from db.provider_registry import PluginInfo
|
|
10
|
+
|
|
11
|
+
PLUGIN: PluginInfo = PluginInfo(
|
|
12
|
+
name="duckdb",
|
|
13
|
+
version="1.0.0",
|
|
14
|
+
description="DuckDB database provider (SQLAlchemy via duckdb_engine)",
|
|
15
|
+
dialects=["duckdb"],
|
|
16
|
+
provider_class=DuckDBProvider,
|
|
17
|
+
transport="native",
|
|
18
|
+
quirks_class=DuckDBQuirks,
|
|
19
|
+
config_class=DuckDBConfig,
|
|
20
|
+
sqlalchemy_url_builder=build_sqlalchemy_url,
|
|
21
|
+
native_driver_module="duckdb",
|
|
22
|
+
)
|