Example #1
0
// BelongsTo signifies a relationship between this model and a
// Parent.  The Parent has the child, and the Child belongs
// to the Parent.
// Usage:  BelongsTo("User")
func BelongsTo(parent string) {
	if r, ok := relationalModelDefinition(false); ok {
		idfield := &gorma.RelationalFieldDefinition{
			Name:              codegen.Goify(inflect.Singularize(parent), true) + "ID",
			Description:       "Belongs To " + codegen.Goify(inflect.Singularize(parent), true),
			Parent:            r,
			Datatype:          gorma.BelongsTo,
			DatabaseFieldName: SanitizeDBFieldName(codegen.Goify(inflect.Singularize(parent), true) + "ID"),
		}

		r.RelationalFields[idfield.Name] = idfield
		bt, ok := r.Parent.RelationalModels[codegen.Goify(inflect.Singularize(parent), true)]
		if ok {
			r.BelongsTo[bt.Name] = bt
		} else {
			models := &gorma.RelationalModelDefinition{
				Name:             codegen.Goify(inflect.Singularize(parent), true),
				Parent:           r.Parent,
				RelationalFields: make(map[string]*gorma.RelationalFieldDefinition),
				BelongsTo:        make(map[string]*gorma.RelationalModelDefinition),
				HasMany:          make(map[string]*gorma.RelationalModelDefinition),
				HasOne:           make(map[string]*gorma.RelationalModelDefinition),
				ManyToMany:       make(map[string]*gorma.ManyToManyDefinition),
			}
			r.BelongsTo[models.Name] = models
		}
	}
}
Example #2
0
// generateContexts iterates through the version resources and actions and generates the action
// contexts.
func (g *Generator) generateContexts(verdir string, api *design.APIDefinition, version *design.APIVersionDefinition) error {
	ctxFile := filepath.Join(verdir, "contexts.go")
	ctxWr, err := NewContextsWriter(ctxFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Contexts", version.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("golang.org/x/net/context"),
		codegen.SimpleImport("strconv"),
		codegen.SimpleImport("strings"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("github.com/goadesign/goa"),
	}
	if !version.IsDefault() {
		appPkg, err := AppPackagePath()
		if err != nil {
			return err
		}
		imports = append(imports, codegen.SimpleImport(appPkg))
	}
	ctxWr.WriteHeader(title, packageName(version), imports)
	err = version.IterateResources(func(r *design.ResourceDefinition) error {
		if !r.SupportsVersion(version.Version) {
			return nil
		}
		return r.IterateActions(func(a *design.ActionDefinition) error {
			ctxName := codegen.Goify(a.Name, true) + codegen.Goify(a.Parent.Name, true) + "Context"
			headers := r.Headers.Merge(a.Headers)
			if headers != nil && len(headers.Type.ToObject()) == 0 {
				headers = nil // So that {{if .Headers}} returns false in templates
			}
			params := a.AllParams()
			if params != nil && len(params.Type.ToObject()) == 0 {
				params = nil // So that {{if .Params}} returns false in templates
			}
			ctxData := ContextTemplateData{
				Name:         ctxName,
				ResourceName: r.Name,
				ActionName:   a.Name,
				Payload:      a.Payload,
				Params:       params,
				Headers:      headers,
				Routes:       a.Routes,
				Responses:    MergeResponses(r.Responses, a.Responses),
				API:          api,
				Version:      version,
				DefaultPkg:   TargetPackage,
			}
			return ctxWr.Execute(&ctxData)
		})
	})
	g.genfiles = append(g.genfiles, ctxFile)
	if err != nil {
		return err
	}
	return ctxWr.FormatCode()
}
Example #3
0
// generateContexts iterates through the API resources and actions and generates the action
// contexts.
func (g *Generator) generateContexts() error {
	ctxFile := filepath.Join(g.OutDir, "contexts.go")
	ctxWr, err := NewContextsWriter(ctxFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Contexts", g.API.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("golang.org/x/net/context"),
		codegen.SimpleImport("strconv"),
		codegen.SimpleImport("strings"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("unicode/utf8"),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.NewImport("uuid", "github.com/satori/go.uuid"),
	}
	g.genfiles = append(g.genfiles, ctxFile)
	ctxWr.WriteHeader(title, g.Target, imports)
	err = g.API.IterateResources(func(r *design.ResourceDefinition) error {
		return r.IterateActions(func(a *design.ActionDefinition) error {
			ctxName := codegen.Goify(a.Name, true) + codegen.Goify(a.Parent.Name, true) + "Context"
			headers := r.Headers.Merge(a.Headers)
			if headers != nil && len(headers.Type.ToObject()) == 0 {
				headers = nil // So that {{if .Headers}} returns false in templates
			}
			params := a.AllParams()
			if params != nil && len(params.Type.ToObject()) == 0 {
				params = nil // So that {{if .Params}} returns false in templates
			}

			non101 := make(map[string]*design.ResponseDefinition)
			for k, v := range a.Responses {
				if v.Status != 101 {
					non101[k] = v
				}
			}
			ctxData := ContextTemplateData{
				Name:         ctxName,
				ResourceName: r.Name,
				ActionName:   a.Name,
				Payload:      a.Payload,
				Params:       params,
				Headers:      headers,
				Routes:       a.Routes,
				Responses:    non101,
				API:          g.API,
				DefaultPkg:   g.Target,
				Security:     a.Security,
			}
			return ctxWr.Execute(&ctxData)
		})
	})
	if err != nil {
		return err
	}
	return ctxWr.FormatCode()
}
Example #4
0
File: writers.go Project: DavyC/goa
// Execute writes the code for the context types to the writer.
func (w *ContextsWriter) Execute(data *ContextTemplateData) error {
	fn := template.FuncMap{
		"hasAPIVersion": hasAPIVersion,
	}
	if err := w.ExecuteTemplate("context", ctxT, fn, data); err != nil {
		return err
	}
	fn = template.FuncMap{
		"newCoerceData":  newCoerceData,
		"arrayAttribute": arrayAttribute,
	}
	if err := w.ExecuteTemplate("new", ctxNewT, fn, data); err != nil {
		return err
	}
	if data.Payload != nil {
		if err := w.ExecuteTemplate("payload", payloadT, nil, data); err != nil {
			return err
		}
	}
	fn = template.FuncMap{
		"project": func(mt *design.MediaTypeDefinition, v string) *design.MediaTypeDefinition {
			p, _, _ := mt.Project(v)
			return p
		},
	}
	data.IterateResponses(func(resp *design.ResponseDefinition) error {
		respData := map[string]interface{}{
			"Context":  data,
			"Response": resp,
		}
		if resp.Type != nil {
			respData["Type"] = resp.Type
			if err := w.ExecuteTemplate("response", ctxTRespT, fn, respData); err != nil {
				return err
			}
		} else if mt := design.Design.MediaTypeWithIdentifier(resp.MediaType); mt != nil {
			respData["MediaType"] = mt
			fn["respName"] = func(resp *design.ResponseDefinition, view string) string {
				if view == "default" {
					return codegen.Goify(resp.Name, true)
				}
				base := fmt.Sprintf("%s%s", resp.Name, strings.Title(view))
				return codegen.Goify(base, true)
			}
			if err := w.ExecuteTemplate("response", ctxMTRespT, fn, respData); err != nil {
				return err
			}
		} else {
			if err := w.ExecuteTemplate("response", ctxNoMTRespT, fn, respData); err != nil {
				return err
			}
		}
		return nil
	})
	return nil
}
Example #5
0
// generateContexts iterates through the API resources and actions and generates the action
// contexts.
func (g *Generator) generateContexts(api *design.APIDefinition) error {
	ctxFile := filepath.Join(AppOutputDir(), "contexts.go")
	ctxWr, err := NewContextsWriter(ctxFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Contexts", api.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("fmt"),
		codegen.SimpleImport("golang.org/x/net/context"),
		codegen.SimpleImport("strconv"),
		codegen.SimpleImport("strings"),
		codegen.SimpleImport("time"),
		codegen.SimpleImport("github.com/goadesign/goa"),
		codegen.NewImport("uuid", "github.com/satori/go.uuid"),
	}
	ctxWr.WriteHeader(title, TargetPackage, imports)
	err = api.IterateResources(func(r *design.ResourceDefinition) error {
		return r.IterateActions(func(a *design.ActionDefinition) error {
			ctxName := codegen.Goify(a.Name, true) + codegen.Goify(a.Parent.Name, true) + "Context"
			headers := r.Headers.Merge(a.Headers)
			if headers != nil && len(headers.Type.ToObject()) == 0 {
				headers = nil // So that {{if .Headers}} returns false in templates
			}
			params := a.AllParams()
			if params != nil && len(params.Type.ToObject()) == 0 {
				params = nil // So that {{if .Params}} returns false in templates
			}

			ctxData := ContextTemplateData{
				Name:         ctxName,
				ResourceName: r.Name,
				ActionName:   a.Name,
				Payload:      a.Payload,
				Params:       params,
				Headers:      headers,
				Routes:       a.Routes,
				Responses:    BuildResponses(r.Responses, a.Responses),
				API:          api,
				DefaultPkg:   TargetPackage,
				Security:     a.Security,
			}
			return ctxWr.Execute(&ctxData)
		})
	})
	g.genfiles = append(g.genfiles, ctxFile)
	if err != nil {
		return err
	}
	return ctxWr.FormatCode()
}
Example #6
0
// HasMany signifies a relationship between this model and a
// set of Children.  The Parent has the children, and the Children belong
// to the Parent.  The first parameter becomes the name of the
// field in the model struct, the second parameter is the name
// of the child model.  The Child model will have a ParentID field
// appended to the field list.  The Parent model definition will use
// the first parameter as the field name in the struct definition.
// Usage:  HasMany("Orders", "Order")
// Struct field definition:  Children	[]Child
func HasMany(name, child string) {
	if r, ok := relationalModelDefinition(false); ok {
		field := &gorma.RelationalFieldDefinition{
			Name:        codegen.Goify(name, true),
			HasMany:     child,
			Description: "has many " + inflect.Pluralize(child),
			Datatype:    gorma.HasMany,
			Parent:      r,
		}
		r.RelationalFields[field.Name] = field
		var model *gorma.RelationalModelDefinition
		model, ok := r.Parent.RelationalModels[child]
		if ok {
			r.HasMany[child] = model
			// create the fk field
			f := &gorma.RelationalFieldDefinition{
				Name:              codegen.Goify(inflect.Singularize(r.Name), true) + "ID",
				HasMany:           child,
				Description:       "has many " + child,
				Datatype:          gorma.HasManyKey,
				Parent:            model,
				DatabaseFieldName: SanitizeDBFieldName(codegen.Goify(inflect.Singularize(r.Name), true) + "ID"),
			}
			model.RelationalFields[f.Name] = f
		} else {
			model = &gorma.RelationalModelDefinition{
				Name:             child,
				Parent:           r.Parent,
				RelationalFields: make(map[string]*gorma.RelationalFieldDefinition),
				BelongsTo:        make(map[string]*gorma.RelationalModelDefinition),
				HasMany:          make(map[string]*gorma.RelationalModelDefinition),
				HasOne:           make(map[string]*gorma.RelationalModelDefinition),
				ManyToMany:       make(map[string]*gorma.ManyToManyDefinition),
			}
			r.HasMany[child] = model
			// create the fk field
			f := &gorma.RelationalFieldDefinition{
				Name:              codegen.Goify(inflect.Singularize(r.Name), true) + "ID",
				HasMany:           child,
				Description:       "has many " + child,
				Datatype:          gorma.HasManyKey,
				Parent:            model,
				DatabaseFieldName: SanitizeDBFieldName(codegen.Goify(inflect.Singularize(r.Name), true) + "ID"),
			}
			model.RelationalFields[f.Name] = f
		}
	}
}
Example #7
0
// Generate is the generator entry point called by the meta generator.
func Generate() (files []string, err error) {
	var (
		outDir, target, ver string
		notest              bool
	)

	set := flag.NewFlagSet("app", flag.PanicOnError)
	set.String("design", "", "")
	set.StringVar(&outDir, "out", "", "")
	set.StringVar(&target, "pkg", "app", "")
	set.StringVar(&ver, "version", "", "")
	set.BoolVar(&notest, "notest", false, "")
	set.Bool("force", false, "")
	set.Parse(os.Args[1:])
	outDir = filepath.Join(outDir, target)

	if err := codegen.CheckVersion(ver); err != nil {
		return nil, err
	}

	target = codegen.Goify(target, false)
	g := &Generator{OutDir: outDir, Target: target, NoTest: notest, API: design.Design, validator: codegen.NewValidator()}

	return g.Generate()
}
Example #8
0
// return a ',' joined list of Params as a reference to cmd.XFieldName
// ordered by the required first rules.
func joinFieldhNames(atts ...*design.AttributeDefinition) string {
	var elems []string
	for _, att := range atts {
		if att == nil {
			continue
		}
		obj := att.Type.ToObject()
		var names, optNames []string

		keys := make([]string, len(obj))
		i := 0
		for n := range obj {
			keys[i] = n
			i++
		}
		sort.Strings(keys)

		for _, n := range keys {
			field := fmt.Sprintf("cmd.%s", codegen.Goify(n, true))
			if att.IsRequired(n) {
				names = append(names, field)
			} else {
				optNames = append(optNames, field)
			}
		}
		elems = append(elems, names...)
		elems = append(elems, optNames...)
	}
	return strings.Join(elems, ", ")
}
Example #9
0
// Generate is the generator entry point called by the meta generator.
func Generate() (files []string, err error) {
	var (
		outDir, target, toolDir, tool, ver string
		notool                             bool
	)
	dtool := defaultToolName(design.Design)

	set := flag.NewFlagSet("client", flag.PanicOnError)
	set.String("design", "", "")
	set.StringVar(&outDir, "out", "", "")
	set.StringVar(&target, "pkg", "client", "")
	set.StringVar(&toolDir, "tooldir", "tool", "")
	set.StringVar(&tool, "tool", dtool, "")
	set.StringVar(&ver, "version", "", "")
	set.BoolVar(&notool, "notool", false, "")
	set.Parse(os.Args[1:])

	// First check compatibility
	if err := codegen.CheckVersion(ver); err != nil {
		return nil, err
	}

	// Now proceed
	target = codegen.Goify(target, false)
	g := &Generator{OutDir: outDir, Target: target, ToolDirName: toolDir, Tool: tool, NoTool: notool, API: design.Design}

	return g.Generate()
}
Example #10
0
// Generated package name for resources supporting the given version.
func packageName(version *design.APIVersionDefinition) (pack string) {
	pack = TargetPackage
	if version.Version != "" {
		pack = codegen.Goify(codegen.VersionPackage(version.Version), false)
	}
	return
}
Example #11
0
// PopulateFromModeledType creates fields for the model
// based on the goa UserTypeDefinition it models.
// This happens before fields are processed, so it's
// ok to just assign without testing.
func (f *RelationalModelDefinition) PopulateFromModeledType() {
	if f.BuiltFrom == nil {
		return
	}
	for _, mt := range f.BuiltFrom {
		obj := mt.ToObject()
		obj.IterateAttributes(func(name string, att *design.AttributeDefinition) error {
			rf := &RelationalFieldDefinition{}
			rf.Parent = f
			rf.Name = codegen.Goify(name, true)
			if strings.HasSuffix(rf.Name, "Id") {
				rf.Name = strings.TrimSuffix(rf.Name, "Id")
				rf.Name = rf.Name + "ID"
			}
			switch att.Type.Kind() {
			case design.BooleanKind:
				rf.Datatype = Boolean
			case design.IntegerKind:
				rf.Datatype = Integer
			case design.NumberKind:
				rf.Datatype = Decimal
			case design.StringKind:
				rf.Datatype = String
			case design.DateTimeKind:
				rf.Datatype = Timestamp
			default:
				dslengine.ReportError("Unsupported type: %#v ", att.Type.Kind())
			}
			f.RelationalFields[rf.Name] = rf
			return nil
		})
	}
	return
}
Example #12
0
// generateHrefs iterates through the API resources and generates the href factory methods.
func (g *Generator) generateHrefs(api *design.APIDefinition) error {
	hrefFile := filepath.Join(AppOutputDir(), "hrefs.go")
	resWr, err := NewResourcesWriter(hrefFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Resource Href Factories", api.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("fmt"),
	}
	resWr.WriteHeader(title, TargetPackage, imports)
	err = api.IterateResources(func(r *design.ResourceDefinition) error {
		m := api.MediaTypeWithIdentifier(r.MediaType)
		var identifier string
		if m != nil {
			identifier = m.Identifier
		} else {
			identifier = "text/plain"
		}
		data := ResourceData{
			Name:              codegen.Goify(r.Name, true),
			Identifier:        identifier,
			Description:       r.Description,
			Type:              m,
			CanonicalTemplate: codegen.CanonicalTemplate(r),
			CanonicalParams:   codegen.CanonicalParams(r),
		}
		return resWr.Execute(&data)
	})
	g.genfiles = append(g.genfiles, hrefFile)
	if err != nil {
		return err
	}
	return resWr.FormatCode()
}
Example #13
0
// join is a code generation helper function that generates a function signature built from
// concatenating the properties (name type) of the given attribute type (assuming it's an object).
// join accepts an optional slice of strings which indicates the order in which the parameters
// should appear in the signature. If pos is specified then it must list all the parameters. If
// it's not specified then parameters are sorted alphabetically.
func join(att *design.AttributeDefinition, pos ...[]string) string {
	if att == nil {
		return ""
	}
	obj := att.Type.ToObject()
	elems := make([]string, len(obj))
	var keys []string
	if len(pos) > 0 {
		keys = pos[0]
		if len(keys) != len(obj) {
			panic("invalid position slice, lenght does not match attribute field count") // bug
		}
	} else {
		keys = make([]string, len(obj))
		i := 0
		for n := range obj {
			keys[i] = n
			i++
		}
		sort.Strings(keys)
	}
	for i, n := range keys {
		a := obj[n]
		elems[i] = fmt.Sprintf("%s %s", codegen.Goify(n, false), cmdFieldType(a.Type))
	}
	return strings.Join(elems, ", ")
}
Example #14
0
// PKAttributes constructs a pair of field + definition strings
// useful for method parameters.
func (f *RelationalModelDefinition) PKAttributes() string {
	var attr []string
	for _, pk := range f.PrimaryKeys {
		attr = append(attr, fmt.Sprintf("%s %s", codegen.Goify(pk.DatabaseFieldName, false), goDatatype(pk, true)))
	}
	return strings.Join(attr, ",")
}
Example #15
0
// HasOne signifies a relationship between this model and another model.
// If this model HasOne(OtherModel), then OtherModel is expected
// to have a ThisModelID field as a Foreign Key to this model's
// Primary Key.  ThisModel will have a field named OtherModel of type
// OtherModel.
// Usage:  HasOne("Proposal")
func HasOne(child string) {
	if r, ok := relationalModelDefinition(false); ok {
		field := &gorma.RelationalFieldDefinition{
			Name:        codegen.Goify(inflect.Singularize(child), true),
			HasOne:      child,
			Description: "has one " + child,
			Datatype:    gorma.HasOne,
			Parent:      r,
		}
		r.RelationalFields[field.Name] = field
		bt, ok := r.Parent.RelationalModels[child]
		if ok {
			r.HasOne[child] = bt
			// create the fk field
			f := &gorma.RelationalFieldDefinition{
				Name:              codegen.Goify(inflect.Singularize(r.Name), true) + "ID",
				HasOne:            child,
				Description:       "has one " + child,
				Datatype:          gorma.HasOneKey,
				Parent:            bt,
				DatabaseFieldName: SanitizeDBFieldName(codegen.Goify(inflect.Singularize(r.Name), true) + "ID"),
			}
			bt.RelationalFields[f.Name] = f
		} else {
			models := &gorma.RelationalModelDefinition{
				Name:             child,
				Parent:           r.Parent,
				RelationalFields: make(map[string]*gorma.RelationalFieldDefinition),
				BelongsTo:        make(map[string]*gorma.RelationalModelDefinition),
				HasMany:          make(map[string]*gorma.RelationalModelDefinition),
				HasOne:           make(map[string]*gorma.RelationalModelDefinition),
				ManyToMany:       make(map[string]*gorma.ManyToManyDefinition),
			}
			r.HasOne[child] = models
			// create the fk field
			f := &gorma.RelationalFieldDefinition{
				Name:              codegen.Goify(inflect.Singularize(r.Name), true) + "ID",
				HasOne:            child,
				Description:       "has one " + child,
				Datatype:          gorma.HasOneKey,
				Parent:            bt,
				DatabaseFieldName: SanitizeDBFieldName(codegen.Goify(inflect.Singularize(r.Name), true) + "ID"),
			}
			models.RelationalFields[f.Name] = f
		}
	}
}
Example #16
0
// pathParamNames return the names of the parameters of the path factory function for the given route.
func pathParamNames(r *design.RouteDefinition) string {
	params := r.Params()
	goified := make([]string, len(params))
	for i, p := range params {
		goified[i] = codegen.Goify(p, false)
	}
	return strings.Join(goified, ", ")
}
Example #17
0
// PKWhereFields returns the fields for a where clause for the primary
// keys of a model.
func (f *RelationalModelDefinition) PKWhereFields() string {
	var pkwhere []string
	for _, pk := range f.PrimaryKeys {
		def := fmt.Sprintf("%s", codegen.Goify(pk.DatabaseFieldName, false))
		pkwhere = append(pkwhere, def)
	}
	return strings.Join(pkwhere, ",")
}
Example #18
0
func viewFieldNames(ut *RelationalModelDefinition, v *design.ViewDefinition) []string {
	obj := v.Type.(design.Object)
	var fields []string
	for name := range obj {
		if obj[name].Type.IsPrimitive() {
			if strings.TrimSpace(name) != "" && name != "links" {
				bf, ok := ut.RelationalFields[codegen.Goify(name, true)]

				if ok {
					fields = append(fields, "&"+codegen.Goify(bf.FieldName, false))
				}
			}
		}
	}

	sort.Strings(fields)
	return fields
}
Example #19
0
// SanitizeFieldName is exported for testing purposes
func SanitizeFieldName(name string) string {
	name = codegen.Goify(name, true)
	if strings.HasSuffix(name, "Id") {
		name = strings.TrimSuffix(name, "Id")
		name = name + "ID"
	}

	return name
}
Example #20
0
// generateUserTypes iterates through the user types and generates the data structures and
// marshaling code.
func (g *Generator) generateUserTypes(outdir string, api *design.APIDefinition) error {
	var modelname, filename string
	err := GormaDesign.IterateStores(func(store *RelationalStoreDefinition) error {
		err := store.IterateModels(func(model *RelationalModelDefinition) error {
			modelname = strings.ToLower(codegen.Goify(model.ModelName, false))

			filename = fmt.Sprintf("%s.go", modelname)
			utFile := filepath.Join(outdir, filename)
			err := os.RemoveAll(utFile)
			if err != nil {
				fmt.Println(err)
			}
			utWr, err := NewUserTypesWriter(utFile)
			if err != nil {
				panic(err) // bug
			}
			title := fmt.Sprintf("%s: Models", api.Context())
			imports := []*codegen.ImportSpec{
				codegen.SimpleImport(g.appPkgPath),
				codegen.SimpleImport("time"),
				codegen.SimpleImport("github.com/goadesign/goa"),
				codegen.SimpleImport("github.com/jinzhu/gorm"),
				codegen.SimpleImport("golang.org/x/net/context"),
				codegen.SimpleImport("golang.org/x/net/context"),
				codegen.SimpleImport("github.com/goadesign/goa/uuid"),
			}

			if model.Cached {
				imp := codegen.NewImport("cache", "github.com/patrickmn/go-cache")
				imports = append(imports, imp)
				imp = codegen.SimpleImport("strconv")
				imports = append(imports, imp)
			}
			utWr.WriteHeader(title, g.target, imports)
			data := &UserTypeTemplateData{
				APIDefinition: api,
				UserType:      model,
				DefaultPkg:    g.target,
				AppPkg:        g.appPkgPath,
			}
			err = utWr.Execute(data)
			g.genfiles = append(g.genfiles, utFile)
			if err != nil {
				fmt.Println(err)
				return err
			}
			err = utWr.FormatCode()
			if err != nil {
				fmt.Println(err)
			}
			return err
		})
		return err
	})
	return err
}
Example #21
0
// newCoerceData is a helper function that creates a map that can be given to the "Coerce" template.
func newCoerceData(name string, att *design.AttributeDefinition, pointer bool, pkg string, depth int) map[string]interface{} {
	return map[string]interface{}{
		"Name":      name,
		"VarName":   codegen.Goify(name, false),
		"Pointer":   pointer,
		"Attribute": att,
		"Pkg":       pkg,
		"Depth":     depth,
	}
}
Example #22
0
func attToObject(name string, parent, att *design.AttributeDefinition) *ObjectType {
	obj := &ObjectType{}
	obj.Label = name
	obj.Name = codegen.Goify(name, false)
	obj.Type = codegen.GoTypeRef(att.Type, nil, 0, false)
	if att.Type.IsPrimitive() && parent.IsPrimitivePointer(name) {
		obj.Pointer = "*"
	}
	return obj
}
Example #23
0
// MediaTypeRef produces the JSON reference to the media type definition with the given view.
func MediaTypeRef(api *design.APIDefinition, mt *design.MediaTypeDefinition, view string) string {
	if _, ok := Definitions[mt.TypeName]; !ok {
		GenerateMediaTypeDefinition(api, mt, view)
	}
	ref := fmt.Sprintf("#/definitions/%s", mt.TypeName)
	if view != "default" {
		ref += codegen.Goify(view, true)
	}
	return ref
}
Example #24
0
// PKUpdateFields returns something?  This function doesn't look useful in
// current form.  Perhaps it isn't.
func (f *RelationalModelDefinition) PKUpdateFields(modelname string) string {
	var pkwhere []string
	for _, pk := range f.PrimaryKeys {
		def := fmt.Sprintf("%s.%s", modelname, codegen.Goify(pk.FieldName, true))
		pkwhere = append(pkwhere, def)
	}

	pkw := strings.Join(pkwhere, ",")
	return pkw
}
Example #25
0
// fileServerMethod returns the name of the client method for downloading assets served by the given
// file server.
// Note: the implementation opts for generating good names rather than names that are guaranteed to
// be unique. This means that the generated code could be potentially incorrect in the rare cases
// where it produces the same names for two different file servers. This should be addressed later
// (when it comes up?) using metadata to let users override the default.
func (g *Generator) fileServerMethod(fs *design.FileServerDefinition) string {
	var (
		suffix string

		wcs      = design.ExtractWildcards(fs.RequestPath)
		reqElems = strings.Split(fs.RequestPath, "/")
	)

	if len(wcs) == 0 {
		suffix = path.Base(fs.RequestPath)
		ext := filepath.Ext(suffix)
		suffix = strings.TrimSuffix(suffix, ext)
		suffix += codegen.Goify(ext, true)
	} else {
		if len(reqElems) == 1 {
			suffix = filepath.Base(fs.RequestPath)
			suffix = suffix[1:] // remove "*" prefix
		} else {
			suffix = reqElems[len(reqElems)-2] // should work most of the time
		}
	}
	return "Download" + codegen.Goify(suffix, true)
}
Example #26
0
// joinNames is a code generation helper function that generates a string built from concatenating
// the keys of the given attribute type (assuming it's an object).
func joinNames(att *design.AttributeDefinition) string {
	if att == nil {
		return ""
	}
	obj := att.Type.ToObject()
	names := make([]string, len(obj))
	i := 0
	for n := range obj {
		names[i] = fmt.Sprintf("cmd.%s", codegen.Goify(n, true))
		i++
	}
	sort.Strings(names)
	return strings.Join(names, ", ")
}
Example #27
0
func (g *Generator) okResp(a *design.ActionDefinition) map[string]interface{} {
	var ok *design.ResponseDefinition
	for _, resp := range a.Responses {
		if resp.Status == 200 {
			ok = resp
			break
		}
	}
	if ok == nil {
		return nil
	}
	var mt *design.MediaTypeDefinition
	var ok2 bool
	if mt, ok2 = design.Design.MediaTypes[design.CanonicalIdentifier(ok.MediaType)]; !ok2 {
		return nil
	}
	view := ok.ViewName
	if view == "" {
		view = design.DefaultView
	}
	pmt, _, err := mt.Project(view)
	if err != nil {
		return nil
	}
	var typeref string
	if pmt.IsError() {
		typeref = `goa.ErrInternal("not implemented")`
	} else {
		name := codegen.GoTypeRef(pmt, pmt.AllRequired(), 1, false)
		var pointer string
		if strings.HasPrefix(name, "*") {
			name = name[1:]
			pointer = "*"
		}
		typeref = fmt.Sprintf("%s%s.%s", pointer, g.Target, name)
		if strings.HasPrefix(typeref, "*") {
			typeref = "&" + typeref[1:]
		}
		typeref += "{}"
	}
	var nameSuffix string
	if view != "default" {
		nameSuffix = codegen.Goify(view, true)
	}
	return map[string]interface{}{
		"Name":    ok.Name + nameSuffix,
		"GoType":  codegen.GoNativeType(pmt),
		"TypeRef": typeref,
	}
}
Example #28
0
File: writers.go Project: DavyC/goa
// hasAPIVersion returns true if the given attribute has a child attribute whose goified name is
// "APIVersion". This is used to not generate the built in APIVersion when such a field exists.
func hasAPIVersion(params *design.AttributeDefinition) bool {
	if params == nil {
		return false
	}
	o := params.Type.ToObject()
	if o == nil {
		return false
	}
	for n := range o {
		if codegen.Goify(n, true) == "APIVersion" {
			return true
		}
	}
	return false
}
Example #29
0
func viewSelect(ut *RelationalModelDefinition, v *design.ViewDefinition) string {
	obj := v.Type.(design.Object)
	var fields []string
	for name := range obj {
		if obj[name].Type.IsPrimitive() {
			if strings.TrimSpace(name) != "" && name != "links" {
				bf, ok := ut.RelationalFields[codegen.Goify(name, true)]
				if ok {
					fields = append(fields, bf.DatabaseFieldName)
				}
			}
		}
	}
	sort.Strings(fields)
	return strings.Join(fields, ",")
}
Example #30
0
// generateHrefs iterates through the version resources and generates the href factory methods.
func (g *Generator) generateHrefs(verdir string, version *design.APIVersionDefinition) error {
	hrefFile := filepath.Join(verdir, "hrefs.go")
	resWr, err := NewResourcesWriter(hrefFile)
	if err != nil {
		panic(err) // bug
	}
	title := fmt.Sprintf("%s: Application Resource Href Factories", version.Context())
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport("fmt"),
	}
	resWr.WriteHeader(title, packageName(version), imports)
	err = version.IterateResources(func(r *design.ResourceDefinition) error {
		if !r.SupportsVersion(version.Version) {
			return nil
		}
		m := design.Design.MediaTypeWithIdentifier(r.MediaType)
		var identifier string
		if m != nil {
			identifier = m.Identifier
		} else {
			identifier = "plain/text"
		}
		canoTemplate := r.URITemplate(version)
		canoTemplate = design.WildcardRegex.ReplaceAllLiteralString(canoTemplate, "/%v")
		var canoParams []string
		if ca := r.CanonicalAction(); ca != nil {
			if len(ca.Routes) > 0 {
				canoParams = ca.Routes[0].Params(version)
			}
		}

		data := ResourceData{
			Name:              codegen.Goify(r.Name, true),
			Identifier:        identifier,
			Description:       r.Description,
			Type:              m,
			CanonicalTemplate: canoTemplate,
			CanonicalParams:   canoParams,
		}
		return resWr.Execute(&data)
	})
	g.genfiles = append(g.genfiles, hrefFile)
	if err != nil {
		return err
	}
	return resWr.FormatCode()
}