I'm experimenting with Go to see if I can move over my current project to it. I have several domain models in my current, non-go codebase, that utilize polymorphism based off of a type field.
There isn't a whole lot of documentation or literature on the subject and my day or so of learning go has made traversing and grawking thier source a bit... well, here I am.
Anyway...
Here are examples of a basic interface & implementing structs:
package model
type Filter interface {
SetType(t enum.FilterType)
}
type Base struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
Type enum.FilterType `json:"type,omitempty" bson:"type,omitempty"`
}
func (bf *Base) SetType(t enum.FilterType) {
bf.Type = t
}
type ExampleA struct {
Base `bson:"inline"`
AField string `bson:"aField,omitempty" json:"aField,omitempty"`
}
type ExampleB struct {
Base `bson:"inline"`
BField string `bson:"bField,omitempty" json:"bField,omitempty"`
}
which will have numerous struct implementations so I need to be able to perform a switch based on a field type in the bson.Raw before I can determine which struct to utilize.
So far as I can tell, RegisterHookDecoder [docs] [source] is exactly what I need. However, I can't get it to actually fire off and I'm not sure why.
decoder:
type filterDecoder struct {}
func (d filterDecoder) DecodeValue(ctx bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
fmt.Println("Inside DecodeValue")
return nil
}
package main
func main() {
ctx := context.TODO()
// I'm not sure this is right. I'm trying to get the type of model.Filter so that I can register the HookDecoder against it.
filterType := reflect.TypeOf((*model.Filter)(nil)).Elem()
rb := bsoncodec.NewRegistryBuilder()
rb.RegisterHookDecoder(filterType, filterDecoder{})
// so far as I can tell, these are required. Otherwise I get the error:
// "cannot transform type primitive.D to a BSON Document: no encoder found for primitive.D"
// I haven't seen this approach implemented anywhere aside from the source.
// I'm not sure if this is overriding my hook? changing the order to have
// rb.RegisterHookDecoder(...) below/above these does not have an impact.
bsoncodec.DefaultValueDecoders{}.RegisterDefaultDecoders(rb)
bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb)
client, err := mongo.Connect(ctx,
options.Client().
ApplyURI("mongodb://localhost:27017").
SetRegistry(rb.Build()),
)
col := client.Database("LearningGo").Collection("filters")
cursor, err := col.Find(ctx, bson.M{})
if err != nil {
panic(err)
}
for cursor.Next(ctx) {
var filter model.Filter
cursor.Decode(filter)
}
}
I'm really not sure what I'm missing here. Did I goof up on something obvious?
LookupDecoder(filterType) actually finds a ValueDecoderFunc based on the code below. I'm just not sure if that's a catchall or not. I don't know anywhere near enough about Go to assert more than that.
vd,err := newRegistry.LookupDecoder(filterType)
fmt.Println(reflect.TypeOf(vd).Name())
I appreciate you for reading through this regardless. Thank you for your time.
**edit: Updated to reflect changes suggested by @icza