velocity-python 0.0.131__tar.gz → 0.0.134__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.

Potentially problematic release.


This version of velocity-python might be problematic. Click here for more details.

Files changed (138) hide show
  1. {velocity_python-0.0.131 → velocity_python-0.0.134}/PKG-INFO +1 -1
  2. {velocity_python-0.0.131 → velocity_python-0.0.134}/pyproject.toml +1 -1
  3. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/__init__.py +1 -1
  4. velocity_python-0.0.134/src/velocity/app/tests/__init__.py +1 -0
  5. velocity_python-0.0.134/src/velocity/aws/tests/__init__.py +1 -0
  6. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/decorators.py +20 -3
  7. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/engine.py +33 -7
  8. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/exceptions.py +7 -0
  9. velocity_python-0.0.134/src/velocity/db/servers/base/__init__.py +9 -0
  10. velocity_python-0.0.134/src/velocity/db/servers/base/initializer.py +70 -0
  11. velocity_python-0.0.134/src/velocity/db/servers/base/operators.py +98 -0
  12. velocity_python-0.0.134/src/velocity/db/servers/base/sql.py +503 -0
  13. velocity_python-0.0.134/src/velocity/db/servers/base/types.py +135 -0
  14. velocity_python-0.0.134/src/velocity/db/servers/mysql/__init__.py +73 -0
  15. velocity_python-0.0.134/src/velocity/db/servers/mysql/operators.py +54 -0
  16. velocity_python-0.0.131/src/velocity/db/servers/mysql_reserved.py → velocity_python-0.0.134/src/velocity/db/servers/mysql/reserved.py +2 -14
  17. velocity_python-0.0.134/src/velocity/db/servers/mysql/sql.py +569 -0
  18. {velocity_python-0.0.131/src/velocity/db/servers/postgres → velocity_python-0.0.134/src/velocity/db/servers/mysql}/types.py +31 -33
  19. velocity_python-0.0.134/src/velocity/db/servers/postgres/__init__.py +67 -0
  20. velocity_python-0.0.134/src/velocity/db/servers/postgres/operators.py +57 -0
  21. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/servers/postgres/sql.py +4 -3
  22. velocity_python-0.0.134/src/velocity/db/servers/postgres/types.py +195 -0
  23. velocity_python-0.0.134/src/velocity/db/servers/sqlite/__init__.py +61 -0
  24. velocity_python-0.0.134/src/velocity/db/servers/sqlite/operators.py +52 -0
  25. velocity_python-0.0.134/src/velocity/db/servers/sqlite/reserved.py +20 -0
  26. velocity_python-0.0.134/src/velocity/db/servers/sqlite/sql.py +530 -0
  27. velocity_python-0.0.134/src/velocity/db/servers/sqlite/types.py +92 -0
  28. velocity_python-0.0.134/src/velocity/db/servers/sqlserver/__init__.py +73 -0
  29. velocity_python-0.0.134/src/velocity/db/servers/sqlserver/operators.py +47 -0
  30. velocity_python-0.0.134/src/velocity/db/servers/sqlserver/reserved.py +32 -0
  31. velocity_python-0.0.134/src/velocity/db/servers/sqlserver/sql.py +625 -0
  32. velocity_python-0.0.134/src/velocity/db/servers/sqlserver/types.py +114 -0
  33. velocity_python-0.0.134/src/velocity/db/tests/__init__.py +1 -0
  34. velocity_python-0.0.134/src/velocity/db/tests/postgres/__init__.py +1 -0
  35. velocity_python-0.0.134/src/velocity/db/tests/postgres/common.py +49 -0
  36. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_column.py +29 -0
  37. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_connections.py +25 -0
  38. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_database.py +21 -0
  39. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_engine.py +205 -0
  40. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_general_usage.py +88 -0
  41. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_imports.py +8 -0
  42. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_result.py +19 -0
  43. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_row.py +137 -0
  44. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_schema_locking.py +335 -0
  45. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_schema_locking_unit.py +115 -0
  46. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_sequence.py +34 -0
  47. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_table.py +101 -0
  48. velocity_python-0.0.134/src/velocity/db/tests/postgres/test_transaction.py +106 -0
  49. velocity_python-0.0.134/src/velocity/db/tests/sql/__init__.py +1 -0
  50. velocity_python-0.0.134/src/velocity/db/tests/sql/common.py +177 -0
  51. velocity_python-0.0.134/src/velocity/db/tests/sql/test_postgres_select_advanced.py +285 -0
  52. velocity_python-0.0.134/src/velocity/db/tests/sql/test_postgres_select_variances.py +517 -0
  53. velocity_python-0.0.134/src/velocity/db/tests/test_postgres_unchanged.py +81 -0
  54. velocity_python-0.0.134/src/velocity/db/tests/test_schema_locking_initializers.py +226 -0
  55. velocity_python-0.0.134/src/velocity/db/tests/test_schema_locking_simple.py +97 -0
  56. velocity_python-0.0.134/src/velocity/misc/__init__.py +0 -0
  57. velocity_python-0.0.134/src/velocity/misc/tests/__init__.py +1 -0
  58. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/misc}/tests/test_db.py +1 -1
  59. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/misc}/tests/test_format.py +1 -1
  60. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/misc}/tests/test_iconv.py +1 -1
  61. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/misc}/tests/test_merge.py +1 -1
  62. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/misc}/tests/test_oconv.py +1 -1
  63. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/misc}/tests/test_timer.py +1 -1
  64. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity_python.egg-info/PKG-INFO +1 -1
  65. velocity_python-0.0.134/src/velocity_python.egg-info/SOURCES.txt +128 -0
  66. velocity_python-0.0.131/src/velocity/db/servers/mysql.py +0 -640
  67. velocity_python-0.0.131/src/velocity/db/servers/postgres/__init__.py +0 -17
  68. velocity_python-0.0.131/src/velocity/db/servers/postgres/operators.py +0 -23
  69. velocity_python-0.0.131/src/velocity/db/servers/sqlite.py +0 -968
  70. velocity_python-0.0.131/src/velocity/db/servers/sqlite_reserved.py +0 -208
  71. velocity_python-0.0.131/src/velocity/db/servers/sqlserver.py +0 -921
  72. velocity_python-0.0.131/src/velocity/db/servers/sqlserver_reserved.py +0 -314
  73. velocity_python-0.0.131/src/velocity_python.egg-info/SOURCES.txt +0 -87
  74. {velocity_python-0.0.131 → velocity_python-0.0.134}/LICENSE +0 -0
  75. {velocity_python-0.0.131 → velocity_python-0.0.134}/README.md +0 -0
  76. {velocity_python-0.0.131 → velocity_python-0.0.134}/setup.cfg +0 -0
  77. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/app/__init__.py +0 -0
  78. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/app/invoices.py +0 -0
  79. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/app/orders.py +0 -0
  80. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/app/payments.py +0 -0
  81. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/app/purchase_orders.py +0 -0
  82. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/app}/tests/test_email_processing.py +0 -0
  83. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/app}/tests/test_payment_profile_sorting.py +0 -0
  84. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/app}/tests/test_spreadsheet_functions.py +0 -0
  85. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/__init__.py +0 -0
  86. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/amplify.py +0 -0
  87. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/__init__.py +0 -0
  88. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/base_handler.py +0 -0
  89. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/context.py +0 -0
  90. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/exceptions.py +0 -0
  91. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  92. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  93. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/mixins/activity_tracker.py +0 -0
  94. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/mixins/error_handler.py +0 -0
  95. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/mixins/legacy_mixin.py +0 -0
  96. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/mixins/standard_mixin.py +0 -0
  97. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/response.py +0 -0
  98. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  99. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/aws}/tests/test_lambda_handler_json_serialization.py +0 -0
  100. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/aws}/tests/test_response.py +0 -0
  101. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/__init__.py +0 -0
  102. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/__init__.py +0 -0
  103. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/column.py +0 -0
  104. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/database.py +0 -0
  105. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/result.py +0 -0
  106. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/row.py +0 -0
  107. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/sequence.py +0 -0
  108. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/table.py +0 -0
  109. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/core/transaction.py +0 -0
  110. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/servers/__init__.py +0 -0
  111. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/servers/postgres/reserved.py +0 -0
  112. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/servers/tablehelper.py +0 -0
  113. /velocity_python-0.0.131/src/velocity/misc/__init__.py → /velocity_python-0.0.134/src/velocity/db/tests/common_db_test.py +0 -0
  114. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_cursor_rowcount_fix.py +0 -0
  115. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_db_utils.py +0 -0
  116. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_postgres.py +0 -0
  117. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_process_error_robustness.py +0 -0
  118. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_result_caching.py +0 -0
  119. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_result_sql_aware.py +0 -0
  120. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_row_get_missing_column.py +0 -0
  121. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_sql_builder.py +0 -0
  122. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/db}/tests/test_tablehelper.py +0 -0
  123. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/db/utils.py +0 -0
  124. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/conv/__init__.py +0 -0
  125. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/conv/iconv.py +0 -0
  126. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/conv/oconv.py +0 -0
  127. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/db.py +0 -0
  128. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/export.py +0 -0
  129. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/format.py +0 -0
  130. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/mail.py +0 -0
  131. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/merge.py +0 -0
  132. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/misc}/tests/test_fix.py +0 -0
  133. {velocity_python-0.0.131 → velocity_python-0.0.134/src/velocity/misc}/tests/test_original_error.py +0 -0
  134. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/timer.py +0 -0
  135. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity/misc/tools.py +0 -0
  136. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  137. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity_python.egg-info/requires.txt +0 -0
  138. {velocity_python-0.0.131 → velocity_python-0.0.134}/src/velocity_python.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.131
3
+ Version: 0.0.134
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.0.131"
7
+ version = "0.0.134"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.0.131"
1
+ __version__ = version = "0.0.134"
2
2
 
3
3
  from . import aws
4
4
  from . import db
@@ -0,0 +1 @@
1
+ # App module tests
@@ -0,0 +1 @@
1
+ # AWS module tests
@@ -99,7 +99,8 @@ def return_default(
99
99
 
100
100
  def create_missing(func):
101
101
  """
102
- If the function call fails with DbColumnMissingError or DbTableMissingError, tries to create them and re-run.
102
+ If the function call fails with DbColumnMissingError or DbTableMissingError,
103
+ tries to create them and re-run (only if schema is not locked).
103
104
  """
104
105
 
105
106
  @wraps(func)
@@ -109,8 +110,16 @@ def create_missing(func):
109
110
  result = func(self, *args, **kwds)
110
111
  self.tx.release_savepoint(sp, cursor=self.cursor())
111
112
  return result
112
- except exceptions.DbColumnMissingError:
113
+ except exceptions.DbColumnMissingError as e:
113
114
  self.tx.rollback_savepoint(sp, cursor=self.cursor())
115
+
116
+ # Check if schema is locked
117
+ if self.tx.engine.schema_locked:
118
+ raise exceptions.DbSchemaLockedError(
119
+ f"Cannot create missing column: schema is locked. Original error: {e}"
120
+ ) from e
121
+
122
+ # Existing logic for automatic creation
114
123
  data = {}
115
124
  if "pk" in kwds:
116
125
  data.update(kwds["pk"])
@@ -121,8 +130,16 @@ def create_missing(func):
121
130
  data.update(arg)
122
131
  self.alter(data)
123
132
  return func(self, *args, **kwds)
124
- except exceptions.DbTableMissingError:
133
+ except exceptions.DbTableMissingError as e:
125
134
  self.tx.rollback_savepoint(sp, cursor=self.cursor())
135
+
136
+ # Check if schema is locked
137
+ if self.tx.engine.schema_locked:
138
+ raise exceptions.DbSchemaLockedError(
139
+ f"Cannot create missing table: schema is locked. Original error: {e}"
140
+ ) from e
141
+
142
+ # Existing logic for automatic creation
126
143
  data = {}
127
144
  if "pk" in kwds:
128
145
  data.update(kwds["pk"])
@@ -1,5 +1,7 @@
1
1
  import inspect
2
2
  import re
3
+ import os
4
+ from contextlib import contextmanager
3
5
  from functools import wraps
4
6
  from velocity.db import exceptions
5
7
  from velocity.db.core.transaction import Transaction
@@ -17,11 +19,12 @@ class Engine:
17
19
 
18
20
  MAX_RETRIES = 100
19
21
 
20
- def __init__(self, driver, config, sql, connect_timeout=5):
22
+ def __init__(self, driver, config, sql, connect_timeout=5, schema_locked=False):
21
23
  self.__config = config
22
24
  self.__sql = sql
23
25
  self.__driver = driver
24
26
  self.__connect_timeout = connect_timeout
27
+ self.__schema_locked = schema_locked
25
28
 
26
29
  def __str__(self):
27
30
  return f"[{self.sql.server}] engine({self.config})"
@@ -205,6 +208,29 @@ class Engine:
205
208
  def sql(self):
206
209
  return self.__sql
207
210
 
211
+ @property
212
+ def schema_locked(self):
213
+ """Returns True if schema modifications are locked."""
214
+ return self.__schema_locked
215
+
216
+ def lock_schema(self):
217
+ """Lock schema to prevent automatic modifications."""
218
+ self.__schema_locked = True
219
+
220
+ def unlock_schema(self):
221
+ """Unlock schema to allow automatic modifications."""
222
+ self.__schema_locked = False
223
+
224
+ @contextmanager
225
+ def unlocked_schema(self):
226
+ """Temporarily unlock schema for automatic creation."""
227
+ original_state = self.__schema_locked
228
+ self.__schema_locked = False
229
+ try:
230
+ yield self
231
+ finally:
232
+ self.__schema_locked = original_state
233
+
208
234
  @property
209
235
  def version(self):
210
236
  """
@@ -353,12 +379,12 @@ class Engine:
353
379
  if sql:
354
380
  formatted_sql_info = f" sql={self._format_sql_with_params(sql, parameters)}"
355
381
 
356
- logger.warning(
357
- "Database error caught. Attempting to transform: code=%s message=%s%s",
358
- error_code,
359
- error_message,
360
- formatted_sql_info,
361
- )
382
+ # logger.warning(
383
+ # "Database error caught. Attempting to transform: code=%s message=%s%s",
384
+ # error_code,
385
+ # error_message,
386
+ # formatted_sql_info,
387
+ # )
362
388
 
363
389
  # Direct error code mapping
364
390
  if error_code in self.sql.ApplicationErrorCodes:
@@ -93,6 +93,12 @@ class DbTransactionError(DbException):
93
93
  pass
94
94
 
95
95
 
96
+ class DbSchemaLockedError(DbApplicationError):
97
+ """Raised when attempting to modify schema while schema is locked."""
98
+
99
+ pass
100
+
101
+
96
102
  class DuplicateRowsFoundError(Exception):
97
103
  """Multiple rows found when expecting single result."""
98
104
 
@@ -125,5 +131,6 @@ __all__ = [
125
131
  "DbDataIntegrityError",
126
132
  "DbQueryError",
127
133
  "DbTransactionError",
134
+ "DbSchemaLockedError",
128
135
  "DuplicateRowsFoundError",
129
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 {}