Add the following changes in their appropriate places into the existing generator definition.
gen/server.cue
Generator: gen.Generator & {// Exposed to the user Datamodel: schema.Datamodel// Added to the template input In: { DM: Datamodel }// include the type files for rendering All: [ for _, F in TypeFiles {F}, ]// Define the files generated from our models TypeFiles: [...gen.File] & [ for _, M in Datamodel.Models { In: { TYPE: {// embed the model fields M// Extend to include the fields in CUE order with a list// This is needed because we want a deterministic order// For example, when defining database columns or caluclating a diff// We don't want to sort, rather we want to maintain the order the user specifies// While CUE has consistent ordering, the internal Go maps do not// the mapping from CUE -> Go -> template rendering can misorder OrderedFields: [ for _, F in M.Fields {F}] } } TemplatePath: "type.go"// We name each file the same as the Model name and Filepath: "\(Outdir)/types/\(In.TYPE.Name).go" }, ]}
Type Template
The following creates
a Go struct for our Model
a Go map for storing instances of the type
several Go functions as helpers for the data store
Create a new template called type.go
templates/type.go
package types
import (
"fmt")
// Represents a {{ .TYPE.Name }}
type {{ .TYPE.Name }} struct {
{{ range .TYPE.OrderedFields }}
{{ .Name }} {{ .Type }}
{{- end }}
}
// A map type to store {{ .TYPE.Name }}
type {{ .TYPE.Name }}Map map[string]*{{ .TYPE.Name }}
// A var to work with
var {{ .TYPE.Name }}Store {{ .TYPE.Name }}Map
// Note, we are omitting locking and allowing concurrency issues
// initialize our storage
funcinit() {
{{ .TYPE.Name }}Store = make({{ .TYPE.Name }}Map)
}
//
//// library funcs
//
func {{ .TYPE.Name }}Create(in *{{ .TYPE.Name }}) error {
idx := in.{{ .TYPE.Index }}
// check if already exists
if _, ok := {{ .TYPE.Name }}Store[idx]; ok {
return fmt.Errorf("Entry with %v already exists", idx)
}
// store the new value
{{ .TYPE.Name }}Store[idx] = in
returnnil}
func {{ .TYPE.Name }}Read(idx string) (*{{ .TYPE.Name }}, error) {
// return if exists
if val, ok := {{ .TYPE.Name }}Store[idx]; ok {
return val, nil }
// otherwise return error
returnnil, fmt.Errorf("Entry with %v does not exist", idx)
}
func {{ .TYPE.Name }}Update(in *{{ .TYPE.Name }}) error {
idx := in.{{ .TYPE.Index }}
// replace if exists, note we are not dealing with partial updates here
if _, ok := {{ .TYPE.Name }}Store[idx]; ok {
{{ .TYPE.Name }}Store[idx] = in
returnnil }
// otherwise return error
return fmt.Errorf("Entry with %v does not exist", idx)
}
func {{ .TYPE.Name }}Delete(idx string) error {
// replace if exists, note we are not dealing with partial updates here
if _, ok := {{ .TYPE.Name }}Store[idx]; ok {
delete({{ .TYPE.Name }}Store, idx)
returnnil }
// otherwise return error
return fmt.Errorf("Entry with %v does not exist", idx)
}
Regenerate the server
You can now run hof gen ./example and you should find a new ./output/types directory.