Copied mongo repo (to patch it)

This commit is contained in:
2023-06-18 15:50:55 +02:00
parent 21d241f9b1
commit d471d7c396
544 changed files with 142039 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,57 @@
// Copyright (C) MongoDB, Inc. 2022-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 mgocompat provides Registry, a BSON registry compatible with globalsign/mgo's BSON,
// with some remaining differences. It also provides RegistryRespectNilValues for compatibility
// with mgo's BSON with RespectNilValues set to true. A registry can be configured on a
// mongo.Client with the SetRegistry option. See the bsoncodec docs for more details on registries.
//
// Registry supports Getter and Setter equivalents by registering hooks. Note that if a value
// matches the hook for bsoncodec.Marshaler, bsoncodec.ValueMarshaler, or bsoncodec.Proxy, that
// hook will take priority over the Getter hook. The same is true for the hooks for
// bsoncodec.Unmarshaler and bsoncodec.ValueUnmarshaler and the Setter hook.
//
// The functional differences between Registry and globalsign/mgo's BSON library are:
//
// 1) Registry errors instead of silently skipping mismatched types when decoding.
//
// 2) Registry does not have special handling for marshaling array ops ("$in", "$nin", "$all").
//
// The driver uses different types than mgo's bson. The differences are:
//
// 1. The driver's bson.RawValue is equivalent to mgo's bson.Raw, but uses Value instead of Data and uses Type,
// which is a bsontype.Type object that wraps a byte, instead of bson.Raw's Kind, a byte.
//
// 2. The driver uses primitive.ObjectID, which is a [12]byte instead of mgo's
// bson.ObjectId, a string. Due to this, the zero value marshals and unmarshals differently
// for Extended JSON, with the driver marshaling as {"ID":"000000000000000000000000"} and
// mgo as {"Id":""}. The driver can unmarshal {"ID":""} to a primitive.ObjectID.
//
// 3. The driver's primitive.Symbol is equivalent to mgo's bson.Symbol.
//
// 4. The driver uses primitive.Timestamp instead of mgo's bson.MongoTimestamp. While
// MongoTimestamp is an int64, primitive.Timestamp stores the time and counter as two separate
// uint32 values, T and I respectively.
//
// 5. The driver uses primitive.MinKey and primitive.MaxKey, which are struct{}, instead
// of mgo's bson.MinKey and bson.MaxKey, which are int64.
//
// 6. The driver's primitive.Undefined is equivalent to mgo's bson.Undefined.
//
// 7. The driver's primitive.Binary is equivalent to mgo's bson.Binary, with variables named Subtype
// and Data instead of Kind and Data.
//
// 8. The driver's primitive.Regex is equivalent to mgo's bson.RegEx.
//
// 9. The driver's primitive.JavaScript is equivalent to mgo's bson.JavaScript with no
// scope and primitive.CodeWithScope is equivalent to mgo's bson.JavaScript with scope.
//
// 10. The driver's primitive.DBPointer is equivalent to mgo's bson.DBPointer, with variables
// named DB and Pointer instead of Namespace and Id.
//
// 11. When implementing the Setter interface, mgocompat.ErrSetZero is equivalent to mgo's
// bson.ErrSetZero.
package mgocompat

View File

@@ -0,0 +1,114 @@
// 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 mgocompat
import (
"errors"
"reflect"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/bson/bsonoptions"
"go.mongodb.org/mongo-driver/bson/bsontype"
)
var (
// ErrSetZero may be returned from a SetBSON method to have the value set to its respective zero value.
ErrSetZero = errors.New("set to zero")
tInt = reflect.TypeOf(int(0))
tTime = reflect.TypeOf(time.Time{})
tM = reflect.TypeOf(bson.M{})
tInterfaceSlice = reflect.TypeOf([]interface{}{})
tByteSlice = reflect.TypeOf([]byte{})
tEmpty = reflect.TypeOf((*interface{})(nil)).Elem()
tGetter = reflect.TypeOf((*Getter)(nil)).Elem()
tSetter = reflect.TypeOf((*Setter)(nil)).Elem()
)
// Registry is the mgo compatible bsoncodec.Registry. It contains the default and
// primitive codecs with mgo compatible options.
var Registry = NewRegistryBuilder().Build()
// RegistryRespectNilValues is the bsoncodec.Registry compatible with mgo withSetRespectNilValues set to true.
var RegistryRespectNilValues = NewRespectNilValuesRegistryBuilder().Build()
// NewRegistryBuilder creates a new bsoncodec.RegistryBuilder configured with the default encoders and
// decoders from the bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the
// PrimitiveCodecs type in this package.
func NewRegistryBuilder() *bsoncodec.RegistryBuilder {
rb := bsoncodec.NewRegistryBuilder()
bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb)
bsoncodec.DefaultValueDecoders{}.RegisterDefaultDecoders(rb)
bson.PrimitiveCodecs{}.RegisterPrimitiveCodecs(rb)
structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.DefaultStructTagParser,
bsonoptions.StructCodec().
SetDecodeZeroStruct(true).
SetEncodeOmitDefaultStruct(true).
SetOverwriteDuplicatedInlinedFields(false).
SetAllowUnexportedFields(true))
emptyInterCodec := bsoncodec.NewEmptyInterfaceCodec(
bsonoptions.EmptyInterfaceCodec().
SetDecodeBinaryAsSlice(true))
mapCodec := bsoncodec.NewMapCodec(
bsonoptions.MapCodec().
SetDecodeZerosMap(true).
SetEncodeNilAsEmpty(true).
SetEncodeKeysWithStringer(true))
uintcodec := bsoncodec.NewUIntCodec(bsonoptions.UIntCodec().SetEncodeToMinSize(true))
rb.RegisterTypeDecoder(tEmpty, emptyInterCodec).
RegisterDefaultDecoder(reflect.String, bsoncodec.NewStringCodec(bsonoptions.StringCodec().SetDecodeObjectIDAsHex(false))).
RegisterDefaultDecoder(reflect.Struct, structcodec).
RegisterDefaultDecoder(reflect.Map, mapCodec).
RegisterTypeEncoder(tByteSlice, bsoncodec.NewByteSliceCodec(bsonoptions.ByteSliceCodec().SetEncodeNilAsEmpty(true))).
RegisterDefaultEncoder(reflect.Struct, structcodec).
RegisterDefaultEncoder(reflect.Slice, bsoncodec.NewSliceCodec(bsonoptions.SliceCodec().SetEncodeNilAsEmpty(true))).
RegisterDefaultEncoder(reflect.Map, mapCodec).
RegisterDefaultEncoder(reflect.Uint, uintcodec).
RegisterDefaultEncoder(reflect.Uint8, uintcodec).
RegisterDefaultEncoder(reflect.Uint16, uintcodec).
RegisterDefaultEncoder(reflect.Uint32, uintcodec).
RegisterDefaultEncoder(reflect.Uint64, uintcodec).
RegisterTypeMapEntry(bsontype.Int32, tInt).
RegisterTypeMapEntry(bsontype.DateTime, tTime).
RegisterTypeMapEntry(bsontype.Array, tInterfaceSlice).
RegisterTypeMapEntry(bsontype.Type(0), tM).
RegisterTypeMapEntry(bsontype.EmbeddedDocument, tM).
RegisterHookEncoder(tGetter, bsoncodec.ValueEncoderFunc(GetterEncodeValue)).
RegisterHookDecoder(tSetter, bsoncodec.ValueDecoderFunc(SetterDecodeValue))
return rb
}
// NewRespectNilValuesRegistryBuilder creates a new bsoncodec.RegistryBuilder configured to behave like mgo/bson
// with RespectNilValues set to true.
func NewRespectNilValuesRegistryBuilder() *bsoncodec.RegistryBuilder {
rb := NewRegistryBuilder()
structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.DefaultStructTagParser,
bsonoptions.StructCodec().
SetDecodeZeroStruct(true).
SetEncodeOmitDefaultStruct(true).
SetOverwriteDuplicatedInlinedFields(false).
SetAllowUnexportedFields(true))
mapCodec := bsoncodec.NewMapCodec(
bsonoptions.MapCodec().
SetDecodeZerosMap(true).
SetEncodeNilAsEmpty(false))
rb.RegisterDefaultDecoder(reflect.Struct, structcodec).
RegisterDefaultDecoder(reflect.Map, mapCodec).
RegisterTypeEncoder(tByteSlice, bsoncodec.NewByteSliceCodec(bsonoptions.ByteSliceCodec().SetEncodeNilAsEmpty(false))).
RegisterDefaultEncoder(reflect.Struct, structcodec).
RegisterDefaultEncoder(reflect.Slice, bsoncodec.NewSliceCodec(bsonoptions.SliceCodec().SetEncodeNilAsEmpty(false))).
RegisterDefaultEncoder(reflect.Map, mapCodec)
return rb
}

View File

@@ -0,0 +1,127 @@
// 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 mgocompat
import (
"reflect"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/bson/bsonrw"
)
// Setter interface: a value implementing the bson.Setter interface will receive the BSON
// value via the SetBSON method during unmarshaling, and the object
// itself will not be changed as usual.
//
// If setting the value works, the method should return nil or alternatively
// mgocompat.ErrSetZero to set the respective field to its zero value (nil for
// pointer types). If SetBSON returns a non-nil error, the unmarshalling
// procedure will stop and error out with the provided value.
//
// This interface is generally useful in pointer receivers, since the method
// will want to change the receiver. A type field that implements the Setter
// interface doesn't have to be a pointer, though.
//
// For example:
//
// type MyString string
//
// func (s *MyString) SetBSON(raw bson.RawValue) error {
// return raw.Unmarshal(s)
// }
type Setter interface {
SetBSON(raw bson.RawValue) error
}
// Getter interface: a value implementing the bson.Getter interface will have its GetBSON
// method called when the given value has to be marshalled, and the result
// of this method will be marshaled in place of the actual object.
//
// If GetBSON returns return a non-nil error, the marshalling procedure
// will stop and error out with the provided value.
type Getter interface {
GetBSON() (interface{}, error)
}
// SetterDecodeValue is the ValueDecoderFunc for Setter types.
func SetterDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || (!val.Type().Implements(tSetter) && !reflect.PtrTo(val.Type()).Implements(tSetter)) {
return bsoncodec.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val}
}
if val.Kind() == reflect.Ptr && val.IsNil() {
if !val.CanSet() {
return bsoncodec.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val}
}
val.Set(reflect.New(val.Type().Elem()))
}
if !val.Type().Implements(tSetter) {
if !val.CanAddr() {
return bsoncodec.ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tSetter}, Received: val}
}
val = val.Addr() // If the type doesn't implement the interface, a pointer to it must.
}
t, src, err := bsonrw.Copier{}.CopyValueToBytes(vr)
if err != nil {
return err
}
fn := val.Convert(tSetter).MethodByName("SetBSON")
errVal := fn.Call([]reflect.Value{reflect.ValueOf(bson.RawValue{Type: t, Value: src})})[0]
if !errVal.IsNil() {
err = errVal.Interface().(error)
if err == ErrSetZero {
val.Set(reflect.Zero(val.Type()))
return nil
}
return err
}
return nil
}
// GetterEncodeValue is the ValueEncoderFunc for Getter types.
func GetterEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
// Either val or a pointer to val must implement Getter
switch {
case !val.IsValid():
return bsoncodec.ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val}
case val.Type().Implements(tGetter):
// If Getter is implemented on a concrete type, make sure that val isn't a nil pointer
if isImplementationNil(val, tGetter) {
return vw.WriteNull()
}
case reflect.PtrTo(val.Type()).Implements(tGetter) && val.CanAddr():
val = val.Addr()
default:
return bsoncodec.ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val}
}
fn := val.Convert(tGetter).MethodByName("GetBSON")
returns := fn.Call(nil)
if !returns[1].IsNil() {
return returns[1].Interface().(error)
}
intermediate := returns[0]
encoder, err := ec.Registry.LookupEncoder(intermediate.Type())
if err != nil {
return err
}
return encoder.EncodeValue(ec, vw, intermediate)
}
// isImplementationNil returns if val is a nil pointer and inter is implemented on a concrete type
func isImplementationNil(val reflect.Value, inter reflect.Type) bool {
vt := val.Type()
for vt.Kind() == reflect.Ptr {
vt = vt.Elem()
}
return vt.Implements(inter) && val.Kind() == reflect.Ptr && val.IsNil()
}