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,5 +1,3 @@
1
- import datetime
2
- import decimal
3
1
  from velocity.misc.format import to_json
4
2
 
5
3
 
@@ -7,14 +5,14 @@ class Result:
7
5
  """
8
6
  Wraps a database cursor to provide various convenience transformations
9
7
  (dict, list, tuple, etc.) and helps iterate over query results.
10
-
8
+
11
9
  Features:
12
10
  - Pre-fetches first row for immediate boolean evaluation
13
11
  - Boolean state changes as rows are consumed: bool(result) tells you if MORE rows are available
14
12
  - Supports __bool__, is_empty(), has_results() for checking remaining results
15
13
  - Efficient iteration without unnecessary fetchall() calls
16
14
  - Caches next row to maintain accurate state without redundant database calls
17
-
15
+
18
16
  Boolean Behavior:
19
17
  - Initially: bool(result) = True if query returned any rows
20
18
  - After each row: bool(result) = True if more rows are available to fetch
@@ -29,15 +27,15 @@ class Result:
29
27
  description = getattr(cursor, "description", []) or []
30
28
  self._headers = []
31
29
  for col in description:
32
- if hasattr(col, '__getitem__'): # Tuple-like (col[0])
30
+ if hasattr(col, "__getitem__"): # Tuple-like (col[0])
33
31
  self._headers.append(col[0].lower())
34
- elif hasattr(col, 'name'): # Object with name attribute
32
+ elif hasattr(col, "name"): # Object with name attribute
35
33
  self._headers.append(col.name.lower())
36
34
  else:
37
- self._headers.append(f'column_{len(self._headers)}')
35
+ self._headers.append(f"column_{len(self._headers)}")
38
36
  except (AttributeError, TypeError, IndexError):
39
37
  self._headers = []
40
-
38
+
41
39
  self.__as_strings = False
42
40
  self.__enumerate = False
43
41
  self.__count = -1
@@ -49,7 +47,7 @@ class Result:
49
47
  self._cached_first_row = None
50
48
  self._first_row_fetched = False
51
49
  self._exhausted = False
52
-
50
+
53
51
  # Pre-fetch the first row to enable immediate boolean evaluation
54
52
  self._fetch_first_row()
55
53
 
@@ -60,14 +58,16 @@ class Result:
60
58
  """
61
59
  if self._first_row_fetched or not self._cursor:
62
60
  return
63
-
61
+
64
62
  # Don't try to fetch from INSERT/UPDATE/DELETE operations
65
63
  # These operations don't return rows, only rowcount
66
- if self.__sql and self.__sql.strip().upper().startswith(('INSERT', 'UPDATE', 'DELETE', 'TRUNCATE')):
64
+ if self.__sql and self.__sql.strip().upper().startswith(
65
+ ("INSERT", "UPDATE", "DELETE", "TRUNCATE")
66
+ ):
67
67
  self._exhausted = True
68
68
  self._first_row_fetched = True
69
69
  return
70
-
70
+
71
71
  try:
72
72
  raw_row = self._cursor.fetchone()
73
73
  if raw_row:
@@ -109,7 +109,9 @@ class Result:
109
109
  Return True if there are more rows available to fetch.
110
110
  This is based on whether we have a cached row or the cursor isn't exhausted.
111
111
  """
112
- return self._cached_first_row is not None or (not self._exhausted and self._cursor)
112
+ return self._cached_first_row is not None or (
113
+ not self._exhausted and self._cursor
114
+ )
113
115
 
114
116
  def __next__(self):
115
117
  """
@@ -127,7 +129,7 @@ class Result:
127
129
  if not row:
128
130
  self._exhausted = True
129
131
  raise StopIteration
130
- # Try to pre-fetch the next row to update our state
132
+ # Try to pre-fetch the next row to update our state
131
133
  self._try_cache_next_row()
132
134
  except Exception as e:
133
135
  # Handle cursor errors (e.g., closed cursor)
@@ -154,7 +156,7 @@ class Result:
154
156
  """
155
157
  if not self._cursor or self._cached_first_row is not None:
156
158
  return
157
-
159
+
158
160
  try:
159
161
  next_row = self._cursor.fetchone()
160
162
  if next_row:
@@ -214,18 +216,22 @@ class Result:
214
216
  """
215
217
  if not self.__columns and self._cursor and hasattr(self._cursor, "description"):
216
218
  for column in self._cursor.description:
217
- data = {
218
- "type_name": "unknown" # Default value
219
- }
220
-
219
+ data = {"type_name": "unknown"} # Default value
220
+
221
221
  # Try to get type information (PostgreSQL specific)
222
222
  try:
223
- if hasattr(column, 'type_code') and self.__tx and hasattr(self.__tx, 'pg_types'):
224
- data["type_name"] = self.__tx.pg_types.get(column.type_code, "unknown")
223
+ if (
224
+ hasattr(column, "type_code")
225
+ and self.__tx
226
+ and hasattr(self.__tx, "pg_types")
227
+ ):
228
+ data["type_name"] = self.__tx.pg_types.get(
229
+ column.type_code, "unknown"
230
+ )
225
231
  except (AttributeError, KeyError):
226
232
  # Keep default value
227
233
  pass
228
-
234
+
229
235
  # Get all other column attributes safely
230
236
  for key in dir(column):
231
237
  if not key.startswith("__"):
@@ -234,8 +240,8 @@ class Result:
234
240
  except (AttributeError, TypeError):
235
241
  # Skip attributes that can't be accessed
236
242
  continue
237
-
238
- column_name = getattr(column, 'name', f'column_{len(self.__columns)}')
243
+
244
+ column_name = getattr(column, "name", f"column_{len(self.__columns)}")
239
245
  self.__columns[column_name] = data
240
246
  return self.__columns
241
247
 
@@ -343,7 +349,9 @@ class Result:
343
349
  return row
344
350
  except StopIteration:
345
351
  return default
346
-
352
+
353
+ one_or_none = one
354
+
347
355
  def get_table_data(self, headers=True):
348
356
  """
349
357
  Builds a two-dimensional list: first row is column headers, subsequent rows are data.
velocity/db/core/row.py CHANGED
@@ -44,7 +44,12 @@ class Row:
44
44
  def __setitem__(self, key, val):
45
45
  if key in self.pk:
46
46
  raise Exception("Cannot update a primary key.")
47
- self.table.upsert({key: val}, self.pk)
47
+ if hasattr(self.table, "updins"):
48
+ self.table.updins({key: val}, pk=self.pk)
49
+ elif hasattr(self.table, "upsert"):
50
+ self.table.upsert({key: val}, pk=self.pk)
51
+ else:
52
+ self.table.update({key: val}, pk=self.pk)
48
53
 
49
54
  def __delitem__(self, key):
50
55
  if key in self.pk:
@@ -97,7 +102,9 @@ class Row:
97
102
  except Exception as e:
98
103
  # Check if the error message indicates a missing column
99
104
  error_msg = str(e).lower()
100
- if 'column' in error_msg and ('does not exist' in error_msg or 'not found' in error_msg):
105
+ if "column" in error_msg and (
106
+ "does not exist" in error_msg or "not found" in error_msg
107
+ ):
101
108
  return failobj
102
109
  # Re-raise other exceptions
103
110
  raise
@@ -119,7 +126,12 @@ class Row:
119
126
  if kwds:
120
127
  data.update(kwds)
121
128
  if data:
122
- self.table.upsert(data, self.pk)
129
+ if hasattr(self.table, "updins"):
130
+ self.table.updins(data, pk=self.pk)
131
+ elif hasattr(self.table, "upsert"):
132
+ self.table.upsert(data, pk=self.pk)
133
+ else:
134
+ self.table.update(data, pk=self.pk)
123
135
  return self
124
136
 
125
137
  def __cmp__(self, other):