/
result.go
93 lines (78 loc) · 3.37 KB
/
result.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 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 unified
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsontype"
)
// operationResult holds the result and/or error returned by an op.
type operationResult struct {
// For operations that return a single result, this field holds a BSON representation.
Result bson.RawValue
// CursorResult holds the documents retrieved by iterating a Cursor.
CursorResult []bson.Raw
// Err holds the error returned by an operation. This is mutually exclusive with CursorResult but not with Result
// because some operations (e.g. bulkWrite) can return both a result and an error.
Err error
}
// newEmptyResult returns an operationResult with no fields set. This should be used if the operation does not check
// results or errors.
func newEmptyResult() *operationResult {
return &operationResult{}
}
// newDocumentResult is a helper to create a value result where the value is a BSON document.
func newDocumentResult(result []byte, err error) *operationResult {
return newValueResult(bsontype.EmbeddedDocument, result, err)
}
// newValueResult creates an operationResult where the result is a BSON value of an arbitrary type. Because some
// operations can return both a result and an error (e.g. bulkWrite), the err parameter should be the error returned
// by the op, if any.
func newValueResult(valueType bsontype.Type, data []byte, err error) *operationResult {
return &operationResult{
Result: bson.RawValue{Type: valueType, Value: data},
Err: err,
}
}
// newCursorResult creates an operationResult that contains documents retrieved by fully iterating a cursor.
func newCursorResult(arr []bson.Raw) *operationResult {
// If the operation returned no documents, the array might be nil. It isn't possible to distinguish between this
// case and the case where there is no cursor result, so we overwrite the result with an non-nil empty slice.
result := arr
if result == nil {
result = make([]bson.Raw, 0)
}
return &operationResult{
CursorResult: result,
}
}
// newErrorResult creates an operationResult that only holds an error. This should only be used when executing an
// operation that can return a result or an error, but not both.
func newErrorResult(err error) *operationResult {
return &operationResult{
Err: err,
}
}
// verifyOperationResult checks that the actual and expected results match
func verifyOperationResult(ctx context.Context, expected bson.RawValue, actual *operationResult) error {
actualVal := actual.Result
if actual.CursorResult != nil {
_, data, err := bson.MarshalValue(actual.CursorResult)
if err != nil {
return fmt.Errorf("error converting cursorResult array to BSON: %v", err)
}
actualVal = bson.RawValue{
Type: bsontype.Array,
Value: data,
}
}
// For document results and arrays of root documents (i.e. cursor results), the actual value can have additional
// top-level keys. Single-value array results (e.g. from distinct) must match exactly, so we set extraKeysAllowed to
// false only for that case.
extraKeysAllowed := actual.Result.Type != bsontype.Array
return verifyValuesMatch(ctx, expected, actualVal, extraKeysAllowed)
}