Reputation:
I'm having difficulties understanding go generate
. I also find barely any posts dealing with go generate
.
please explain go generate
in this following example:
package main
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// --- Address
type Address struct {
Id bson.ObjectId `bson:"_id,omitempty"`
AccountId string `bson:"account_id"`
Name string `bson:"name"`
StreetAddress string `bson:"streetaddress"`
Town string `bson:"town"`
Country string `bson:"country"`
}
// --- AddressHandler
type AddressHandler struct {
MS *mgo.Session
}
func NewAddressHandler(ms *mgo.Session) *AddressHandler {
return &AddressHandler{MS: ms.Clone()}
}
func (h *AddressHandler) Close() {
h.MS.Close()
}
// Add
type AddAddressInput struct {
Address *Address
}
type AddAddressOutput struct {
Error error
}
func (h *AddressHandler) AddAddress(in *AddAddressInput, out *AddAddressOutput) {
ms := h.MS.Copy()
defer ms.Close()
c := ms.DB("").C("address")
out.Error = c.Insert(in.Address)
}
// Remove
type RemoveAddressInput struct {
AddressId string
}
type RemoveAddressOutput struct {
Error error
}
func (h *AddressHandler) RemoveAddress(in *RemoveAddressInput, out *RemoveAddressOutput) {
ms := h.MS.Copy()
defer ms.Close()
c := ms.DB("").C("address")
out.Error = c.RemoveId(bson.ObjectIdHex(in.AddressId))
}
// Update
type UpdateAddressInput struct {
Address *Address
}
type UpdateAddressOutput struct {
Error error
}
func (h *AddressHandler) UpdateAddress(in *UpdateAddressInput, out *UpdateAddressOutput) {
ms := h.MS.Copy()
defer ms.Close()
c := ms.DB("").C("address")
out.Error = c.UpdateId(in.Address.AccountId)
}
// GetAllByAccount
type GetAddressInput struct {
AccountId string
}
type GetAddressOutput struct {
Address []*Address
Error error
}
func (h *AddressHandler) GetAddress(in *GetAddressInput, out *GetAddressOutput) {
ms := h.MS.Copy()
defer ms.Close()
c := ms.DB("").C("address")
out.Error = c.Find(bson.ObjectIdHex(in.AccountId)).All(&out.Address)
}
I would like to create almost carbon copies of this not yet template code.
the "template" code:
package main
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// --- Address
type %Model% struct {
Id bson.ObjectId `bson:"_id,omitempty"`
}
// --- %Model%Handler
type %Model%Handler struct {
MS *mgo.Session
}
func New%Model%Handler(ms *mgo.Session) *%Model%Handler {
return &%Model%Handler{MS: ms.Clone()}
}
func (h *%Model%Handler) Close() {
h.MS.Close()
}
// Add
type Add%Model%Input struct {
%Model% *%Model%
}
type Add%Model%Output struct {
Error error
}
func (h *%Model%Handler) Add%Model%(in *Add%Model%Input, out *Add%Model%Output) {
ms := h.MS.Copy()
defer ms.Close()
c := ms.DB("").C("%Model%")
out.Error = c.Insert(in.%Model%)
}
// Remove %Model%
type Remove%Model%Input struct {
%Model%Id string
}
type Remove%Model%Output struct {
Error error
}
func (h *%Model%Handler) Remove%Model%(in *Remove%Model%Input, out *Remove%Model%Output) {
ms := h.MS.Copy()
defer ms.Close()
c := ms.DB("").C("%Model%")
out.Error = c.RemoveId(bson.ObjectIdHex(in.%Model%Id))
}
// Update
type Update%Model%Input struct {
%Model% *%Model%
}
type Update%Model%Output struct {
Error error
}
func (h *%Model%Handler) Update%Model%(in *Update%Model%Input, out *Update%Model%Output) {
ms := h.MS.Copy()
defer ms.Close()
c := ms.DB("").C("%Model%")
out.Error = c.UpdateId(in.%Model%.AccountId)
}
// GetAllByAccount
type Get%Model%Input struct {
AccountId string
}
type Get%Model%Output struct {
%Model% []*%Model%
Error error
}
func (h *%Model%Handler) Get%Model%(in *Get%Model%Input, out *Get%Model%Output) {
ms := h.MS.Copy()
defer ms.Close()
c := ms.DB("").C("%Model%")
out.Error = c.Find(bson.ObjectIdHex(in.AccountId)).All(&out.%Model%)
}
What do I need to add or change so I can go generate
output from this supposed template. As you can see everything Address
is replaced with %Model%
.
Upvotes: 11
Views: 13283
Reputation: 12273
I am not expert with go generate, but AFAIK, go generate is called to perform commands specified in buildable go files, normally with the intent to produce something new.
Generate scans for files searching for a specific directive: //go:generate
and, if found, it will execute the command following it.
To understand better what's happening, let's make a simple example: a template go file will have a string to be replaced.
Let's make a command that replace the template string, NAME
, with another string, AkiRoss
:
#!/usr/bin/sh
sed "s/NAME/AkiRoss/g" $1 > $2
Here follows the go template, note the directive:
package main
import "fmt"
//go:generate ./repl.sh $GOFILE aki_$GOFILE
func main() {
fmt.Println("Hello,", NAME)
}
Both files are in the same directory, for convenience, and repl.sh is executable. If I run go generate
in the directory, the go tool will call repl.sh templ.go aki_templ.go
, being $GOFILE
expanded to be the name of the file processed by generate.
Here's what I get:
package main
import "fmt"
//go:generate ./repl.sh $GOFILE aki_$GOFILE
func main() {
fmt.Println("Hello,", AkiRoss)
}
Regarding your example, you will need to place the //go:generate
directive somewhere. It is likely, however, that the directive will be included in a different file, not the template file, that calls a replacement script, similar to the one I made, to produce a file which is needed for building.
Let me explain this better by changing my example:
#!/usr/bin/sh
sed "s/%NAME%/$3/g" $1 > $2
// This is a template for a go file
package main
import "fmt"
type %NAME% struct {
foo string
bar int
}
func (self *%NAME%) Perform() {
fmt.Println(self.foo, self.bar)
}
package main
import "fmt"
//go:generate ./repl.sh templ.txt foobar.go FooBar
func main() {
var fb = FooBar{"AkiRoss", -1}
fmt.Println("Running!")
fb.Perform()
}
Running go generate
will produce a new file
// This is a template for a go file
package main
import "fmt"
type FooBar struct {
foo string
bar int
}
func (self *FooBar) Perform() {
fmt.Println(self.foo, self.bar)
}
which allows now to compile correctly the main:
$ go build
$ ./program
Running!
AkiRoss -1
I hope this clarified.
More details here, and a better example is here.
Upvotes: 18