copier.go raw

   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 bsonrw
   8  
   9  import (
  10  	"fmt"
  11  	"io"
  12  
  13  	"go.mongodb.org/mongo-driver/bson/bsontype"
  14  	"go.mongodb.org/mongo-driver/bson/primitive"
  15  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
  16  )
  17  
  18  // Copier is a type that allows copying between ValueReaders, ValueWriters, and
  19  // []byte values.
  20  //
  21  // Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
  22  // supported in Go Driver 2.0.
  23  type Copier struct{}
  24  
  25  // NewCopier creates a new copier with the given registry. If a nil registry is provided
  26  // a default registry is used.
  27  //
  28  // Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
  29  // supported in Go Driver 2.0.
  30  func NewCopier() Copier {
  31  	return Copier{}
  32  }
  33  
  34  // CopyDocument handles copying a document from src to dst.
  35  //
  36  // Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
  37  // supported in Go Driver 2.0.
  38  func CopyDocument(dst ValueWriter, src ValueReader) error {
  39  	return Copier{}.CopyDocument(dst, src)
  40  }
  41  
  42  // CopyDocument handles copying one document from the src to the dst.
  43  //
  44  // Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
  45  // supported in Go Driver 2.0.
  46  func (c Copier) CopyDocument(dst ValueWriter, src ValueReader) error {
  47  	dr, err := src.ReadDocument()
  48  	if err != nil {
  49  		return err
  50  	}
  51  
  52  	dw, err := dst.WriteDocument()
  53  	if err != nil {
  54  		return err
  55  	}
  56  
  57  	return c.copyDocumentCore(dw, dr)
  58  }
  59  
  60  // CopyArrayFromBytes copies the values from a BSON array represented as a
  61  // []byte to a ValueWriter.
  62  //
  63  // Deprecated: Copying BSON arrays using the ValueWriter and ValueReader interfaces will not be
  64  // supported in Go Driver 2.0.
  65  func (c Copier) CopyArrayFromBytes(dst ValueWriter, src []byte) error {
  66  	aw, err := dst.WriteArray()
  67  	if err != nil {
  68  		return err
  69  	}
  70  
  71  	err = c.CopyBytesToArrayWriter(aw, src)
  72  	if err != nil {
  73  		return err
  74  	}
  75  
  76  	return aw.WriteArrayEnd()
  77  }
  78  
  79  // CopyDocumentFromBytes copies the values from a BSON document represented as a
  80  // []byte to a ValueWriter.
  81  //
  82  // Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
  83  // supported in Go Driver 2.0.
  84  func (c Copier) CopyDocumentFromBytes(dst ValueWriter, src []byte) error {
  85  	dw, err := dst.WriteDocument()
  86  	if err != nil {
  87  		return err
  88  	}
  89  
  90  	err = c.CopyBytesToDocumentWriter(dw, src)
  91  	if err != nil {
  92  		return err
  93  	}
  94  
  95  	return dw.WriteDocumentEnd()
  96  }
  97  
  98  type writeElementFn func(key string) (ValueWriter, error)
  99  
 100  // CopyBytesToArrayWriter copies the values from a BSON Array represented as a []byte to an
 101  // ArrayWriter.
 102  //
 103  // Deprecated: Copying BSON arrays using the ArrayWriter interface will not be supported in Go
 104  // Driver 2.0.
 105  func (c Copier) CopyBytesToArrayWriter(dst ArrayWriter, src []byte) error {
 106  	wef := func(_ string) (ValueWriter, error) {
 107  		return dst.WriteArrayElement()
 108  	}
 109  
 110  	return c.copyBytesToValueWriter(src, wef)
 111  }
 112  
 113  // CopyBytesToDocumentWriter copies the values from a BSON document represented as a []byte to a
 114  // DocumentWriter.
 115  //
 116  // Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
 117  // supported in Go Driver 2.0.
 118  func (c Copier) CopyBytesToDocumentWriter(dst DocumentWriter, src []byte) error {
 119  	wef := func(key string) (ValueWriter, error) {
 120  		return dst.WriteDocumentElement(key)
 121  	}
 122  
 123  	return c.copyBytesToValueWriter(src, wef)
 124  }
 125  
 126  func (c Copier) copyBytesToValueWriter(src []byte, wef writeElementFn) error {
 127  	// TODO(skriptble): Create errors types here. Anything that is a tag should be a property.
 128  	length, rem, ok := bsoncore.ReadLength(src)
 129  	if !ok {
 130  		return fmt.Errorf("couldn't read length from src, not enough bytes. length=%d", len(src))
 131  	}
 132  	if len(src) < int(length) {
 133  		return fmt.Errorf("length read exceeds number of bytes available. length=%d bytes=%d", len(src), length)
 134  	}
 135  	rem = rem[:length-4]
 136  
 137  	var t bsontype.Type
 138  	var key string
 139  	var val bsoncore.Value
 140  	for {
 141  		t, rem, ok = bsoncore.ReadType(rem)
 142  		if !ok {
 143  			return io.EOF
 144  		}
 145  		if t == bsontype.Type(0) {
 146  			if len(rem) != 0 {
 147  				return fmt.Errorf("document end byte found before end of document. remaining bytes=%v", rem)
 148  			}
 149  			break
 150  		}
 151  
 152  		key, rem, ok = bsoncore.ReadKey(rem)
 153  		if !ok {
 154  			return fmt.Errorf("invalid key found. remaining bytes=%v", rem)
 155  		}
 156  
 157  		// write as either array element or document element using writeElementFn
 158  		vw, err := wef(key)
 159  		if err != nil {
 160  			return err
 161  		}
 162  
 163  		val, rem, ok = bsoncore.ReadValue(rem, t)
 164  		if !ok {
 165  			return fmt.Errorf("not enough bytes available to read type. bytes=%d type=%s", len(rem), t)
 166  		}
 167  		err = c.CopyValueFromBytes(vw, t, val.Data)
 168  		if err != nil {
 169  			return err
 170  		}
 171  	}
 172  	return nil
 173  }
 174  
 175  // CopyDocumentToBytes copies an entire document from the ValueReader and
 176  // returns it as bytes.
 177  //
 178  // Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
 179  // supported in Go Driver 2.0.
 180  func (c Copier) CopyDocumentToBytes(src ValueReader) ([]byte, error) {
 181  	return c.AppendDocumentBytes(nil, src)
 182  }
 183  
 184  // AppendDocumentBytes functions the same as CopyDocumentToBytes, but will
 185  // append the result to dst.
 186  //
 187  // Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
 188  // supported in Go Driver 2.0.
 189  func (c Copier) AppendDocumentBytes(dst []byte, src ValueReader) ([]byte, error) {
 190  	if br, ok := src.(BytesReader); ok {
 191  		_, dst, err := br.ReadValueBytes(dst)
 192  		return dst, err
 193  	}
 194  
 195  	vw := vwPool.Get().(*valueWriter)
 196  	defer putValueWriter(vw)
 197  
 198  	vw.reset(dst)
 199  
 200  	err := c.CopyDocument(vw, src)
 201  	dst = vw.buf
 202  	return dst, err
 203  }
 204  
 205  // AppendArrayBytes copies an array from the ValueReader to dst.
 206  //
 207  // Deprecated: Copying BSON arrays using the ValueWriter and ValueReader interfaces will not be
 208  // supported in Go Driver 2.0.
 209  func (c Copier) AppendArrayBytes(dst []byte, src ValueReader) ([]byte, error) {
 210  	if br, ok := src.(BytesReader); ok {
 211  		_, dst, err := br.ReadValueBytes(dst)
 212  		return dst, err
 213  	}
 214  
 215  	vw := vwPool.Get().(*valueWriter)
 216  	defer putValueWriter(vw)
 217  
 218  	vw.reset(dst)
 219  
 220  	err := c.copyArray(vw, src)
 221  	dst = vw.buf
 222  	return dst, err
 223  }
 224  
 225  // CopyValueFromBytes will write the value represtend by t and src to dst.
 226  //
 227  // Deprecated: Use [go.mongodb.org/mongo-driver/bson.UnmarshalValue] instead.
 228  func (c Copier) CopyValueFromBytes(dst ValueWriter, t bsontype.Type, src []byte) error {
 229  	if wvb, ok := dst.(BytesWriter); ok {
 230  		return wvb.WriteValueBytes(t, src)
 231  	}
 232  
 233  	vr := vrPool.Get().(*valueReader)
 234  	defer vrPool.Put(vr)
 235  
 236  	vr.reset(src)
 237  	vr.pushElement(t)
 238  
 239  	return c.CopyValue(dst, vr)
 240  }
 241  
 242  // CopyValueToBytes copies a value from src and returns it as a bsontype.Type and a
 243  // []byte.
 244  //
 245  // Deprecated: Use [go.mongodb.org/mongo-driver/bson.MarshalValue] instead.
 246  func (c Copier) CopyValueToBytes(src ValueReader) (bsontype.Type, []byte, error) {
 247  	return c.AppendValueBytes(nil, src)
 248  }
 249  
 250  // AppendValueBytes functions the same as CopyValueToBytes, but will append the
 251  // result to dst.
 252  //
 253  // Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
 254  // Driver 2.0.
 255  func (c Copier) AppendValueBytes(dst []byte, src ValueReader) (bsontype.Type, []byte, error) {
 256  	if br, ok := src.(BytesReader); ok {
 257  		return br.ReadValueBytes(dst)
 258  	}
 259  
 260  	vw := vwPool.Get().(*valueWriter)
 261  	defer putValueWriter(vw)
 262  
 263  	start := len(dst)
 264  
 265  	vw.reset(dst)
 266  	vw.push(mElement)
 267  
 268  	err := c.CopyValue(vw, src)
 269  	if err != nil {
 270  		return 0, dst, err
 271  	}
 272  
 273  	return bsontype.Type(vw.buf[start]), vw.buf[start+2:], nil
 274  }
 275  
 276  // CopyValue will copy a single value from src to dst.
 277  //
 278  // Deprecated: Copying BSON values using the ValueWriter and ValueReader interfaces will not be
 279  // supported in Go Driver 2.0.
 280  func (c Copier) CopyValue(dst ValueWriter, src ValueReader) error {
 281  	var err error
 282  	switch src.Type() {
 283  	case bsontype.Double:
 284  		var f64 float64
 285  		f64, err = src.ReadDouble()
 286  		if err != nil {
 287  			break
 288  		}
 289  		err = dst.WriteDouble(f64)
 290  	case bsontype.String:
 291  		var str string
 292  		str, err = src.ReadString()
 293  		if err != nil {
 294  			return err
 295  		}
 296  		err = dst.WriteString(str)
 297  	case bsontype.EmbeddedDocument:
 298  		err = c.CopyDocument(dst, src)
 299  	case bsontype.Array:
 300  		err = c.copyArray(dst, src)
 301  	case bsontype.Binary:
 302  		var data []byte
 303  		var subtype byte
 304  		data, subtype, err = src.ReadBinary()
 305  		if err != nil {
 306  			break
 307  		}
 308  		err = dst.WriteBinaryWithSubtype(data, subtype)
 309  	case bsontype.Undefined:
 310  		err = src.ReadUndefined()
 311  		if err != nil {
 312  			break
 313  		}
 314  		err = dst.WriteUndefined()
 315  	case bsontype.ObjectID:
 316  		var oid primitive.ObjectID
 317  		oid, err = src.ReadObjectID()
 318  		if err != nil {
 319  			break
 320  		}
 321  		err = dst.WriteObjectID(oid)
 322  	case bsontype.Boolean:
 323  		var b bool
 324  		b, err = src.ReadBoolean()
 325  		if err != nil {
 326  			break
 327  		}
 328  		err = dst.WriteBoolean(b)
 329  	case bsontype.DateTime:
 330  		var dt int64
 331  		dt, err = src.ReadDateTime()
 332  		if err != nil {
 333  			break
 334  		}
 335  		err = dst.WriteDateTime(dt)
 336  	case bsontype.Null:
 337  		err = src.ReadNull()
 338  		if err != nil {
 339  			break
 340  		}
 341  		err = dst.WriteNull()
 342  	case bsontype.Regex:
 343  		var pattern, options string
 344  		pattern, options, err = src.ReadRegex()
 345  		if err != nil {
 346  			break
 347  		}
 348  		err = dst.WriteRegex(pattern, options)
 349  	case bsontype.DBPointer:
 350  		var ns string
 351  		var pointer primitive.ObjectID
 352  		ns, pointer, err = src.ReadDBPointer()
 353  		if err != nil {
 354  			break
 355  		}
 356  		err = dst.WriteDBPointer(ns, pointer)
 357  	case bsontype.JavaScript:
 358  		var js string
 359  		js, err = src.ReadJavascript()
 360  		if err != nil {
 361  			break
 362  		}
 363  		err = dst.WriteJavascript(js)
 364  	case bsontype.Symbol:
 365  		var symbol string
 366  		symbol, err = src.ReadSymbol()
 367  		if err != nil {
 368  			break
 369  		}
 370  		err = dst.WriteSymbol(symbol)
 371  	case bsontype.CodeWithScope:
 372  		var code string
 373  		var srcScope DocumentReader
 374  		code, srcScope, err = src.ReadCodeWithScope()
 375  		if err != nil {
 376  			break
 377  		}
 378  
 379  		var dstScope DocumentWriter
 380  		dstScope, err = dst.WriteCodeWithScope(code)
 381  		if err != nil {
 382  			break
 383  		}
 384  		err = c.copyDocumentCore(dstScope, srcScope)
 385  	case bsontype.Int32:
 386  		var i32 int32
 387  		i32, err = src.ReadInt32()
 388  		if err != nil {
 389  			break
 390  		}
 391  		err = dst.WriteInt32(i32)
 392  	case bsontype.Timestamp:
 393  		var t, i uint32
 394  		t, i, err = src.ReadTimestamp()
 395  		if err != nil {
 396  			break
 397  		}
 398  		err = dst.WriteTimestamp(t, i)
 399  	case bsontype.Int64:
 400  		var i64 int64
 401  		i64, err = src.ReadInt64()
 402  		if err != nil {
 403  			break
 404  		}
 405  		err = dst.WriteInt64(i64)
 406  	case bsontype.Decimal128:
 407  		var d128 primitive.Decimal128
 408  		d128, err = src.ReadDecimal128()
 409  		if err != nil {
 410  			break
 411  		}
 412  		err = dst.WriteDecimal128(d128)
 413  	case bsontype.MinKey:
 414  		err = src.ReadMinKey()
 415  		if err != nil {
 416  			break
 417  		}
 418  		err = dst.WriteMinKey()
 419  	case bsontype.MaxKey:
 420  		err = src.ReadMaxKey()
 421  		if err != nil {
 422  			break
 423  		}
 424  		err = dst.WriteMaxKey()
 425  	default:
 426  		err = fmt.Errorf("Cannot copy unknown BSON type %s", src.Type())
 427  	}
 428  
 429  	return err
 430  }
 431  
 432  func (c Copier) copyArray(dst ValueWriter, src ValueReader) error {
 433  	ar, err := src.ReadArray()
 434  	if err != nil {
 435  		return err
 436  	}
 437  
 438  	aw, err := dst.WriteArray()
 439  	if err != nil {
 440  		return err
 441  	}
 442  
 443  	for {
 444  		vr, err := ar.ReadValue()
 445  		if err == ErrEOA {
 446  			break
 447  		}
 448  		if err != nil {
 449  			return err
 450  		}
 451  
 452  		vw, err := aw.WriteArrayElement()
 453  		if err != nil {
 454  			return err
 455  		}
 456  
 457  		err = c.CopyValue(vw, vr)
 458  		if err != nil {
 459  			return err
 460  		}
 461  	}
 462  
 463  	return aw.WriteArrayEnd()
 464  }
 465  
 466  func (c Copier) copyDocumentCore(dw DocumentWriter, dr DocumentReader) error {
 467  	for {
 468  		key, vr, err := dr.ReadElement()
 469  		if err == ErrEOD {
 470  			break
 471  		}
 472  		if err != nil {
 473  			return err
 474  		}
 475  
 476  		vw, err := dw.WriteDocumentElement(key)
 477  		if err != nil {
 478  			return err
 479  		}
 480  
 481  		err = c.CopyValue(vw, vr)
 482  		if err != nil {
 483  			return err
 484  		}
 485  	}
 486  
 487  	return dw.WriteDocumentEnd()
 488  }
 489