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