func fieldAssignmentTypeToModel(model *RelationalModelDefinition, ut *design.UserTypeDefinition, utype, mtype string) string { // Get a sortable slice of field names var keys []string for k := range model.RelationalFields { keys = append(keys, k) } sort.Strings(keys) var fieldAssignments []string for _, fname := range keys { field := model.RelationalFields[fname] var mpointer, upointer bool mpointer = field.Nullable obj := ut.ToObject() definition := ut.Definition() if field.Datatype == "" { continue } for key := range obj { gfield := obj[key] if field.Underscore() == key || field.DatabaseFieldName == key { // this is our field if gfield.Type.IsObject() || definition.IsPrimitivePointer(key) { upointer = true } else { // set it explicitly because we're reusing the same bool upointer = false } var prefix string if upointer != mpointer { prefix = "*" } fa := fmt.Sprintf("\t%s.%s = %s%s.%s", mtype, fname, prefix, utype, codegen.Goify(key, true)) fieldAssignments = append(fieldAssignments, fa) } } } return strings.Join(fieldAssignments, "\n") }
// Type implements the type definition dsl. A type definition describes a data structure consisting // of attributes. Each attribute has a type which can also refer to a type definition (or use a // primitive type or nested attibutes). The dsl syntax for define a type definition is the // Attribute dsl, see Attribute. // // On top of specifying any attribute type, type definitions can also be used to describe the data // structure of a request payload. They can also be used by media type definitions as reference, see // Reference. Here is an example: // // Type("createPayload", func() { // Description("Type of create and upload action payloads") // APIVersion("1.0") // Attribute("name", String, "name of bottle") // Attribute("origin", Origin, "Details on wine origin") // See Origin definition below // Required("name") // }) // // var Origin = Type("origin", func() { // Description("Origin of bottle") // Attribute("Country") // }) // // This function returns the newly defined type so the value can be used throughout the dsl. func Type(name string, dsl func()) *design.UserTypeDefinition { if design.Design.Types == nil { design.Design.Types = make(map[string]*design.UserTypeDefinition) } else if _, ok := design.Design.Types[name]; ok { dslengine.ReportError("type %#v defined twice", name) return nil } var t *design.UserTypeDefinition if dslengine.TopLevelDefinition(true) { t = &design.UserTypeDefinition{ TypeName: name, AttributeDefinition: &design.AttributeDefinition{DSLFunc: dsl}, } if dsl == nil { t.Type = design.String } design.Design.Types[name] = t } return t }
// GoTypeTransform produces Go code that initializes the data structure defined by target from an // instance of the data structure described by source. The algorithm matches object fields by name // or using the value of the "transform:key" attribute metadata when present. // The function returns an error if target is not compatible with source (different type, fields of // different type etc). It ignores fields in target that don't have a match in source. func GoTypeTransform(source, target *design.UserTypeDefinition, targetPkg, funcName string) (string, error) { var impl string var err error switch { case source.IsObject(): if !target.IsObject() { return "", fmt.Errorf("source is an object but target type is %s", target.Type.Name()) } impl, err = transformObject(source.ToObject(), target.ToObject(), targetPkg, target.TypeName, "source", "target", 1) case source.IsArray(): if !target.IsArray() { return "", fmt.Errorf("source is an array but target type is %s", target.Type.Name()) } impl, err = transformArray(source.ToArray(), target.ToArray(), targetPkg, "source", "target", 1) case source.IsHash(): if !target.IsHash() { return "", fmt.Errorf("source is a hash but target type is %s", target.Type.Name()) } impl, err = transformHash(source.ToHash(), target.ToHash(), targetPkg, "source", "target", 1) default: panic("cannot transform primitive types") // bug } if err != nil { return "", err } t := GoTypeRef(target, nil, 0) if strings.HasPrefix(t, "*") && len(targetPkg) > 0 { t = fmt.Sprintf("*%s.%s", targetPkg, t[1:]) } data := map[string]interface{}{ "Name": funcName, "Source": source, "Target": target, "TargetRef": t, "TargetPkg": targetPkg, "Impl": impl, } return RunTemplate(transformT, data), nil }
// userTypeMarshalerFuncName returns the name for the given media type marshaler function. func userTypeMarshalerFuncName(u *design.UserTypeDefinition) string { return fmt.Sprintf("Marshal%s", GoTypeName(u, u.AllRequired(), 0)) }
// UserTypeUnmarshalerImpl returns the code implementing the user type unmarshaler function. func UserTypeUnmarshalerImpl(u *design.UserTypeDefinition, versioned bool, defaultPkg, context string) string { validation := RecursiveChecker(u.AttributeDefinition, false, false, "source", context, 1) var impl string switch { case u.IsObject(): impl = objectUnmarshalerR(u, u.AllRequired(), u.AllNonZero(), versioned, defaultPkg, context, "source", "target", 1) case u.IsArray(): impl = arrayUnmarshalerR(u.ToArray(), versioned, defaultPkg, context, "source", "target", 1) case u.IsHash(): impl = hashUnmarshalerR(u.ToHash(), versioned, defaultPkg, context, "source", "target", 1) default: return "" // No function for primitive types - they just get casted } data := map[string]interface{}{ "Name": userTypeUnmarshalerFuncName(u), "Type": u, "Impl": impl, "MustValidate": strings.TrimSpace(validation) != "", } return RunTemplate(unmUserImplT, data) }