-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathObjectSchema.go
141 lines (109 loc) · 3.25 KB
/
ObjectSchema.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package presilo
import (
"encoding/json"
"errors"
"fmt"
)
/*
A schema which describes an integer.
*/
type ObjectSchema struct {
Schema
Properties map[string]TypeSchema
RequiredProperties []string `json:"required"`
// TODO: MaxProperties *int `json:"maxProperties"`
// TODO: MinProperties *int `json:"minProperties"`
// TODO: AdditionalProperties *bool `json:"additionalProperties"`
// NOT SUPPORTED: patternProperties
RawProperties map[string]*json.RawMessage `json:"properties"`
ConstrainedProperties SortableStringArray
UnconstrainedProperties SortableStringArray
}
func NewObjectSchema() *ObjectSchema {
var ret *ObjectSchema
ret = new(ObjectSchema)
ret.typeCode = SCHEMATYPE_OBJECT
ret.Properties = make(map[string]TypeSchema)
return ret
}
/*
Creates a new object schema from a byte slice that can be interpreted as json.
Object schemas may contain multiple schemas.
*/
func ParseObjectSchema(contents []byte, context *SchemaParseContext) (*ObjectSchema, error) {
var ret *ObjectSchema
var sub TypeSchema
var subschemaBytes []byte
var err error
ret = NewObjectSchema()
err = json.Unmarshal(contents, &ret)
if err != nil {
return ret, err
}
err = ret.checkRequiredProperties()
if err != nil {
return ret, err
}
// parse individual sub-schemas
for propertyName, propertyContents := range ret.RawProperties {
subschemaBytes, err = propertyContents.MarshalJSON()
if err != nil {
return ret, err
}
sub, err = ParseSchema(subschemaBytes, propertyName, context)
if err != nil {
return ret, err
}
ret.Properties[propertyName] = sub
}
// for convenience, populate "ConstrainedProperties" to all required properties,
// along with any other properties which have constraints
for propertyName, subschema := range ret.Properties {
if subschema.HasConstraints() {
ret.ConstrainedProperties = append(ret.ConstrainedProperties, propertyName)
} else {
ret.UnconstrainedProperties = append(ret.UnconstrainedProperties, propertyName)
}
}
ret.ConstrainedProperties.Sort()
ret.UnconstrainedProperties.Sort()
return ret, nil
}
func (this *ObjectSchema) AddProperty(name string, schema TypeSchema) {
this.Properties[name] = schema
if(schema.HasConstraints()) {
this.ConstrainedProperties = append(this.ConstrainedProperties, name)
this.ConstrainedProperties.Sort()
} else {
this.UnconstrainedProperties = append(this.UnconstrainedProperties, name)
this.UnconstrainedProperties.Sort()
}
}
/*
Returns an ordered array of property names, guaranteed to be the same for the same schema input over multiple runs of the program.
*/
func (this *ObjectSchema) GetOrderedPropertyNames() []string {
var ret SortableStringArray
// fill
for key, _ := range this.Properties {
ret = append(ret, key)
}
ret.Sort()
return ret
}
func (this *ObjectSchema) checkRequiredProperties() error {
var propertyName string
var found bool
// make sure all required properties are defined
for _, propertyName = range this.RequiredProperties {
_, found = this.RawProperties[propertyName]
if !found {
errorMsg := fmt.Sprintf("Property '%s' was listed as required, but was not defined\n", propertyName)
return errors.New(errorMsg)
}
}
return nil
}
func (this *ObjectSchema) HasConstraints() bool {
return false
}