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 mongo 8 9 import ( 10 "context" 11 "errors" 12 "fmt" 13 14 "go.mongodb.org/mongo-driver/bson" 15 "go.mongodb.org/mongo-driver/bson/bsoncodec" 16 "go.mongodb.org/mongo-driver/mongo/options" 17 ) 18 19 // ErrNoDocuments is returned by SingleResult methods when the operation that created the SingleResult did not return 20 // any documents. 21 var ErrNoDocuments = errors.New("mongo: no documents in result") 22 23 // SingleResult represents a single document returned from an operation. If the operation resulted in an error, all 24 // SingleResult methods will return that error. If the operation did not return any documents, all SingleResult methods 25 // will return ErrNoDocuments. 26 type SingleResult struct { 27 ctx context.Context 28 err error 29 cur *Cursor 30 rdr bson.Raw 31 bsonOpts *options.BSONOptions 32 reg *bsoncodec.Registry 33 } 34 35 // NewSingleResultFromDocument creates a SingleResult with the provided error, registry, and an underlying Cursor pre-loaded with 36 // the provided document, error and registry. If no registry is provided, bson.DefaultRegistry will be used. If an error distinct 37 // from the one provided occurs during creation of the SingleResult, that error will be stored on the returned SingleResult. 38 // 39 // The document parameter must be a non-nil document. 40 func NewSingleResultFromDocument(document interface{}, err error, registry *bsoncodec.Registry) *SingleResult { 41 if document == nil { 42 return &SingleResult{err: ErrNilDocument} 43 } 44 if registry == nil { 45 registry = bson.DefaultRegistry 46 } 47 48 cur, createErr := NewCursorFromDocuments([]interface{}{document}, err, registry) 49 if createErr != nil { 50 return &SingleResult{err: createErr} 51 } 52 53 return &SingleResult{ 54 cur: cur, 55 err: err, 56 reg: registry, 57 } 58 } 59 60 // Decode will unmarshal the document represented by this SingleResult into v. If there was an error from the operation 61 // that created this SingleResult, that error will be returned. If the operation returned no documents, Decode will 62 // return ErrNoDocuments. 63 // 64 // If the operation was successful and returned a document, Decode will return any errors from the unmarshalling process 65 // without any modification. If v is nil or is a typed nil, an error will be returned. 66 func (sr *SingleResult) Decode(v interface{}) error { 67 if sr.err != nil { 68 return sr.err 69 } 70 if sr.reg == nil { 71 return bson.ErrNilRegistry 72 } 73 74 if sr.err = sr.setRdrContents(); sr.err != nil { 75 return sr.err 76 } 77 78 dec, err := getDecoder(sr.rdr, sr.bsonOpts, sr.reg) 79 if err != nil { 80 return fmt.Errorf("error configuring BSON decoder: %w", err) 81 } 82 83 return dec.Decode(v) 84 } 85 86 // Raw returns the document represented by this SingleResult as a bson.Raw. If 87 // there was an error from the operation that created this SingleResult, both 88 // the result and that error will be returned. If the operation returned no 89 // documents, this will return (nil, ErrNoDocuments). 90 func (sr *SingleResult) Raw() (bson.Raw, error) { 91 if sr.err != nil { 92 return sr.rdr, sr.err 93 } 94 95 if sr.err = sr.setRdrContents(); sr.err != nil { 96 return nil, sr.err 97 } 98 return sr.rdr, nil 99 } 100 101 // DecodeBytes will return the document represented by this SingleResult as a bson.Raw. If there was an error from the 102 // operation that created this SingleResult, both the result and that error will be returned. If the operation returned 103 // no documents, this will return (nil, ErrNoDocuments). 104 // 105 // Deprecated: Use [SingleResult.Raw] instead. 106 func (sr *SingleResult) DecodeBytes() (bson.Raw, error) { 107 return sr.Raw() 108 } 109 110 // setRdrContents will set the contents of rdr by iterating the underlying cursor if necessary. 111 func (sr *SingleResult) setRdrContents() error { 112 switch { 113 case sr.err != nil: 114 return sr.err 115 case sr.rdr != nil: 116 return nil 117 case sr.cur != nil: 118 defer sr.cur.Close(sr.ctx) 119 120 if !sr.cur.Next(sr.ctx) { 121 if err := sr.cur.Err(); err != nil { 122 return err 123 } 124 125 return ErrNoDocuments 126 } 127 sr.rdr = sr.cur.Current 128 return nil 129 } 130 131 return ErrNoDocuments 132 } 133 134 // Err provides a way to check for query errors without calling Decode. Err returns the error, if 135 // any, that was encountered while running the operation. If the operation was successful but did 136 // not return any documents, Err returns ErrNoDocuments. If this error is not nil, this error will 137 // also be returned from Decode. 138 func (sr *SingleResult) Err() error { 139 sr.err = sr.setRdrContents() 140 141 return sr.err 142 } 143