feat(validators): add composite validators
Implement AllOf and AnyOf for combining multiple checks into composite validation rules.
This commit is contained in:
90
src/veritext/validators/composite.py
Normal file
90
src/veritext/validators/composite.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""Composite validators for combining multiple checks."""
|
||||
|
||||
from veritext.core.types import CheckResult, ValidationContext, ValidationResult
|
||||
from veritext.validators.base import Check
|
||||
|
||||
|
||||
class AllOf:
|
||||
"""Passes only if all checks pass."""
|
||||
|
||||
def __init__(self, checks: list[Check]) -> None:
|
||||
"""
|
||||
Initialise the AllOf composite validator.
|
||||
|
||||
Args:
|
||||
checks: List of checks that must all pass.
|
||||
|
||||
Raises:
|
||||
ValueError: If checks list is empty.
|
||||
"""
|
||||
if not checks:
|
||||
raise ValueError("checks list cannot be empty")
|
||||
|
||||
self._checks = checks
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of this composite check."""
|
||||
return "all_of"
|
||||
|
||||
def check(self, text: str, context: ValidationContext) -> ValidationResult:
|
||||
"""
|
||||
Run all checks and return aggregate result.
|
||||
|
||||
Args:
|
||||
text: The text to validate.
|
||||
context: Validation context containing reference text and metadata.
|
||||
|
||||
Returns:
|
||||
ValidationResult that passes only if all checks pass.
|
||||
"""
|
||||
results: list[CheckResult] = []
|
||||
for check in self._checks:
|
||||
results.append(check.check(text, context))
|
||||
|
||||
all_passed = all(r.passed for r in results)
|
||||
|
||||
return ValidationResult(passed=all_passed, checks=results)
|
||||
|
||||
|
||||
class AnyOf:
|
||||
"""Passes if any check passes."""
|
||||
|
||||
def __init__(self, checks: list[Check]) -> None:
|
||||
"""
|
||||
Initialise the AnyOf composite validator.
|
||||
|
||||
Args:
|
||||
checks: List of checks where at least one must pass.
|
||||
|
||||
Raises:
|
||||
ValueError: If checks list is empty.
|
||||
"""
|
||||
if not checks:
|
||||
raise ValueError("checks list cannot be empty")
|
||||
|
||||
self._checks = checks
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of this composite check."""
|
||||
return "any_of"
|
||||
|
||||
def check(self, text: str, context: ValidationContext) -> ValidationResult:
|
||||
"""
|
||||
Run all checks and return aggregate result.
|
||||
|
||||
Args:
|
||||
text: The text to validate.
|
||||
context: Validation context containing reference text and metadata.
|
||||
|
||||
Returns:
|
||||
ValidationResult that passes if any check passes.
|
||||
"""
|
||||
results: list[CheckResult] = []
|
||||
for check in self._checks:
|
||||
results.append(check.check(text, context))
|
||||
|
||||
any_passed = any(r.passed for r in results)
|
||||
|
||||
return ValidationResult(passed=any_passed, checks=results)
|
||||
Reference in New Issue
Block a user