...

Source file src/go.mongodb.org/mongo-driver/bson/bsonrw/copier.go

Documentation: go.mongodb.org/mongo-driver/bson/bsonrw

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

View as plain text