bwq_lint/validation/
engine.rs1use super::rules::*;
2use super::{ValidationContext, ValidationRule};
3use crate::ast::*;
4use crate::error::{LintError, LintReport, LintWarning};
5
6pub struct ValidationEngine {
7 rules: Vec<Box<dyn ValidationRule>>,
8}
9
10impl ValidationEngine {
11 pub fn new() -> Self {
12 Self {
13 rules: vec![
14 Box::new(RatingFieldRule),
16 Box::new(CoordinateFieldRule),
17 Box::new(LanguageFieldRule),
18 Box::new(AuthorGenderFieldRule),
19 Box::new(BooleanFieldRule),
20 Box::new(EngagementTypeFieldRule),
21 Box::new(VerifiedTypeFieldRule),
22 Box::new(MinuteOfDayFieldRule),
23 Box::new(RangeFieldRule),
24 Box::new(MixedAndOrRule),
26 Box::new(MixedNearRule),
27 Box::new(PureNegativeRule),
28 Box::new(BinaryOperatorRule),
29 Box::new(WildcardPerformanceRule),
31 Box::new(ShortTermRule),
32 Box::new(RangePerformanceRule),
33 ],
34 }
35 }
36
37 pub fn validate(&self, query: &Query) -> LintReport {
38 let mut all_errors = Vec::new();
39 let mut all_warnings = Vec::new();
40
41 let ctx = ValidationContext::default();
42 self.walk_expression(&query.expression, &ctx, &mut all_errors, &mut all_warnings);
43
44 LintReport {
45 errors: all_errors,
46 warnings: all_warnings,
47 }
48 }
49
50 fn walk_expression(
51 &self,
52 expr: &Expression,
53 ctx: &ValidationContext,
54 errors: &mut Vec<LintError>,
55 warnings: &mut Vec<LintWarning>,
56 ) {
57 for rule in &self.rules {
59 if rule.can_validate(expr) {
60 let result = rule.validate(expr, ctx);
61 errors.extend(result.errors);
62 warnings.extend(result.warnings);
63 }
64 }
65
66 match expr {
68 Expression::BooleanOp {
69 operator,
70 left,
71 right,
72 ..
73 } => {
74 let mut child_ctx = ctx.clone();
75 child_ctx.parent_operator = Some(operator.clone());
76
77 self.walk_expression(left, &child_ctx, errors, warnings);
78 if let Some(right_expr) = right {
79 self.walk_expression(right_expr, &child_ctx, errors, warnings);
80 }
81 }
82 Expression::Group { expression, .. } => {
83 let mut group_ctx = ctx.clone();
84 group_ctx.inside_group = true;
85 self.walk_expression(expression, &group_ctx, errors, warnings);
86 }
87 Expression::Proximity { terms, .. } => {
88 for term in terms {
89 self.walk_expression(term, ctx, errors, warnings);
90 }
91 }
92 Expression::Field { field, value, .. } => {
93 let mut field_ctx = ctx.clone();
94 field_ctx.field_context = Some(field.clone());
95 self.walk_expression(value, &field_ctx, errors, warnings);
96 }
97 Expression::Range { .. } | Expression::Term { .. } | Expression::Comment { .. } => {
98 }
100 }
101 }
102}
103
104impl Default for ValidationEngine {
105 fn default() -> Self {
106 Self::new()
107 }
108}