forked from alecthomas/jsonschema
-
Notifications
You must be signed in to change notification settings - Fork 3
/
subschemas_boolean.go
121 lines (104 loc) · 4.94 KB
/
subschemas_boolean.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package jsonschema
import (
"reflect"
)
// File named in respect to https://json-schema.org/latest/json-schema-validation.html#rfc.section.6.7
var andAnyOfType = reflect.TypeOf((*andAnyOf)(nil)).Elem()
var anyOfType = reflect.TypeOf((*anyOf)(nil)).Elem()
var andOneOfType = reflect.TypeOf((*andOneOf)(nil)).Elem()
var oneOfType = reflect.TypeOf((*oneOf)(nil)).Elem()
var andAllOfType = reflect.TypeOf((*andAllOf)(nil)).Elem()
var allOfType = reflect.TypeOf((*allOf)(nil)).Elem()
// AndAnyOf will generate the anyOf rule and retain the jsonschema rules for the struct that implements it
// `anyOf` is used to ensure that the data must be valid against *at least one* of the cases *or more*
// { "type": "number", "anyOf": [ { "multipleOf": 5 }, { "multipleOf": 3 } ]}
// In the example above, the input must be a number and can be either a multiple of 5 or 3 or both but never neither
type andAnyOf interface {
AndAnyOf() []reflect.StructField
}
// AnyOf will overrule all jsonschema rules for the struct that implements it
// `anyOf` is used to ensure that the data must be valid against *at least one* of the cases *or more*
// { "anyOf": [ { "type": "number", "multipleOf": 5 }, { "type": "number", "multipleOf": 3 } ] }
// In the example above, the input must be a number and can be either a multiple of 5 or 3 or both but never neither
type anyOf interface {
AnyOf() []reflect.StructField
}
// AndOneOf will generate the oneOf rule and retain the jsonschema rules for the struct that implements it
// `oneOf` can be used to factor out common parts of subschema and when *only one case* must be valid
// { "type": "number", "oneOf": [ { "multipleOf": 5 }, { "multipleOf": 3 } ]}
// In the example above, the input must be a number and must be either a multiple of 5 or 3 but not both and never neither
type andOneOf interface {
AndOneOf() []reflect.StructField
}
// OneOf will overrule all jsonschema rules for the struct that implements it
// `oneOf` can be used to factor out common parts of subschema and when *only one case* must be valid
// { "oneOf": [ { "type": "number", "multipleOf": 5 }, { "type": "number", "multipleOf": 3 } ] }
// In the example above, the input must be a number and must be either a multiple of 5 or 3 but not both and never neither
type oneOf interface {
OneOf() []reflect.StructField
}
// AllOf will generate the allOf rule and retain the jsonschema rules for the struct that implements it
// `allOf` is used to ensure that the data must be valid against *all cases*
// { "type": "number", "allOf": [ { "multipleOf": 5 }, { "multipleOf": 3 } ]}
// In the example above, the input must be a number and a multiple of 5 *and* 3
type andAllOf interface {
AndAllOf() []reflect.StructField
}
// AllOf will overrule all jsonschema rules for the struct that implements it
// `allOf` is used to ensure that the data must be valid against *all cases*
// { "allOf": [ { "type": "number", "multipleOf": 5 }, { "type": "number", "multipleOf": 3 } ] }
// In the example above, the input must be a number and a multiple of 5 *and* 3
type allOf interface {
AllOf() []reflect.StructField
}
// When AnyOf/OneOf/AllOf are implemented, the jsonschema for the implementing struct will be supplanted with
// exclusive anyOf/oneOf/allOf rules
func (r *Reflector) getExclusiveSubschemaForBooleanCases(definitions Definitions, t reflect.Type) *Type {
var nonNilPointer interface{}
t, nonNilPointer = getNonNilPointerTypeAndInterface(t)
if t.Implements(anyOfType) {
s := nonNilPointer.(anyOf).AnyOf()
return &Type{AnyOf: r.getSubschemasForBooleanCases(definitions, s)}
}
if t.Implements(oneOfType) {
s := nonNilPointer.(oneOf).OneOf()
return &Type{OneOf: r.getSubschemasForBooleanCases(definitions, s)}
}
if t.Implements(allOfType) {
s := nonNilPointer.(allOf).AllOf()
return &Type{AllOf: r.getSubschemasForBooleanCases(definitions, s)}
}
return nil
}
// Append jsonschema rules from AndOneOf/AndAnyOf/AndAllOf interfaces
// to the jsonschema for the struct that implements them
func (r *Reflector) addSubschemasForBooleanCases(schema *Type, definitions Definitions, t reflect.Type) {
if schema == nil {
return
}
var nonNilPointer interface{}
t, nonNilPointer = getNonNilPointerTypeAndInterface(t)
if t.Implements(andAnyOfType) {
s := nonNilPointer.(andAnyOf).AndAnyOf()
schema.AnyOf = r.getSubschemasForBooleanCases(definitions, s)
}
if t.Implements(andOneOfType) {
s := nonNilPointer.(andOneOf).AndOneOf()
schema.OneOf = r.getSubschemasForBooleanCases(definitions, s)
}
if t.Implements(andAllOfType) {
s := nonNilPointer.(andAllOf).AndAllOf()
schema.AllOf = r.getSubschemasForBooleanCases(definitions, s)
}
}
func (r *Reflector) getSubschemasForBooleanCases(definitions Definitions, s []reflect.StructField) []*Type {
oneOfList := make([]*Type, 0)
for _, oneType := range s {
if oneType.Type == nil {
oneOfList = append(oneOfList, &Type{Type: "null"})
} else {
oneOfList = append(oneOfList, r.reflectTypeToSchema(definitions, oneType.Type))
}
}
return oneOfList
}