velocity-python 0.0.109__py3-none-any.whl → 0.0.161__py3-none-any.whl

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 (120) hide show
  1. velocity/__init__.py +3 -1
  2. velocity/app/orders.py +3 -4
  3. velocity/app/tests/__init__.py +1 -0
  4. velocity/app/tests/test_email_processing.py +112 -0
  5. velocity/app/tests/test_payment_profile_sorting.py +191 -0
  6. velocity/app/tests/test_spreadsheet_functions.py +124 -0
  7. velocity/aws/__init__.py +3 -0
  8. velocity/aws/amplify.py +10 -6
  9. velocity/aws/handlers/__init__.py +2 -0
  10. velocity/aws/handlers/base_handler.py +248 -0
  11. velocity/aws/handlers/context.py +251 -2
  12. velocity/aws/handlers/exceptions.py +16 -0
  13. velocity/aws/handlers/lambda_handler.py +24 -85
  14. velocity/aws/handlers/mixins/__init__.py +16 -0
  15. velocity/aws/handlers/mixins/activity_tracker.py +181 -0
  16. velocity/aws/handlers/mixins/aws_session_mixin.py +192 -0
  17. velocity/aws/handlers/mixins/error_handler.py +192 -0
  18. velocity/aws/handlers/mixins/legacy_mixin.py +53 -0
  19. velocity/aws/handlers/mixins/standard_mixin.py +73 -0
  20. velocity/aws/handlers/response.py +1 -1
  21. velocity/aws/handlers/sqs_handler.py +28 -143
  22. velocity/aws/tests/__init__.py +1 -0
  23. velocity/aws/tests/test_lambda_handler_json_serialization.py +120 -0
  24. velocity/aws/tests/test_response.py +163 -0
  25. velocity/db/__init__.py +16 -4
  26. velocity/db/core/decorators.py +48 -13
  27. velocity/db/core/engine.py +187 -840
  28. velocity/db/core/result.py +33 -25
  29. velocity/db/core/row.py +15 -3
  30. velocity/db/core/table.py +493 -50
  31. velocity/db/core/transaction.py +28 -15
  32. velocity/db/exceptions.py +42 -18
  33. velocity/db/servers/base/__init__.py +9 -0
  34. velocity/db/servers/base/initializer.py +70 -0
  35. velocity/db/servers/base/operators.py +98 -0
  36. velocity/db/servers/base/sql.py +503 -0
  37. velocity/db/servers/base/types.py +135 -0
  38. velocity/db/servers/mysql/__init__.py +73 -0
  39. velocity/db/servers/mysql/operators.py +54 -0
  40. velocity/db/servers/{mysql_reserved.py → mysql/reserved.py} +2 -14
  41. velocity/db/servers/mysql/sql.py +718 -0
  42. velocity/db/servers/mysql/types.py +107 -0
  43. velocity/db/servers/postgres/__init__.py +59 -11
  44. velocity/db/servers/postgres/operators.py +34 -0
  45. velocity/db/servers/postgres/sql.py +474 -120
  46. velocity/db/servers/postgres/types.py +88 -2
  47. velocity/db/servers/sqlite/__init__.py +61 -0
  48. velocity/db/servers/sqlite/operators.py +52 -0
  49. velocity/db/servers/sqlite/reserved.py +20 -0
  50. velocity/db/servers/sqlite/sql.py +677 -0
  51. velocity/db/servers/sqlite/types.py +92 -0
  52. velocity/db/servers/sqlserver/__init__.py +73 -0
  53. velocity/db/servers/sqlserver/operators.py +47 -0
  54. velocity/db/servers/sqlserver/reserved.py +32 -0
  55. velocity/db/servers/sqlserver/sql.py +805 -0
  56. velocity/db/servers/sqlserver/types.py +114 -0
  57. velocity/db/servers/tablehelper.py +117 -91
  58. velocity/db/tests/__init__.py +1 -0
  59. velocity/db/tests/common_db_test.py +0 -0
  60. velocity/db/tests/postgres/__init__.py +1 -0
  61. velocity/db/tests/postgres/common.py +49 -0
  62. velocity/db/tests/postgres/test_column.py +29 -0
  63. velocity/db/tests/postgres/test_connections.py +25 -0
  64. velocity/db/tests/postgres/test_database.py +21 -0
  65. velocity/db/tests/postgres/test_engine.py +205 -0
  66. velocity/db/tests/postgres/test_general_usage.py +88 -0
  67. velocity/db/tests/postgres/test_imports.py +8 -0
  68. velocity/db/tests/postgres/test_result.py +19 -0
  69. velocity/db/tests/postgres/test_row.py +137 -0
  70. velocity/db/tests/postgres/test_row_comprehensive.py +720 -0
  71. velocity/db/tests/postgres/test_schema_locking.py +335 -0
  72. velocity/db/tests/postgres/test_schema_locking_unit.py +115 -0
  73. velocity/db/tests/postgres/test_sequence.py +34 -0
  74. velocity/db/tests/postgres/test_sql_comprehensive.py +462 -0
  75. velocity/db/tests/postgres/test_table.py +101 -0
  76. velocity/db/tests/postgres/test_table_comprehensive.py +646 -0
  77. velocity/db/tests/postgres/test_transaction.py +106 -0
  78. velocity/db/tests/sql/__init__.py +1 -0
  79. velocity/db/tests/sql/common.py +177 -0
  80. velocity/db/tests/sql/test_postgres_select_advanced.py +285 -0
  81. velocity/db/tests/sql/test_postgres_select_variances.py +517 -0
  82. velocity/db/tests/test_cursor_rowcount_fix.py +150 -0
  83. velocity/db/tests/test_db_utils.py +270 -0
  84. velocity/db/tests/test_postgres.py +448 -0
  85. velocity/db/tests/test_postgres_unchanged.py +81 -0
  86. velocity/db/tests/test_process_error_robustness.py +292 -0
  87. velocity/db/tests/test_result_caching.py +279 -0
  88. velocity/db/tests/test_result_sql_aware.py +117 -0
  89. velocity/db/tests/test_row_get_missing_column.py +72 -0
  90. velocity/db/tests/test_schema_locking_initializers.py +226 -0
  91. velocity/db/tests/test_schema_locking_simple.py +97 -0
  92. velocity/db/tests/test_sql_builder.py +165 -0
  93. velocity/db/tests/test_tablehelper.py +486 -0
  94. velocity/db/utils.py +129 -51
  95. velocity/misc/conv/__init__.py +2 -0
  96. velocity/misc/conv/iconv.py +5 -4
  97. velocity/misc/export.py +1 -4
  98. velocity/misc/merge.py +1 -1
  99. velocity/misc/tests/__init__.py +1 -0
  100. velocity/misc/tests/test_db.py +90 -0
  101. velocity/misc/tests/test_fix.py +78 -0
  102. velocity/misc/tests/test_format.py +64 -0
  103. velocity/misc/tests/test_iconv.py +203 -0
  104. velocity/misc/tests/test_merge.py +82 -0
  105. velocity/misc/tests/test_oconv.py +144 -0
  106. velocity/misc/tests/test_original_error.py +52 -0
  107. velocity/misc/tests/test_timer.py +74 -0
  108. velocity/misc/tools.py +0 -1
  109. {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/METADATA +2 -2
  110. velocity_python-0.0.161.dist-info/RECORD +129 -0
  111. velocity/db/core/exceptions.py +0 -70
  112. velocity/db/servers/mysql.py +0 -641
  113. velocity/db/servers/sqlite.py +0 -968
  114. velocity/db/servers/sqlite_reserved.py +0 -208
  115. velocity/db/servers/sqlserver.py +0 -921
  116. velocity/db/servers/sqlserver_reserved.py +0 -314
  117. velocity_python-0.0.109.dist-info/RECORD +0 -56
  118. {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/WHEEL +0 -0
  119. {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/licenses/LICENSE +0 -0
  120. {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,30 @@
1
1
  import time
2
2
  import random
3
- import traceback
4
3
  from functools import wraps
5
4
  from velocity.db import exceptions
6
5
 
7
6
 
7
+ _PRIMARY_KEY_PATTERNS = (
8
+ "primary key",
9
+ "key 'primary'",
10
+ 'key "primary"',
11
+ )
12
+
13
+
14
+ def _is_primary_key_duplicate(error):
15
+ """Return True when the duplicate-key error is targeting the primary key."""
16
+
17
+ message = str(error or "")
18
+ lowered = message.lower()
19
+
20
+ if "sys_id" in lowered:
21
+ return True
22
+
23
+ return any(pattern in lowered for pattern in _PRIMARY_KEY_PATTERNS)
24
+
25
+
8
26
  def retry_on_dup_key(func):
9
- """
10
- Retries a function call if it raises DbDuplicateKeyError, up to max_retries.
11
- """
27
+ """Retry when insert/update fails because the primary key already exists."""
12
28
 
13
29
  @wraps(func)
14
30
  def retry_decorator(self, *args, **kwds):
@@ -20,10 +36,12 @@ def retry_on_dup_key(func):
20
36
  result = func(self, *args, **kwds)
21
37
  self.tx.release_savepoint(sp, cursor=self.cursor())
22
38
  return result
23
- except exceptions.DbDuplicateKeyError:
39
+ except exceptions.DbDuplicateKeyError as error:
24
40
  self.tx.rollback_savepoint(sp, cursor=self.cursor())
25
41
  if "sys_id" in kwds.get("data", {}):
26
42
  raise
43
+ if not _is_primary_key_duplicate(error):
44
+ raise
27
45
  retries += 1
28
46
  if retries >= max_retries:
29
47
  raise
@@ -35,9 +53,7 @@ def retry_on_dup_key(func):
35
53
 
36
54
 
37
55
  def reset_id_on_dup_key(func):
38
- """
39
- Wraps an INSERT/UPSERT to reset the sys_id sequence on duplicate key collisions.
40
- """
56
+ """Retry sys_id sequence bump only when the primary key collides."""
41
57
 
42
58
  @wraps(func)
43
59
  def reset_decorator(self, *args, retries=0, **kwds):
@@ -46,10 +62,12 @@ def reset_id_on_dup_key(func):
46
62
  result = func(self, *args, **kwds)
47
63
  self.tx.release_savepoint(sp, cursor=self.cursor())
48
64
  return result
49
- except exceptions.DbDuplicateKeyError:
65
+ except exceptions.DbDuplicateKeyError as error:
50
66
  self.tx.rollback_savepoint(sp, cursor=self.cursor())
51
67
  if "sys_id" in kwds.get("data", {}):
52
68
  raise
69
+ if not _is_primary_key_duplicate(error):
70
+ raise
53
71
  if retries < 3:
54
72
  backoff_time = (2**retries) * 0.01 + random.uniform(0, 0.02)
55
73
  time.sleep(backoff_time)
@@ -100,7 +118,8 @@ def return_default(
100
118
 
101
119
  def create_missing(func):
102
120
  """
103
- If the function call fails with DbColumnMissingError or DbTableMissingError, tries to create them and re-run.
121
+ If the function call fails with DbColumnMissingError or DbTableMissingError,
122
+ tries to create them and re-run (only if schema is not locked).
104
123
  """
105
124
 
106
125
  @wraps(func)
@@ -110,8 +129,16 @@ def create_missing(func):
110
129
  result = func(self, *args, **kwds)
111
130
  self.tx.release_savepoint(sp, cursor=self.cursor())
112
131
  return result
113
- except exceptions.DbColumnMissingError:
132
+ except exceptions.DbColumnMissingError as e:
114
133
  self.tx.rollback_savepoint(sp, cursor=self.cursor())
134
+
135
+ # Check if schema is locked
136
+ if self.tx.engine.schema_locked:
137
+ raise exceptions.DbSchemaLockedError(
138
+ f"Cannot create missing column: schema is locked. Original error: {e}"
139
+ ) from e
140
+
141
+ # Existing logic for automatic creation
115
142
  data = {}
116
143
  if "pk" in kwds:
117
144
  data.update(kwds["pk"])
@@ -120,10 +147,18 @@ def create_missing(func):
120
147
  for i, arg in enumerate(args):
121
148
  if isinstance(arg, dict):
122
149
  data.update(arg)
123
- self.alter(data)
150
+ self.alter(data, mode="add")
124
151
  return func(self, *args, **kwds)
125
- except exceptions.DbTableMissingError:
152
+ except exceptions.DbTableMissingError as e:
126
153
  self.tx.rollback_savepoint(sp, cursor=self.cursor())
154
+
155
+ # Check if schema is locked
156
+ if self.tx.engine.schema_locked:
157
+ raise exceptions.DbSchemaLockedError(
158
+ f"Cannot create missing table: schema is locked. Original error: {e}"
159
+ ) from e
160
+
161
+ # Existing logic for automatic creation
127
162
  data = {}
128
163
  if "pk" in kwds:
129
164
  data.update(kwds["pk"])