velocity-python 0.1.37__tar.gz → 0.1.39__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 (190) hide show
  1. {velocity_python-0.1.37/src/velocity_python.egg-info → velocity_python-0.1.39}/PKG-INFO +1 -1
  2. {velocity_python-0.1.37 → velocity_python-0.1.39}/pyproject.toml +1 -1
  3. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/decorators.py +103 -17
  5. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/table.py +579 -7
  6. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/exceptions.py +7 -0
  7. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/base/sql.py +4 -0
  8. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/mysql/sql.py +17 -2
  9. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/postgres/sql.py +32 -10
  10. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlite/sql.py +11 -1
  11. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlserver/sql.py +17 -2
  12. velocity_python-0.1.39/src/velocity/db/tests/postgres/test_schema_locking.py +631 -0
  13. {velocity_python-0.1.37 → velocity_python-0.1.39/src/velocity_python.egg-info}/PKG-INFO +1 -1
  14. velocity_python-0.1.37/src/velocity/db/tests/postgres/test_schema_locking.py +0 -348
  15. {velocity_python-0.1.37 → velocity_python-0.1.39}/LICENSE +0 -0
  16. {velocity_python-0.1.37 → velocity_python-0.1.39}/README.md +0 -0
  17. {velocity_python-0.1.37 → velocity_python-0.1.39}/setup.cfg +0 -0
  18. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/__init__.py +0 -0
  19. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/amplify.py +0 -0
  20. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/amplify_build.py +0 -0
  21. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/assets/__init__.py +0 -0
  22. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/assets/backfill.py +0 -0
  23. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/assets/indexing.py +0 -0
  24. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/assets/references.py +0 -0
  25. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/assets/service.py +0 -0
  26. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/assets/usage_index.py +0 -0
  27. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/dirty_pipeline.py +0 -0
  28. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/__init__.py +0 -0
  29. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/base_handler.py +0 -0
  30. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/context.py +0 -0
  31. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/context_factory.py +0 -0
  32. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/exceptions.py +0 -0
  33. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  34. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  35. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  36. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  37. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/perf.py +0 -0
  38. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/response.py +0 -0
  39. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  40. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/s3.py +0 -0
  41. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/ssm_config.py +0 -0
  42. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/tests/__init__.py +0 -0
  43. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  44. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  45. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/aws/tests/test_response.py +0 -0
  46. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/__init__.py +0 -0
  47. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/__init__.py +0 -0
  48. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/async_support.py +0 -0
  49. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/column.py +0 -0
  50. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/database.py +0 -0
  51. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/engine.py +0 -0
  52. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/result.py +0 -0
  53. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/row.py +0 -0
  54. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/sequence.py +0 -0
  55. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/transaction.py +0 -0
  56. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/core/view.py +0 -0
  57. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/migrations.py +0 -0
  58. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/__init__.py +0 -0
  59. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/base/__init__.py +0 -0
  60. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/base/initializer.py +0 -0
  61. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/base/operators.py +0 -0
  62. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/base/types.py +0 -0
  63. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/mysql/__init__.py +0 -0
  64. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/mysql/operators.py +0 -0
  65. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/mysql/reserved.py +0 -0
  66. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/mysql/types.py +0 -0
  67. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/postgres/__init__.py +0 -0
  68. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/postgres/operators.py +0 -0
  69. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/postgres/reserved.py +0 -0
  70. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/postgres/types.py +0 -0
  71. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  72. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlite/operators.py +0 -0
  73. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  74. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlite/types.py +0 -0
  75. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  76. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  77. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  78. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/sqlserver/types.py +0 -0
  79. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/servers/tablehelper.py +0 -0
  80. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/__init__.py +0 -0
  81. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/common_db_test.py +0 -0
  82. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/__init__.py +0 -0
  83. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/common.py +0 -0
  84. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_column.py +0 -0
  85. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  86. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_database.py +0 -0
  87. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  88. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  89. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  90. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_result.py +0 -0
  91. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_row.py +0 -0
  92. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  93. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  94. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  95. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  96. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_table.py +0 -0
  97. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  98. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  99. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/sql/__init__.py +0 -0
  100. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/sql/common.py +0 -0
  101. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  102. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  103. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  104. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_db_utils.py +0 -0
  105. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_postgres.py +0 -0
  106. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  107. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  108. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_result_caching.py +0 -0
  109. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  110. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  111. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  112. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  113. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_sql_builder.py +0 -0
  114. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_tablehelper.py +0 -0
  115. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/tests/test_view_helper.py +0 -0
  116. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/db/utils.py +0 -0
  117. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/logging.py +0 -0
  118. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/__init__.py +0 -0
  119. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/conv/__init__.py +0 -0
  120. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/conv/iconv.py +0 -0
  121. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/conv/oconv.py +0 -0
  122. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/db.py +0 -0
  123. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/export.py +0 -0
  124. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/format.py +0 -0
  125. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/mail.py +0 -0
  126. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/merge.py +0 -0
  127. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/pdf.py +0 -0
  128. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/__init__.py +0 -0
  129. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/test_db.py +0 -0
  130. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/test_fix.py +0 -0
  131. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/test_format.py +0 -0
  132. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/test_iconv.py +0 -0
  133. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/test_merge.py +0 -0
  134. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/test_oconv.py +0 -0
  135. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/test_original_error.py +0 -0
  136. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tests/test_timer.py +0 -0
  137. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/timer.py +0 -0
  138. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/misc/tools.py +0 -0
  139. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/__init__.py +0 -0
  140. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/authorizenet_adapter.py +0 -0
  141. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/authorizenet_mirror.py +0 -0
  142. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/base_adapter.py +0 -0
  143. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/braintree_adapter.py +0 -0
  144. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/braintree_mirror.py +0 -0
  145. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/charge_rules.py +0 -0
  146. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/stripe_adapter.py +0 -0
  147. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity/payment/stripe_mirror.py +0 -0
  148. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity_python.egg-info/SOURCES.txt +0 -0
  149. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  150. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity_python.egg-info/entry_points.txt +0 -0
  151. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity_python.egg-info/requires.txt +0 -0
  152. {velocity_python-0.1.37 → velocity_python-0.1.39}/src/velocity_python.egg-info/top_level.txt +0 -0
  153. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_amplify_build.py +0 -0
  154. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_asset_indexing.py +0 -0
  155. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_asset_references.py +0 -0
  156. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_assets_service.py +0 -0
  157. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_async_support.py +0 -0
  158. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_batch_operations.py +0 -0
  159. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_concurrency_safety.py +0 -0
  160. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_connection_pool.py +0 -0
  161. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_connection_resilience.py +0 -0
  162. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_decorators.py +0 -0
  163. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_dirty_pipeline_fast_path.py +0 -0
  164. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_email_processing.py +0 -0
  165. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_iconv_money_to_cents.py +0 -0
  166. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_lambda_handler.py +0 -0
  167. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_lambda_handler_auth.py +0 -0
  168. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_mixins_import.py +0 -0
  169. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_n_plus_one.py +0 -0
  170. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_observability.py +0 -0
  171. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_payment_authorizenet_adapter.py +0 -0
  172. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_payment_braintree_adapter.py +0 -0
  173. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_payment_braintree_mirror.py +0 -0
  174. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_payment_profile_sorting.py +0 -0
  175. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_payment_stripe_adapter.py +0 -0
  176. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_pdf.py +0 -0
  177. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_prepared_statements.py +0 -0
  178. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_psycopg3_upgrade.py +0 -0
  179. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_query_cache.py +0 -0
  180. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_row_batch_update.py +0 -0
  181. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_row_cache_staleness.py +0 -0
  182. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_row_dirty_tracking.py +0 -0
  183. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_schema_migrations.py +0 -0
  184. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_security_hardening.py +0 -0
  185. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_server_cursor.py +0 -0
  186. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_spreadsheet_functions.py +0 -0
  187. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_sqs_per_record_transactions.py +0 -0
  188. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  189. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_table_alter.py +0 -0
  190. {velocity_python-0.1.37 → velocity_python-0.1.39}/tests/test_where_clause_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.37
3
+ Version: 0.1.39
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Velocity Team <info@codeclubs.org>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "velocity-python"
7
- version = "0.1.37"
7
+ version = "0.1.39"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.37"
1
+ __version__ = version = "0.1.39"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import time
3
3
  import random
4
+ from collections.abc import Mapping, Sequence
4
5
  from functools import wraps
5
6
  from velocity.db import exceptions
6
7
 
@@ -148,6 +149,73 @@ def return_default(
148
149
  return decorator
149
150
 
150
151
 
152
+ def _merge_schema_seed(target, value):
153
+ """Collect representative columns from dict payloads or lists of dict rows."""
154
+
155
+ if isinstance(value, Mapping):
156
+ for key, val in value.items():
157
+ if isinstance(key, str) and key not in target:
158
+ target[key] = val
159
+ return
160
+
161
+ if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray)):
162
+ for item in value:
163
+ if isinstance(item, Mapping):
164
+ _merge_schema_seed(target, item)
165
+
166
+
167
+ def _collect_schema_seed(args, kwds):
168
+ data = {}
169
+
170
+ for key in ("pk", "data"):
171
+ _merge_schema_seed(data, kwds.get(key))
172
+
173
+ for arg in args:
174
+ _merge_schema_seed(data, arg)
175
+
176
+ return data
177
+
178
+
179
+ def _normalize_conflict_columns(pk):
180
+ if pk is None:
181
+ return []
182
+ if isinstance(pk, str):
183
+ return [pk]
184
+ if isinstance(pk, Mapping):
185
+ return [str(key) for key in pk.keys()]
186
+ if isinstance(pk, Sequence) and not isinstance(pk, (str, bytes, bytearray)):
187
+ return [str(column) for column in pk]
188
+
189
+ try:
190
+ return [str(column) for column in pk]
191
+ except TypeError:
192
+ return [str(pk)]
193
+
194
+
195
+ def _infer_conflict_columns(func, args, kwds):
196
+ """Infer explicit ON CONFLICT columns for upsert operations."""
197
+
198
+ if func.__name__ not in {"merge", "upsert_many"}:
199
+ return []
200
+
201
+ pk = kwds.get("pk")
202
+ if pk is None and len(args) >= 2:
203
+ pk = args[1]
204
+
205
+ columns = [column.lower() for column in _normalize_conflict_columns(pk) if column]
206
+ if len(columns) == 1 and columns[0] == "sys_id":
207
+ return []
208
+ return columns
209
+
210
+
211
+ def _missing_conflict_constraint_error(exc):
212
+ message = str(exc or "").lower()
213
+ return (
214
+ "no unique or exclusion constraint matching the on conflict specification"
215
+ in message
216
+ )
217
+
218
+
151
219
  def create_missing(func):
152
220
  """
153
221
  If the function call fails with DbColumnMissingError or DbTableMissingError,
@@ -161,6 +229,8 @@ def create_missing(func):
161
229
 
162
230
  @wraps(func)
163
231
  def wrapper(self, *args, **kwds):
232
+ conflict_columns = _infer_conflict_columns(func, args, kwds)
233
+
164
234
  sp = self.tx.create_savepoint(cursor=self.cursor())
165
235
  try:
166
236
  result = func(self, *args, **kwds)
@@ -181,14 +251,7 @@ def create_missing(func):
181
251
  ) from e
182
252
 
183
253
  # Existing logic for automatic creation
184
- data = {}
185
- if "pk" in kwds:
186
- data.update(kwds["pk"])
187
- if "data" in kwds:
188
- data.update(kwds["data"])
189
- for i, arg in enumerate(args):
190
- if isinstance(arg, dict):
191
- data.update(arg)
254
+ data = _collect_schema_seed(args, kwds)
192
255
 
193
256
  # ALTER TABLE ADD COLUMN IF NOT EXISTS — acquire an advisory
194
257
  # lock to serialize DDL across concurrent Lambda containers,
@@ -220,15 +283,7 @@ def create_missing(func):
220
283
  ) from e
221
284
 
222
285
  # Existing logic for automatic creation
223
- data = {}
224
- if "pk" in kwds:
225
- data.update(kwds["pk"])
226
- if "data" in kwds:
227
- data.update(kwds["data"])
228
- for i, arg in enumerate(args):
229
- if isinstance(arg, dict):
230
- data.update(arg)
231
-
286
+ data = _collect_schema_seed(args, kwds)
232
287
  # CREATE TABLE IF NOT EXISTS — acquire advisory lock then
233
288
  # guard against concurrent creation with a savepoint.
234
289
  try:
@@ -242,6 +297,37 @@ def create_missing(func):
242
297
  except exceptions.DbObjectExistsError:
243
298
  self.tx.rollback_savepoint(sp2, cursor=self.cursor())
244
299
 
300
+ if conflict_columns:
301
+ self.create_index(conflict_columns, unique=True)
302
+
303
+ return func(self, *args, **kwds)
304
+ except exceptions.DbException as e:
305
+ self.tx.rollback_savepoint(sp, cursor=self.cursor())
306
+
307
+ if not conflict_columns or not _missing_conflict_constraint_error(e):
308
+ raise
309
+
310
+ if self.tx.engine.schema_locked:
311
+ logger.warning(
312
+ "@create_missing triggered on locked schema: table=%s error=%s",
313
+ self.name, e,
314
+ extra={
315
+ "table_name": self.name,
316
+ "operation": "create_missing_conflict_index",
317
+ "schema_locked": True,
318
+ },
319
+ )
320
+ raise exceptions.DbSchemaLockedError(
321
+ "Cannot create missing unique index: schema is locked. "
322
+ f"Original error: {e}"
323
+ ) from e
324
+
325
+ try:
326
+ self.tx.advisory_lock(f"velocity_ddl_{self.name}")
327
+ except Exception:
328
+ pass
329
+
330
+ self.create_index(conflict_columns, unique=True)
245
331
  return func(self, *args, **kwds)
246
332
 
247
333
  return wrapper