Пример #1
0
// 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)
}
Пример #2
0
// RecursiveFinalizer produces Go code that sets the default values for fields recursively for the
// given attribute.
func RecursiveFinalizer(att *design.AttributeDefinition, target string, depth int, vs ...map[string]bool) string {
	var assignments []string
	if o := att.Type.ToObject(); o != nil {
		if mt, ok := att.Type.(*design.MediaTypeDefinition); ok {
			if len(vs) == 0 {
				vs = []map[string]bool{make(map[string]bool)}
			} else if _, ok := vs[0][mt.TypeName]; ok {
				return ""
			}
			vs[0][mt.TypeName] = true
			att = mt.AttributeDefinition
		} else if ut, ok := att.Type.(*design.UserTypeDefinition); ok {
			if len(vs) == 0 {
				vs = []map[string]bool{make(map[string]bool)}
			} else if _, ok := vs[0][ut.TypeName]; ok {
				return ""
			}
			vs[0][ut.TypeName] = true
			att = ut.AttributeDefinition
		}
		o.IterateAttributes(func(n string, catt *design.AttributeDefinition) error {
			if att.HasDefaultValue(n) {
				data := map[string]interface{}{
					"target":     target,
					"field":      n,
					"catt":       catt,
					"depth":      depth,
					"isDatetime": catt.Type == design.DateTime,
					"defaultVal": printVal(catt.Type, catt.DefaultValue),
				}
				assignments = append(assignments, RunTemplate(assignmentT, data))
			}
			assignment := RecursiveFinalizer(
				catt,
				fmt.Sprintf("%s.%s", target, Goify(n, true)),
				depth+1,
				vs...,
			)
			if assignment != "" {
				if catt.Type.IsObject() {
					assignment = fmt.Sprintf("%sif %s.%s != nil {\n%s\n%s}",
						Tabs(depth), target, Goify(n, true), assignment, Tabs(depth))
				}
				assignments = append(assignments, assignment)
			}
			return nil
		})
	} else if a := att.Type.ToArray(); a != nil {
		data := map[string]interface{}{
			"elemType": a.ElemType,
			"target":   target,
			"depth":    1,
		}
		assignment := RunTemplate(arrayAssignmentT, data)
		if assignment != "" {
			assignments = append(assignments, assignment)
		}
	}
	return strings.Join(assignments, "\n")
}
Пример #3
0
// 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")
}
Пример #4
0
func (f *Finalizer) recurse(att *design.AttributeDefinition, target string, depth int) *bytes.Buffer {
	var (
		buf   = new(bytes.Buffer)
		first = true
	)

	// Break infinite recursions
	switch dt := att.Type.(type) {
	case *design.MediaTypeDefinition:
		if buf, ok := f.seen[dt.TypeName]; ok {
			return buf
		}
		f.seen[dt.TypeName] = buf
		att = dt.AttributeDefinition
	case *design.UserTypeDefinition:
		if buf, ok := f.seen[dt.TypeName]; ok {
			return buf
		}
		f.seen[dt.TypeName] = buf
		att = dt.AttributeDefinition
	}

	if o := att.Type.ToObject(); o != nil {
		o.IterateAttributes(func(n string, catt *design.AttributeDefinition) error {
			if att.HasDefaultValue(n) {
				data := map[string]interface{}{
					"target":     target,
					"field":      n,
					"catt":       catt,
					"depth":      depth,
					"isDatetime": catt.Type == design.DateTime,
					"defaultVal": printVal(catt.Type, catt.DefaultValue),
				}
				if !first {
					buf.WriteByte('\n')
				} else {
					first = false
				}
				buf.WriteString(RunTemplate(f.assignmentT, data))
			}
			a := f.recurse(catt, fmt.Sprintf("%s.%s", target, Goify(n, true)), depth+1).String()
			if a != "" {
				if catt.Type.IsObject() {
					a = fmt.Sprintf("%sif %s.%s != nil {\n%s\n%s}",
						Tabs(depth), target, Goify(n, true), a, Tabs(depth))
				}
				if !first {
					buf.WriteByte('\n')
				} else {
					first = false
				}
				buf.WriteString(a)
			}
			return nil
		})
	} else if a := att.Type.ToArray(); a != nil {
		data := map[string]interface{}{
			"elemType": a.ElemType,
			"target":   target,
			"depth":    1,
		}
		if as := RunTemplate(f.arrayAssignmentT, data); as != "" {
			buf.WriteString(as)
		}
	}
	return buf
}
Пример #5
0
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
}
Пример #6
0
// 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")
}