Skip to main content

valico/json_dsl/
param.rs

1use serde::Serialize;
2use serde_json::{to_value, Value};
3
4use super::super::json_schema;
5use super::builder;
6use super::coercers;
7use super::validators;
8
9pub struct Param {
10    pub name: String,
11    pub coercer: Option<Box<dyn coercers::Coercer + Send + Sync>>,
12    pub nest: Option<builder::Builder>,
13    pub description: Option<String>,
14    pub allow_null: bool,
15    pub validators: validators::Validators,
16    pub default: Option<Value>,
17    pub schema_builder: Option<builder::DynBuilder>,
18    pub schema_id: Option<url::Url>,
19}
20
21unsafe impl Send for Param {}
22
23impl Param {
24    pub fn new(name: &str) -> Param {
25        Param {
26            name: name.to_string(),
27            description: None,
28            coercer: None,
29            nest: None,
30            allow_null: false,
31            validators: vec![],
32            default: None,
33            schema_builder: None,
34            schema_id: None,
35        }
36    }
37
38    pub fn new_with_coercer(
39        name: &str,
40        coercer: Box<dyn coercers::Coercer + Send + Sync>,
41    ) -> Param {
42        Param {
43            name: name.to_string(),
44            description: None,
45            coercer: Some(coercer),
46            nest: None,
47            allow_null: false,
48            validators: vec![],
49            default: None,
50            schema_builder: None,
51            schema_id: None,
52        }
53    }
54
55    pub fn new_with_nest(
56        name: &str,
57        coercer: Box<dyn coercers::Coercer + Send + Sync>,
58        nest: builder::Builder,
59    ) -> Param {
60        Param {
61            name: name.to_string(),
62            description: None,
63            coercer: Some(coercer),
64            nest: Some(nest),
65            allow_null: false,
66            validators: vec![],
67            default: None,
68            schema_builder: None,
69            schema_id: None,
70        }
71    }
72
73    pub fn build<F>(name: &str, build_def: F) -> Param
74    where
75        F: FnOnce(&mut Param),
76    {
77        let mut param = Param::new(name);
78        build_def(&mut param);
79
80        param
81    }
82
83    pub fn desc(&mut self, description: &str) {
84        self.description = Some(description.to_string());
85    }
86
87    pub fn schema_id(&mut self, id: url::Url) {
88        self.schema_id = Some(id);
89    }
90
91    pub fn schema<F>(&mut self, build: F)
92    where
93        F: Fn(&mut json_schema::Builder) + 'static + Send + Sync,
94    {
95        self.schema_builder = Some(Box::new(build));
96    }
97
98    pub fn coerce(&mut self, coercer: Box<dyn coercers::Coercer + Send + Sync>) {
99        self.coercer = Some(coercer);
100    }
101
102    pub fn nest<F>(&mut self, nest_def: F)
103    where
104        F: FnOnce(&mut builder::Builder),
105    {
106        self.nest = Some(builder::Builder::build(nest_def));
107    }
108
109    pub fn allow_null(&mut self) {
110        self.allow_null = true;
111    }
112
113    pub fn regex(&mut self, regex: fancy_regex::Regex) {
114        self.validators.push(Box::new(regex));
115    }
116
117    pub fn validate(&mut self, validator: Box<dyn validators::Validator + 'static + Send + Sync>) {
118        self.validators.push(validator);
119    }
120
121    pub fn validate_with<F>(&mut self, validator: F)
122    where
123        F: Fn(&Value, &str) -> super::validators::ValidatorResult + 'static + Send + Sync,
124    {
125        self.validators.push(Box::new(validator));
126    }
127
128    fn process_validators(&self, val: &Value, path: &str) -> super::super::ValicoErrors {
129        let mut errors = vec![];
130        for validator in self.validators.iter() {
131            match validator.validate(val, path) {
132                Ok(()) => (),
133                Err(validation_errors) => errors.extend(validation_errors),
134            }
135        }
136
137        errors
138    }
139
140    pub fn process(
141        &self,
142        val: &mut Value,
143        path: &str,
144        scope: Option<&json_schema::Scope>,
145    ) -> super::ExtendedResult<Option<Value>> {
146        if val.is_null() && self.allow_null {
147            return super::ExtendedResult::new(None);
148        }
149
150        let mut result = super::ExtendedResult::new(None);
151        let mut return_value = None;
152
153        {
154            let val = if self.coercer.is_some() {
155                match self.coercer.as_ref().unwrap().coerce(val, path) {
156                    Ok(None) => val,
157                    Ok(Some(new_value)) => {
158                        return_value = Some(new_value);
159                        return_value.as_mut().unwrap()
160                    }
161                    Err(errors) => {
162                        result.state.errors.extend(errors);
163                        return result;
164                    }
165                }
166            } else {
167                val
168            };
169
170            if self.nest.is_some() {
171                let process_state = self.nest.as_ref().unwrap().process_nest(val, path, scope);
172                result.append(process_state);
173            }
174
175            let validation_errors = self.process_validators(val, path);
176            result.state.errors.extend(validation_errors);
177
178            if let Some(ref id) = self.schema_id {
179                if let Some(scope) = scope {
180                    let schema = scope.resolve(id);
181                    match schema {
182                        Some(schema) => result.append(schema.validate_in(val, path)),
183                        None => result.state.missing.push(id.clone()),
184                    }
185                }
186            }
187        }
188
189        if return_value.is_some() {
190            result.value = return_value;
191        }
192
193        result
194    }
195}
196
197impl Param {
198    pub fn allow_values<T: Serialize>(&mut self, values: &[T]) {
199        self.validators
200            .push(Box::new(validators::AllowedValues::new(
201                values.iter().map(|v| to_value(v).unwrap()).collect(),
202            )));
203    }
204
205    pub fn reject_values<T: Serialize>(&mut self, values: &[T]) {
206        self.validators
207            .push(Box::new(validators::RejectedValues::new(
208                values.iter().map(|v| to_value(v).unwrap()).collect(),
209            )));
210    }
211
212    pub fn default<T: Serialize>(&mut self, default: T) {
213        self.default = Some(to_value(&default).unwrap());
214    }
215}