velocity-python 0.0.115__py3-none-any.whl → 0.0.117__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.
Potentially problematic release.
This version of velocity-python might be problematic. Click here for more details.
- velocity/__init__.py +1 -1
- velocity/aws/amplify.py +8 -3
- velocity/aws/handlers/base_handler.py +245 -0
- velocity/aws/handlers/context.py +66 -44
- velocity/aws/handlers/exceptions.py +16 -0
- velocity/aws/handlers/lambda_handler.py +12 -77
- velocity/aws/handlers/sqs_handler.py +22 -138
- velocity/db/__init__.py +1 -1
- velocity/db/core/engine.py +30 -26
- velocity/db/core/exceptions.py +3 -0
- velocity/db/core/result.py +30 -22
- velocity/db/core/row.py +3 -1
- velocity/db/core/table.py +2 -1
- velocity/db/exceptions.py +35 -18
- velocity/db/servers/postgres/__init__.py +10 -12
- velocity/db/servers/postgres/sql.py +32 -13
- velocity/db/servers/tablehelper.py +117 -91
- velocity/db/utils.py +61 -46
- {velocity_python-0.0.115.dist-info → velocity_python-0.0.117.dist-info}/METADATA +1 -1
- {velocity_python-0.0.115.dist-info → velocity_python-0.0.117.dist-info}/RECORD +23 -21
- {velocity_python-0.0.115.dist-info → velocity_python-0.0.117.dist-info}/WHEEL +0 -0
- {velocity_python-0.0.115.dist-info → velocity_python-0.0.117.dist-info}/licenses/LICENSE +0 -0
- {velocity_python-0.0.115.dist-info → velocity_python-0.0.117.dist-info}/top_level.txt +0 -0
velocity/db/exceptions.py
CHANGED
|
@@ -5,108 +5,125 @@ Database exceptions for the velocity library.
|
|
|
5
5
|
|
|
6
6
|
class DbException(Exception):
|
|
7
7
|
"""Base class for all database exceptions."""
|
|
8
|
+
|
|
8
9
|
pass
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class DbApplicationError(DbException):
|
|
12
13
|
"""Application-level database error."""
|
|
14
|
+
|
|
13
15
|
pass
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
class DbForeignKeyMissingError(DbException):
|
|
17
19
|
"""Foreign key constraint violation."""
|
|
20
|
+
|
|
18
21
|
pass
|
|
19
22
|
|
|
20
23
|
|
|
21
24
|
class DbDatabaseMissingError(DbException):
|
|
22
25
|
"""Database does not exist."""
|
|
26
|
+
|
|
23
27
|
pass
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
class DbTableMissingError(DbException):
|
|
27
31
|
"""Table does not exist."""
|
|
32
|
+
|
|
28
33
|
pass
|
|
29
34
|
|
|
30
35
|
|
|
31
36
|
class DbColumnMissingError(DbException):
|
|
32
37
|
"""Column does not exist."""
|
|
38
|
+
|
|
33
39
|
pass
|
|
34
40
|
|
|
35
41
|
|
|
36
42
|
class DbTruncationError(DbException):
|
|
37
43
|
"""Data truncation error."""
|
|
44
|
+
|
|
38
45
|
pass
|
|
39
46
|
|
|
40
47
|
|
|
41
48
|
class DbConnectionError(DbException):
|
|
42
49
|
"""Database connection error."""
|
|
50
|
+
|
|
43
51
|
pass
|
|
44
52
|
|
|
45
53
|
|
|
46
54
|
class DbDuplicateKeyError(DbException):
|
|
47
55
|
"""Duplicate key constraint violation."""
|
|
56
|
+
|
|
48
57
|
pass
|
|
49
58
|
|
|
50
59
|
|
|
51
60
|
class DbObjectExistsError(DbException):
|
|
52
61
|
"""Database object already exists."""
|
|
62
|
+
|
|
53
63
|
pass
|
|
54
64
|
|
|
55
65
|
|
|
56
66
|
class DbLockTimeoutError(DbException):
|
|
57
67
|
"""Lock timeout error."""
|
|
68
|
+
|
|
58
69
|
pass
|
|
59
70
|
|
|
60
71
|
|
|
61
72
|
class DbRetryTransaction(DbException):
|
|
62
73
|
"""Transaction should be retried."""
|
|
74
|
+
|
|
63
75
|
pass
|
|
64
76
|
|
|
65
77
|
|
|
66
78
|
class DbDataIntegrityError(DbException):
|
|
67
79
|
"""Data integrity constraint violation."""
|
|
80
|
+
|
|
68
81
|
pass
|
|
69
82
|
|
|
70
83
|
|
|
71
84
|
class DbQueryError(DbException):
|
|
72
85
|
"""Database query error."""
|
|
86
|
+
|
|
73
87
|
pass
|
|
74
88
|
|
|
75
89
|
|
|
76
90
|
class DbTransactionError(DbException):
|
|
77
91
|
"""Database transaction error."""
|
|
92
|
+
|
|
78
93
|
pass
|
|
79
94
|
|
|
80
95
|
|
|
81
96
|
class DuplicateRowsFoundError(Exception):
|
|
82
97
|
"""Multiple rows found when expecting single result."""
|
|
98
|
+
|
|
83
99
|
pass
|
|
84
100
|
|
|
85
101
|
|
|
86
102
|
# Add aliases for backward compatibility with engine.py
|
|
87
103
|
class DatabaseError(DbException):
|
|
88
104
|
"""Generic database error - alias for DbException."""
|
|
105
|
+
|
|
89
106
|
pass
|
|
90
107
|
|
|
108
|
+
|
|
91
109
|
__all__ = [
|
|
92
110
|
# Base exceptions
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
111
|
+
"DbException",
|
|
112
|
+
"DatabaseError",
|
|
96
113
|
# Specific exceptions
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
"DbApplicationError",
|
|
115
|
+
"DbForeignKeyMissingError",
|
|
116
|
+
"DbDatabaseMissingError",
|
|
117
|
+
"DbTableMissingError",
|
|
118
|
+
"DbColumnMissingError",
|
|
119
|
+
"DbTruncationError",
|
|
120
|
+
"DbConnectionError",
|
|
121
|
+
"DbDuplicateKeyError",
|
|
122
|
+
"DbObjectExistsError",
|
|
123
|
+
"DbLockTimeoutError",
|
|
124
|
+
"DbRetryTransaction",
|
|
125
|
+
"DbDataIntegrityError",
|
|
126
|
+
"DbQueryError",
|
|
127
|
+
"DbTransactionError",
|
|
128
|
+
"DuplicateRowsFoundError",
|
|
112
129
|
]
|
|
@@ -4,16 +4,14 @@ from .sql import SQL
|
|
|
4
4
|
from velocity.db.core import engine
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
def initialize(config=None, **kwargs):
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return engine.Engine(psycopg2, config, SQL)
|
|
8
|
+
konfig = {
|
|
9
|
+
"database": os.environ["DBDatabase"],
|
|
10
|
+
"host": os.environ["DBHost"],
|
|
11
|
+
"port": os.environ["DBPort"],
|
|
12
|
+
"user": os.environ["DBUser"],
|
|
13
|
+
"password": os.environ["DBPassword"],
|
|
14
|
+
}
|
|
15
|
+
konfig.update(config or {})
|
|
16
|
+
konfig.update(kwargs)
|
|
17
|
+
return engine.Engine(psycopg2, konfig, SQL)
|
|
@@ -37,7 +37,7 @@ def _handle_predicate_errors(predicates, operation="WHERE"):
|
|
|
37
37
|
"""Process a list of predicates with error handling."""
|
|
38
38
|
sql_parts = []
|
|
39
39
|
vals = []
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
for pred, val in predicates:
|
|
42
42
|
sql_parts.append(pred)
|
|
43
43
|
if val is None:
|
|
@@ -46,7 +46,7 @@ def _handle_predicate_errors(predicates, operation="WHERE"):
|
|
|
46
46
|
vals.extend(val)
|
|
47
47
|
else:
|
|
48
48
|
vals.append(val)
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
return sql_parts, vals
|
|
51
51
|
|
|
52
52
|
|
|
@@ -75,8 +75,19 @@ class SQL:
|
|
|
75
75
|
ColumnMissingErrorCodes = ["42703"]
|
|
76
76
|
ForeignKeyMissingErrorCodes = ["42704"]
|
|
77
77
|
|
|
78
|
-
ConnectionErrorCodes = [
|
|
79
|
-
|
|
78
|
+
ConnectionErrorCodes = [
|
|
79
|
+
"08001",
|
|
80
|
+
"08S01",
|
|
81
|
+
"57P03",
|
|
82
|
+
"08006",
|
|
83
|
+
"53300",
|
|
84
|
+
"08003",
|
|
85
|
+
"08004",
|
|
86
|
+
"08P01",
|
|
87
|
+
]
|
|
88
|
+
DuplicateKeyErrorCodes = [
|
|
89
|
+
"23505"
|
|
90
|
+
] # unique_violation - no longer relying only on regex
|
|
80
91
|
RetryTransactionCodes = ["40001", "40P01", "40002"]
|
|
81
92
|
TruncationErrorCodes = ["22001"]
|
|
82
93
|
LockTimeoutErrorCodes = ["55P03"]
|
|
@@ -111,7 +122,7 @@ class SQL:
|
|
|
111
122
|
"""
|
|
112
123
|
if not table:
|
|
113
124
|
raise ValueError("Table name is required.")
|
|
114
|
-
|
|
125
|
+
|
|
115
126
|
# Validate pagination parameters
|
|
116
127
|
if start is not None and not isinstance(start, int):
|
|
117
128
|
raise ValueError("Start (OFFSET) must be an integer.")
|
|
@@ -148,7 +159,7 @@ class SQL:
|
|
|
148
159
|
columns = [c.strip() for c in columns if c.strip()] # Remove empty columns
|
|
149
160
|
if not columns:
|
|
150
161
|
raise ValueError("No valid columns specified")
|
|
151
|
-
|
|
162
|
+
|
|
152
163
|
distinct = False
|
|
153
164
|
|
|
154
165
|
# Check for DISTINCT keyword in any column
|
|
@@ -188,7 +199,7 @@ class SQL:
|
|
|
188
199
|
new_orderby = []
|
|
189
200
|
if isinstance(orderby, str):
|
|
190
201
|
orderby = th.split_columns(orderby)
|
|
191
|
-
|
|
202
|
+
|
|
192
203
|
# Handle orderby references
|
|
193
204
|
if isinstance(orderby, Sequence):
|
|
194
205
|
for column in orderby:
|
|
@@ -200,7 +211,9 @@ class SQL:
|
|
|
200
211
|
# Validate direction
|
|
201
212
|
direction = direction.upper()
|
|
202
213
|
if direction not in ("ASC", "DESC"):
|
|
203
|
-
raise ValueError(
|
|
214
|
+
raise ValueError(
|
|
215
|
+
f"Invalid ORDER BY direction: {direction}"
|
|
216
|
+
)
|
|
204
217
|
col_name = th.resolve_references(
|
|
205
218
|
col_name.strip(), options={"alias_only": True}
|
|
206
219
|
)
|
|
@@ -213,7 +226,9 @@ class SQL:
|
|
|
213
226
|
)
|
|
214
227
|
new_orderby.append(resolved_col)
|
|
215
228
|
except Exception as e:
|
|
216
|
-
raise ValueError(
|
|
229
|
+
raise ValueError(
|
|
230
|
+
f"Error processing ORDER BY column '{column}': {e}"
|
|
231
|
+
)
|
|
217
232
|
|
|
218
233
|
elif isinstance(orderby, Mapping):
|
|
219
234
|
for key, val in orderby.items():
|
|
@@ -222,11 +237,13 @@ class SQL:
|
|
|
222
237
|
direction = str(val).upper()
|
|
223
238
|
if direction not in ("ASC", "DESC"):
|
|
224
239
|
raise ValueError(f"Invalid ORDER BY direction: {direction}")
|
|
225
|
-
parsed_key = th.resolve_references(
|
|
240
|
+
parsed_key = th.resolve_references(
|
|
241
|
+
key, options={"alias_only": True}
|
|
242
|
+
)
|
|
226
243
|
new_orderby.append(f"{parsed_key} {direction}")
|
|
227
244
|
except Exception as e:
|
|
228
245
|
raise ValueError(f"Error processing ORDER BY key '{key}': {e}")
|
|
229
|
-
|
|
246
|
+
|
|
230
247
|
orderby = new_orderby
|
|
231
248
|
|
|
232
249
|
# Handle groupby
|
|
@@ -256,7 +273,9 @@ class SQL:
|
|
|
256
273
|
|
|
257
274
|
# FROM clause
|
|
258
275
|
if th.foreign_keys:
|
|
259
|
-
sql_parts["FROM"].append(
|
|
276
|
+
sql_parts["FROM"].append(
|
|
277
|
+
f"{TableHelper.quote(table)} AS {TableHelper.quote(alias)}"
|
|
278
|
+
)
|
|
260
279
|
# Handle joins
|
|
261
280
|
done = []
|
|
262
281
|
for key, ref_info in th.foreign_keys.items():
|
|
@@ -463,7 +482,7 @@ class SQL:
|
|
|
463
482
|
# Create a temporary TableHelper instance for quoting
|
|
464
483
|
# Note: We pass None for tx since we only need quoting functionality
|
|
465
484
|
temp_helper = TableHelper(None, table)
|
|
466
|
-
|
|
485
|
+
|
|
467
486
|
keys = []
|
|
468
487
|
vals_placeholders = []
|
|
469
488
|
args = []
|