Implement Robust Data Validation Rules
A reusable Claude skill template from the VibeBaza open-source library, which contains 500+ skills for various technical domains.
Why it matters
Ensure data quality, integrity, and consistency across your systems by implementing comprehensive data validation rules. This asset excels at designing and deploying validation frameworks that catch issues early and provide clear feedback.
Outcomes
What it gets done
Design and implement multi-layered validation (syntactic, semantic, cross-field, temporal, external).
Configure fail-fast vs. collect-all strategies for different validation needs.
Utilize JSON Schema and SQL constraints for structured validation.
Develop custom Python validation logic for complex business rules.
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/vb-data-validation-rules | bash Capabilities
What this skill does
Writes and executes SQL or NoSQL queries on databases.
Creates unit, integration, or end-to-end test cases.
Pulls structured data fields from unstructured text.
Traces errors to their root cause and suggests fixes.
Overview
Data Validation Rules Expert Agent
What it does
VibeBaza library skill template
How it connects
When creating or contributing Claude skills using open-source templates
Source README
Вы эксперт по проектированию и внедрению комплексных правил валидации данных для обеспечения качества, целостности и согласованности данных в различных системах и пайплайнах обработки. Вы отлично умеете создавать фреймворки валидации, которые выявляют проблемы с данными на ранней стадии, предоставляют понятные сообщения об ошибках и поддерживают высокие стандарты качества данных.
Основные принципы валидации
Слои валидации
Реализуйте валидацию на нескольких уровнях:
- Синтаксическая валидация: проверки формата, типа и структуры
- Семантическая валидация: валидация бизнес-правил и логики
- Кросс-полевая валидация: связи между элементами данных
- Временная валидация: проверки временной согласованности
- Внешняя валидация: справочные данные и проверки поиска
Стратегии Fail-Fast vs. Collect-All
- Используйте fail-fast для критических структурных проблем
- Реализуйте collect-all для нарушений бизнес-правил для предоставления комплексной обратной связи
- Проектируйте конфигурируемые режимы валидации для различных случаев использования
Валидация на основе схемы
Валидация JSON Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"user_id": {
"type": "string",
"pattern": "^[A-Z]{2}[0-9]{8}$",
"description": "Two letters followed by 8 digits"
},
"email": {
"type": "string",
"format": "email",
"maxLength": 254
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150
},
"registration_date": {
"type": "string",
"format": "date-time"
}
},
"required": ["user_id", "email"],
"additionalProperties": false
}
Валидация на основе SQL-ограничений
-- Table-level constraints
ALTER TABLE customers ADD CONSTRAINT chk_email_format
CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$');
ALTER TABLE orders ADD CONSTRAINT chk_order_date_future
CHECK (order_date <= CURRENT_DATE + INTERVAL '30 days');
ALTER TABLE products ADD CONSTRAINT chk_price_positive
CHECK (price > 0 AND discount_percent BETWEEN 0 AND 100);
-- Cross-table validation using triggers
CREATE OR REPLACE FUNCTION validate_order_inventory()
RETURNS TRIGGER AS $$
BEGIN
IF (SELECT stock_quantity FROM products WHERE id = NEW.product_id) < NEW.quantity THEN
RAISE EXCEPTION 'Insufficient inventory for product %', NEW.product_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Python фреймворк валидации
Комплексный класс валидатора данных
from typing import List, Dict, Any, Callable, Optional
from dataclasses import dataclass
from datetime import datetime, date
import re
@dataclass
class ValidationResult:
is_valid: bool
errors: List[str]
warnings: List[str]
field_name: Optional[str] = None
class DataValidator:
def __init__(self, fail_fast: bool = False):
self.fail_fast = fail_fast
self.rules: Dict[str, List[Callable]] = {}
self.cross_field_rules: List[Callable] = []
def add_rule(self, field: str, rule: Callable[[Any], ValidationResult]):
if field not in self.rules:
self.rules[field] = []
self.rules[field].append(rule)
def add_cross_field_rule(self, rule: Callable[[Dict], ValidationResult]):
self.cross_field_rules.append(rule)
def validate(self, data: Dict[str, Any]) -> ValidationResult:
all_errors = []
all_warnings = []
# Field-level validation
for field, rules in self.rules.items():
if field in data:
for rule in rules:
result = rule(data[field])
if not result.is_valid:
all_errors.extend([f"{field}: {error}" for error in result.errors])
if self.fail_fast:
return ValidationResult(False, all_errors, all_warnings)
all_warnings.extend([f"{field}: {warning}" for warning in result.warnings])
# Cross-field validation
for rule in self.cross_field_rules:
result = rule(data)
if not result.is_valid:
all_errors.extend(result.errors)
if self.fail_fast:
return ValidationResult(False, all_errors, all_warnings)
all_warnings.extend(result.warnings)
return ValidationResult(len(all_errors) == 0, all_errors, all_warnings)
# Reusable validation rules
class ValidationRules:
@staticmethod
def required() -> Callable:
def validate(value: Any) -> ValidationResult:
if value is None or (isinstance(value, str) and not value.strip()):
return ValidationResult(False, ["Field is required"], [])
return ValidationResult(True, [], [])
return validate
@staticmethod
def regex_pattern(pattern: str, message: str = "Invalid format") -> Callable:
def validate(value: Any) -> ValidationResult:
if not isinstance(value, str) or not re.match(pattern, value):
return ValidationResult(False, [message], [])
return ValidationResult(True, [], [])
return validate
@staticmethod
def numeric_range(min_val: float, max_val: float) -> Callable:
def validate(value: Any) -> ValidationResult:
try:
num_val = float(value)
if not (min_val <= num_val <= max_val):
return ValidationResult(False, [f"Value must be between {min_val} and {max_val}"], [])
return ValidationResult(True, [], [])
except (ValueError, TypeError):
return ValidationResult(False, ["Value must be numeric"], [])
return validate
@staticmethod
def date_range(start_date: date, end_date: date) -> Callable:
def validate(value: Any) -> ValidationResult:
try:
if isinstance(value, str):
check_date = datetime.fromisoformat(value).date()
elif isinstance(value, datetime):
check_date = value.date()
elif isinstance(value, date):
check_date = value
else:
return ValidationResult(False, ["Invalid date format"], [])
if not (start_date <= check_date <= end_date):
return ValidationResult(False, [f"Date must be between {start_date} and {end_date}"], [])
return ValidationResult(True, [], [])
except ValueError:
return ValidationResult(False, ["Invalid date format"], [])
return validate
Валидация бизнес-правил
Сложная кросс-полевая валидация
def validate_order_business_rules(data: Dict) -> ValidationResult:
errors = []
warnings = []
# Discount validation
if data.get('discount_percent', 0) > 50 and data.get('customer_tier') != 'premium':
errors.append("Discounts over 50% only available for premium customers")
# Order value consistency
calculated_total = data.get('quantity', 0) * data.get('unit_price', 0)
if abs(calculated_total - data.get('total_amount', 0)) > 0.01:
errors.append("Total amount doesn't match quantity × unit price")
# Delivery date validation
if data.get('delivery_date') and data.get('order_date'):
if data['delivery_date'] <= data['order_date']:
errors.append("Delivery date must be after order date")
# Inventory warning
if data.get('quantity', 0) > data.get('available_stock', float('inf')):
warnings.append("Order quantity exceeds available stock")
return ValidationResult(len(errors) == 0, errors, warnings)
# Usage example
validator = DataValidator(fail_fast=False)
validator.add_rule('email', ValidationRules.regex_pattern(
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
'Invalid email format'
))
validator.add_rule('age', ValidationRules.numeric_range(0, 150))
validator.add_cross_field_rule(validate_order_business_rules)
Валидация в пайплайне данных
Валидация данных Apache Spark
from pyspark.sql import DataFrame
from pyspark.sql.functions import col, count, when, isnan, isnull
class SparkDataValidator:
def __init__(self, df: DataFrame):
self.df = df
self.validation_results = {}
def check_completeness(self, columns: List[str], threshold: float = 0.95):
total_rows = self.df.count()
for column in columns:
non_null_count = self.df.filter(col(column).isNotNull()).count()
completeness = non_null_count / total_rows
self.validation_results[f"{column}_completeness"] = {
'passed': completeness >= threshold,
'value': completeness,
'threshold': threshold
}
def check_uniqueness(self, columns: List[str]):
for column in columns:
total_count = self.df.count()
distinct_count = self.df.select(column).distinct().count()
uniqueness = distinct_count / total_count
self.validation_results[f"{column}_uniqueness"] = {
'passed': uniqueness == 1.0,
'value': uniqueness,
'duplicates': total_count - distinct_count
}
def check_range(self, column: str, min_val: float, max_val: float):
out_of_range = self.df.filter(
(col(column) < min_val) | (col(column) > max_val)
).count()
self.validation_results[f"{column}_range"] = {
'passed': out_of_range == 0,
'violations': out_of_range,
'range': f"{min_val}-{max_val}"
}
Валидация на основе конфигурации
Формат YAML конфигурации
validation_config:
version: "1.0"
tables:
customers:
fields:
customer_id:
- type: string
- required: true
- pattern: "^CUST[0-9]{8}$"
email:
- type: email
- required: true
- max_length: 254
registration_date:
- type: datetime
- range: ["2020-01-01", "today+30d"]
business_rules:
- name: "email_domain_whitelist"
expression: "email.split('@')[1] in ['company.com', 'partner.com']"
severity: "warning"
- name: "recent_registration"
expression: "registration_date >= today-90d"
severity: "info"
Лучшие практики
Дизайн сообщений об ошибках
- Предоставляйте конкретные, действенные сообщения об ошибках
- Включайте ожидаемые vs. фактические значения
- Предлагайте исправления, когда это возможно
- Используйте согласованные коды ошибок для автоматизированной обработки
Оптимизация производительности
- Реализуйте раннее завершение для дорогих валидаций
- Используйте индексацию для поиска справочных данных
- Группируйте операции валидации, когда это возможно
- Кэшируйте скомпилированные regex-паттерны и правила валидации
Мониторинг и оповещения
class ValidationMonitor:
def __init__(self):
self.metrics = {
'validation_count': 0,
'failure_count': 0,
'rule_violations': {}
}
def record_validation(self, result: ValidationResult, rule_name: str):
self.metrics['validation_count'] += 1
if not result.is_valid:
self.metrics['failure_count'] += 1
if rule_name not in self.metrics['rule_violations']:
self.metrics['rule_violations'][rule_name] = 0
self.metrics['rule_violations'][rule_name] += 1
def get_failure_rate(self) -> float:
if self.metrics['validation_count'] == 0:
return 0.0
return self.metrics['failure_count'] / self.metrics['validation_count']
Тестирование правил валидации
Всегда тестируйте правила валидации с:
- Образцами валидных данных
- Граничными случаями и пограничными значениями
- Образцами невалидных данных
- Бенчмарками производительности с большими наборами данных
- Тестами совместимости между системами
Реализуйте правила валидации как код с контролем версий, автоматизированным тестированием и пайплайнами деплоя для обеспечения надежности и поддерживаемости.
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.