velocity-python 0.1.43__tar.gz → 0.1.45__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.43/src/velocity_python.egg-info → velocity_python-0.1.45}/PKG-INFO +1 -1
  2. {velocity_python-0.1.43 → velocity_python-0.1.45}/pyproject.toml +1 -1
  3. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/table.py +75 -11
  5. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/tablehelper.py +11 -0
  6. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_tablehelper.py +23 -0
  7. {velocity_python-0.1.43 → velocity_python-0.1.45/src/velocity_python.egg-info}/PKG-INFO +1 -1
  8. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_table_alter.py +48 -0
  9. {velocity_python-0.1.43 → velocity_python-0.1.45}/LICENSE +0 -0
  10. {velocity_python-0.1.43 → velocity_python-0.1.45}/README.md +0 -0
  11. {velocity_python-0.1.43 → velocity_python-0.1.45}/setup.cfg +0 -0
  12. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/__init__.py +0 -0
  13. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/amplify.py +0 -0
  14. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/amplify_build.py +0 -0
  15. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/assets/__init__.py +0 -0
  16. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/assets/backfill.py +0 -0
  17. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/assets/indexing.py +0 -0
  18. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/assets/references.py +0 -0
  19. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/assets/service.py +0 -0
  20. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/assets/usage_index.py +0 -0
  21. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/dirty_pipeline.py +0 -0
  22. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/__init__.py +0 -0
  23. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/base_handler.py +0 -0
  24. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/context.py +0 -0
  25. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/context_factory.py +0 -0
  26. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/exceptions.py +0 -0
  27. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  28. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  29. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  30. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  31. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/perf.py +0 -0
  32. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/response.py +0 -0
  33. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  34. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/s3.py +0 -0
  35. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/ssm_config.py +0 -0
  36. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/tests/__init__.py +0 -0
  37. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  38. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  39. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/aws/tests/test_response.py +0 -0
  40. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/__init__.py +0 -0
  41. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/__init__.py +0 -0
  42. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/async_support.py +0 -0
  43. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/column.py +0 -0
  44. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/database.py +0 -0
  45. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/decorators.py +0 -0
  46. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/engine.py +0 -0
  47. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/result.py +0 -0
  48. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/row.py +0 -0
  49. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/sequence.py +0 -0
  50. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/transaction.py +0 -0
  51. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/core/view.py +0 -0
  52. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/exceptions.py +0 -0
  53. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/migrations.py +0 -0
  54. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/__init__.py +0 -0
  55. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/base/__init__.py +0 -0
  56. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/base/initializer.py +0 -0
  57. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/base/operators.py +0 -0
  58. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/base/sql.py +0 -0
  59. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/base/types.py +0 -0
  60. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/mysql/__init__.py +0 -0
  61. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/mysql/operators.py +0 -0
  62. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/mysql/reserved.py +0 -0
  63. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/mysql/sql.py +0 -0
  64. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/mysql/types.py +0 -0
  65. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/postgres/__init__.py +0 -0
  66. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/postgres/operators.py +0 -0
  67. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/postgres/reserved.py +0 -0
  68. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/postgres/sql.py +0 -0
  69. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/postgres/types.py +0 -0
  70. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  71. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlite/operators.py +0 -0
  72. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  73. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlite/sql.py +0 -0
  74. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlite/types.py +0 -0
  75. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  76. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  77. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  78. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  79. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/servers/sqlserver/types.py +0 -0
  80. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/__init__.py +0 -0
  81. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/common_db_test.py +0 -0
  82. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/__init__.py +0 -0
  83. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/common.py +0 -0
  84. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_column.py +0 -0
  85. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  86. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_database.py +0 -0
  87. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  88. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  89. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  90. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_result.py +0 -0
  91. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_row.py +0 -0
  92. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  93. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  94. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  95. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  96. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  97. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_table.py +0 -0
  98. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  99. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  100. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/sql/__init__.py +0 -0
  101. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/sql/common.py +0 -0
  102. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  103. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  104. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  105. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_db_utils.py +0 -0
  106. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_postgres.py +0 -0
  107. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  108. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  109. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_result_caching.py +0 -0
  110. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  111. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  112. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  113. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  114. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_sql_builder.py +0 -0
  115. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/tests/test_view_helper.py +0 -0
  116. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/db/utils.py +0 -0
  117. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/logging.py +0 -0
  118. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/__init__.py +0 -0
  119. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/conv/__init__.py +0 -0
  120. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/conv/iconv.py +0 -0
  121. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/conv/oconv.py +0 -0
  122. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/db.py +0 -0
  123. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/export.py +0 -0
  124. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/format.py +0 -0
  125. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/mail.py +0 -0
  126. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/merge.py +0 -0
  127. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/pdf.py +0 -0
  128. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/__init__.py +0 -0
  129. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/test_db.py +0 -0
  130. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/test_fix.py +0 -0
  131. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/test_format.py +0 -0
  132. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/test_iconv.py +0 -0
  133. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/test_merge.py +0 -0
  134. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/test_oconv.py +0 -0
  135. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/test_original_error.py +0 -0
  136. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tests/test_timer.py +0 -0
  137. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/timer.py +0 -0
  138. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/misc/tools.py +0 -0
  139. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/__init__.py +0 -0
  140. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/authorizenet_adapter.py +0 -0
  141. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/authorizenet_mirror.py +0 -0
  142. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/base_adapter.py +0 -0
  143. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/braintree_adapter.py +0 -0
  144. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/braintree_mirror.py +0 -0
  145. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/charge_rules.py +0 -0
  146. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/stripe_adapter.py +0 -0
  147. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity/payment/stripe_mirror.py +0 -0
  148. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity_python.egg-info/SOURCES.txt +0 -0
  149. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  150. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity_python.egg-info/entry_points.txt +0 -0
  151. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity_python.egg-info/requires.txt +0 -0
  152. {velocity_python-0.1.43 → velocity_python-0.1.45}/src/velocity_python.egg-info/top_level.txt +0 -0
  153. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_amplify_build.py +0 -0
  154. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_asset_indexing.py +0 -0
  155. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_asset_references.py +0 -0
  156. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_assets_service.py +0 -0
  157. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_async_support.py +0 -0
  158. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_batch_operations.py +0 -0
  159. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_concurrency_safety.py +0 -0
  160. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_connection_pool.py +0 -0
  161. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_connection_resilience.py +0 -0
  162. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_context_job_descriptions.py +0 -0
  163. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_decorators.py +0 -0
  164. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_dirty_pipeline_fast_path.py +0 -0
  165. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_email_processing.py +0 -0
  166. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_iconv_money_to_cents.py +0 -0
  167. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_lambda_handler.py +0 -0
  168. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_lambda_handler_auth.py +0 -0
  169. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_mixins_import.py +0 -0
  170. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_n_plus_one.py +0 -0
  171. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_observability.py +0 -0
  172. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_payment_authorizenet_adapter.py +0 -0
  173. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_payment_braintree_adapter.py +0 -0
  174. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_payment_braintree_mirror.py +0 -0
  175. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_payment_profile_sorting.py +0 -0
  176. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_payment_stripe_adapter.py +0 -0
  177. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_pdf.py +0 -0
  178. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_prepared_statements.py +0 -0
  179. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_psycopg3_upgrade.py +0 -0
  180. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_query_cache.py +0 -0
  181. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_row_batch_update.py +0 -0
  182. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_row_cache_staleness.py +0 -0
  183. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_row_dirty_tracking.py +0 -0
  184. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_schema_migrations.py +0 -0
  185. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_security_hardening.py +0 -0
  186. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_server_cursor.py +0 -0
  187. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_spreadsheet_functions.py +0 -0
  188. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_sqs_per_record_transactions.py +0 -0
  189. {velocity_python-0.1.43 → velocity_python-0.1.45}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  190. {velocity_python-0.1.43 → velocity_python-0.1.45}/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.43
3
+ Version: 0.1.45
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.43"
7
+ version = "0.1.45"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.43"
1
+ __version__ = version = "0.1.45"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -234,6 +234,63 @@ def _normalize_index_expression(expression):
234
234
  return normalized.strip().lower()
235
235
 
236
236
 
237
+ def _split_top_level_boolean_terms(expression):
238
+ parts = []
239
+ operators = []
240
+ start = 0
241
+ depth = 0
242
+ position = 0
243
+ while position < len(expression):
244
+ char = expression[position]
245
+ if char == "(":
246
+ depth += 1
247
+ position += 1
248
+ continue
249
+ if char == ")":
250
+ depth = max(0, depth - 1)
251
+ position += 1
252
+ continue
253
+ if depth == 0:
254
+ lowered = expression[position:].lower()
255
+ for operator in (" and ", " or "):
256
+ if lowered.startswith(operator):
257
+ parts.append(expression[start:position].strip())
258
+ operators.append(operator.strip())
259
+ position += len(operator)
260
+ start = position
261
+ break
262
+ else:
263
+ position += 1
264
+ continue
265
+ position += 1
266
+
267
+ if operators:
268
+ parts.append(expression[start:].strip())
269
+
270
+ return parts, operators
271
+
272
+
273
+ def _normalize_index_where_clause(expression):
274
+ normalized = _normalize_index_expression(expression)
275
+ parts, operators = _split_top_level_boolean_terms(normalized)
276
+ if not operators:
277
+ return normalized
278
+
279
+ simplified_parts = []
280
+ for part in parts:
281
+ stripped = _strip_redundant_outer_parens(part)
282
+ nested_parts, nested_operators = _split_top_level_boolean_terms(stripped)
283
+ if nested_operators:
284
+ simplified_parts.append(part)
285
+ else:
286
+ simplified_parts.append(stripped)
287
+
288
+ combined = [simplified_parts[0]]
289
+ for operator, part in zip(operators, simplified_parts[1:]):
290
+ combined.extend([operator, part])
291
+ return " ".join(combined).strip()
292
+
293
+
237
294
  def _parse_index_signature(index_sql):
238
295
  normalized_sql = " ".join(str(index_sql or "").split())
239
296
  upper_sql = normalized_sql.upper()
@@ -257,7 +314,7 @@ def _parse_index_signature(index_sql):
257
314
  where_clause = None
258
315
  where_pos = upper_sql.find(" WHERE ", closing_index)
259
316
  if where_pos != -1:
260
- where_clause = _normalize_index_expression(normalized_sql[where_pos + 7 :])
317
+ where_clause = _normalize_index_where_clause(normalized_sql[where_pos + 7 :])
261
318
 
262
319
  return {
263
320
  "name": index_name,
@@ -686,16 +743,23 @@ class Table:
686
743
  return signatures
687
744
 
688
745
  def _desired_index_signature(self, spec):
689
- sql, _vals = self.create_index(
690
- spec["columns"],
691
- unique=spec["unique"],
692
- direction=spec["direction"],
693
- where=spec["where"],
694
- lower=spec["lower"],
695
- name=spec["name"],
696
- sql_only=True,
697
- )
698
- return _parse_index_signature(sql)
746
+ columns = []
747
+ for column_name in spec["columns"]:
748
+ normalized_column = _normalize_identifier(column_name)
749
+ if spec.get("lower"):
750
+ normalized_column = f"lower({normalized_column})"
751
+ columns.append(normalized_column)
752
+
753
+ return {
754
+ "name": _normalize_identifier(spec.get("name")) if spec.get("name") else None,
755
+ "unique": bool(spec.get("unique")),
756
+ "columns": tuple(columns),
757
+ "where": (
758
+ _normalize_index_where_clause(spec.get("where"))
759
+ if spec.get("where")
760
+ else None
761
+ ),
762
+ }
699
763
 
700
764
  def _existing_foreign_key_signatures(self):
701
765
  sql, vals = self.sql.foreign_key_info(table=self.name, column=None)
@@ -196,6 +196,17 @@ class TableHelper:
196
196
 
197
197
  alias = self.get_table_alias("current_table")
198
198
  if not self.has_pointer(column):
199
+ raw_expression = self.remove_operator(key).strip()
200
+ if column.upper() in self.reserved and re.search(
201
+ r"(?i)\bcase\s+when\b|\bexists\s*\(|\bselect\b|\bfrom\b|\bwhere\b",
202
+ raw_expression,
203
+ ):
204
+ if options.get("bypass_on_error"):
205
+ return key
206
+ raise ValueError(
207
+ f"Could not safely resolve complex SQL expression: {key}"
208
+ )
209
+
199
210
  # Standard column - no pointer syntax
200
211
  if (
201
212
  options.get("alias_table")
@@ -198,6 +198,29 @@ class TestTableHelper(unittest.TestCase):
198
198
  f"Failed for '{input_expr}': expected '{expected}', got '{result}'",
199
199
  )
200
200
 
201
+ def test_resolve_references_preserves_complex_case_exists_expression(self):
202
+ """Complex CASE/EXISTS expressions should remain raw when not safely rewritable."""
203
+ original_reserved = TableHelper.reserved
204
+ TableHelper.reserved = ["CASE", "WHEN", "THEN", "ELSE", "END", "EXISTS"]
205
+ try:
206
+ expr = """coalesce(sum(case when exists (
207
+ select 1
208
+ from donor_users du
209
+ where lower(du.email_address) = lower(swipegive_settings.email_address)
210
+ and lower(coalesce(nullif(du.plaid_status, ''), 'ready')) not in ('error', 'purged')
211
+ ) then 1 else 0 end), 0) as active"""
212
+ result = self.helper.resolve_references(
213
+ expr,
214
+ options={
215
+ "alias_column": True,
216
+ "alias_table": True,
217
+ "bypass_on_error": True,
218
+ },
219
+ )
220
+ self.assertEqual(result, expr)
221
+ finally:
222
+ TableHelper.reserved = original_reserved
223
+
201
224
  def test_extract_column_name_cast_expressions(self):
202
225
  """Test extracting column names from CAST expressions"""
203
226
  test_cases = [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.43
3
+ Version: 0.1.45
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
@@ -558,6 +558,54 @@ class TableAlterTests(unittest.TestCase):
558
558
  _parse_index_signature(desired),
559
559
  )
560
560
 
561
+ def test_parse_index_signature_ignores_redundant_boolean_term_parentheses(self):
562
+ existing = (
563
+ "CREATE INDEX idx_pending_transactions_scheduled_capture_at "
564
+ "ON public.pending_transactions USING btree (scheduled_capture_at) "
565
+ "WHERE ((status = 'authorized'::text) AND (captured_at IS NULL) AND "
566
+ "(canceled_at IS NULL))"
567
+ )
568
+ desired = (
569
+ "CREATE INDEX idx_pending_transactions_scheduled_capture_at "
570
+ "ON pending_transactions (scheduled_capture_at) "
571
+ "WHERE status = 'authorized' AND captured_at IS NULL AND canceled_at IS NULL"
572
+ )
573
+
574
+ self.assertEqual(
575
+ _parse_index_signature(existing),
576
+ _parse_index_signature(desired),
577
+ )
578
+
579
+ def test_desired_index_signature_allows_system_columns_not_in_declared_spec(self):
580
+ table = FakeTable(
581
+ PostgresSQL,
582
+ {
583
+ "product_sys_id": {"type": "BIGINT", "nullable": False},
584
+ },
585
+ )
586
+
587
+ signature = Table._desired_index_signature(
588
+ table,
589
+ {
590
+ "name": "idx_inventory_ledger_product_sys_id_sys_id",
591
+ "columns": ["product_sys_id", "sys_id"],
592
+ "unique": False,
593
+ "direction": None,
594
+ "where": None,
595
+ "lower": None,
596
+ },
597
+ )
598
+
599
+ self.assertEqual(
600
+ signature,
601
+ {
602
+ "name": "idx_inventory_ledger_product_sys_id_sys_id",
603
+ "unique": False,
604
+ "columns": ("product_sys_id", "sys_id"),
605
+ "where": None,
606
+ },
607
+ )
608
+
561
609
 
562
610
  if __name__ == "__main__":
563
611
  unittest.main()