Skip to content

Commit

Permalink
feat: implement Marshaler & Unmarshaler for schema
Browse files Browse the repository at this point in the history
  • Loading branch information
dingwenjiang committed Mar 29, 2021
1 parent 99c235d commit aa9f9a8
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 30 deletions.
19 changes: 16 additions & 3 deletions schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
package gojsonschema

import (
"encoding/json"
"errors"
"math/big"
"reflect"
Expand Down Expand Up @@ -1086,6 +1087,18 @@ func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subS
return nil
}

func (d *Schema) GetSchema() *subSchema {
return d.rootSchema
}
// MarshalJSON convert schema to json
func (d *Schema) MarshalJSON() ([]byte, error) {
return json.Marshal(d.rootSchema)
}

// UnmarshalJSON convert json to schema
func (d *Schema) UnmarshalJSON(bytes []byte) error {
loader := NewSchemaLoader()
if schema, err := loader.Compile(NewBytesLoader(bytes)); err != nil {
return err
} else {
*d = *schema
return nil
}
}
123 changes: 96 additions & 27 deletions subSchema.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"encoding/json"
"github.com/xeipuuv/gojsonreference"
"math/big"
"reflect"
"regexp"
)

Expand Down Expand Up @@ -150,43 +151,111 @@ type subSchema struct {
}

func (v *subSchema) MarshalJSON() ([]byte, error) {
ret := make(map[string]interface{})
if len(v.property) != 0{
ret["title"] = v.property
}
tmp := make(map[string]interface{})
result := make(map[string]interface{})
if len(v.types.types) > 0 {
ret["type"] = v.types.types[0]
switch ret["type"] {
case "number":
if v.multipleOf != nil{
ret["multipleOf"] = v.multipleOf
}
if v.maximum != nil {
ret["maximum"] = v.maximum.Num()
}
if v.minimum != nil {
ret["minimum"] = v.minimum.Num()
switch v.types.types[0] {
//case "boolean", "null": // do nothing
case "number", "integer":
// type、multipleOf、minimum、exclusiveMinimum、maximum、exclusiveMaximum
tmp = map[string]interface{}{
"multipleOf": ensureField(v.multipleOf),
"minimum": ensureField(v.minimum),
"exclusiveMinimum": ensureField(v.exclusiveMinimum),
"maximum": ensureField(v.maximum),
"exclusiveMaximum": ensureField(v.exclusiveMaximum),
}
case "string":
if len(v.format) != 0 {
ret["format"] = v.format
// type、minLength、maxLength、pattern、format
tmp = map[string]interface{}{
"minLength": ensureField(v.minLength),
"maxLength": ensureField(v.maxLength),
"pattern": ensureField(v.pattern),
"format": ensureField(v.format),
}
if v.minLength != nil {
ret["minLength"] = v.minLength
case "object":
// type、properties、additionalProperties、required, propertyNames、minProperties、
tmp = map[string]interface{}{
"minProperties": ensureField(v.minProperties),
"maxProperties": ensureField(v.maxProperties),
"required": ensureField(v.required),
"dependencies": ensureField(v.dependencies),
"additionalProperties": ensureField(v.additionalProperties),
"patternProperties": ensureField(v.patternProperties),
"propertyNames": ensureField(v.propertyNames),
}
if v.maxLength != nil {
ret["maxLength"] = v.maxLength
if v.propertiesChildren != nil {
properties := make(map[string]interface{})
for _, propertyChild := range v.propertiesChildren {
properties[propertyChild.property] = propertyChild
}
tmp["properties"] = properties
}
if v.pattern != nil {
ret["pattern"] = v.maxLength
case "array":
tmp = map[string]interface{}{
"minItems": ensureField(v.minItems),
"maxItems": ensureField(v.maxItems),
"uniqueItems": ensureField(v.uniqueItems),
"contains": ensureField(v.contains),
"additionalItems": ensureField(v.additionalItems),
}
case "boolean":
case "object":
}
tmp["type"] = v.types.types[0]
tmp["const"] = ensureField(v._const)
tmp["enum"] = ensureField(v.enum)
}
for key, value := range tmp {
if value != nil {
result[key] = value
}
}
return json.Marshal(result)
}


func ensureField(p interface{}) interface{} {
if isNil(p) {
return nil
}
return json.Marshal(ret)
var ret interface{}
rv := reflect.ValueOf(p)
if rv.Kind() == reflect.Ptr {
if rv.Type() == reflect.TypeOf(&big.Rat{}) {
ret = (p.(*big.Rat)).Num()
} else if rv.Type() == reflect.TypeOf(&regexp.Regexp{}) {
ret = (p.(*regexp.Regexp)).String()
} else {
switch rv.Elem().Kind() {
case reflect.Int:
ret = *(p.(*int))
case reflect.String:
ret = *(p.(*string))
case reflect.Slice, reflect.Interface, reflect.Map:
ret = p
}
}
} else {
switch rv.Kind() {
case reflect.String:
tmp := p.(string)
if len(tmp) != 0 {
ret = tmp
}
case reflect.Slice:
ret = p
}
}
return ret
}

func isNil(i interface{}) bool {
// https://mangatmodi.medium.com/go-check-nil-interface-the-right-way-d142776edef1
if i == nil {
return true
}
switch reflect.TypeOf(i).Kind() {
case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice:
return reflect.ValueOf(i).IsNil()
}
return false

}

0 comments on commit aa9f9a8

Please sign in to comment.