1

我正在尝试使用 Go 来查看是否可以将当前项目转移到它。我当前的非 Go 代码库中有几个域模型,它们利用基于类型字段的多态性。

关于该主题的文档或文献并不多,而我一天左右的学习时间使遍历和研究其来源有点……好吧,我来了。

反正...

以下是基本接口和实现结构的示例:

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"`
}

它将有许多结构实现,因此我需要能够基于字段type中的字段执行切换,bson.Raw然后才能确定struct要使用哪个。

据我所知,RegisterHookDecoder[ docs ] [ source ] 正是我所需要的。但是,我无法让它真正启动,我不知道为什么。

解码器:

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)
    }
}

我真的不确定我在这里缺少什么。我在明显的事情上犯错了吗?

LookupDecoder(filterType)ValueDecoderFunc实际上根据下面的代码找到了一个。我只是不确定这是否是一个包罗万象的东西。我对 Go 的了解还远远不够,无法断言更多。

    vd,err := newRegistry.LookupDecoder(filterType)
    fmt.Println(reflect.TypeOf(vd).Name())

无论如何,我感谢您阅读本文。感谢您的时间。

**编辑:更新以反映@icza 建议的更改

4

0 回答 0