// attributeTags computes the struct field tags. func attributeTags(parent, att *design.AttributeDefinition, name string, private bool) string { var elems []string keys := make([]string, len(att.Metadata)) i := 0 for k := range att.Metadata { keys[i] = k i++ } sort.Strings(keys) for _, key := range keys { val := att.Metadata[key] if strings.HasPrefix(key, "struct:tag:") { name := key[11:] value := strings.Join(val, ",") elems = append(elems, fmt.Sprintf("%s:\"%s\"", name, value)) } } if len(elems) > 0 { return " `" + strings.Join(elems, " ") + "`" } // Default algorithm var omit string if private || (!parent.IsRequired(name) && !parent.HasDefaultValue(name)) { omit = ",omitempty" } return fmt.Sprintf(" `form:\"%s%s\" json:\"%s%s\" xml:\"%s%s\"`", name, omit, name, omit, name, omit) }
func paramsFromDefinition(params *design.AttributeDefinition, path string) ([]*Parameter, error) { if params == nil { return nil, nil } obj := params.Type.ToObject() if obj == nil { return nil, fmt.Errorf("invalid parameters definition, not an object") } res := make([]*Parameter, len(obj)) i := 0 wildcards := design.ExtractWildcards(path) obj.IterateAttributes(func(n string, at *design.AttributeDefinition) error { in := "query" required := params.IsRequired(n) for _, w := range wildcards { if n == w { in = "path" required = true break } } param := paramFor(at, n, in, required) res[i] = param i++ return nil }) return res, nil }
// RecursiveChecker produces Go code that runs the validation checks recursively over the given // attribute. func RecursiveChecker(att *design.AttributeDefinition, nonzero, required, hasDefault bool, target, context string, depth int, private bool) string { var checks []string if o := att.Type.ToObject(); o != nil { if mt, ok := att.Type.(*design.MediaTypeDefinition); ok { att = mt.AttributeDefinition } else if ut, ok := att.Type.(*design.UserTypeDefinition); ok { att = ut.AttributeDefinition } validation := ValidationChecker(att, nonzero, required, hasDefault, target, context, depth, private) if validation != "" { checks = append(checks, validation) } o.IterateAttributes(func(n string, catt *design.AttributeDefinition) error { actualDepth := depth if catt.Type.IsObject() { actualDepth = depth + 1 } validation := RecursiveChecker( catt, att.IsNonZero(n), att.IsRequired(n), att.HasDefaultValue(n), fmt.Sprintf("%s.%s", target, Goify(n, true)), fmt.Sprintf("%s.%s", context, n), actualDepth, private, ) if validation != "" { if catt.Type.IsObject() { validation = fmt.Sprintf("%sif %s.%s != nil {\n%s\n%s}", Tabs(depth), target, Goify(n, true), validation, Tabs(depth)) } checks = append(checks, validation) } return nil }) } else if a := att.Type.ToArray(); a != nil { data := map[string]interface{}{ "elemType": a.ElemType, "context": context, "target": target, "depth": 1, "private": private, } validation := RunTemplate(arrayValT, data) if validation != "" { checks = append(checks, validation) } } else { validation := ValidationChecker(att, nonzero, required, hasDefault, target, context, depth, private) if validation != "" { checks = append(checks, validation) } } return strings.Join(checks, "\n") }
func paramsFromDefinition(params *design.AttributeDefinition, path string) ([]*Parameter, error) { if params == nil { return nil, nil } obj := params.Type.ToObject() if obj == nil { return nil, fmt.Errorf("invalid parameters definition, not an object") } res := make([]*Parameter, len(obj)) i := 0 wildcards := design.ExtractWildcards(path) obj.IterateAttributes(func(n string, at *design.AttributeDefinition) error { in := "query" required := params.IsRequired(n) for _, w := range wildcards { if n == w { in = "path" required = true break } } param := &Parameter{ Name: n, Default: at.DefaultValue, Description: at.Description, Required: required, In: in, Type: at.Type.Name(), } var items *Items if at.Type.IsArray() { items = itemsFromDefinition(at) } param.Items = items initValidations(at, param) res[i] = param i++ return nil }) return res, nil }
// RecursiveChecker produces Go code that runs the validation checks recursively over the given // attribute. func RecursiveChecker(att *design.AttributeDefinition, nonzero, required bool, target, context string, depth int) string { var checks []string validation := ValidationChecker(att, nonzero, required, target, context, depth) if validation != "" { checks = append(checks, validation) } if o := att.Type.ToObject(); o != nil { if mt, ok := att.Type.(*design.MediaTypeDefinition); ok { att = mt.AttributeDefinition } else if ut, ok := att.Type.(*design.UserTypeDefinition); ok { att = ut.AttributeDefinition } o.IterateAttributes(func(n string, catt *design.AttributeDefinition) error { validation := RecursiveChecker( catt, att.IsNonZero(n), att.IsRequired(n), fmt.Sprintf("%s.%s", target, Goify(n, true)), fmt.Sprintf("%s.%s", context, n), depth+1, ) if validation != "" { checks = append(checks, validation) } return nil }) } else if a := att.Type.ToArray(); a != nil { data := map[string]interface{}{ "elemType": a.ElemType, "context": context, "target": target, "depth": 1, } validation := RunTemplate(arrayValT, data) if validation != "" { checks = append(checks, validation) } } return strings.Join(checks, "\n") }
var _ = Describe("IsRequired", func() { var required string var attName string var attribute *design.AttributeDefinition var res bool JustBeforeEach(func() { integer := &design.AttributeDefinition{Type: design.Integer} attribute = &design.AttributeDefinition{ Type: design.Object{required: integer}, Validations: []dslengine.ValidationDefinition{ &dslengine.RequiredValidationDefinition{Names: []string{required}}, }, } res = attribute.IsRequired(attName) }) Context("called on a required field", func() { BeforeEach(func() { attName = "required" required = "required" }) It("returns true", func() { Ω(res).Should(BeTrue()) }) }) Context("called on a non-required field", func() { BeforeEach(func() {
func (v *Validator) recurseAttribute(att, catt *design.AttributeDefinition, n, target, context string, depth int, private bool) string { var validation string if ds, ok := catt.Type.(design.DataStructure); ok { // We need to check empirically whether there are validations to be // generated, we can't just generate and check whether something was // generated to avoid infinite recursions. hasValidations := false done := errors.New("done") ds.Walk(func(a *design.AttributeDefinition) error { if a.Validation != nil { if private { hasValidations = true return done } // For public data structures there is a case where // there is validation but no actual validation // code: if the validation is a required validation // that applies to attributes that cannot be nil or // empty string i.e. primitive types other than // string. if !a.Validation.HasRequiredOnly() { hasValidations = true return done } for _, name := range a.Validation.Required { att := a.Type.ToObject()[name] if att != nil && (!att.Type.IsPrimitive() || att.Type.Kind() == design.StringKind) { hasValidations = true return done } } } return nil }) if hasValidations { validation = RunTemplate(v.userValT, map[string]interface{}{ "depth": depth, "target": fmt.Sprintf("%s.%s", target, GoifyAtt(catt, n, true)), }) } } else { dp := depth if catt.Type.IsObject() { dp++ } validation = v.recurse( catt, att.IsNonZero(n), att.IsRequired(n), att.HasDefaultValue(n), fmt.Sprintf("%s.%s", target, GoifyAtt(catt, n, true)), fmt.Sprintf("%s.%s", context, n), dp, private, ).String() } if validation != "" { if catt.Type.IsObject() { validation = fmt.Sprintf("%sif %s.%s != nil {\n%s\n%s}", Tabs(depth), target, GoifyAtt(catt, n, true), validation, Tabs(depth)) } } return validation }
// RecursiveChecker produces Go code that runs the validation checks recursively over the given // attribute. func RecursiveChecker(att *design.AttributeDefinition, nonzero, required, hasDefault bool, target, context string, depth int, private bool) string { var checks []string if o := att.Type.ToObject(); o != nil { if ds, ok := att.Type.(design.DataStructure); ok { att = ds.Definition() } validation := ValidationChecker(att, nonzero, required, hasDefault, target, context, depth, private) if validation != "" { checks = append(checks, validation) } o.IterateAttributes(func(n string, catt *design.AttributeDefinition) error { var validation string if ds, ok := catt.Type.(design.DataStructure); ok { // We need to check empirically whether there are validations to be // generated, we can't just generate and check whether something was // generated to avoid infinite recursions. hasValidations := false done := errors.New("done") ds.Walk(func(a *design.AttributeDefinition) error { if a.Validation != nil { if private { hasValidations = true return done } // For public data structures there is a case where // there is validation but no actual validation // code: if the validation is a required validation // that applies to attributes that cannot be nil or // empty string i.e. primitive types other than // string. if !a.Validation.HasRequiredOnly() { hasValidations = true return done } for _, name := range a.Validation.Required { att := a.Type.ToObject()[name] if att != nil && (!att.Type.IsPrimitive() || att.Type.Kind() == design.StringKind) { hasValidations = true return done } } } return nil }) if hasValidations { validation = RunTemplate( userValT, map[string]interface{}{ "depth": depth, "target": fmt.Sprintf("%s.%s", target, GoifyAtt(catt, n, true)), }, ) } } else { dp := depth if catt.Type.IsObject() { dp++ } validation = RecursiveChecker( catt, att.IsNonZero(n), att.IsRequired(n), att.HasDefaultValue(n), fmt.Sprintf("%s.%s", target, GoifyAtt(catt, n, true)), fmt.Sprintf("%s.%s", context, n), dp, private, ) } if validation != "" { if catt.Type.IsObject() { validation = fmt.Sprintf("%sif %s.%s != nil {\n%s\n%s}", Tabs(depth), target, GoifyAtt(catt, n, true), validation, Tabs(depth)) } checks = append(checks, validation) } return nil }) } else if a := att.Type.ToArray(); a != nil { // Perform any validation on the array type such as MinLength, MaxLength, etc. validation := ValidationChecker(att, nonzero, required, hasDefault, target, context, depth, private) if validation != "" { checks = append(checks, validation) } data := map[string]interface{}{ "elemType": a.ElemType, "context": context, "target": target, "depth": 1, "private": private, } validation = RunTemplate(arrayValT, data) if validation != "" { checks = append(checks, validation) } } else { validation := ValidationChecker(att, nonzero, required, hasDefault, target, context, depth, private) if validation != "" { checks = append(checks, validation) } } return strings.Join(checks, "\n") }