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.
- velocity/__init__.py +3 -1
- velocity/app/orders.py +3 -4
- velocity/app/tests/__init__.py +1 -0
- velocity/app/tests/test_email_processing.py +112 -0
- velocity/app/tests/test_payment_profile_sorting.py +191 -0
- velocity/app/tests/test_spreadsheet_functions.py +124 -0
- velocity/aws/__init__.py +3 -0
- velocity/aws/amplify.py +10 -6
- velocity/aws/handlers/__init__.py +2 -0
- velocity/aws/handlers/base_handler.py +248 -0
- velocity/aws/handlers/context.py +251 -2
- velocity/aws/handlers/exceptions.py +16 -0
- velocity/aws/handlers/lambda_handler.py +24 -85
- velocity/aws/handlers/mixins/__init__.py +16 -0
- velocity/aws/handlers/mixins/activity_tracker.py +181 -0
- velocity/aws/handlers/mixins/aws_session_mixin.py +192 -0
- velocity/aws/handlers/mixins/error_handler.py +192 -0
- velocity/aws/handlers/mixins/legacy_mixin.py +53 -0
- velocity/aws/handlers/mixins/standard_mixin.py +73 -0
- velocity/aws/handlers/response.py +1 -1
- velocity/aws/handlers/sqs_handler.py +28 -143
- velocity/aws/tests/__init__.py +1 -0
- velocity/aws/tests/test_lambda_handler_json_serialization.py +120 -0
- velocity/aws/tests/test_response.py +163 -0
- velocity/db/__init__.py +16 -4
- velocity/db/core/decorators.py +48 -13
- velocity/db/core/engine.py +187 -840
- velocity/db/core/result.py +33 -25
- velocity/db/core/row.py +15 -3
- velocity/db/core/table.py +493 -50
- velocity/db/core/transaction.py +28 -15
- velocity/db/exceptions.py +42 -18
- velocity/db/servers/base/__init__.py +9 -0
- velocity/db/servers/base/initializer.py +70 -0
- velocity/db/servers/base/operators.py +98 -0
- velocity/db/servers/base/sql.py +503 -0
- velocity/db/servers/base/types.py +135 -0
- velocity/db/servers/mysql/__init__.py +73 -0
- velocity/db/servers/mysql/operators.py +54 -0
- velocity/db/servers/{mysql_reserved.py → mysql/reserved.py} +2 -14
- velocity/db/servers/mysql/sql.py +718 -0
- velocity/db/servers/mysql/types.py +107 -0
- velocity/db/servers/postgres/__init__.py +59 -11
- velocity/db/servers/postgres/operators.py +34 -0
- velocity/db/servers/postgres/sql.py +474 -120
- velocity/db/servers/postgres/types.py +88 -2
- velocity/db/servers/sqlite/__init__.py +61 -0
- velocity/db/servers/sqlite/operators.py +52 -0
- velocity/db/servers/sqlite/reserved.py +20 -0
- velocity/db/servers/sqlite/sql.py +677 -0
- velocity/db/servers/sqlite/types.py +92 -0
- velocity/db/servers/sqlserver/__init__.py +73 -0
- velocity/db/servers/sqlserver/operators.py +47 -0
- velocity/db/servers/sqlserver/reserved.py +32 -0
- velocity/db/servers/sqlserver/sql.py +805 -0
- velocity/db/servers/sqlserver/types.py +114 -0
- velocity/db/servers/tablehelper.py +117 -91
- velocity/db/tests/__init__.py +1 -0
- velocity/db/tests/common_db_test.py +0 -0
- velocity/db/tests/postgres/__init__.py +1 -0
- velocity/db/tests/postgres/common.py +49 -0
- velocity/db/tests/postgres/test_column.py +29 -0
- velocity/db/tests/postgres/test_connections.py +25 -0
- velocity/db/tests/postgres/test_database.py +21 -0
- velocity/db/tests/postgres/test_engine.py +205 -0
- velocity/db/tests/postgres/test_general_usage.py +88 -0
- velocity/db/tests/postgres/test_imports.py +8 -0
- velocity/db/tests/postgres/test_result.py +19 -0
- velocity/db/tests/postgres/test_row.py +137 -0
- velocity/db/tests/postgres/test_row_comprehensive.py +720 -0
- velocity/db/tests/postgres/test_schema_locking.py +335 -0
- velocity/db/tests/postgres/test_schema_locking_unit.py +115 -0
- velocity/db/tests/postgres/test_sequence.py +34 -0
- velocity/db/tests/postgres/test_sql_comprehensive.py +462 -0
- velocity/db/tests/postgres/test_table.py +101 -0
- velocity/db/tests/postgres/test_table_comprehensive.py +646 -0
- velocity/db/tests/postgres/test_transaction.py +106 -0
- velocity/db/tests/sql/__init__.py +1 -0
- velocity/db/tests/sql/common.py +177 -0
- velocity/db/tests/sql/test_postgres_select_advanced.py +285 -0
- velocity/db/tests/sql/test_postgres_select_variances.py +517 -0
- velocity/db/tests/test_cursor_rowcount_fix.py +150 -0
- velocity/db/tests/test_db_utils.py +270 -0
- velocity/db/tests/test_postgres.py +448 -0
- velocity/db/tests/test_postgres_unchanged.py +81 -0
- velocity/db/tests/test_process_error_robustness.py +292 -0
- velocity/db/tests/test_result_caching.py +279 -0
- velocity/db/tests/test_result_sql_aware.py +117 -0
- velocity/db/tests/test_row_get_missing_column.py +72 -0
- velocity/db/tests/test_schema_locking_initializers.py +226 -0
- velocity/db/tests/test_schema_locking_simple.py +97 -0
- velocity/db/tests/test_sql_builder.py +165 -0
- velocity/db/tests/test_tablehelper.py +486 -0
- velocity/db/utils.py +129 -51
- velocity/misc/conv/__init__.py +2 -0
- velocity/misc/conv/iconv.py +5 -4
- velocity/misc/export.py +1 -4
- velocity/misc/merge.py +1 -1
- velocity/misc/tests/__init__.py +1 -0
- velocity/misc/tests/test_db.py +90 -0
- velocity/misc/tests/test_fix.py +78 -0
- velocity/misc/tests/test_format.py +64 -0
- velocity/misc/tests/test_iconv.py +203 -0
- velocity/misc/tests/test_merge.py +82 -0
- velocity/misc/tests/test_oconv.py +144 -0
- velocity/misc/tests/test_original_error.py +52 -0
- velocity/misc/tests/test_timer.py +74 -0
- velocity/misc/tools.py +0 -1
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/METADATA +2 -2
- velocity_python-0.0.161.dist-info/RECORD +129 -0
- velocity/db/core/exceptions.py +0 -70
- velocity/db/servers/mysql.py +0 -641
- velocity/db/servers/sqlite.py +0 -968
- velocity/db/servers/sqlite_reserved.py +0 -208
- velocity/db/servers/sqlserver.py +0 -921
- velocity/db/servers/sqlserver_reserved.py +0 -314
- velocity_python-0.0.109.dist-info/RECORD +0 -56
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/WHEEL +0 -0
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/licenses/LICENSE +0 -0
- {velocity_python-0.0.109.dist-info → velocity_python-0.0.161.dist-info}/top_level.txt +0 -0
velocity/db/core/transaction.py
CHANGED
|
@@ -6,6 +6,7 @@ from velocity.db.core.result import Result
|
|
|
6
6
|
from velocity.db.core.column import Column
|
|
7
7
|
from velocity.db.core.database import Database
|
|
8
8
|
from velocity.db.core.sequence import Sequence
|
|
9
|
+
from velocity.db.utils import mask_config_for_display
|
|
9
10
|
from velocity.misc.db import randomword
|
|
10
11
|
|
|
11
12
|
debug = False
|
|
@@ -22,10 +23,14 @@ class Transaction:
|
|
|
22
23
|
self.__pg_types = {}
|
|
23
24
|
|
|
24
25
|
def __str__(self):
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
config = mask_config_for_display(self.engine.config)
|
|
27
|
+
|
|
28
|
+
if isinstance(config, dict):
|
|
29
|
+
server = config.get("host", config.get("server"))
|
|
30
|
+
database = config.get("database", config.get("dbname"))
|
|
31
|
+
return f"{self.engine.sql.server}.transaction({server}:{database})"
|
|
32
|
+
|
|
33
|
+
return f"{self.engine.sql.server}.transaction({config})"
|
|
29
34
|
|
|
30
35
|
def __enter__(self):
|
|
31
36
|
return self
|
|
@@ -164,17 +169,25 @@ class Transaction:
|
|
|
164
169
|
"""
|
|
165
170
|
return Row(self.table(tablename), pk, lock=lock)
|
|
166
171
|
|
|
167
|
-
def get(self, tablename, where, lock=None):
|
|
168
|
-
"""
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
172
|
+
def get(self, tablename, where, lock=None, use_where=False):
|
|
173
|
+
"""Shortcut to table.get() with optional ``use_where`` passthrough."""
|
|
174
|
+
return self.table(tablename).get(where, lock=lock, use_where=use_where)
|
|
175
|
+
|
|
176
|
+
def find(
|
|
177
|
+
self,
|
|
178
|
+
tablename,
|
|
179
|
+
where,
|
|
180
|
+
lock=None,
|
|
181
|
+
use_where=False,
|
|
182
|
+
raise_if_missing=False,
|
|
183
|
+
):
|
|
184
|
+
"""Shortcut to table.find() with ``use_where``/``raise_if_missing`` passthrough."""
|
|
185
|
+
return self.table(tablename).find(
|
|
186
|
+
where,
|
|
187
|
+
lock=lock,
|
|
188
|
+
use_where=use_where,
|
|
189
|
+
raise_if_missing=raise_if_missing,
|
|
190
|
+
)
|
|
178
191
|
|
|
179
192
|
def column(self, tablename, colname):
|
|
180
193
|
"""
|
velocity/db/exceptions.py
CHANGED
|
@@ -5,108 +5,132 @@ 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
|
+
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class DbSchemaLockedError(DbApplicationError):
|
|
97
|
+
"""Raised when attempting to modify schema while schema is locked."""
|
|
98
|
+
|
|
78
99
|
pass
|
|
79
100
|
|
|
80
101
|
|
|
81
102
|
class DuplicateRowsFoundError(Exception):
|
|
82
103
|
"""Multiple rows found when expecting single result."""
|
|
104
|
+
|
|
83
105
|
pass
|
|
84
106
|
|
|
85
107
|
|
|
86
108
|
# Add aliases for backward compatibility with engine.py
|
|
87
109
|
class DatabaseError(DbException):
|
|
88
110
|
"""Generic database error - alias for DbException."""
|
|
111
|
+
|
|
89
112
|
pass
|
|
90
113
|
|
|
114
|
+
|
|
91
115
|
__all__ = [
|
|
92
116
|
# Base exceptions
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
117
|
+
"DbException",
|
|
118
|
+
"DatabaseError",
|
|
96
119
|
# Specific exceptions
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
"DbApplicationError",
|
|
121
|
+
"DbForeignKeyMissingError",
|
|
122
|
+
"DbDatabaseMissingError",
|
|
123
|
+
"DbTableMissingError",
|
|
124
|
+
"DbColumnMissingError",
|
|
125
|
+
"DbTruncationError",
|
|
126
|
+
"DbConnectionError",
|
|
127
|
+
"DbDuplicateKeyError",
|
|
128
|
+
"DbObjectExistsError",
|
|
129
|
+
"DbLockTimeoutError",
|
|
130
|
+
"DbRetryTransaction",
|
|
131
|
+
"DbDataIntegrityError",
|
|
132
|
+
"DbQueryError",
|
|
133
|
+
"DbTransactionError",
|
|
134
|
+
"DbSchemaLockedError",
|
|
135
|
+
"DuplicateRowsFoundError",
|
|
112
136
|
]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base abstract classes for database server implementations.
|
|
3
|
+
"""
|
|
4
|
+
from .sql import BaseSQLDialect
|
|
5
|
+
from .types import BaseTypes
|
|
6
|
+
from .operators import BaseOperators
|
|
7
|
+
from .initializer import BaseInitializer
|
|
8
|
+
|
|
9
|
+
__all__ = ["BaseSQLDialect", "BaseTypes", "BaseOperators", "BaseInitializer"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Abstract base class for database initialization.
|
|
3
|
+
"""
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
from velocity.db.core import engine
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BaseInitializer(ABC):
|
|
10
|
+
"""
|
|
11
|
+
Abstract base class for database connection initialization.
|
|
12
|
+
|
|
13
|
+
Each database implementation should provide a concrete implementation
|
|
14
|
+
of the initialize method to set up database connections properly.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def initialize(config: Optional[Dict[str, Any]] = None, schema_locked: bool = False, **kwargs) -> engine.Engine:
|
|
20
|
+
"""
|
|
21
|
+
Initialize a database engine with the appropriate driver and configuration.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
config: Configuration dictionary (can be None)
|
|
25
|
+
schema_locked: Boolean to lock schema modifications (default: False)
|
|
26
|
+
**kwargs: Additional configuration parameters
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Configured Engine instance
|
|
30
|
+
|
|
31
|
+
Raises:
|
|
32
|
+
ImportError: If required database driver is not available
|
|
33
|
+
ValueError: If configuration is invalid
|
|
34
|
+
"""
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def _merge_config(base_config: Dict[str, Any], config: Optional[Dict[str, Any]], **kwargs) -> Dict[str, Any]:
|
|
39
|
+
"""
|
|
40
|
+
Helper method to merge configuration from multiple sources.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
base_config: Base configuration (e.g., from environment)
|
|
44
|
+
config: User-provided configuration
|
|
45
|
+
**kwargs: Additional keyword arguments
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Merged configuration dictionary
|
|
49
|
+
"""
|
|
50
|
+
final_config = base_config.copy()
|
|
51
|
+
if config:
|
|
52
|
+
final_config.update(config)
|
|
53
|
+
final_config.update(kwargs)
|
|
54
|
+
return final_config
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _validate_required_config(config: Dict[str, Any], required_keys: list[str]) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Validate that required configuration keys are present.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
config: Configuration to validate
|
|
63
|
+
required_keys: List of required configuration keys
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
ValueError: If required keys are missing
|
|
67
|
+
"""
|
|
68
|
+
missing_keys = [key for key in required_keys if key not in config]
|
|
69
|
+
if missing_keys:
|
|
70
|
+
raise ValueError(f"Missing required configuration keys: {missing_keys}")
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Abstract base class for database operator mapping implementations.
|
|
3
|
+
"""
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from typing import Dict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BaseOperators(ABC):
|
|
9
|
+
"""
|
|
10
|
+
Abstract base class that defines the interface for database operator mappings.
|
|
11
|
+
|
|
12
|
+
Each database implementation should provide concrete implementations of operator
|
|
13
|
+
mappings to handle conversion between Velocity.DB operators and SQL operators.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def get_operators(cls) -> Dict[str, str]:
|
|
19
|
+
"""
|
|
20
|
+
Returns a dictionary mapping Velocity.DB operators to SQL operators.
|
|
21
|
+
|
|
22
|
+
This method should return a complete mapping of all operators supported
|
|
23
|
+
by this database implementation.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Dictionary mapping operator symbols to SQL operators
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
{
|
|
30
|
+
"=": "=",
|
|
31
|
+
"!=": "<>",
|
|
32
|
+
"<>": "<>",
|
|
33
|
+
"%": "LIKE",
|
|
34
|
+
"!%": "NOT LIKE",
|
|
35
|
+
"%%": "ILIKE", # PostgreSQL case-insensitive
|
|
36
|
+
"!%%": "NOT ILIKE",
|
|
37
|
+
"><": "BETWEEN",
|
|
38
|
+
"!><": "NOT BETWEEN",
|
|
39
|
+
# ... etc
|
|
40
|
+
}
|
|
41
|
+
"""
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def get_base_operators(cls) -> Dict[str, str]:
|
|
46
|
+
"""
|
|
47
|
+
Returns common operators supported by most databases.
|
|
48
|
+
Subclasses can use this as a starting point and override specific operators.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Dictionary of common SQL operators
|
|
52
|
+
"""
|
|
53
|
+
return {
|
|
54
|
+
"=": "=",
|
|
55
|
+
"==": "=",
|
|
56
|
+
"!=": "<>",
|
|
57
|
+
"<>": "<>",
|
|
58
|
+
"!": "<>",
|
|
59
|
+
"<": "<",
|
|
60
|
+
">": ">",
|
|
61
|
+
"<=": "<=",
|
|
62
|
+
">=": ">=",
|
|
63
|
+
"%": "LIKE",
|
|
64
|
+
"!%": "NOT LIKE",
|
|
65
|
+
"><": "BETWEEN",
|
|
66
|
+
"!><": "NOT BETWEEN",
|
|
67
|
+
">!<": "NOT BETWEEN",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def supports_case_insensitive_like(cls) -> bool:
|
|
72
|
+
"""
|
|
73
|
+
Returns True if this database supports case-insensitive LIKE operations.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
True if database supports ILIKE or similar
|
|
77
|
+
"""
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def supports_regex(cls) -> bool:
|
|
82
|
+
"""
|
|
83
|
+
Returns True if this database supports regular expressions.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
True if database supports regex operators
|
|
87
|
+
"""
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def get_regex_operators(cls) -> Dict[str, str]:
|
|
92
|
+
"""
|
|
93
|
+
Returns regex operators if supported by this database.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Dictionary of regex operators or empty dict if not supported
|
|
97
|
+
"""
|
|
98
|
+
return {}
|