In a db
package, I don't want to expose MongoDB's primitive.ObjectID
type as part of its public API. Instead, I want to define type Id interface{}
within the db
package and expose that. Since the driver doesn't know how to transform the database's ObjectID type into my custom ID type, I registered a type decoder like so:
type Id interface{}
var idType = reflect.TypeOf((*Id)(nil)).Elem()
type User struct {
Id `bson:"_id,omitempty"`
}
func main() {
reg := bson.NewRegistryBuilder().
RegisterTypeDecoder(idType, bsoncodec.ValueDecoderFunc(idDecodeValue)).
Build()
client, err := mongo.Connect(context.TODO(), options.Client().
ApplyURI("...").
SetRegistry(reg))
coll := client.Database("...").Collection("...")
var u0 User
coll.InsertOne(context.TODO(), u0)
var u1 User
coll.FindOne(context.TODO(), bson.D{}).Decode(&u1)
}
func idDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || val.Type() != idType {
return bsoncodec.ValueDecoderError{
Name: "IdDecodeValue",
Types: []reflect.Type{idType},
Received: val,
}
}
oid, _ := vr.ReadObjectID()
val.Set(reflect.ValueOf(oid))
return nil
}
I saw that there exists a bsoncodec.NewEmptyInterfaceCodec()
to use in place of idDecodeValue
, but that only seems to work when User.Id
's type is exactly interface{}
. I wrote idDecodeValue
based off of the existing codecs, but I'm not entirely sure what's going on (mostly due to not knowing when val.IsValid()
would ever return false). Is all of this the best, most idiomatic way to go about supporting a custom ID type?