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