1 Star 0 Fork 0

青文杰/mongo-go-driver

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
encode.go 19.98 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package bson
import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"net/url"
"reflect"
"strconv"
"strings"
"time"
"github.com/mongodb/mongo-go-driver/bson/decimal"
"github.com/mongodb/mongo-go-driver/bson/objectid"
)
// ErrEncoderNilWriter indicates that encoder.Encode was called with a nil argument.
var ErrEncoderNilWriter = errors.New("encoder.Encode called on Encoder with nil io.Writer")
var tByteSlice = reflect.TypeOf(([]byte)(nil))
var tByte = reflect.TypeOf(byte(0x00))
var tElement = reflect.TypeOf((*Element)(nil))
var tURL = reflect.TypeOf(url.URL{})
var tJSONNumber = reflect.TypeOf(json.Number(""))
// Marshaler describes a type that can marshal a BSON representation of itself into bytes.
type Marshaler interface {
MarshalBSON() ([]byte, error)
}
// DocumentMarshaler describes a type that can marshal itself into a bson.Document.
type DocumentMarshaler interface {
MarshalBSONDocument() (*Document, error)
}
// ElementMarshaler describes a type that can marshal itself into a bson.Element.
type ElementMarshaler interface {
MarshalBSONElement() (*Element, error)
}
// ValueMarshaler describes a type that can marshal itself into a bson.Value.
type ValueMarshaler interface {
MarshalBSONValue() (*Value, error)
}
// Encoder describes a type that can encode itself into a value.
type Encoder interface {
// Encode encodes a value from an io.Writer into the given value.
//
// The value can be any one of the following types:
//
// - bson.Marshaler
// - io.Reader
// - []byte
// - bson.Reader
// - any map with string keys
// - a struct (possibly with tags)
//
// In the case of a struct, the lowercased field name is used as the key for each exported
// field but this behavior may be changed using a struct tag. The tag may also contain flags to
// adjust the marshalling behavior for the field. The tag formats accepted are:
//
// "[<key>][,<flag1>[,<flag2>]]"
//
// `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
//
// The following flags are currently supported:
//
// omitempty Only include the field if it's not set to the zero value for the type or to
// empty slices or maps.
//
// minsize Marshal an integer of a type larger than 32 bits value as an int32, if that's
// feasible while preserving the numeric value.
//
// inline Inline the field, which must be a struct or a map, causing all of its fields
// or keys to be processed as if they were part of the outer struct.
//
// An example:
//
// type T struct {
// A bool
// B int "myb"
// C string "myc,omitempty"
// D string `bson:",omitempty" json:"jsonkey"`
// E int64 ",minsize"
// F int64 "myf,omitempty,minsize"
// }
Encode(interface{}) error
}
// DocumentEncoder describes a type that can marshal itself into a value and return the bson.Document it represents.
type DocumentEncoder interface {
EncodeDocument(interface{}) (*Document, error)
}
// Zeroer allows custom struct types to implement a report of zero
// state. All struct types that don't implement Zeroer or where IsZero
// returns false are considered to be not zero.
type Zeroer interface {
IsZero() bool
}
type encoder struct {
w io.Writer
}
// NewEncoder creates an encoder that writes to w.
func NewEncoder(w io.Writer) Encoder {
return &encoder{w: w}
}
// NewDocumentEncoder creates an encoder that encodes into a *Document.
func NewDocumentEncoder() DocumentEncoder {
return &encoder{}
}
func (e *encoder) Encode(v interface{}) error {
var err error
if e.w == nil {
return ErrEncoderNilWriter
}
switch t := v.(type) {
case Marshaler:
var b []byte
b, err = t.MarshalBSON()
if err != nil {
return err
}
_, err = Reader(b).Validate()
if err != nil {
return err
}
_, err = e.w.Write(b)
return err
case io.Reader:
var r Reader
r, err = NewFromIOReader(t)
if err != nil {
return err
}
_, err = r.Validate()
if err != nil {
return err
}
_, err = e.w.Write(r)
case []byte:
_, err = Reader(t).Validate()
if err != nil {
return err
}
_, err = e.w.Write(t)
case Reader:
_, err = t.Validate()
if err != nil {
return err
}
_, err = e.w.Write(t)
default:
var elems []*Element
rval := reflect.ValueOf(v)
elems, err = e.reflectEncode(rval)
if err != nil {
return err
}
_, err = NewDocument(elems...).WriteTo(e.w)
}
return err
}
// EncodeDocument encodes a value from an io.Writer into the given value and returns the document
// it represents.
//
// EncodeDocument accepts the same types as Encoder.Encode.
func (e *encoder) EncodeDocument(v interface{}) (*Document, error) {
var err error
d := NewDocument()
switch t := v.(type) {
case *Document:
err = d.Concat(t)
case Marshaler:
var b []byte
b, err = t.MarshalBSON()
if err != nil {
return nil, err
}
_, err = Reader(b).Validate()
if err != nil {
return nil, err
}
err = d.Concat(b)
case io.Reader:
var r Reader
r, err = NewFromIOReader(t)
if err != nil {
return nil, err
}
_, err = r.Validate()
if err != nil {
return nil, err
}
err = d.Concat(r)
case []byte:
_, err = Reader(t).Validate()
if err != nil {
return nil, err
}
err = d.Concat(t)
case Reader:
_, err = t.Validate()
if err != nil {
return nil, err
}
err = d.Concat(t)
default:
var elems []*Element
rval := reflect.ValueOf(v)
elems, err = e.reflectEncode(rval)
if err != nil {
return nil, err
}
d.Append(elems...)
}
if err != nil {
return nil, err
}
return d, nil
}
// underlyingVal will unwrap the given reflect.Value until it is not a pointer
// nor an interface.
func (e *encoder) underlyingVal(val reflect.Value) reflect.Value {
if val.Kind() != reflect.Ptr && val.Kind() != reflect.Interface {
return val
}
if val.IsNil() {
return val
}
return e.underlyingVal(val.Elem())
}
func (e *encoder) reflectEncode(val reflect.Value) ([]*Element, error) {
val = e.underlyingVal(val)
var elems []*Element
var err error
switch val.Kind() {
case reflect.Map:
elems, err = e.encodeMap(val)
case reflect.Slice, reflect.Array:
elems, err = e.encodeSlice(val)
case reflect.Struct:
elems, err = e.encodeStruct(val)
default:
err = fmt.Errorf("Cannot encode type %s as a BSON Document", val.Type())
}
if err != nil {
return nil, err
}
return elems, nil
}
func (e *encoder) encodeMap(val reflect.Value) ([]*Element, error) {
mapkeys := val.MapKeys()
elems := make([]*Element, 0, val.Len())
for _, rkey := range mapkeys {
orig := rkey
rkey = e.underlyingVal(rkey)
var key string
switch rkey.Kind() {
case reflect.Bool:
key = strconv.FormatBool(rkey.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
key = strconv.FormatInt(rkey.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
key = strconv.FormatUint(rkey.Uint(), 10)
case reflect.Float32:
key = strconv.FormatFloat(rkey.Float(), 'g', -1, 32)
case reflect.Float64:
key = strconv.FormatFloat(rkey.Float(), 'g', -1, 64)
case reflect.Complex64, reflect.Complex128:
key = fmt.Sprintf("%g", rkey.Complex())
case reflect.String:
key = rkey.String()
default:
switch rkey.Type() {
case tOID:
key = fmt.Sprintf("%s", rkey.Interface())
case tURL:
rkey = orig
key = fmt.Sprintf("%s", rkey.Interface())
case tDecimal:
key = fmt.Sprintf("%s", rkey.Interface())
default:
return nil, fmt.Errorf("Unsupported map key type %s", rkey.Kind())
}
}
rval := val.MapIndex(rkey)
switch t := rval.Interface().(type) {
case *Element:
elems = append(elems, t)
continue
case *Document:
elems = append(elems, EC.SubDocument(key, t))
continue
case Reader:
elems = append(elems, EC.SubDocumentFromReader(key, t))
continue
case json.Number:
// We try to do an int first
if i64, err := t.Int64(); err == nil {
elems = append(elems, EC.Int64(key, i64))
continue
}
f64, err := t.Float64()
if err != nil {
return nil, fmt.Errorf("Invalid json.Number used as map value: %s", err)
}
elems = append(elems, EC.Double(key, f64))
continue
case *url.URL:
elems = append(elems, EC.String(key, t.String()))
continue
case decimal.Decimal128:
elems = append(elems, EC.Decimal128(key, t))
continue
}
rval = e.underlyingVal(rval)
elem, err := e.elemFromValue(key, rval, false)
if err != nil {
return nil, err
}
elems = append(elems, elem)
}
return elems, nil
}
func (e *encoder) encodeSlice(val reflect.Value) ([]*Element, error) {
elems := make([]*Element, 0, val.Len())
for i := 0; i < val.Len(); i++ {
sval := val.Index(i)
key := strconv.Itoa(i)
switch t := sval.Interface().(type) {
case *Element:
elems = append(elems, t)
continue
case *Document:
elems = append(elems, EC.SubDocument(key, t))
continue
case Reader:
elems = append(elems, EC.SubDocumentFromReader(key, t))
continue
case json.Number:
// We try to do an int first
if i64, err := t.Int64(); err == nil {
elems = append(elems, EC.Int64(key, i64))
continue
}
f64, err := t.Float64()
if err != nil {
return nil, fmt.Errorf("Invalid json.Number used as map value: %s", err)
}
elems = append(elems, EC.Double(key, f64))
continue
case *url.URL:
elems = append(elems, EC.String(key, t.String()))
continue
case decimal.Decimal128:
elems = append(elems, EC.Decimal128(key, t))
continue
}
sval = e.underlyingVal(sval)
elem, err := e.elemFromValue(key, sval, false)
if err != nil {
return nil, err
}
elems = append(elems, elem)
}
return elems, nil
}
func (e *encoder) encodeSliceAsArray(rval reflect.Value, minsize bool) ([]*Value, error) {
vals := make([]*Value, 0, rval.Len())
for i := 0; i < rval.Len(); i++ {
sval := rval.Index(i)
switch t := sval.Interface().(type) {
case *Element:
vals = append(vals, t.value)
continue
case *Value:
vals = append(vals, t)
continue
case *Document:
vals = append(vals, VC.Document(t))
continue
case Reader:
vals = append(vals, VC.DocumentFromReader(t))
continue
case json.Number:
// We try to do an int first
if i64, err := t.Int64(); err == nil {
vals = append(vals, VC.Int64(i64))
continue
}
f64, err := t.Float64()
if err != nil {
return nil, fmt.Errorf("Invalid json.Number used as map value: %s", err)
}
vals = append(vals, VC.Double(f64))
continue
case *url.URL:
vals = append(vals, VC.String(t.String()))
continue
case decimal.Decimal128:
vals = append(vals, VC.Decimal128(t))
continue
case time.Time:
vals = append(vals, VC.DateTime(t.Unix()*1000+int64(t.Nanosecond()/1e6)))
continue
}
sval = e.underlyingVal(sval)
val, err := e.valueFromValue(sval, minsize)
if err != nil {
return nil, err
}
vals = append(vals, val)
}
return vals, nil
}
func (e *encoder) encodeStruct(val reflect.Value) ([]*Element, error) {
elems := make([]*Element, 0, val.NumField())
sType := val.Type()
for i := 0; i < val.NumField(); i++ {
sf := sType.Field(i)
if sf.PkgPath != "" {
continue
}
key := strings.ToLower(sf.Name)
tag, ok := sf.Tag.Lookup("bson")
var omitempty, minsize, inline = false, false, false
switch {
case ok:
if tag == "-" {
continue
}
for idx, str := range strings.Split(tag, ",") {
if idx == 0 && str != "" {
key = str
}
switch str {
case "omitempty":
omitempty = true
case "minsize":
minsize = true
case "inline":
inline = true
}
}
case !ok && !strings.Contains(string(sf.Tag), ":") && len(sf.Tag) > 0:
key = string(sf.Tag)
}
field := val.Field(i)
if omitempty && e.isZero(field) {
continue
}
switch t := field.Interface().(type) {
case *Element:
elems = append(elems, t)
continue
case *Document:
elems = append(elems, EC.SubDocument(key, t))
continue
case Reader:
elems = append(elems, EC.SubDocumentFromReader(key, t))
continue
case json.Number:
// We try to do an int first
if i64, err := t.Int64(); err == nil {
elems = append(elems, EC.Int64(key, i64))
continue
}
f64, err := t.Float64()
if err != nil {
return nil, fmt.Errorf("Invalid json.Number used as map value: %s", err)
}
elems = append(elems, EC.Double(key, f64))
continue
case *url.URL:
elems = append(elems, EC.String(key, t.String()))
continue
case decimal.Decimal128:
elems = append(elems, EC.Decimal128(key, t))
continue
case time.Time:
elems = append(elems, EC.DateTime(key, t.Unix()*1000+int64(t.Nanosecond()/1e6)))
continue
}
field = e.underlyingVal(field)
if inline {
switch sf.Type.Kind() {
case reflect.Map:
melems, err := e.encodeMap(field)
if err != nil {
return nil, err
}
elems = append(elems, melems...)
continue
case reflect.Struct:
selems, err := e.encodeStruct(field)
if err != nil {
return nil, err
}
elems = append(elems, selems...)
continue
default:
return nil, errors.New("inline is only supported for map and struct types")
}
}
elem, err := e.elemFromValue(key, field, minsize)
if err != nil {
return nil, err
}
elems = append(elems, elem)
}
return elems, nil
}
func (e *encoder) isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
case reflect.Struct:
if z, ok := v.Interface().(Zeroer); ok {
return z.IsZero()
}
return false
}
return false
}
func (e *encoder) elemFromValue(key string, val reflect.Value, minsize bool) (*Element, error) {
var elem *Element
switch val.Kind() {
case reflect.Interface, reflect.Ptr:
if !val.IsNil() {
return nil, errors.New("Values must be unwrapped when calling elemFromValue, try calling underlyingVal first")
}
elem = EC.Null(key)
case reflect.Bool:
elem = EC.Boolean(key, val.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32:
elem = EC.Int32(key, int32(val.Int()))
case reflect.Int, reflect.Int64:
i := val.Int()
if minsize && i < math.MaxInt32 {
elem = EC.Int32(key, int32(val.Int()))
break
}
elem = EC.Int64(key, val.Int())
case reflect.Uint8, reflect.Uint16:
i := val.Uint()
elem = EC.Int32(key, int32(i))
case reflect.Uint, reflect.Uint32, reflect.Uint64:
i := val.Uint()
switch {
case i < math.MaxInt32 && minsize:
elem = EC.Int32(key, int32(i))
case i < math.MaxInt64:
elem = EC.Int64(key, int64(i))
default:
return nil, fmt.Errorf("BSON only has signed integer types and %d overflows an int64", i)
}
case reflect.Float32, reflect.Float64:
elem = EC.Double(key, val.Float())
case reflect.String:
elem = EC.String(key, val.String())
case reflect.Map:
// We specifically check if the value is nil so we can properly round trip.
// If we didn't do this, we couldn't differentiate between an empty map, which should
// be a document, and a nil map, which should be null. In Go, there is a difference
// between the empty value and nil, we should preserve that.
if val.IsNil() {
elem = EC.Null(key)
break
}
mapElems, err := e.encodeMap(val)
if err != nil {
return nil, err
}
elem = EC.SubDocumentFromElements(key, mapElems...)
case reflect.Slice:
// We specifically check if the value is nil so we can properly round trip.
// If we didn't do this, we couldn't differentiate between an empty slice, which should
// be an array, and a nil slice, which should be null. In Go, there is a difference
// between the empty value and nil, we should preserve that.
if val.IsNil() {
elem = EC.Null(key)
break
}
if val.Type() == tByteSlice {
elem = EC.Binary(key, val.Slice(0, val.Len()).Interface().([]byte))
break
}
sliceElems, err := e.encodeSliceAsArray(val, minsize)
if err != nil {
return nil, err
}
elem = EC.ArrayFromElements(key, sliceElems...)
case reflect.Array:
switch {
case val.Type() == tOID:
elem = EC.ObjectID(key, val.Interface().(objectid.ObjectID))
case val.Type().Elem() == tByte:
b := make([]byte, val.Len())
for i := 0; i < val.Len(); i++ {
b[i] = byte(val.Index(i).Uint())
}
elem = EC.Binary(key, b)
default:
arrayElems, err := e.encodeSliceAsArray(val, minsize)
if err != nil {
return nil, err
}
elem = EC.ArrayFromElements(key, arrayElems...)
}
case reflect.Struct:
structElems, err := e.encodeStruct(val)
if err != nil {
return nil, err
}
elem = EC.SubDocumentFromElements(key, structElems...)
default:
return nil, fmt.Errorf("Unsupported value type %s", val.Kind())
}
return elem, nil
}
func (e *encoder) valueFromValue(val reflect.Value, minsize bool) (*Value, error) {
var elem *Value
switch val.Kind() {
case reflect.Interface, reflect.Ptr:
if !val.IsNil() {
return nil, errors.New("Values must be unwrapped when calling elemFromValue, try calling underlyingVal first")
}
elem = VC.Null()
case reflect.Bool:
elem = VC.Boolean(val.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32:
elem = VC.Int32(int32(val.Int()))
case reflect.Int, reflect.Int64:
i := val.Int()
if minsize && i < math.MaxInt32 {
elem = VC.Int32(int32(val.Int()))
break
}
elem = VC.Int64(val.Int())
case reflect.Uint8, reflect.Uint16:
i := val.Uint()
elem = VC.Int32(int32(i))
case reflect.Uint, reflect.Uint32, reflect.Uint64:
i := val.Uint()
switch {
case i < math.MaxInt32 && minsize:
elem = VC.Int32(int32(i))
case i < math.MaxInt64:
elem = VC.Int64(int64(i))
default:
return nil, fmt.Errorf("BSON only has signed integer types and %d overflows an int64", i)
}
case reflect.Float32, reflect.Float64:
elem = VC.Double(val.Float())
case reflect.String:
elem = VC.String(val.String())
case reflect.Map:
// We specifically check if the value is nil so we can properly round trip.
// If we didn't do this, we couldn't differentiate between an empty map, which should
// be a document, and a nil map, which should be null. In Go, there is a difference
// between the empty value and nil, we should preserve that.
if val.IsNil() {
elem = VC.Null()
break
}
mapElems, err := e.encodeMap(val)
if err != nil {
return nil, err
}
elem = VC.DocumentFromElements(mapElems...)
case reflect.Slice:
// We specifically check if the value is nil so we can properly round trip.
// If we didn't do this, we couldn't differentiate between an empty slice, which should
// be an array, and a nil slice, which should be null. In Go, there is a difference
// between the empty value and nil, we should preserve that.
if val.IsNil() {
elem = VC.Null()
break
}
if val.Type() == tByteSlice {
elem = VC.Binary(val.Slice(0, val.Len()).Interface().([]byte))
break
}
sliceElems, err := e.encodeSliceAsArray(val, minsize)
if err != nil {
return nil, err
}
elem = VC.ArrayFromValues(sliceElems...)
case reflect.Array:
switch {
case val.Type() == tOID:
elem = VC.ObjectID(val.Interface().(objectid.ObjectID))
case val.Type().Elem() == tByte:
b := make([]byte, val.Len())
for i := 0; i < val.Len(); i++ {
b[i] = byte(val.Index(i).Uint())
}
elem = VC.Binary(b)
default:
arrayElems, err := e.encodeSliceAsArray(val, minsize)
if err != nil {
return nil, err
}
elem = VC.ArrayFromValues(arrayElems...)
}
case reflect.Struct:
structElems, err := e.encodeStruct(val)
if err != nil {
return nil, err
}
elem = VC.DocumentFromElements(structElems...)
default:
return nil, fmt.Errorf("Unsupported value type %s", val.Kind())
}
return elem, nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/qingwenjie/mongo-go-driver.git
git@gitee.com:qingwenjie/mongo-go-driver.git
qingwenjie
mongo-go-driver
mongo-go-driver
v0.0.5

搜索帮助