velocity-python 0.1.62__tar.gz → 0.1.63__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 (203) hide show
  1. {velocity_python-0.1.62 → velocity_python-0.1.63}/PKG-INFO +1 -1
  2. {velocity_python-0.1.62 → velocity_python-0.1.63}/pyproject.toml +1 -1
  3. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/__init__.py +1 -1
  4. velocity_python-0.1.63/src/velocity/db/core/jsonproxy.py +175 -0
  5. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/row.py +19 -3
  6. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/table.py +24 -7
  7. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/base/sql.py +16 -0
  8. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/mysql/types.py +7 -0
  9. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/postgres/sql.py +14 -0
  10. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/postgres/types.py +10 -0
  11. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlite/sql.py +3 -3
  12. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity_python.egg-info/PKG-INFO +1 -1
  13. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity_python.egg-info/SOURCES.txt +2 -0
  14. velocity_python-0.1.63/tests/test_json_columns.py +305 -0
  15. {velocity_python-0.1.62 → velocity_python-0.1.63}/LICENSE +0 -0
  16. {velocity_python-0.1.62 → velocity_python-0.1.63}/README.md +0 -0
  17. {velocity_python-0.1.62 → velocity_python-0.1.63}/setup.cfg +0 -0
  18. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/__init__.py +0 -0
  19. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/amplify.py +0 -0
  20. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/amplify_build.py +0 -0
  21. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/assets/__init__.py +0 -0
  22. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/assets/backfill.py +0 -0
  23. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/assets/indexing.py +0 -0
  24. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/assets/references.py +0 -0
  25. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/assets/service.py +0 -0
  26. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/assets/usage_index.py +0 -0
  27. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/dirty_pipeline.py +0 -0
  28. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/__init__.py +0 -0
  29. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/base_handler.py +0 -0
  30. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/context.py +0 -0
  31. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/context_factory.py +0 -0
  32. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/exceptions.py +0 -0
  33. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  34. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  35. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  36. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  37. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/perf.py +0 -0
  38. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/response.py +0 -0
  39. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  40. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/s3.py +0 -0
  41. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/ssm_config.py +0 -0
  42. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/tests/__init__.py +0 -0
  43. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  44. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  45. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/aws/tests/test_response.py +0 -0
  46. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/__init__.py +0 -0
  47. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/__init__.py +0 -0
  48. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/async_support.py +0 -0
  49. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/column.py +0 -0
  50. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/database.py +0 -0
  51. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/decorators.py +0 -0
  52. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/engine.py +0 -0
  53. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/result.py +0 -0
  54. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/sequence.py +0 -0
  55. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/transaction.py +0 -0
  56. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/core/view.py +0 -0
  57. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/exceptions.py +0 -0
  58. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/migrations.py +0 -0
  59. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/__init__.py +0 -0
  60. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/base/__init__.py +0 -0
  61. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/base/initializer.py +0 -0
  62. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/base/operators.py +0 -0
  63. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/base/types.py +0 -0
  64. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/mysql/__init__.py +0 -0
  65. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/mysql/operators.py +0 -0
  66. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/mysql/reserved.py +0 -0
  67. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/mysql/sql.py +0 -0
  68. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/postgres/__init__.py +0 -0
  69. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/postgres/operators.py +0 -0
  70. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/postgres/reserved.py +0 -0
  71. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  72. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlite/operators.py +0 -0
  73. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  74. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlite/types.py +0 -0
  75. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  76. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  77. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  78. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  79. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/sqlserver/types.py +0 -0
  80. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/servers/tablehelper.py +0 -0
  81. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/__init__.py +0 -0
  82. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/common_db_test.py +0 -0
  83. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/__init__.py +0 -0
  84. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/common.py +0 -0
  85. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/conftest.py +0 -0
  86. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_column.py +0 -0
  87. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  88. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_database.py +0 -0
  89. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  90. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  91. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  92. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_result.py +0 -0
  93. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_row.py +0 -0
  94. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  95. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  96. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  97. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  98. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  99. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_table.py +0 -0
  100. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  101. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  102. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/sql/__init__.py +0 -0
  103. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/sql/common.py +0 -0
  104. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  105. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  106. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  107. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_db_utils.py +0 -0
  108. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_postgres.py +0 -0
  109. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  110. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  111. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_result_caching.py +0 -0
  112. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  113. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  114. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  115. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  116. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_sql_builder.py +0 -0
  117. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_tablehelper.py +0 -0
  118. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/tests/test_view_helper.py +0 -0
  119. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/db/utils.py +0 -0
  120. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/logging.py +0 -0
  121. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/__init__.py +0 -0
  122. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/conv/__init__.py +0 -0
  123. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/conv/iconv.py +0 -0
  124. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/conv/oconv.py +0 -0
  125. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/db.py +0 -0
  126. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/export.py +0 -0
  127. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/format.py +0 -0
  128. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/mail.py +0 -0
  129. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/merge.py +0 -0
  130. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/pdf.py +0 -0
  131. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/__init__.py +0 -0
  132. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/test_db.py +0 -0
  133. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/test_fix.py +0 -0
  134. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/test_format.py +0 -0
  135. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/test_iconv.py +0 -0
  136. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/test_merge.py +0 -0
  137. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/test_oconv.py +0 -0
  138. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/test_original_error.py +0 -0
  139. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tests/test_timer.py +0 -0
  140. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/timer.py +0 -0
  141. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/misc/tools.py +0 -0
  142. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/__init__.py +0 -0
  143. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/authorizenet_adapter.py +0 -0
  144. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/authorizenet_mirror.py +0 -0
  145. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/base_adapter.py +0 -0
  146. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/braintree_adapter.py +0 -0
  147. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/braintree_mirror.py +0 -0
  148. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/charge_rules.py +0 -0
  149. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/stripe_adapter.py +0 -0
  150. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity/payment/stripe_mirror.py +0 -0
  151. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  152. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity_python.egg-info/entry_points.txt +0 -0
  153. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity_python.egg-info/requires.txt +0 -0
  154. {velocity_python-0.1.62 → velocity_python-0.1.63}/src/velocity_python.egg-info/top_level.txt +0 -0
  155. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_amplify_build.py +0 -0
  156. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_asset_indexing.py +0 -0
  157. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_asset_references.py +0 -0
  158. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_assets_service.py +0 -0
  159. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_async_support.py +0 -0
  160. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_batch_operations.py +0 -0
  161. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_concurrency_safety.py +0 -0
  162. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_connection_pool.py +0 -0
  163. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_connection_resilience.py +0 -0
  164. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_context_job_descriptions.py +0 -0
  165. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_db_credentials_ssm_cascade.py +0 -0
  166. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_decorators.py +0 -0
  167. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_dirty_pipeline_fast_path.py +0 -0
  168. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_email_processing.py +0 -0
  169. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_http_handler_rollback.py +0 -0
  170. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_iconv_money_to_cents.py +0 -0
  171. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_identifier_injection_guard.py +0 -0
  172. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_jsonb_dict_adapter.py +0 -0
  173. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_lambda_handler.py +0 -0
  174. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_lambda_handler_auth.py +0 -0
  175. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_mixins_import.py +0 -0
  176. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_n_plus_one.py +0 -0
  177. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_observability.py +0 -0
  178. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_payment_authorizenet_adapter.py +0 -0
  179. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_payment_braintree_adapter.py +0 -0
  180. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_payment_braintree_mirror.py +0 -0
  181. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_payment_profile_sorting.py +0 -0
  182. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_payment_stripe_adapter.py +0 -0
  183. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_pdf.py +0 -0
  184. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_prepared_statements.py +0 -0
  185. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_psycopg3_upgrade.py +0 -0
  186. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_query_cache.py +0 -0
  187. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_restricted_direct_tables.py +0 -0
  188. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_retry_side_effect_guard.py +0 -0
  189. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_return_default_safety.py +0 -0
  190. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_row_batch_update.py +0 -0
  191. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_row_cache_staleness.py +0 -0
  192. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_row_dirty_tracking.py +0 -0
  193. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_schema_migrations.py +0 -0
  194. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_security_hardening.py +0 -0
  195. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_server_cursor.py +0 -0
  196. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_single_autocommit_safety.py +0 -0
  197. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_spreadsheet_functions.py +0 -0
  198. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_sqs_per_record_transactions.py +0 -0
  199. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_ssm_config.py +0 -0
  200. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  201. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_table_alter.py +0 -0
  202. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_where_clause_validation.py +0 -0
  203. {velocity_python-0.1.62 → velocity_python-0.1.63}/tests/test_write_hook_create_flow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.62
3
+ Version: 0.1.63
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.62"
7
+ version = "0.1.63"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.62"
1
+ __version__ = version = "0.1.63"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -0,0 +1,175 @@
1
+ """
2
+ Live list/dict proxies for JSON column values.
3
+
4
+ A ``list`` or ``dict`` stored in a row is just a JSON column (JSONB on
5
+ PostgreSQL). ``Row.__getitem__`` wraps such values in :class:`BoundList` /
6
+ :class:`BoundDict` so in-place mutation writes the whole value back through
7
+ the owning row::
8
+
9
+ row["tags"].append("vip") # UPDATE ... SET tags = '["a","vip"]'
10
+ row["meta"]["verified"] = True # whole "meta" value written back
11
+
12
+ There are no relation declarations and no diffing: every mutation persists
13
+ the complete top-level value. Nested containers share the root's flush, so
14
+ a deep mutation also writes the root value back.
15
+ """
16
+
17
+
18
+ class _Controller:
19
+ """Shared link between a root proxy and all of its nested proxies."""
20
+
21
+ __slots__ = ("flush", "root")
22
+
23
+ def __init__(self, flush):
24
+ self.flush = flush
25
+ self.root = None
26
+
27
+ def notify(self):
28
+ self.flush(unwrap(self.root))
29
+
30
+
31
+ def bind(value, flush):
32
+ """
33
+ Wrap ``value`` (a dict or list) in a bound proxy tree.
34
+
35
+ ``flush(plain_value)`` is called with the plain (unwrapped) top-level
36
+ value after every mutation anywhere in the tree. Non-container values
37
+ are returned unchanged.
38
+ """
39
+ if not isinstance(value, (dict, list)):
40
+ return value
41
+ ctrl = _Controller(flush)
42
+ root = _wrap(value, ctrl)
43
+ ctrl.root = root
44
+ return root
45
+
46
+
47
+ def unwrap(value):
48
+ """Return a plain dict/list copy of a (possibly bound) value tree."""
49
+ if isinstance(value, dict):
50
+ return {k: unwrap(v) for k, v in value.items()}
51
+ if isinstance(value, list):
52
+ return [unwrap(v) for v in value]
53
+ return value
54
+
55
+
56
+ def _wrap(value, ctrl):
57
+ if isinstance(value, dict):
58
+ return BoundDict(value, ctrl)
59
+ if isinstance(value, list):
60
+ return BoundList(value, ctrl)
61
+ return value
62
+
63
+
64
+ class BoundList(list):
65
+ """A list whose mutations flush the root value back to its column."""
66
+
67
+ def __init__(self, iterable, ctrl):
68
+ super().__init__(_wrap(v, ctrl) for v in iterable)
69
+ self._ctrl = ctrl
70
+
71
+ # -- mutators ------------------------------------------------------
72
+ def __setitem__(self, index, value):
73
+ if isinstance(index, slice):
74
+ value = [_wrap(v, self._ctrl) for v in value]
75
+ else:
76
+ value = _wrap(value, self._ctrl)
77
+ super().__setitem__(index, value)
78
+ self._ctrl.notify()
79
+
80
+ def __delitem__(self, index):
81
+ super().__delitem__(index)
82
+ self._ctrl.notify()
83
+
84
+ def __iadd__(self, other):
85
+ self.extend(other)
86
+ return self
87
+
88
+ def __imul__(self, n):
89
+ result = super().__imul__(n)
90
+ self._ctrl.notify()
91
+ return result
92
+
93
+ def append(self, value):
94
+ super().append(_wrap(value, self._ctrl))
95
+ self._ctrl.notify()
96
+
97
+ def extend(self, iterable):
98
+ super().extend(_wrap(v, self._ctrl) for v in iterable)
99
+ self._ctrl.notify()
100
+
101
+ def insert(self, index, value):
102
+ super().insert(index, _wrap(value, self._ctrl))
103
+ self._ctrl.notify()
104
+
105
+ def remove(self, value):
106
+ super().remove(value)
107
+ self._ctrl.notify()
108
+
109
+ def pop(self, index=-1):
110
+ result = super().pop(index)
111
+ self._ctrl.notify()
112
+ return result
113
+
114
+ def clear(self):
115
+ super().clear()
116
+ self._ctrl.notify()
117
+
118
+ def sort(self, **kwds):
119
+ super().sort(**kwds)
120
+ self._ctrl.notify()
121
+
122
+ def reverse(self):
123
+ super().reverse()
124
+ self._ctrl.notify()
125
+
126
+
127
+ class BoundDict(dict):
128
+ """A dict whose mutations flush the root value back to its column."""
129
+
130
+ def __init__(self, mapping, ctrl):
131
+ super().__init__({k: _wrap(v, ctrl) for k, v in mapping.items()})
132
+ self._ctrl = ctrl
133
+
134
+ # -- mutators ------------------------------------------------------
135
+ def __setitem__(self, key, value):
136
+ super().__setitem__(key, _wrap(value, self._ctrl))
137
+ self._ctrl.notify()
138
+
139
+ def __delitem__(self, key):
140
+ super().__delitem__(key)
141
+ self._ctrl.notify()
142
+
143
+ def update(self, dict_=None, **kwds):
144
+ data = {}
145
+ if dict_:
146
+ data.update(dict_)
147
+ data.update(kwds)
148
+ for k, v in data.items():
149
+ super().__setitem__(k, _wrap(v, self._ctrl))
150
+ if data:
151
+ self._ctrl.notify()
152
+
153
+ def pop(self, key, *args):
154
+ existed = key in self
155
+ result = super().pop(key, *args)
156
+ if existed:
157
+ self._ctrl.notify()
158
+ return result
159
+
160
+ def popitem(self):
161
+ result = super().popitem()
162
+ self._ctrl.notify()
163
+ return result
164
+
165
+ def clear(self):
166
+ super().clear()
167
+ self._ctrl.notify()
168
+
169
+ def setdefault(self, key, default=None):
170
+ if key in self:
171
+ return self[key]
172
+ wrapped = _wrap(default, self._ctrl)
173
+ super().__setitem__(key, wrapped)
174
+ self._ctrl.notify()
175
+ return wrapped
@@ -2,6 +2,7 @@ import pprint
2
2
  import time as _time
3
3
  from collections.abc import MutableMapping
4
4
  from velocity.db.exceptions import DbColumnMissingError
5
+ from velocity.db.core import jsonproxy
5
6
 
6
7
 
7
8
  # Attributes that live on the Row instance itself and must never be
@@ -133,9 +134,24 @@ class Row(MutableMapping):
133
134
  return self.pk[key]
134
135
  cache = self._ensure_cache()
135
136
  if key in cache:
136
- return cache[key]
137
+ val = cache[key]
138
+ # JSON columns come back as plain dict/list — wrap them in live
139
+ # proxies so in-place mutation writes the whole value back.
140
+ if isinstance(val, (dict, list)) and not isinstance(
141
+ val, (jsonproxy.BoundDict, jsonproxy.BoundList)
142
+ ):
143
+ val = jsonproxy.bind(
144
+ val, lambda plain, _k=key: self.__setitem__(_k, plain)
145
+ )
146
+ cache[key] = val
147
+ return val
137
148
  # Fall back to a direct DB fetch for columns not in the initial SELECT
138
- return self.table.get_value(key, self.pk)
149
+ val = self.table.get_value(key, self.pk)
150
+ if isinstance(val, (dict, list)):
151
+ val = jsonproxy.bind(
152
+ val, lambda plain, _k=key: self.__setitem__(_k, plain)
153
+ )
154
+ return val
139
155
 
140
156
  def __setitem__(self, key, val):
141
157
  if key in self.pk:
@@ -327,7 +343,7 @@ class Row(MutableMapping):
327
343
  """
328
344
  Returns the row as a dictionary (from cache or via a SELECT on self.pk).
329
345
  """
330
- return dict(self._ensure_cache())
346
+ return {k: jsonproxy.unwrap(v) for k, v in self._ensure_cache().items()}
331
347
 
332
348
  def extract(self, *args):
333
349
  """
@@ -1984,12 +1984,21 @@ class Table:
1984
1984
  _ddl_logger.warning("DDL ALTER COLUMN TYPE on %s column=%s", self.name, column)
1985
1985
  self.tx.execute(sql, vals, cursor=self.cursor())
1986
1986
 
1987
+ def _adapt_data(self, data):
1988
+ """
1989
+ Apply the dialect's data-value adaptation (e.g. dict/list -> JSONB on
1990
+ PostgreSQL, JSON text elsewhere) to a column->value mapping. Used for
1991
+ INSERT/UPDATE data only — WHERE values keep native driver adaptation.
1992
+ """
1993
+ adapt = self.sql.adapt_data_value
1994
+ return {k: adapt(v) for k, v in data.items()}
1995
+
1987
1996
  @create_missing
1988
1997
  def update(self, data, where=None, pk=None, **kwds):
1989
1998
  """
1990
1999
  Performs an UPDATE of rows matching `where` or `pk` with `data`.
1991
2000
  """
1992
- sql, vals = self.sql.update(self.tx, self.name, data, where, pk)
2001
+ sql, vals = self.sql.update(self.tx, self.name, self._adapt_data(data), where, pk)
1993
2002
  if kwds.get("sql_only", False):
1994
2003
  return sql, vals
1995
2004
  self.tx.invalidate_cache(self.name)
@@ -2002,7 +2011,7 @@ class Table:
2002
2011
  """
2003
2012
  Performs an INSERT of the given data into this table. Resets sys_id on duplicate keys if needed.
2004
2013
  """
2005
- sql, vals = self.sql.insert(self.name, data)
2014
+ sql, vals = self.sql.insert(self.name, self._adapt_data(data))
2006
2015
  if kwds.get("sql_only", False):
2007
2016
  return sql, vals
2008
2017
  self.tx.invalidate_cache(self.name)
@@ -2018,7 +2027,7 @@ class Table:
2018
2027
  sql, vals = self.sql.merge(
2019
2028
  self.tx,
2020
2029
  self.name,
2021
- data,
2030
+ self._adapt_data(data),
2022
2031
  pk,
2023
2032
  on_conflict_do_nothing=False,
2024
2033
  on_conflict_update=True,
@@ -2047,7 +2056,9 @@ class Table:
2047
2056
  """
2048
2057
  if not rows:
2049
2058
  return 0
2050
- sql, args_list, template = self.sql.insert_many(self.name, rows)
2059
+ sql, args_list, template = self.sql.insert_many(
2060
+ self.name, [self._adapt_data(row) for row in rows]
2061
+ )
2051
2062
  page_size = kwds.get("page_size", 1000)
2052
2063
  self.tx.invalidate_cache(self.name)
2053
2064
  return self.tx._execute_values(sql, args_list, template=template, page_size=page_size)
@@ -2068,7 +2079,9 @@ class Table:
2068
2079
  """
2069
2080
  if not rows:
2070
2081
  return 0
2071
- sql, args_list, template = self.sql.merge_many(self.tx, self.name, rows, pk=pk)
2082
+ sql, args_list, template = self.sql.merge_many(
2083
+ self.tx, self.name, [self._adapt_data(row) for row in rows], pk=pk
2084
+ )
2072
2085
  page_size = kwds.get("page_size", 1000)
2073
2086
  self.tx.invalidate_cache(self.name)
2074
2087
  return self.tx._execute_values(sql, args_list, template=template, page_size=page_size)
@@ -2172,7 +2185,9 @@ class Table:
2172
2185
  "Current SQL dialect does not support insert-if-not-exists operations."
2173
2186
  )
2174
2187
 
2175
- sql, vals = ins_builder(self.tx, self.name, insert_payload, exists_where)
2188
+ sql, vals = ins_builder(
2189
+ self.tx, self.name, self._adapt_data(insert_payload), exists_where
2190
+ )
2176
2191
  if sql_only:
2177
2192
  return {"update": update_stmt, "insert": (sql, vals)}
2178
2193
  result = self.tx.execute(sql, vals, cursor=self.cursor())
@@ -2200,7 +2215,9 @@ class Table:
2200
2215
  must be present in `data`.
2201
2216
  :return: rowcount (0 or 1) or (sql, params) when sql_only=True
2202
2217
  """
2203
- sql, vals = self.sql.insert_if_not_exists(self.tx, self.name, data, where)
2218
+ sql, vals = self.sql.insert_if_not_exists(
2219
+ self.tx, self.name, self._adapt_data(data), where
2220
+ )
2204
2221
  if kwds.get("sql_only", False):
2205
2222
  return sql, vals
2206
2223
  result = self.tx.execute(sql, vals, cursor=self.cursor())
@@ -2,6 +2,7 @@
2
2
  Abstract base class for SQL dialect implementations.
3
3
  """
4
4
 
5
+ import json
5
6
  from abc import ABC, abstractmethod
6
7
  from typing import Any, Dict, List, Optional, Tuple, Union
7
8
 
@@ -38,6 +39,21 @@ class BaseSQLDialect(ABC):
38
39
  DatabaseObjectExistsErrorCodes: List[str] = []
39
40
  DataIntegrityErrorCodes: List[str] = []
40
41
 
42
+ @classmethod
43
+ def adapt_data_value(cls, val: Any) -> Any:
44
+ """
45
+ Adapt a Python value being written to a column (INSERT/UPDATE data
46
+ values only — never WHERE parameters, which keep their native driver
47
+ adaptation, e.g. list -> ANY(...) on PostgreSQL).
48
+
49
+ Default: serialize dict/list to a JSON string for backends without a
50
+ native JSON parameter adapter (SQLite, SQL Server, MySQL). PostgreSQL
51
+ overrides this to bind JSONB natively.
52
+ """
53
+ if isinstance(val, (dict, list)):
54
+ return json.dumps(val)
55
+ return val
56
+
41
57
  @classmethod
42
58
  def quote_identifier(cls, name: str) -> str:
43
59
  """Always-quote a single SQL identifier to prevent injection.
@@ -23,6 +23,7 @@ class TYPES(BaseTypes):
23
23
  LONGTEXT = "LONGTEXT"
24
24
  MEDIUMTEXT = "MEDIUMTEXT"
25
25
  VARCHAR = "VARCHAR"
26
+ JSON = "JSON"
26
27
 
27
28
  @classmethod
28
29
  def get_type(cls, v):
@@ -51,6 +52,8 @@ class TYPES(BaseTypes):
51
52
  return cls.TIME
52
53
  if isinstance(v, bytes) or v is bytes:
53
54
  return cls.BINARY
55
+ if isinstance(v, (dict, list)) or v is dict or v is list:
56
+ return cls.JSON
54
57
  return cls.TEXT
55
58
 
56
59
  @classmethod
@@ -80,6 +83,8 @@ class TYPES(BaseTypes):
80
83
  return cls.TIME
81
84
  if isinstance(v, bytes) or v is bytes:
82
85
  return cls.BINARY
86
+ if isinstance(v, (dict, list)) or v is dict or v is list:
87
+ return cls.JSON
83
88
  return cls.TEXT
84
89
 
85
90
  @classmethod
@@ -108,4 +113,6 @@ class TYPES(BaseTypes):
108
113
  return datetime.datetime
109
114
  if v == cls.BINARY or "BLOB" in v:
110
115
  return bytes
116
+ if v == cls.JSON:
117
+ return dict
111
118
  raise Exception(f"Unmapped MySQL type {v}")
@@ -71,6 +71,20 @@ class SQL(BaseSQLDialect):
71
71
  DatabaseObjectExistsErrorCodes = ["42710", "42P07", "42P04"]
72
72
  DataIntegrityErrorCodes = ["23503", "23502", "23514", "23P01", "22003"]
73
73
 
74
+ @classmethod
75
+ def adapt_data_value(cls, val):
76
+ """
77
+ Bind dict/list data values as JSONB. Lists must be wrapped here
78
+ because psycopg's native list adaptation targets PostgreSQL arrays
79
+ (kept for WHERE params, e.g. ``= ANY(%s)``); bare dicts also work via
80
+ the engine-registered dumper, but wrapping both keeps it uniform.
81
+ """
82
+ if isinstance(val, (dict, list)):
83
+ from psycopg.types.json import Jsonb
84
+
85
+ return Jsonb(val)
86
+ return val
87
+
74
88
  @classmethod
75
89
  def get_error(cls, e):
76
90
  # psycopg v3 uses 'sqlstate'; psycopg2 used 'pgcode'.
@@ -23,6 +23,8 @@ class TYPES(BaseTypes):
23
23
  BOOLEAN = "BOOLEAN"
24
24
  BINARY = "BYTEA"
25
25
  INTERVAL = "INTERVAL"
26
+ JSONB = "JSONB"
27
+ JSON = "JSON"
26
28
 
27
29
  @classmethod
28
30
  def get_type(cls, v):
@@ -52,6 +54,8 @@ class TYPES(BaseTypes):
52
54
  return cls.INTERVAL
53
55
  if isinstance(v, bytes) or v is bytes:
54
56
  return cls.BINARY
57
+ if isinstance(v, (dict, list)) or v is dict or v is list:
58
+ return cls.JSONB
55
59
  return cls.TEXT
56
60
 
57
61
  @classmethod
@@ -81,6 +85,8 @@ class TYPES(BaseTypes):
81
85
  return cls.INTERVAL
82
86
  if isinstance(v, bytes) or v is bytes:
83
87
  return cls.BINARY
88
+ if isinstance(v, (dict, list)) or v is dict or v is list:
89
+ return cls.JSONB
84
90
  return cls.TEXT
85
91
 
86
92
  @classmethod
@@ -107,4 +113,8 @@ class TYPES(BaseTypes):
107
113
  return datetime.timedelta
108
114
  if v == cls.DATETIME_TZ or v == cls.TIMESTAMP_TZ:
109
115
  return datetime.datetime
116
+ if v == cls.JSONB or v == cls.JSON:
117
+ # JSON columns hold either a dict or a list; dict is the
118
+ # canonical marker type for schema purposes.
119
+ return dict
110
120
  raise Exception(f"Unmapped type {v}")
@@ -660,15 +660,15 @@ END;
660
660
 
661
661
  @classmethod
662
662
  def create_savepoint(cls, sp):
663
- return f"SAVEPOINT {sp}"
663
+ return f"SAVEPOINT {sp}", tuple()
664
664
 
665
665
  @classmethod
666
666
  def release_savepoint(cls, sp):
667
- return f"RELEASE SAVEPOINT {sp}"
667
+ return f"RELEASE SAVEPOINT {sp}", tuple()
668
668
 
669
669
  @classmethod
670
670
  def rollback_savepoint(cls, sp):
671
- return f"ROLLBACK TO SAVEPOINT {sp}"
671
+ return f"ROLLBACK TO SAVEPOINT {sp}", tuple()
672
672
 
673
673
  @classmethod
674
674
  def create_view(cls, name, query, temp=False, silent=True):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.62
3
+ Version: 0.1.63
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
@@ -41,6 +41,7 @@ src/velocity/db/core/column.py
41
41
  src/velocity/db/core/database.py
42
42
  src/velocity/db/core/decorators.py
43
43
  src/velocity/db/core/engine.py
44
+ src/velocity/db/core/jsonproxy.py
44
45
  src/velocity/db/core/result.py
45
46
  src/velocity/db/core/row.py
46
47
  src/velocity/db/core/sequence.py
@@ -165,6 +166,7 @@ tests/test_email_processing.py
165
166
  tests/test_http_handler_rollback.py
166
167
  tests/test_iconv_money_to_cents.py
167
168
  tests/test_identifier_injection_guard.py
169
+ tests/test_json_columns.py
168
170
  tests/test_jsonb_dict_adapter.py
169
171
  tests/test_lambda_handler.py
170
172
  tests/test_lambda_handler_auth.py