omnibase_infra 0.2.9__py3-none-any.whl → 0.3.0__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.
- omnibase_infra/__init__.py +1 -1
- omnibase_infra/errors/__init__.py +18 -0
- omnibase_infra/errors/repository/__init__.py +78 -0
- omnibase_infra/errors/repository/errors_repository.py +424 -0
- omnibase_infra/nodes/contract_registry_reducer/reducer.py +12 -2
- omnibase_infra/runtime/db/__init__.py +73 -0
- omnibase_infra/runtime/db/models/__init__.py +41 -0
- omnibase_infra/runtime/db/models/model_repository_runtime_config.py +211 -0
- omnibase_infra/runtime/db/postgres_repository_runtime.py +545 -0
- omnibase_infra/validation/infra_validators.py +4 -1
- omnibase_infra/validation/validation_exemptions.yaml +18 -0
- {omnibase_infra-0.2.9.dist-info → omnibase_infra-0.3.0.dist-info}/METADATA +2 -2
- {omnibase_infra-0.2.9.dist-info → omnibase_infra-0.3.0.dist-info}/RECORD +16 -10
- {omnibase_infra-0.2.9.dist-info → omnibase_infra-0.3.0.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.9.dist-info → omnibase_infra-0.3.0.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.2.9.dist-info → omnibase_infra-0.3.0.dist-info}/licenses/LICENSE +0 -0
omnibase_infra/__init__.py
CHANGED
|
@@ -23,6 +23,11 @@ Exports:
|
|
|
23
23
|
ChainPropagationError: Correlation/causation chain validation errors
|
|
24
24
|
ArchitectureViolationError: Architecture validation errors (blocks startup)
|
|
25
25
|
BindingResolutionError: Binding resolution errors (declarative operation bindings)
|
|
26
|
+
RepositoryError: Base error for repository operations
|
|
27
|
+
RepositoryContractError: Contract-level errors (bad op_name, missing params)
|
|
28
|
+
RepositoryValidationError: Validation errors (type mismatch, constraints)
|
|
29
|
+
RepositoryExecutionError: Execution errors (asyncpg, connection issues)
|
|
30
|
+
RepositoryTimeoutError: Query timeout exceeded
|
|
26
31
|
|
|
27
32
|
Correlation ID Assignment:
|
|
28
33
|
All infrastructure errors support correlation_id for distributed tracing.
|
|
@@ -117,6 +122,13 @@ from omnibase_infra.errors.error_infra import (
|
|
|
117
122
|
from omnibase_infra.errors.error_message_type_registry import MessageTypeRegistryError
|
|
118
123
|
from omnibase_infra.errors.error_policy_registry import PolicyRegistryError
|
|
119
124
|
from omnibase_infra.errors.error_vault import InfraVaultError
|
|
125
|
+
from omnibase_infra.errors.repository import (
|
|
126
|
+
RepositoryContractError,
|
|
127
|
+
RepositoryError,
|
|
128
|
+
RepositoryExecutionError,
|
|
129
|
+
RepositoryTimeoutError,
|
|
130
|
+
RepositoryValidationError,
|
|
131
|
+
)
|
|
120
132
|
from omnibase_infra.models.errors.model_infra_error_context import (
|
|
121
133
|
ModelInfraErrorContext,
|
|
122
134
|
)
|
|
@@ -150,6 +162,12 @@ __all__: list[str] = [
|
|
|
150
162
|
"ModelTimeoutErrorContext",
|
|
151
163
|
"PolicyRegistryError",
|
|
152
164
|
"ProtocolConfigurationError",
|
|
165
|
+
# Repository errors
|
|
166
|
+
"RepositoryContractError",
|
|
167
|
+
"RepositoryError",
|
|
168
|
+
"RepositoryExecutionError",
|
|
169
|
+
"RepositoryTimeoutError",
|
|
170
|
+
"RepositoryValidationError",
|
|
153
171
|
# Error classes
|
|
154
172
|
"RuntimeHostError",
|
|
155
173
|
"SecretResolutionError",
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Repository Error Classes Module.
|
|
4
|
+
|
|
5
|
+
This module provides error classes specific to repository operations,
|
|
6
|
+
enabling typed exception handling for the PostgresRepositoryRuntime.
|
|
7
|
+
|
|
8
|
+
Error Hierarchy:
|
|
9
|
+
RuntimeHostError (from omnibase_infra.errors)
|
|
10
|
+
└── RepositoryError (base repository error)
|
|
11
|
+
├── RepositoryContractError (contract-level errors)
|
|
12
|
+
├── RepositoryValidationError (validation errors)
|
|
13
|
+
├── RepositoryExecutionError (execution errors)
|
|
14
|
+
└── RepositoryTimeoutError (query timeout errors)
|
|
15
|
+
|
|
16
|
+
Exports:
|
|
17
|
+
RepositoryError: Base error for all repository operations
|
|
18
|
+
RepositoryContractError: Bad op_name, missing params, forbidden op
|
|
19
|
+
RepositoryValidationError: Param type mismatch, constraint violation
|
|
20
|
+
RepositoryExecutionError: asyncpg errors, connection issues
|
|
21
|
+
RepositoryTimeoutError: Query timeout exceeded
|
|
22
|
+
|
|
23
|
+
Common Fields (all exceptions):
|
|
24
|
+
op_name: str | None - Operation name from repository contract
|
|
25
|
+
table: str | None - Target table for the operation
|
|
26
|
+
retriable: bool - Whether the operation can be retried
|
|
27
|
+
sql_fingerprint: str | None - SQL fingerprint for query tracking
|
|
28
|
+
|
|
29
|
+
Example Usage::
|
|
30
|
+
|
|
31
|
+
from omnibase_infra.errors.repository import (
|
|
32
|
+
RepositoryContractError,
|
|
33
|
+
RepositoryExecutionError,
|
|
34
|
+
RepositoryTimeoutError,
|
|
35
|
+
RepositoryValidationError,
|
|
36
|
+
)
|
|
37
|
+
from omnibase_infra.models.errors import ModelInfraErrorContext
|
|
38
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
39
|
+
|
|
40
|
+
# Contract error - unknown operation
|
|
41
|
+
context = ModelInfraErrorContext.with_correlation(
|
|
42
|
+
transport_type=EnumInfraTransportType.DATABASE,
|
|
43
|
+
operation="execute_operation",
|
|
44
|
+
)
|
|
45
|
+
raise RepositoryContractError(
|
|
46
|
+
"Unknown operation 'invalid_op'",
|
|
47
|
+
op_name="invalid_op",
|
|
48
|
+
table="users",
|
|
49
|
+
context=context,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Check retriability in error handling
|
|
53
|
+
try:
|
|
54
|
+
result = await runtime.execute("find_all", {})
|
|
55
|
+
except RepositoryError as e:
|
|
56
|
+
if e.retriable:
|
|
57
|
+
# Can retry with backoff
|
|
58
|
+
pass
|
|
59
|
+
else:
|
|
60
|
+
# Non-retriable, propagate
|
|
61
|
+
raise
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
from omnibase_infra.errors.repository.errors_repository import (
|
|
65
|
+
RepositoryContractError,
|
|
66
|
+
RepositoryError,
|
|
67
|
+
RepositoryExecutionError,
|
|
68
|
+
RepositoryTimeoutError,
|
|
69
|
+
RepositoryValidationError,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
"RepositoryContractError",
|
|
74
|
+
"RepositoryError",
|
|
75
|
+
"RepositoryExecutionError",
|
|
76
|
+
"RepositoryTimeoutError",
|
|
77
|
+
"RepositoryValidationError",
|
|
78
|
+
]
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Repository Error Classes for PostgresRepositoryRuntime.
|
|
4
|
+
|
|
5
|
+
This module defines error classes specific to repository operations,
|
|
6
|
+
providing granular error handling for contract-driven database access.
|
|
7
|
+
|
|
8
|
+
Error Hierarchy:
|
|
9
|
+
RuntimeHostError (from error_infra)
|
|
10
|
+
└── RepositoryError (base repository error)
|
|
11
|
+
├── RepositoryContractError (contract-level errors)
|
|
12
|
+
├── RepositoryValidationError (validation errors)
|
|
13
|
+
├── RepositoryExecutionError (execution errors)
|
|
14
|
+
└── RepositoryTimeoutError (query timeout errors)
|
|
15
|
+
|
|
16
|
+
All errors:
|
|
17
|
+
- Extend RuntimeHostError for infrastructure consistency
|
|
18
|
+
- Include repository-specific fields: op_name, table, retriable
|
|
19
|
+
- Support optional sql_fingerprint for query tracking
|
|
20
|
+
- Use EnumCoreErrorCode for error classification
|
|
21
|
+
- Support correlation IDs for distributed tracing
|
|
22
|
+
|
|
23
|
+
Retriability Guidelines:
|
|
24
|
+
- RepositoryContractError: NOT retriable (contract/configuration issue)
|
|
25
|
+
- RepositoryValidationError: NOT retriable (data validation issue)
|
|
26
|
+
- RepositoryExecutionError: Generally retriable (transient failures)
|
|
27
|
+
- RepositoryTimeoutError: Retriable (timeout may be transient)
|
|
28
|
+
|
|
29
|
+
Example::
|
|
30
|
+
|
|
31
|
+
from omnibase_infra.errors.repository import (
|
|
32
|
+
RepositoryContractError,
|
|
33
|
+
RepositoryExecutionError,
|
|
34
|
+
RepositoryTimeoutError,
|
|
35
|
+
RepositoryValidationError,
|
|
36
|
+
)
|
|
37
|
+
from omnibase_infra.models.errors import ModelInfraErrorContext
|
|
38
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
39
|
+
|
|
40
|
+
# Contract error - unknown operation
|
|
41
|
+
context = ModelInfraErrorContext.with_correlation(
|
|
42
|
+
transport_type=EnumInfraTransportType.DATABASE,
|
|
43
|
+
operation="execute_operation",
|
|
44
|
+
)
|
|
45
|
+
raise RepositoryContractError(
|
|
46
|
+
"Unknown operation 'invalid_op' not defined in contract",
|
|
47
|
+
op_name="invalid_op",
|
|
48
|
+
table="users",
|
|
49
|
+
context=context,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Execution error with SQL fingerprint
|
|
53
|
+
raise RepositoryExecutionError(
|
|
54
|
+
"Connection pool exhausted",
|
|
55
|
+
op_name="find_by_id",
|
|
56
|
+
table="users",
|
|
57
|
+
sql_fingerprint="SELECT * FROM users WHERE id = $1",
|
|
58
|
+
context=context,
|
|
59
|
+
) from e
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
from omnibase_core.enums import EnumCoreErrorCode
|
|
63
|
+
from omnibase_infra.errors.error_infra import RuntimeHostError
|
|
64
|
+
from omnibase_infra.models.errors.model_infra_error_context import (
|
|
65
|
+
ModelInfraErrorContext,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class RepositoryError(RuntimeHostError):
|
|
70
|
+
"""Base error class for all repository operations.
|
|
71
|
+
|
|
72
|
+
Provides common structured fields for repository-specific errors:
|
|
73
|
+
- op_name: The operation name from the repository contract
|
|
74
|
+
- table: The target table for the operation
|
|
75
|
+
- retriable: Whether the operation can be retried
|
|
76
|
+
- sql_fingerprint: Optional SQL fingerprint for query tracking
|
|
77
|
+
|
|
78
|
+
Subclasses set default retriability based on error category:
|
|
79
|
+
- Contract errors: NOT retriable
|
|
80
|
+
- Validation errors: NOT retriable
|
|
81
|
+
- Execution errors: Generally retriable
|
|
82
|
+
- Timeout errors: Retriable
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
86
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
87
|
+
... operation="execute_operation",
|
|
88
|
+
... )
|
|
89
|
+
>>> raise RepositoryError(
|
|
90
|
+
... "Repository operation failed",
|
|
91
|
+
... op_name="find_by_id",
|
|
92
|
+
... table="users",
|
|
93
|
+
... context=context,
|
|
94
|
+
... )
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
# Default retriability for base class (conservative: not retriable)
|
|
98
|
+
_default_retriable: bool = False
|
|
99
|
+
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
message: str,
|
|
103
|
+
*,
|
|
104
|
+
op_name: str | None = None,
|
|
105
|
+
table: str | None = None,
|
|
106
|
+
retriable: bool | None = None,
|
|
107
|
+
sql_fingerprint: str | None = None,
|
|
108
|
+
error_code: EnumCoreErrorCode | None = None,
|
|
109
|
+
context: ModelInfraErrorContext | None = None,
|
|
110
|
+
**extra_context: object,
|
|
111
|
+
) -> None:
|
|
112
|
+
"""Initialize RepositoryError with repository-specific fields.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
message: Human-readable error message
|
|
116
|
+
op_name: Operation name from the repository contract
|
|
117
|
+
table: Target table for the operation
|
|
118
|
+
retriable: Whether the operation can be retried. If None, uses
|
|
119
|
+
class default (_default_retriable)
|
|
120
|
+
sql_fingerprint: SQL fingerprint for query tracking (sanitized)
|
|
121
|
+
error_code: Error code (defaults to DATABASE_OPERATION_ERROR)
|
|
122
|
+
context: Bundled infrastructure context
|
|
123
|
+
**extra_context: Additional context information
|
|
124
|
+
"""
|
|
125
|
+
# Add repository-specific fields to extra_context
|
|
126
|
+
if op_name is not None:
|
|
127
|
+
extra_context["op_name"] = op_name
|
|
128
|
+
if table is not None:
|
|
129
|
+
extra_context["table"] = table
|
|
130
|
+
if sql_fingerprint is not None:
|
|
131
|
+
extra_context["sql_fingerprint"] = sql_fingerprint
|
|
132
|
+
|
|
133
|
+
# Resolve retriability: explicit > class default
|
|
134
|
+
resolved_retriable = (
|
|
135
|
+
retriable if retriable is not None else self._default_retriable
|
|
136
|
+
)
|
|
137
|
+
extra_context["retriable"] = resolved_retriable
|
|
138
|
+
|
|
139
|
+
# Store as instance attributes for programmatic access
|
|
140
|
+
self.op_name = op_name
|
|
141
|
+
self.table = table
|
|
142
|
+
self.retriable = resolved_retriable
|
|
143
|
+
self.sql_fingerprint = sql_fingerprint
|
|
144
|
+
|
|
145
|
+
super().__init__(
|
|
146
|
+
message=message,
|
|
147
|
+
error_code=error_code or EnumCoreErrorCode.DATABASE_OPERATION_ERROR,
|
|
148
|
+
context=context,
|
|
149
|
+
**extra_context,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class RepositoryContractError(RepositoryError):
|
|
154
|
+
"""Raised for contract-level errors in repository operations.
|
|
155
|
+
|
|
156
|
+
Used when:
|
|
157
|
+
- Operation name (op_name) is not defined in the contract
|
|
158
|
+
- Required parameters are missing for the operation
|
|
159
|
+
- Operation is explicitly forbidden in the contract
|
|
160
|
+
- Contract schema validation fails
|
|
161
|
+
|
|
162
|
+
Contract errors are NOT retriable - they indicate a configuration
|
|
163
|
+
or programming error that requires code or contract changes to fix.
|
|
164
|
+
|
|
165
|
+
Example:
|
|
166
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
167
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
168
|
+
... operation="execute_operation",
|
|
169
|
+
... )
|
|
170
|
+
>>> raise RepositoryContractError(
|
|
171
|
+
... "Operation 'drop_table' is forbidden in contract",
|
|
172
|
+
... op_name="drop_table",
|
|
173
|
+
... table="users",
|
|
174
|
+
... context=context,
|
|
175
|
+
... )
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
_default_retriable: bool = False
|
|
179
|
+
|
|
180
|
+
def __init__(
|
|
181
|
+
self,
|
|
182
|
+
message: str,
|
|
183
|
+
*,
|
|
184
|
+
op_name: str | None = None,
|
|
185
|
+
table: str | None = None,
|
|
186
|
+
retriable: bool | None = None,
|
|
187
|
+
sql_fingerprint: str | None = None,
|
|
188
|
+
context: ModelInfraErrorContext | None = None,
|
|
189
|
+
**extra_context: object,
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Initialize RepositoryContractError.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
message: Human-readable error message
|
|
195
|
+
op_name: Operation name that caused the contract error
|
|
196
|
+
table: Target table (if applicable)
|
|
197
|
+
retriable: Override default (False). Contract errors are
|
|
198
|
+
generally NOT retriable.
|
|
199
|
+
sql_fingerprint: SQL fingerprint (if applicable)
|
|
200
|
+
context: Bundled infrastructure context
|
|
201
|
+
**extra_context: Additional context information
|
|
202
|
+
"""
|
|
203
|
+
super().__init__(
|
|
204
|
+
message=message,
|
|
205
|
+
op_name=op_name,
|
|
206
|
+
table=table,
|
|
207
|
+
retriable=retriable,
|
|
208
|
+
sql_fingerprint=sql_fingerprint,
|
|
209
|
+
error_code=EnumCoreErrorCode.INVALID_CONFIGURATION,
|
|
210
|
+
context=context,
|
|
211
|
+
**extra_context,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class RepositoryValidationError(RepositoryError):
|
|
216
|
+
"""Raised for validation errors in repository operations.
|
|
217
|
+
|
|
218
|
+
Used when:
|
|
219
|
+
- Parameter type mismatches (e.g., string passed for int column)
|
|
220
|
+
- Constraint violations (e.g., null for non-nullable column)
|
|
221
|
+
- Value out of allowed range
|
|
222
|
+
- Invalid data format
|
|
223
|
+
|
|
224
|
+
Validation errors are NOT retriable - they indicate invalid input
|
|
225
|
+
data that must be corrected before retrying.
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
229
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
230
|
+
... operation="execute_operation",
|
|
231
|
+
... )
|
|
232
|
+
>>> raise RepositoryValidationError(
|
|
233
|
+
... "Parameter 'user_id' expected int, got str",
|
|
234
|
+
... op_name="find_by_id",
|
|
235
|
+
... table="users",
|
|
236
|
+
... context=context,
|
|
237
|
+
... param_name="user_id",
|
|
238
|
+
... expected_type="int",
|
|
239
|
+
... actual_type="str",
|
|
240
|
+
... )
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
_default_retriable: bool = False
|
|
244
|
+
|
|
245
|
+
def __init__(
|
|
246
|
+
self,
|
|
247
|
+
message: str,
|
|
248
|
+
*,
|
|
249
|
+
op_name: str | None = None,
|
|
250
|
+
table: str | None = None,
|
|
251
|
+
retriable: bool | None = None,
|
|
252
|
+
sql_fingerprint: str | None = None,
|
|
253
|
+
context: ModelInfraErrorContext | None = None,
|
|
254
|
+
**extra_context: object,
|
|
255
|
+
) -> None:
|
|
256
|
+
"""Initialize RepositoryValidationError.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
message: Human-readable error message
|
|
260
|
+
op_name: Operation name that triggered validation
|
|
261
|
+
table: Target table (if applicable)
|
|
262
|
+
retriable: Override default (False). Validation errors are
|
|
263
|
+
generally NOT retriable.
|
|
264
|
+
sql_fingerprint: SQL fingerprint (if applicable)
|
|
265
|
+
context: Bundled infrastructure context
|
|
266
|
+
**extra_context: Additional context (param_name, expected_type, etc.)
|
|
267
|
+
"""
|
|
268
|
+
super().__init__(
|
|
269
|
+
message=message,
|
|
270
|
+
op_name=op_name,
|
|
271
|
+
table=table,
|
|
272
|
+
retriable=retriable,
|
|
273
|
+
sql_fingerprint=sql_fingerprint,
|
|
274
|
+
error_code=EnumCoreErrorCode.VALIDATION_ERROR,
|
|
275
|
+
context=context,
|
|
276
|
+
**extra_context,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class RepositoryExecutionError(RepositoryError):
|
|
281
|
+
"""Raised for execution errors in repository operations.
|
|
282
|
+
|
|
283
|
+
Used when:
|
|
284
|
+
- asyncpg errors during query execution
|
|
285
|
+
- Connection pool exhaustion
|
|
286
|
+
- Database connection lost mid-operation
|
|
287
|
+
- Deadlock detected
|
|
288
|
+
- Serialization failures
|
|
289
|
+
|
|
290
|
+
Execution errors are generally retriable - they often indicate
|
|
291
|
+
transient failures that may succeed on retry with backoff.
|
|
292
|
+
|
|
293
|
+
Example:
|
|
294
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
295
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
296
|
+
... operation="execute_operation",
|
|
297
|
+
... )
|
|
298
|
+
>>> try:
|
|
299
|
+
... result = await pool.execute(sql, *params)
|
|
300
|
+
... except asyncpg.PostgresError as e:
|
|
301
|
+
... raise RepositoryExecutionError(
|
|
302
|
+
... f"Query execution failed: {e}",
|
|
303
|
+
... op_name="create_user",
|
|
304
|
+
... table="users",
|
|
305
|
+
... sql_fingerprint="INSERT INTO users (...) VALUES (...)",
|
|
306
|
+
... context=context,
|
|
307
|
+
... ) from e
|
|
308
|
+
"""
|
|
309
|
+
|
|
310
|
+
_default_retriable: bool = True
|
|
311
|
+
|
|
312
|
+
def __init__(
|
|
313
|
+
self,
|
|
314
|
+
message: str,
|
|
315
|
+
*,
|
|
316
|
+
op_name: str | None = None,
|
|
317
|
+
table: str | None = None,
|
|
318
|
+
retriable: bool | None = None,
|
|
319
|
+
sql_fingerprint: str | None = None,
|
|
320
|
+
context: ModelInfraErrorContext | None = None,
|
|
321
|
+
**extra_context: object,
|
|
322
|
+
) -> None:
|
|
323
|
+
"""Initialize RepositoryExecutionError.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
message: Human-readable error message
|
|
327
|
+
op_name: Operation name that failed during execution
|
|
328
|
+
table: Target table (if applicable)
|
|
329
|
+
retriable: Override default (True). Set False for non-retriable
|
|
330
|
+
execution errors (e.g., constraint violations from DB).
|
|
331
|
+
sql_fingerprint: SQL fingerprint for query tracking
|
|
332
|
+
context: Bundled infrastructure context
|
|
333
|
+
**extra_context: Additional context (asyncpg error details, etc.)
|
|
334
|
+
"""
|
|
335
|
+
super().__init__(
|
|
336
|
+
message=message,
|
|
337
|
+
op_name=op_name,
|
|
338
|
+
table=table,
|
|
339
|
+
retriable=retriable,
|
|
340
|
+
sql_fingerprint=sql_fingerprint,
|
|
341
|
+
error_code=EnumCoreErrorCode.DATABASE_OPERATION_ERROR,
|
|
342
|
+
context=context,
|
|
343
|
+
**extra_context,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
class RepositoryTimeoutError(RepositoryError):
|
|
348
|
+
"""Raised when a repository query exceeds its timeout.
|
|
349
|
+
|
|
350
|
+
Used when:
|
|
351
|
+
- Query exceeds statement_timeout
|
|
352
|
+
- Connection acquisition times out
|
|
353
|
+
- Transaction times out
|
|
354
|
+
|
|
355
|
+
Timeout errors are retriable - the same query may succeed
|
|
356
|
+
under different load conditions or with adjusted timeouts.
|
|
357
|
+
|
|
358
|
+
Example:
|
|
359
|
+
>>> context = ModelInfraErrorContext.with_correlation(
|
|
360
|
+
... transport_type=EnumInfraTransportType.DATABASE,
|
|
361
|
+
... operation="execute_operation",
|
|
362
|
+
... )
|
|
363
|
+
>>> raise RepositoryTimeoutError(
|
|
364
|
+
... "Query exceeded 30s timeout",
|
|
365
|
+
... op_name="complex_report",
|
|
366
|
+
... table="analytics",
|
|
367
|
+
... timeout_seconds=30.0,
|
|
368
|
+
... sql_fingerprint="SELECT ... FROM analytics ...",
|
|
369
|
+
... context=context,
|
|
370
|
+
... )
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
_default_retriable: bool = True
|
|
374
|
+
|
|
375
|
+
def __init__(
|
|
376
|
+
self,
|
|
377
|
+
message: str,
|
|
378
|
+
*,
|
|
379
|
+
op_name: str | None = None,
|
|
380
|
+
table: str | None = None,
|
|
381
|
+
retriable: bool | None = None,
|
|
382
|
+
sql_fingerprint: str | None = None,
|
|
383
|
+
timeout_seconds: float | None = None,
|
|
384
|
+
context: ModelInfraErrorContext | None = None,
|
|
385
|
+
**extra_context: object,
|
|
386
|
+
) -> None:
|
|
387
|
+
"""Initialize RepositoryTimeoutError.
|
|
388
|
+
|
|
389
|
+
Args:
|
|
390
|
+
message: Human-readable error message
|
|
391
|
+
op_name: Operation name that timed out
|
|
392
|
+
table: Target table (if applicable)
|
|
393
|
+
retriable: Override default (True). Timeout errors are
|
|
394
|
+
generally retriable.
|
|
395
|
+
sql_fingerprint: SQL fingerprint for query tracking
|
|
396
|
+
timeout_seconds: The timeout value that was exceeded
|
|
397
|
+
context: Bundled infrastructure context
|
|
398
|
+
**extra_context: Additional context information
|
|
399
|
+
"""
|
|
400
|
+
if timeout_seconds is not None:
|
|
401
|
+
extra_context["timeout_seconds"] = timeout_seconds
|
|
402
|
+
|
|
403
|
+
# Store for programmatic access
|
|
404
|
+
self.timeout_seconds = timeout_seconds
|
|
405
|
+
|
|
406
|
+
super().__init__(
|
|
407
|
+
message=message,
|
|
408
|
+
op_name=op_name,
|
|
409
|
+
table=table,
|
|
410
|
+
retriable=retriable,
|
|
411
|
+
sql_fingerprint=sql_fingerprint,
|
|
412
|
+
error_code=EnumCoreErrorCode.TIMEOUT_ERROR,
|
|
413
|
+
context=context,
|
|
414
|
+
**extra_context,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
__all__ = [
|
|
419
|
+
"RepositoryContractError",
|
|
420
|
+
"RepositoryError",
|
|
421
|
+
"RepositoryExecutionError",
|
|
422
|
+
"RepositoryTimeoutError",
|
|
423
|
+
"RepositoryValidationError",
|
|
424
|
+
]
|
|
@@ -702,13 +702,18 @@ class ContractRegistryReducer:
|
|
|
702
702
|
# We store it as-is; the Effect layer handles resolution.
|
|
703
703
|
topic_suffix = consumed.get("topic")
|
|
704
704
|
if topic_suffix and isinstance(topic_suffix, str):
|
|
705
|
+
# Validate event_type is string (may be missing or wrong type in malformed YAML)
|
|
706
|
+
event_type_raw = consumed.get("event_type")
|
|
707
|
+
event_type = (
|
|
708
|
+
event_type_raw if isinstance(event_type_raw, str) else None
|
|
709
|
+
)
|
|
705
710
|
payload = ModelPayloadUpdateTopic(
|
|
706
711
|
correlation_id=correlation_id,
|
|
707
712
|
topic_suffix=topic_suffix,
|
|
708
713
|
direction="subscribe",
|
|
709
714
|
contract_id=contract_id,
|
|
710
715
|
node_name=event.node_name,
|
|
711
|
-
event_type=
|
|
716
|
+
event_type=event_type,
|
|
712
717
|
last_seen_at=event.timestamp,
|
|
713
718
|
)
|
|
714
719
|
intents.append(
|
|
@@ -728,13 +733,18 @@ class ContractRegistryReducer:
|
|
|
728
733
|
# Effect layer handles resolution (see docstring above).
|
|
729
734
|
topic_suffix = published.get("topic")
|
|
730
735
|
if topic_suffix and isinstance(topic_suffix, str):
|
|
736
|
+
# Validate event_type is string (may be missing or wrong type in malformed YAML)
|
|
737
|
+
event_type_raw = published.get("event_type")
|
|
738
|
+
event_type = (
|
|
739
|
+
event_type_raw if isinstance(event_type_raw, str) else None
|
|
740
|
+
)
|
|
731
741
|
payload = ModelPayloadUpdateTopic(
|
|
732
742
|
correlation_id=correlation_id,
|
|
733
743
|
topic_suffix=topic_suffix,
|
|
734
744
|
direction="publish",
|
|
735
745
|
contract_id=contract_id,
|
|
736
746
|
node_name=event.node_name,
|
|
737
|
-
event_type=
|
|
747
|
+
event_type=event_type,
|
|
738
748
|
last_seen_at=event.timestamp,
|
|
739
749
|
)
|
|
740
750
|
intents.append(
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Database runtime module for omnibase_infra.
|
|
4
|
+
|
|
5
|
+
This module provides the PostgresRepositoryRuntime and associated models for
|
|
6
|
+
database operations with safety constraints and deterministic query behavior.
|
|
7
|
+
|
|
8
|
+
Components:
|
|
9
|
+
- PostgresRepositoryRuntime: Generic Postgres runtime for contract execution
|
|
10
|
+
- ModelRepositoryRuntimeConfig: Configuration for runtime behavior
|
|
11
|
+
- ModelDbRepositoryContract: Repository contract specification
|
|
12
|
+
- ModelDbOperation: Database operation specification
|
|
13
|
+
- ModelDbReturn: Return type specification
|
|
14
|
+
|
|
15
|
+
The db module enables safe, configurable database operations with:
|
|
16
|
+
- Contract-driven operations (all ops defined in ModelDbRepositoryContract)
|
|
17
|
+
- Operation allowlisting (select, insert, update, upsert)
|
|
18
|
+
- Row limits for multi-row selects
|
|
19
|
+
- Query timeouts with asyncio.wait_for()
|
|
20
|
+
- Deterministic ORDER BY injection
|
|
21
|
+
- Metrics emission
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
>>> import asyncpg
|
|
25
|
+
>>> from omnibase_infra.runtime.db import (
|
|
26
|
+
... PostgresRepositoryRuntime,
|
|
27
|
+
... ModelDbRepositoryContract,
|
|
28
|
+
... ModelDbOperation,
|
|
29
|
+
... ModelDbReturn,
|
|
30
|
+
... ModelRepositoryRuntimeConfig,
|
|
31
|
+
... )
|
|
32
|
+
>>>
|
|
33
|
+
>>> # Define contract
|
|
34
|
+
>>> contract = ModelDbRepositoryContract(
|
|
35
|
+
... name="users",
|
|
36
|
+
... database_ref="primary",
|
|
37
|
+
... ops={
|
|
38
|
+
... "find_by_id": ModelDbOperation(
|
|
39
|
+
... mode="select",
|
|
40
|
+
... sql="SELECT * FROM users WHERE id = $1",
|
|
41
|
+
... params=["user_id"],
|
|
42
|
+
... returns=ModelDbReturn(many=False),
|
|
43
|
+
... ),
|
|
44
|
+
... },
|
|
45
|
+
... )
|
|
46
|
+
>>>
|
|
47
|
+
>>> # Create runtime with pool
|
|
48
|
+
>>> pool = await asyncpg.create_pool(...)
|
|
49
|
+
>>> runtime = PostgresRepositoryRuntime(pool, contract)
|
|
50
|
+
>>>
|
|
51
|
+
>>> # Execute operation
|
|
52
|
+
>>> user = await runtime.call("find_by_id", 123)
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
from __future__ import annotations
|
|
56
|
+
|
|
57
|
+
from omnibase_infra.runtime.db.models import (
|
|
58
|
+
ModelDbOperation,
|
|
59
|
+
ModelDbRepositoryContract,
|
|
60
|
+
ModelDbReturn,
|
|
61
|
+
ModelRepositoryRuntimeConfig,
|
|
62
|
+
)
|
|
63
|
+
from omnibase_infra.runtime.db.postgres_repository_runtime import (
|
|
64
|
+
PostgresRepositoryRuntime,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
__all__: list[str] = [
|
|
68
|
+
"ModelDbOperation",
|
|
69
|
+
"ModelDbRepositoryContract",
|
|
70
|
+
"ModelDbReturn",
|
|
71
|
+
"ModelRepositoryRuntimeConfig",
|
|
72
|
+
"PostgresRepositoryRuntime",
|
|
73
|
+
]
|