我的博客

golang mongo-driver 源码阅读 SingleResult.Decode

目录
  1. 主要流程
  2. StructCodec.describeStruct
  3. reflect.Value.Field
  4. reflect.Value.FieldByIndex

主要流程

SingleResult 是 Collection.FindOne 的返回结果的类型。

Collection 的代码在 go.mongodb.org\mongo-driver\mongo\collection.go

FindOne 返回的类型是 SingleResult。

SingleResult 在 go.mongodb.org\mongo-driver\mongo\single_result.go

我们看到 Decode 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Decode will attempt to decode the first document into v. If there was an
// error from the operation that created this SingleResult then the error
// will be returned. If there were no returned documents, ErrNoDocuments is
// returned. If v is nil or is a typed nil, an error will be returned.
func (sr *SingleResult) Decode(v interface{}) error {
if sr.err != nil {
return sr.err
}
if sr.reg == nil {
return bson.ErrNilRegistry
}

if sr.err = sr.setRdrContents(); sr.err != nil {
return sr.err
}
return bson.UnmarshalWithRegistry(sr.reg, sr.rdr, v)
}

再看 bson 的 UnmarshalWithRegistry

go.mongodb.org\mongo-driver\bson\unmarshal.go

1
2
3
4
5
6
7
// UnmarshalWithRegistry parses the BSON-encoded data using Registry r and
// stores the result in the value pointed to by val. If val is nil or not
// a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError.
func UnmarshalWithRegistry(r *bsoncodec.Registry, data []byte, val interface{}) error {
vr := bsonrw.NewBSONDocumentReader(data)
return unmarshalFromReader(bsoncodec.DecodeContext{Registry: r}, vr, val)
}

再看下文的 unmarshalFromReader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func unmarshalFromReader(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val interface{}) error {
dec := decPool.Get().(*Decoder)
defer decPool.Put(dec)

err := dec.Reset(vr)
if err != nil {
return err
}
err = dec.SetContext(dc)
if err != nil {
return err
}

return dec.Decode(val)
}

再看 Decoder.Decode 在 go.mongodb.org\mongo-driver\bson\decoder.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Decode reads the next BSON document from the stream and decodes it into the
// value pointed to by val.
//
// The documentation for Unmarshal contains details about of BSON into a Go
// value.
func (d *Decoder) Decode(val interface{}) error {
if unmarshaler, ok := val.(Unmarshaler); ok {
// TODO(skriptble): Reuse a []byte here and use the AppendDocumentBytes method.
buf, err := bsonrw.Copier{}.CopyDocumentToBytes(d.vr)
if err != nil {
return err
}
return unmarshaler.UnmarshalBSON(buf)
}

rval := reflect.ValueOf(val)
if rval.Kind() != reflect.Ptr {
return fmt.Errorf("argument to Decode must be a pointer to a type, but got %v", rval)
}
if rval.IsNil() {
return ErrDecodeToNil
}
rval = rval.Elem()
decoder, err := d.dc.LookupDecoder(rval.Type())
if err != nil {
return err
}
return decoder.DecodeValue(d.dc, d.vr, rval)
}

再看 ValueDecoder.DecodeValue 声明在

go.mongodb.org\mongo-driver\bson\bsoncodec\bsoncodec.go

我们这里的参数是 struct ,执行的是

go.mongodb.org\mongo-driver\bson\bsoncodec\struct_codec.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// DecodeValue implements the Codec interface.
// By default, map types in val will not be cleared. If a map has existing key/value pairs, it will be extended with the new ones from vr.
// For slices, the decoder will set the length of the slice to zero and append all elements. The underlying array will not be cleared.
func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Kind() != reflect.Struct {
return ValueDecoderError{Name: "StructCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val}
}

switch vr.Type() {
case bsontype.Type(0), bsontype.EmbeddedDocument:
default:
return fmt.Errorf("cannot decode %v into a %s", vr.Type(), val.Type())
}

sd, err := sc.describeStruct(r.Registry, val.Type())
if err != nil {
return err
}

var decoder ValueDecoder
var inlineMap reflect.Value
if sd.inlineMap >= 0 {
inlineMap = val.Field(sd.inlineMap)
if inlineMap.IsNil() {
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
}
decoder, err = r.LookupDecoder(inlineMap.Type().Elem())
if err != nil {
return err
}
}

dr, err := vr.ReadDocument()
if err != nil {
return err
}

for {
name, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD {
break
}
if err != nil {
return err
}

fd, exists := sd.fm[name]
if !exists {
if sd.inlineMap < 0 {
// The encoding/json package requires a flag to return on error for non-existent fields.
// This functionality seems appropriate for the struct codec.
err = vr.Skip()
if err != nil {
return err
}
continue
}

elem := reflect.New(inlineMap.Type().Elem()).Elem()
err = decoder.DecodeValue(r, vr, elem)
if err != nil {
return err
}
inlineMap.SetMapIndex(reflect.ValueOf(name), elem)
continue
}

var field reflect.Value
if fd.inline == nil {
field = val.Field(fd.idx)
} else {
field = val.FieldByIndex(fd.inline)
}

if !field.CanSet() { // Being settable is a super set of being addressable.
return fmt.Errorf("cannot decode element '%s' into field %v; it is not settable", name, field)
}
if field.Kind() == reflect.Ptr && field.IsNil() {
field.Set(reflect.New(field.Type().Elem()))
}
field = field.Addr()

dctx := DecodeContext{Registry: r.Registry, Truncate: fd.truncate}
if fd.decoder == nil {
return ErrNoDecoder{Type: field.Elem().Type()}
}

if decoder, ok := fd.decoder.(ValueDecoder); ok {
err = decoder.DecodeValue(dctx, vr, field.Elem())
if err != nil {
return err
}
continue
}
err = fd.decoder.DecodeValue(dctx, vr, field)
if err != nil {
return err
}
}

return nil
}

这次这个比较长,但是终于到此为止了。

把查询到的数据赋给我们的变量的过程在 38 行的 for 循环中进行。

39 行,读取一对键值;40 行,如果没取到(已读完所有数据),则退出;
47 - 66 行,判断读取到的值在我们传入的结构体中是否存在,如果不存在则 continue;

StructCodec.describeStruct

(待读)

reflect.Value.Field

Go\src\reflect\value.go

reflect.Value.FieldByIndex

Go\src\reflect\value.go

评论无需登录,可以匿名,欢迎评论!