Don Newton | 379ae25 | 2019-04-01 12:17:06 -0400 | [diff] [blame^] | 1 | // Copyright (C) MongoDB, Inc. 2017-present. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 4 | // not use this file except in compliance with the License. You may obtain |
| 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| 6 | |
| 7 | package bson |
| 8 | |
| 9 | import ( |
| 10 | "bytes" |
| 11 | "errors" |
| 12 | "fmt" |
| 13 | "reflect" |
| 14 | "time" |
| 15 | |
| 16 | "github.com/mongodb/mongo-go-driver/bson/bsoncodec" |
| 17 | "github.com/mongodb/mongo-go-driver/bson/bsonrw" |
| 18 | "github.com/mongodb/mongo-go-driver/bson/bsontype" |
| 19 | "github.com/mongodb/mongo-go-driver/bson/primitive" |
| 20 | "github.com/mongodb/mongo-go-driver/x/bsonx/bsoncore" |
| 21 | ) |
| 22 | |
| 23 | // ErrNilContext is returned when the provided DecodeContext is nil. |
| 24 | var ErrNilContext = errors.New("DecodeContext cannot be nil") |
| 25 | |
| 26 | // ErrNilRegistry is returned when the provided registry is nil. |
| 27 | var ErrNilRegistry = errors.New("Registry cannot be nil") |
| 28 | |
| 29 | // RawValue represents a BSON value in byte form. It can be used to hold unprocessed BSON or to |
| 30 | // defer processing of BSON. Type is the BSON type of the value and Value are the raw bytes that |
| 31 | // represent the element. |
| 32 | // |
| 33 | // This type wraps bsoncore.Value for most of it's functionality. |
| 34 | type RawValue struct { |
| 35 | Type bsontype.Type |
| 36 | Value []byte |
| 37 | |
| 38 | r *bsoncodec.Registry |
| 39 | } |
| 40 | |
| 41 | // Unmarshal deserializes BSON into the provided val. If RawValue cannot be unmarshaled into val, an |
| 42 | // error is returned. This method will use the registry used to create the RawValue, if the RawValue |
| 43 | // was created from partial BSON processing, or it will use the default registry. Users wishing to |
| 44 | // specify the registry to use should use UnmarshalWithRegistry. |
| 45 | func (rv RawValue) Unmarshal(val interface{}) error { |
| 46 | reg := rv.r |
| 47 | if reg == nil { |
| 48 | reg = DefaultRegistry |
| 49 | } |
| 50 | return rv.UnmarshalWithRegistry(reg, val) |
| 51 | } |
| 52 | |
| 53 | // Equal compares rv and rv2 and returns true if they are equal. |
| 54 | func (rv RawValue) Equal(rv2 RawValue) bool { |
| 55 | if rv.Type != rv2.Type { |
| 56 | return false |
| 57 | } |
| 58 | |
| 59 | if !bytes.Equal(rv.Value, rv2.Value) { |
| 60 | return false |
| 61 | } |
| 62 | |
| 63 | return true |
| 64 | } |
| 65 | |
| 66 | // UnmarshalWithRegistry performs the same unmarshalling as Unmarshal but uses the provided registry |
| 67 | // instead of the one attached or the default registry. |
| 68 | func (rv RawValue) UnmarshalWithRegistry(r *bsoncodec.Registry, val interface{}) error { |
| 69 | if r == nil { |
| 70 | return ErrNilRegistry |
| 71 | } |
| 72 | |
| 73 | vr := bsonrw.NewBSONValueReader(rv.Type, rv.Value) |
| 74 | rval := reflect.ValueOf(val) |
| 75 | if rval.Kind() != reflect.Ptr { |
| 76 | return fmt.Errorf("argument to Unmarshal* must be a pointer to a type, but got %v", rval) |
| 77 | } |
| 78 | rval = rval.Elem() |
| 79 | dec, err := r.LookupDecoder(rval.Type()) |
| 80 | if err != nil { |
| 81 | return err |
| 82 | } |
| 83 | return dec.DecodeValue(bsoncodec.DecodeContext{Registry: r}, vr, rval) |
| 84 | } |
| 85 | |
| 86 | // UnmarshalWithContext performs the same unmarshalling as Unmarshal but uses the provided DecodeContext |
| 87 | // instead of the one attached or the default registry. |
| 88 | func (rv RawValue) UnmarshalWithContext(dc *bsoncodec.DecodeContext, val interface{}) error { |
| 89 | if dc == nil { |
| 90 | return ErrNilContext |
| 91 | } |
| 92 | |
| 93 | vr := bsonrw.NewBSONValueReader(rv.Type, rv.Value) |
| 94 | rval := reflect.ValueOf(val) |
| 95 | if rval.Kind() != reflect.Ptr { |
| 96 | return fmt.Errorf("argument to Unmarshal* must be a pointer to a type, but got %v", rval) |
| 97 | } |
| 98 | rval = rval.Elem() |
| 99 | dec, err := dc.LookupDecoder(rval.Type()) |
| 100 | if err != nil { |
| 101 | return err |
| 102 | } |
| 103 | return dec.DecodeValue(*dc, vr, rval) |
| 104 | } |
| 105 | |
| 106 | func convertFromCoreValue(v bsoncore.Value) RawValue { return RawValue{Type: v.Type, Value: v.Data} } |
| 107 | func convertToCoreValue(v RawValue) bsoncore.Value { return bsoncore.Value{Type: v.Type, Data: v.Value} } |
| 108 | |
| 109 | // Validate ensures the value is a valid BSON value. |
| 110 | func (rv RawValue) Validate() error { return convertToCoreValue(rv).Validate() } |
| 111 | |
| 112 | // IsNumber returns true if the type of v is a numeric BSON type. |
| 113 | func (rv RawValue) IsNumber() bool { return convertToCoreValue(rv).IsNumber() } |
| 114 | |
| 115 | // String implements the fmt.String interface. This method will return values in extended JSON |
| 116 | // format. If the value is not valid, this returns an empty string |
| 117 | func (rv RawValue) String() string { return convertToCoreValue(rv).String() } |
| 118 | |
| 119 | // DebugString outputs a human readable version of Document. It will attempt to stringify the |
| 120 | // valid components of the document even if the entire document is not valid. |
| 121 | func (rv RawValue) DebugString() string { return convertToCoreValue(rv).DebugString() } |
| 122 | |
| 123 | // Double returns the float64 value for this element. |
| 124 | // It panics if e's BSON type is not bsontype.Double. |
| 125 | func (rv RawValue) Double() float64 { return convertToCoreValue(rv).Double() } |
| 126 | |
| 127 | // DoubleOK is the same as Double, but returns a boolean instead of panicking. |
| 128 | func (rv RawValue) DoubleOK() (float64, bool) { return convertToCoreValue(rv).DoubleOK() } |
| 129 | |
| 130 | // StringValue returns the string value for this element. |
| 131 | // It panics if e's BSON type is not bsontype.String. |
| 132 | // |
| 133 | // NOTE: This method is called StringValue to avoid a collision with the String method which |
| 134 | // implements the fmt.Stringer interface. |
| 135 | func (rv RawValue) StringValue() string { return convertToCoreValue(rv).StringValue() } |
| 136 | |
| 137 | // StringValueOK is the same as StringValue, but returns a boolean instead of |
| 138 | // panicking. |
| 139 | func (rv RawValue) StringValueOK() (string, bool) { return convertToCoreValue(rv).StringValueOK() } |
| 140 | |
| 141 | // Document returns the BSON document the Value represents as a Document. It panics if the |
| 142 | // value is a BSON type other than document. |
| 143 | func (rv RawValue) Document() Raw { return Raw(convertToCoreValue(rv).Document()) } |
| 144 | |
| 145 | // DocumentOK is the same as Document, except it returns a boolean |
| 146 | // instead of panicking. |
| 147 | func (rv RawValue) DocumentOK() (Raw, bool) { |
| 148 | doc, ok := convertToCoreValue(rv).DocumentOK() |
| 149 | return Raw(doc), ok |
| 150 | } |
| 151 | |
| 152 | // Array returns the BSON array the Value represents as an Array. It panics if the |
| 153 | // value is a BSON type other than array. |
| 154 | func (rv RawValue) Array() Raw { return Raw(convertToCoreValue(rv).Array()) } |
| 155 | |
| 156 | // ArrayOK is the same as Array, except it returns a boolean instead |
| 157 | // of panicking. |
| 158 | func (rv RawValue) ArrayOK() (Raw, bool) { |
| 159 | doc, ok := convertToCoreValue(rv).ArrayOK() |
| 160 | return Raw(doc), ok |
| 161 | } |
| 162 | |
| 163 | // Binary returns the BSON binary value the Value represents. It panics if the value is a BSON type |
| 164 | // other than binary. |
| 165 | func (rv RawValue) Binary() (subtype byte, data []byte) { return convertToCoreValue(rv).Binary() } |
| 166 | |
| 167 | // BinaryOK is the same as Binary, except it returns a boolean instead of |
| 168 | // panicking. |
| 169 | func (rv RawValue) BinaryOK() (subtype byte, data []byte, ok bool) { |
| 170 | return convertToCoreValue(rv).BinaryOK() |
| 171 | } |
| 172 | |
| 173 | // ObjectID returns the BSON objectid value the Value represents. It panics if the value is a BSON |
| 174 | // type other than objectid. |
| 175 | func (rv RawValue) ObjectID() primitive.ObjectID { return convertToCoreValue(rv).ObjectID() } |
| 176 | |
| 177 | // ObjectIDOK is the same as ObjectID, except it returns a boolean instead of |
| 178 | // panicking. |
| 179 | func (rv RawValue) ObjectIDOK() (primitive.ObjectID, bool) { return convertToCoreValue(rv).ObjectIDOK() } |
| 180 | |
| 181 | // Boolean returns the boolean value the Value represents. It panics if the |
| 182 | // value is a BSON type other than boolean. |
| 183 | func (rv RawValue) Boolean() bool { return convertToCoreValue(rv).Boolean() } |
| 184 | |
| 185 | // BooleanOK is the same as Boolean, except it returns a boolean instead of |
| 186 | // panicking. |
| 187 | func (rv RawValue) BooleanOK() (bool, bool) { return convertToCoreValue(rv).BooleanOK() } |
| 188 | |
| 189 | // DateTime returns the BSON datetime value the Value represents as a |
| 190 | // unix timestamp. It panics if the value is a BSON type other than datetime. |
| 191 | func (rv RawValue) DateTime() int64 { return convertToCoreValue(rv).DateTime() } |
| 192 | |
| 193 | // DateTimeOK is the same as DateTime, except it returns a boolean instead of |
| 194 | // panicking. |
| 195 | func (rv RawValue) DateTimeOK() (int64, bool) { return convertToCoreValue(rv).DateTimeOK() } |
| 196 | |
| 197 | // Time returns the BSON datetime value the Value represents. It panics if the value is a BSON |
| 198 | // type other than datetime. |
| 199 | func (rv RawValue) Time() time.Time { return convertToCoreValue(rv).Time() } |
| 200 | |
| 201 | // TimeOK is the same as Time, except it returns a boolean instead of |
| 202 | // panicking. |
| 203 | func (rv RawValue) TimeOK() (time.Time, bool) { return convertToCoreValue(rv).TimeOK() } |
| 204 | |
| 205 | // Regex returns the BSON regex value the Value represents. It panics if the value is a BSON |
| 206 | // type other than regex. |
| 207 | func (rv RawValue) Regex() (pattern, options string) { return convertToCoreValue(rv).Regex() } |
| 208 | |
| 209 | // RegexOK is the same as Regex, except it returns a boolean instead of |
| 210 | // panicking. |
| 211 | func (rv RawValue) RegexOK() (pattern, options string, ok bool) { |
| 212 | return convertToCoreValue(rv).RegexOK() |
| 213 | } |
| 214 | |
| 215 | // DBPointer returns the BSON dbpointer value the Value represents. It panics if the value is a BSON |
| 216 | // type other than DBPointer. |
| 217 | func (rv RawValue) DBPointer() (string, primitive.ObjectID) { return convertToCoreValue(rv).DBPointer() } |
| 218 | |
| 219 | // DBPointerOK is the same as DBPoitner, except that it returns a boolean |
| 220 | // instead of panicking. |
| 221 | func (rv RawValue) DBPointerOK() (string, primitive.ObjectID, bool) { |
| 222 | return convertToCoreValue(rv).DBPointerOK() |
| 223 | } |
| 224 | |
| 225 | // JavaScript returns the BSON JavaScript code value the Value represents. It panics if the value is |
| 226 | // a BSON type other than JavaScript code. |
| 227 | func (rv RawValue) JavaScript() string { return convertToCoreValue(rv).JavaScript() } |
| 228 | |
| 229 | // JavaScriptOK is the same as Javascript, excepti that it returns a boolean |
| 230 | // instead of panicking. |
| 231 | func (rv RawValue) JavaScriptOK() (string, bool) { return convertToCoreValue(rv).JavaScriptOK() } |
| 232 | |
| 233 | // Symbol returns the BSON symbol value the Value represents. It panics if the value is a BSON |
| 234 | // type other than symbol. |
| 235 | func (rv RawValue) Symbol() string { return convertToCoreValue(rv).Symbol() } |
| 236 | |
| 237 | // SymbolOK is the same as Symbol, excepti that it returns a boolean |
| 238 | // instead of panicking. |
| 239 | func (rv RawValue) SymbolOK() (string, bool) { return convertToCoreValue(rv).SymbolOK() } |
| 240 | |
| 241 | // CodeWithScope returns the BSON JavaScript code with scope the Value represents. |
| 242 | // It panics if the value is a BSON type other than JavaScript code with scope. |
| 243 | func (rv RawValue) CodeWithScope() (string, Raw) { |
| 244 | code, scope := convertToCoreValue(rv).CodeWithScope() |
| 245 | return code, Raw(scope) |
| 246 | } |
| 247 | |
| 248 | // CodeWithScopeOK is the same as CodeWithScope, except that it returns a boolean instead of |
| 249 | // panicking. |
| 250 | func (rv RawValue) CodeWithScopeOK() (string, Raw, bool) { |
| 251 | code, scope, ok := convertToCoreValue(rv).CodeWithScopeOK() |
| 252 | return code, Raw(scope), ok |
| 253 | } |
| 254 | |
| 255 | // Int32 returns the int32 the Value represents. It panics if the value is a BSON type other than |
| 256 | // int32. |
| 257 | func (rv RawValue) Int32() int32 { return convertToCoreValue(rv).Int32() } |
| 258 | |
| 259 | // Int32OK is the same as Int32, except that it returns a boolean instead of |
| 260 | // panicking. |
| 261 | func (rv RawValue) Int32OK() (int32, bool) { return convertToCoreValue(rv).Int32OK() } |
| 262 | |
| 263 | // Timestamp returns the BSON timestamp value the Value represents. It panics if the value is a |
| 264 | // BSON type other than timestamp. |
| 265 | func (rv RawValue) Timestamp() (t, i uint32) { return convertToCoreValue(rv).Timestamp() } |
| 266 | |
| 267 | // TimestampOK is the same as Timestamp, except that it returns a boolean |
| 268 | // instead of panicking. |
| 269 | func (rv RawValue) TimestampOK() (t, i uint32, ok bool) { return convertToCoreValue(rv).TimestampOK() } |
| 270 | |
| 271 | // Int64 returns the int64 the Value represents. It panics if the value is a BSON type other than |
| 272 | // int64. |
| 273 | func (rv RawValue) Int64() int64 { return convertToCoreValue(rv).Int64() } |
| 274 | |
| 275 | // Int64OK is the same as Int64, except that it returns a boolean instead of |
| 276 | // panicking. |
| 277 | func (rv RawValue) Int64OK() (int64, bool) { return convertToCoreValue(rv).Int64OK() } |
| 278 | |
| 279 | // Decimal128 returns the decimal the Value represents. It panics if the value is a BSON type other than |
| 280 | // decimal. |
| 281 | func (rv RawValue) Decimal128() primitive.Decimal128 { return convertToCoreValue(rv).Decimal128() } |
| 282 | |
| 283 | // Decimal128OK is the same as Decimal128, except that it returns a boolean |
| 284 | // instead of panicking. |
| 285 | func (rv RawValue) Decimal128OK() (primitive.Decimal128, bool) { |
| 286 | return convertToCoreValue(rv).Decimal128OK() |
| 287 | } |