valico/json_dsl/
builder.rs
1use serde_json::{Value, to_value};
2use url;
3
4use super::super::json_schema;
5use super::param;
6use super::coercers;
7use super::validators;
8use super::errors;
9
10pub struct Builder {
11 requires: Vec<param::Param>,
12 optional: Vec<param::Param>,
13 validators: validators::Validators,
14 schema_builder: Option<Box<Fn(&mut json_schema::Builder) + Send + Sync>>,
15 schema_id: Option<url::Url>
16}
17
18unsafe impl Send for Builder { }
19
20impl Builder {
21
22 pub fn new() -> Builder {
23 Builder {
24 requires: vec![],
25 optional: vec![],
26 validators: vec![],
27 schema_builder: None,
28 schema_id: None
29 }
30 }
31
32 pub fn build<F>(rules: F) -> Builder where F: FnOnce(&mut Builder) {
33 let mut builder = Builder::new();
34 rules(&mut builder);
35
36 builder
37 }
38
39 pub fn get_required(&self) -> &Vec<param::Param> {
40 return &self.requires;
41 }
42
43 pub fn get_optional(&self) -> &Vec<param::Param> {
44 return &self.optional;
45 }
46
47 pub fn get_validators(&self) -> &validators::Validators {
48 return &self.validators;
49 }
50
51 pub fn req_defined(&mut self, name: &str) {
52 let params = param::Param::new(name);
53 self.requires.push(params);
54 }
55
56 pub fn req_typed(&mut self, name: &str, coercer: Box<coercers::Coercer + Send + Sync>) {
57 let params = param::Param::new_with_coercer(name, coercer);
58 self.requires.push(params);
59 }
60
61 pub fn req_nested<F>(&mut self, name: &str, coercer: Box<coercers::Coercer + Send + Sync>, nest_def: F) where F: FnOnce(&mut Builder) {
62 let nest_builder = Builder::build(nest_def);
63 let params = param::Param::new_with_nest(name, coercer, nest_builder);
64 self.requires.push(params);
65 }
66
67 pub fn req<F>(&mut self, name: &str, param_builder: F) where F: FnOnce(&mut param::Param) {
68 let params = param::Param::build(name, param_builder);
69 self.requires.push(params);
70 }
71
72 pub fn opt_defined(&mut self, name: &str) {
73 let params = param::Param::new(name);
74 self.optional.push(params);
75 }
76
77 pub fn opt_typed(&mut self, name: &str, coercer: Box<coercers::Coercer + Send + Sync>) {
78 let params = param::Param::new_with_coercer(name, coercer);
79 self.optional.push(params);
80 }
81
82 pub fn opt_nested<F>(&mut self, name: &str, coercer: Box<coercers::Coercer + Send + Sync>, nest_def: F) where F: FnOnce(&mut Builder) {
83 let nest_builder = Builder::build(nest_def);
84 let params = param::Param::new_with_nest(name, coercer, nest_builder);
85 self.optional.push(params);
86 }
87
88 pub fn opt<F>(&mut self, name: &str, param_builder: F) where F: FnOnce(&mut param::Param) {
89 let params = param::Param::build(name, param_builder);
90 self.optional.push(params);
91 }
92
93 pub fn validate(&mut self, validator: Box<validators::Validator + 'static + Send + Sync>) {
94 self.validators.push(validator);
95 }
96
97 pub fn validate_with<F>(&mut self, validator: F) where F: Fn(&Value, &str) -> validators::ValidatorResult + 'static + Send+Sync {
98 self.validators.push(Box::new(validator));
99 }
100
101 pub fn mutually_exclusive(&mut self, params: &[&str]) {
102 let validator = Box::new(validators::MutuallyExclusive::new(params));
103 self.validators.push(validator);
104 }
105
106 pub fn exactly_one_of(&mut self, params: &[&str]) {
107 let validator = Box::new(validators::ExactlyOneOf::new(params));
108 self.validators.push(validator);
109 }
110
111 pub fn at_least_one_of(&mut self, params: &[&str]) {
112 let validator = Box::new(validators::AtLeastOneOf::new(params));
113 self.validators.push(validator);
114 }
115
116 pub fn schema_id(&mut self, id: url::Url) {
117 self.schema_id = Some(id);
118 }
119
120 pub fn schema<F>(&mut self, build: F) where F: Fn(&mut json_schema::Builder,) + 'static + Send + Sync {
121 self.schema_builder = Some(Box::new(build));
122 }
123
124 pub fn build_schemes(&mut self, scope: &mut json_schema::Scope) -> Result<(), json_schema::SchemaError> {
125 for param in self.requires.iter_mut().chain(self.optional.iter_mut()) {
126 if param.schema_builder.is_some() {
127 let json_schema = json_schema::builder::schema_box(param.schema_builder.take().unwrap());
128 let id = try!(scope.compile(to_value(&json_schema).unwrap(), true));
129 param.schema_id = Some(id);
130 }
131
132 if param.nest.is_some() {
133 try!(param.nest.as_mut().unwrap().build_schemes(scope));
134 }
135 }
136
137 if self.schema_builder.is_some() {
138 let json_schema = json_schema::builder::schema_box(self.schema_builder.take().unwrap());
139 let id = try!(scope.compile(to_value(&json_schema).unwrap(), true));
140 self.schema_id = Some(id);
141 }
142
143 Ok(())
144 }
145
146 pub fn process(&self, val: &mut Value, scope: &Option<&json_schema::Scope>) -> json_schema::ValidationState {
147 self.process_nest(val, "", scope)
148 }
149
150 pub fn process_nest(&self, val: &mut Value, path: &str, scope: &Option<&json_schema::Scope>) -> json_schema::ValidationState {
151 let mut state = if val.is_array() {
152 let mut state = json_schema::ValidationState::new();
153 let array = val.as_array_mut().unwrap();
154 for (idx, item) in array.iter_mut().enumerate() {
155 let item_path = [path, idx.to_string().as_ref()].join("/");
156 if item.is_object() {
157 let process_state = self.process_object(item, item_path.as_ref(), scope);
158 state.append(process_state);
159 } else {
160 state.errors.push(
161 Box::new(errors::WrongType {
162 path: item_path.to_string(),
163 detail: "List value is not and object".to_string()
164 })
165 )
166 }
167 }
168
169 state
170 } else if val.is_object() {
171 self.process_object(val, path, scope)
172 } else {
173 let mut state = json_schema::ValidationState::new();
174 state.errors.push(
175 Box::new(errors::WrongType {
176 path: path.to_string(),
177 detail: "Value is not an object or an array".to_string()
178 })
179 );
180
181 state
182 };
183
184 let path = if path == "" {
185 "/"
186 } else {
187 path
188 };
189
190 if self.schema_id.is_some() && scope.is_some() {
191 let id = self.schema_id.as_ref().unwrap();
192 let schema = scope.as_ref().unwrap().resolve(id);
193 match schema {
194 Some(schema) => state.append(schema.validate_in(val, path)),
195 None => state.missing.push(id.clone())
196 }
197 }
198
199 state
200 }
201
202 fn process_object(&self, val: &mut Value, path: &str, scope: &Option<&json_schema::Scope>) -> json_schema::ValidationState {
203
204 let mut state = json_schema::ValidationState::new();
205
206 {
207 let object = val.as_object_mut().expect("We expect object here");
208 for param in self.requires.iter() {
209 let ref name = param.name;
210 let present = object.contains_key(name);
211 let param_path = [path, name.as_ref()].join("/");
212 if present {
213 let process_result = param.process(object.get_mut(name).unwrap(), param_path.as_ref(), scope);
214 match process_result.value {
215 Some(new_value) => { object.insert(name.clone(), new_value); },
216 None => ()
217 }
218
219 state.append(process_result.state);
220 } else {
221 state.errors.push(Box::new(errors::Required {
222 path: param_path.clone()
223 }))
224 }
225 }
226
227 for param in self.optional.iter() {
228 let ref name = param.name;
229 let present = object.contains_key(name);
230 let param_path = [path, name.as_ref()].join("/");
231 if present {
232 let process_result = param.process(object.get_mut(name).unwrap(), param_path.as_ref(), scope);
233 match process_result.value {
234 Some(new_value) => { object.insert(name.clone(), new_value); },
235 None => ()
236 }
237
238 state.append(process_result.state);
239 }
240 }
241 }
242
243 let path = if path == "" {
244 "/"
245 } else {
246 path
247 };
248
249 for validator in self.validators.iter() {
250 match validator.validate(val, path) {
251 Ok(()) => (),
252 Err(err) => {
253 state.errors.extend(err);
254 }
255 };
256 }
257
258 {
259 if state.is_valid() {
260 let object = val.as_object_mut().expect("We expect object here");
261
262 for param in self.optional.iter() {
264 let ref name = param.name;
265 let present = object.contains_key(name);
266 if !present {
267 match param.default.as_ref() {
268 Some(val) => { object.insert(name.clone(), val.clone()); },
269 None => ()
270 };
271 }
272 }
273 }
274 }
275
276 state
277 }
278}
279
280