Suppose you have a workflow that consists of multiple embedded nodes of different types. Since nodes are of different types, I thought of using Golang interfaces here and ca
Following Simon Fox's answer regarding the implementation of SetBSON, here is a more precise answer.
Let's take the original piece of code:
type Workflow struct {
CreatedAt time.Time
StartedAt time.Time
CreatedBy string
Nodes []Node
}
type Node interface {
Exec() (int, error)
}
type EmailNode struct {
From string
To string
Subject string
Body string
}
type TwitterNode struct {
Tweet string
Image []byte
}
func (n *EmailNode) Exec() (int, error){
//send email
return 0, nil
}
func (n *TwitterNode) Exec() (int, error) {
//send tweet
return 0, nil
}
What you want to do now is: once you unmarshal the BSON object from Mongo, you want to be able to know if each node is either an EmailNode or a TwitterNode.
As you are storing the nodes as a Node interface, mgo has no way to know what struct to implement, so you have to tell it explicitly. Here comes SetBSON.
In your example, the problem comes from this Workflow.Nodes, which is a slice of Node interface. As it is a simple slice, the best is that you create a custom type that mgo will be able to call when unmarshalling the BSON:
type NodesList []Node
// The updated Workflow struct:
type Workflow struct {
CreatedAt time.Time
StartedAt time.Time
CreatedBy string
Nodes NodesList
}
Now, you can implement SetBSON on this NodesList and describe how it works. Please note that as you are using a pointer, you can define what is contained inside the variable:
// Note that you must use a pointer to the slice
func (list *NodesList) SetBSON(raw raw.BSON) error {
// Now you need to create the objects according to your
// own domain logic and what's contained inside "raw":
if raw.something {
*list = append(*list, &TwitterNode{})
} else {
*list = append(*list, &EmailNode{})
}
return nil
}