dblift 3.2.1__tar.gz → 3.3.0__tar.gz

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