Skip to content

Commit 8ab036b

Browse files
committed
backport Dima fix
1 parent 76fd15b commit 8ab036b

File tree

1 file changed

+59
-25
lines changed

1 file changed

+59
-25
lines changed

jsonschema/schema.go

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package jsonschema
1717

1818
import (
1919
"encoding/json"
20+
"fmt"
2021
"reflect"
2122
"strings"
2223

@@ -55,14 +56,22 @@ func New(data []byte) (*JSONSchema, error) {
5556
// ProcessObject checks if the object is valid from this schema's standpoint
5657
// and returns an object with defaults set up according to schema's spec
5758
func (j *JSONSchema) ProcessObject(in interface{}) (interface{}, error) {
58-
result, err := j.schema.Validate(gojsonschema.NewGoLoader(in))
59+
defaults := setDefaults(j.rawSchema, in)
60+
61+
result, err := j.schema.Validate(gojsonschema.NewGoLoader(defaults))
5962
if err != nil {
6063
return nil, trace.Wrap(err)
6164
}
6265
if !result.Valid() {
63-
return nil, trace.Wrap(trace.Errorf("errors: %v", schemaErrors(result.Errors())))
66+
errors := result.Errors()
67+
output := make([]string, len(errors))
68+
for i, err := range errors {
69+
output[i] = fmt.Sprintf("%v", err)
70+
}
71+
72+
return nil, trace.Errorf("failed to validate: %v", strings.Join(output, ","))
6473
}
65-
return setDefaults(j.rawSchema, in), nil
74+
return defaults, nil
6675
}
6776

6877
func setDefaults(ischema interface{}, ivars interface{}) interface{} {
@@ -73,37 +82,49 @@ func setDefaults(ischema interface{}, ivars interface{}) interface{} {
7382
if !ok {
7483
return ivars
7584
}
76-
tp := getStringProp(schema, "type")
77-
switch tp {
85+
itemType := getStringProp(schema, "type")
86+
switch itemType {
7887
case "object":
79-
vars, ok := ivars.(map[string]interface{})
80-
if !ok {
81-
return ivars
82-
}
83-
if len(vars) == 0 {
84-
vars = make(map[string]interface{})
88+
var vars map[string]interface{}
89+
if ivars == nil {
90+
vars = map[string]interface{}{}
91+
} else {
92+
var ok bool
93+
vars, ok = ivars.(map[string]interface{})
94+
if !ok {
95+
return ivars
96+
}
8597
}
86-
props, ok := getProperties(schema, "properties")
87-
if !ok {
98+
var props map[string]interface{}
99+
if props = getSchemaProperties(schema, vars); props == nil {
88100
return ivars
89101
}
90102
out := make(map[string]interface{})
91103
for key, prop := range props {
92104
_, have := vars[key]
93105
defval := setDefaults(prop, vars[key])
94106
// only set default value if the property
95-
// is missing and retunred default value is not empty
107+
// is missing and returned default value is not empty
96108
// otherwise we will return a bunch of nils
97109
if !have && isEmpty(defval) {
98110
continue
99111
}
100112
out[key] = defval
101113
}
114+
if len(out) == 0 {
115+
return nil
116+
}
102117
return out
103118
case "array":
104-
vars, ok := ivars.([]interface{})
105-
if !ok {
106-
return ivars
119+
var vars []interface{}
120+
if ivars == nil {
121+
vars = []interface{}{}
122+
} else {
123+
var ok bool
124+
vars, ok = ivars.([]interface{})
125+
if !ok {
126+
return ivars
127+
}
107128
}
108129
if len(vars) == 0 {
109130
return ivars
@@ -130,6 +151,27 @@ func setDefaults(ischema interface{}, ivars interface{}) interface{} {
130151
return ivars
131152
}
132153

154+
func getSchemaProperties(schema map[string]interface{}, input map[string]interface{}) map[string]interface{} {
155+
objectProperties, ok := getProperties(schema, "properties")
156+
if !ok {
157+
if objectProperties, ok = getProperties(schema, "patternProperties"); !ok {
158+
return nil
159+
}
160+
// pattern properties define a single property with a name pattern;
161+
// we ignore the pattern - validation will verify if it's correct
162+
var property interface{}
163+
for _, property = range objectProperties {
164+
}
165+
// override the result to contain the pattern property for each
166+
// input key
167+
objectProperties = map[string]interface{}{}
168+
for key, _ := range input {
169+
objectProperties[key] = property
170+
}
171+
}
172+
return objectProperties
173+
}
174+
133175
func isEmpty(x interface{}) bool {
134176
return x == nil || reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
135177
}
@@ -161,11 +203,3 @@ func getProperties(schema map[string]interface{}, name string) (map[string]inter
161203
}
162204
return v, true
163205
}
164-
165-
func schemaErrors(errors []gojsonschema.ResultError) string {
166-
out := make([]string, len(errors))
167-
for i, err := range errors {
168-
out[i] = err.Description()
169-
}
170-
return strings.Join(out, ",")
171-
}

0 commit comments

Comments
 (0)