valico/json_schema/
builder.rs

1use serde::{Serialize, Serializer};
2use serde_json::value::{to_value, Value};
3use std::collections;
4
5pub struct SchemaArray {
6    items: Vec<Value>,
7}
8
9impl SchemaArray {
10    pub fn new() -> SchemaArray {
11        SchemaArray { items: vec![] }
12    }
13
14    pub fn push<F>(&mut self, build: F)
15    where
16        F: FnOnce(&mut Builder),
17    {
18        self.items.push(Builder::build(build).into_json())
19    }
20}
21
22pub struct SchemaHash {
23    items: collections::HashMap<String, Value>,
24}
25
26impl SchemaHash {
27    pub fn new() -> SchemaHash {
28        SchemaHash {
29            items: collections::HashMap::new(),
30        }
31    }
32
33    pub fn insert<F>(&mut self, key: &str, build: F)
34    where
35        F: FnOnce(&mut Builder),
36    {
37        self.items
38            .insert(key.to_string(), Builder::build(build).into_json());
39    }
40}
41
42pub struct Dependencies {
43    deps: collections::HashMap<String, Dependency>,
44}
45
46impl Dependencies {
47    pub fn new() -> Dependencies {
48        Dependencies {
49            deps: collections::HashMap::new(),
50        }
51    }
52
53    pub fn schema<F>(&mut self, property: &str, build: F)
54    where
55        F: FnOnce(&mut Builder),
56    {
57        self.deps.insert(
58            property.to_string(),
59            Dependency::Schema(Builder::build(build).into_json()),
60        );
61    }
62
63    pub fn property(&mut self, property: &str, properties: Vec<String>) {
64        self.deps
65            .insert(property.to_string(), Dependency::Property(properties));
66    }
67
68    pub fn build<F>(build: F) -> Dependencies
69    where
70        F: FnOnce(&mut Dependencies),
71    {
72        let mut deps = Dependencies::new();
73        build(&mut deps);
74        deps
75    }
76}
77
78impl Serialize for Dependencies {
79    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80    where
81        S: Serializer,
82    {
83        self.deps.serialize(serializer)
84    }
85}
86
87pub enum Dependency {
88    Schema(Value),
89    Property(Vec<String>),
90}
91
92impl Serialize for Dependency {
93    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94    where
95        S: Serializer,
96    {
97        match self {
98            Dependency::Schema(ref json) => json.serialize(serializer),
99            Dependency::Property(ref array) => array.serialize(serializer),
100        }
101    }
102}
103
104/// Builder provides simple DSL to build Schema. It allows you not to use
105/// strings and raw JSON manipulation. It also prevent some kinds of spelling
106/// and type errors.
107pub struct Builder {
108    obj_builder: jsonway::ObjectBuilder,
109}
110
111impl Builder {
112    pub fn new() -> Builder {
113        Builder {
114            obj_builder: jsonway::ObjectBuilder::new(),
115        }
116    }
117
118    pub fn id(&mut self, url: &str) {
119        self.obj_builder.set("$id", url.to_string())
120    }
121
122    pub fn ref_(&mut self, url: &str) {
123        self.obj_builder.set("$ref", url.to_string())
124    }
125
126    pub fn schema(&mut self, url: &str) {
127        self.obj_builder.set("$schema", url.to_string())
128    }
129
130    pub fn desc(&mut self, text: &str) {
131        self.obj_builder.set("description", text.to_string())
132    }
133
134    pub fn title(&mut self, text: &str) {
135        self.obj_builder.set("title", text.to_string())
136    }
137
138    pub fn default<T>(&mut self, default: T)
139    where
140        T: Serialize,
141    {
142        self.obj_builder.set("default", default)
143    }
144
145    pub fn multiple_of(&mut self, number: f64) {
146        self.obj_builder.set("multipleOf", number)
147    }
148
149    pub fn maximum(&mut self, number: f64) {
150        self.obj_builder.set("maximum", number);
151    }
152
153    pub fn exclusive_maximum(&mut self, number: f64) {
154        self.obj_builder.set("exclusiveMaximum", number);
155    }
156
157    pub fn minimum(&mut self, number: f64) {
158        self.obj_builder.set("minimum", number);
159    }
160
161    pub fn exclusive_minimum(&mut self, number: f64) {
162        self.obj_builder.set("exclusiveMinimum", number);
163    }
164
165    pub fn max_length(&mut self, number: u64) {
166        self.obj_builder.set("maxLength", number)
167    }
168
169    pub fn min_length(&mut self, number: u64) {
170        self.obj_builder.set("minLength", number)
171    }
172
173    pub fn pattern(&mut self, pattern: &str) {
174        self.obj_builder.set("pattern", pattern.to_string())
175    }
176
177    pub fn format(&mut self, format: &str) {
178        self.obj_builder.set("format", format.to_string())
179    }
180
181    pub fn items_schema<F>(&mut self, build: F)
182    where
183        F: FnOnce(&mut Builder),
184    {
185        self.obj_builder
186            .set("items", Builder::build(build).into_json())
187    }
188
189    pub fn items_array<F>(&mut self, build: F)
190    where
191        F: FnOnce(&mut SchemaArray),
192    {
193        let mut items = SchemaArray::new();
194        build(&mut items);
195        self.obj_builder.set("items", items.items)
196    }
197
198    pub fn additional_items(&mut self, allow: bool) {
199        self.obj_builder.set("additionalItems", allow)
200    }
201
202    pub fn additional_items_schema<F>(&mut self, build: F)
203    where
204        F: FnOnce(&mut Builder),
205    {
206        self.obj_builder
207            .set("additionalItems", Builder::build(build).into_json())
208    }
209
210    pub fn max_items(&mut self, number: u64) {
211        self.obj_builder.set("maxItems", number)
212    }
213
214    pub fn min_items(&mut self, number: u64) {
215        self.obj_builder.set("minItems", number)
216    }
217
218    pub fn unique_items(&mut self, unique: bool) {
219        self.obj_builder.set("uniqueItems", unique)
220    }
221
222    pub fn max_properties(&mut self, number: u64) {
223        self.obj_builder.set("maxProperties", number)
224    }
225
226    pub fn min_properties(&mut self, number: u64) {
227        self.obj_builder.set("minProperties", number)
228    }
229
230    pub fn required(&mut self, items: Vec<String>) {
231        self.obj_builder.set("required", items)
232    }
233
234    pub fn properties<F>(&mut self, build: F)
235    where
236        F: FnOnce(&mut SchemaHash),
237    {
238        let mut items = SchemaHash::new();
239        build(&mut items);
240        self.obj_builder.set("properties", items.items)
241    }
242
243    pub fn pattern_properties<F>(&mut self, build: F)
244    where
245        F: FnOnce(&mut SchemaHash),
246    {
247        let mut items = SchemaHash::new();
248        build(&mut items);
249        self.obj_builder.set("patternProperties", items.items)
250    }
251
252    pub fn additional_properties(&mut self, allow: bool) {
253        self.obj_builder.set("additionalProperties", allow)
254    }
255
256    pub fn additional_properties_schema<F>(&mut self, build: F)
257    where
258        F: FnOnce(&mut Builder),
259    {
260        self.obj_builder
261            .set("additionalProperties", Builder::build(build).into_json())
262    }
263
264    pub fn dependencies<F>(&mut self, build: F)
265    where
266        F: FnOnce(&mut Dependencies),
267    {
268        self.obj_builder
269            .set("dependencies", Dependencies::build(build))
270    }
271
272    pub fn enum_<F>(&mut self, build: F)
273    where
274        F: FnOnce(&mut jsonway::ArrayBuilder),
275    {
276        self.obj_builder.set("enum", jsonway::array(build).unwrap())
277    }
278
279    pub fn array(&mut self) {
280        self.obj_builder
281            .set("type", super::PrimitiveType::Array.to_string())
282    }
283    pub fn boolean(&mut self) {
284        self.obj_builder
285            .set("type", super::PrimitiveType::Boolean.to_string())
286    }
287    pub fn integer(&mut self) {
288        self.obj_builder
289            .set("type", super::PrimitiveType::Integer.to_string())
290    }
291    pub fn number(&mut self) {
292        self.obj_builder
293            .set("type", super::PrimitiveType::Number.to_string())
294    }
295    pub fn null(&mut self) {
296        self.obj_builder
297            .set("type", super::PrimitiveType::Null.to_string())
298    }
299    pub fn object(&mut self) {
300        self.obj_builder
301            .set("type", super::PrimitiveType::Object.to_string())
302    }
303    pub fn string(&mut self) {
304        self.obj_builder
305            .set("type", super::PrimitiveType::String.to_string())
306    }
307    pub fn type_(&mut self, type_: super::PrimitiveType) {
308        self.obj_builder.set("type", type_.to_string())
309    }
310    pub fn types(&mut self, types: &[super::PrimitiveType]) {
311        self.obj_builder.set(
312            "type",
313            to_value(types.iter().map(|t| t.to_string()).collect::<Vec<String>>()).unwrap(),
314        )
315    }
316
317    pub fn all_of<F>(&mut self, build: F)
318    where
319        F: FnOnce(&mut SchemaArray),
320    {
321        let mut items = SchemaArray::new();
322        build(&mut items);
323        self.obj_builder.set("allOf", items.items)
324    }
325
326    pub fn any_of<F>(&mut self, build: F)
327    where
328        F: FnOnce(&mut SchemaArray),
329    {
330        let mut items = SchemaArray::new();
331        build(&mut items);
332        self.obj_builder.set("anyOf", items.items)
333    }
334
335    pub fn one_of<F>(&mut self, build: F)
336    where
337        F: FnOnce(&mut SchemaArray),
338    {
339        let mut items = SchemaArray::new();
340        build(&mut items);
341        self.obj_builder.set("oneOf", items.items)
342    }
343
344    pub fn not<F>(&mut self, build: F)
345    where
346        F: FnOnce(&mut Builder),
347    {
348        self.obj_builder
349            .set("not", Builder::build(build).into_json())
350    }
351
352    pub fn build<F>(build: F) -> Builder
353    where
354        F: FnOnce(&mut Builder),
355    {
356        let mut builder = Builder::new();
357        build(&mut builder);
358        builder
359    }
360
361    pub fn into_json(self) -> Value {
362        self.obj_builder.unwrap()
363    }
364
365    pub fn content_media_type(&mut self, type_: super::keywords::content_media::ContentMediaType) {
366        self.obj_builder.set("contentMediaType", type_.as_str())
367    }
368
369    pub fn content_encoding(&mut self, type_: super::keywords::content_media::ContentEncoding) {
370        self.obj_builder.set("contentEncoding", type_.as_str())
371    }
372
373    pub fn if_<F>(&mut self, build: F)
374    where
375        F: FnOnce(&mut Builder),
376    {
377        self.obj_builder
378            .set("if", Builder::build(build).into_json())
379    }
380
381    pub fn then_<F>(&mut self, build: F)
382    where
383        F: FnOnce(&mut Builder),
384    {
385        self.obj_builder
386            .set("then", Builder::build(build).into_json())
387    }
388
389    pub fn else_<F>(&mut self, build: F)
390    where
391        F: FnOnce(&mut Builder),
392    {
393        self.obj_builder
394            .set("else", Builder::build(build).into_json())
395    }
396
397    pub fn custom_vocabulary<V: Serialize, N: Into<String>>(&mut self, name: N, value: V) {
398        self.obj_builder.set(name, value);
399    }
400}
401
402impl Serialize for Builder {
403    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
404    where
405        S: Serializer,
406    {
407        self.obj_builder.serialize(serializer)
408    }
409}
410
411pub fn schema<F>(build: F) -> Builder
412where
413    F: FnOnce(&mut Builder),
414{
415    Builder::build(build)
416}
417
418pub fn schema_box(build: Box<dyn Fn(&mut Builder) + Send>) -> Builder {
419    let mut builder = Builder::new();
420    build(&mut builder);
421    builder
422}