Skip to content

Commit

Permalink
GODRIVER-360: correct semantics for bson.Lookup and friends
Browse files Browse the repository at this point in the history
Change-Id: I48774e72943378695b1ac3ae31a53ad43c4fdce7
  • Loading branch information
Sam Kleinman authored and tychoish committed May 22, 2018
1 parent 01a9a6c commit ba9aede
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 90 deletions.
2 changes: 1 addition & 1 deletion bson/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (a *Array) lookupTraverse(index uint, keys ...string) (*Value, error) {

switch value.Type() {
case TypeEmbeddedDocument:
element, err := value.MutableDocument().Lookup(keys...)
element, err := value.MutableDocument().LookupElementErr(keys...)
if err != nil {
return nil, err
}
Expand Down
41 changes: 39 additions & 2 deletions bson/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,44 @@ func (d *Document) Set(elem *Element) *Document {

// Lookup searches the document and potentially subdocuments or arrays for the
// provided key. Each key provided to this method represents a layer of depth.
func (d *Document) Lookup(key ...string) (*Element, error) {
//
// Lookup will return nil if it encounters an error.
func (d *Document) Lookup(key ...string) *Value {
elem, err := d.LookupElementErr(key...)
if err != nil {
return nil
}

return elem.value
}

// LookupErr searches the document and potentially subdocuments or arrays for the
// provided key. Each key provided to this method represents a layer of depth.
func (d *Document) LookupErr(key ...string) (*Value, error) {
elem, err := d.LookupElementErr(key...)
if err != nil {
return nil, err
}

return elem.value, nil
}

// LookupElement searches the document and potentially subdocuments or arrays for the
// provided key. Each key provided to this method represents a layer of depth.
//
// LookupElement will return nil if it encounters an error.
func (d *Document) LookupElement(key ...string) *Element {
elem, err := d.LookupElementErr(key...)
if err != nil {
return nil
}

return elem
}

// LookupElementErr searches the document and potentially subdocuments or arrays for the
// provided key. Each key provided to this method represents a layer of depth.
func (d *Document) LookupElementErr(key ...string) (*Element, error) {
if d == nil {
return nil, ErrNilDocument
}
Expand All @@ -294,7 +331,7 @@ func (d *Document) Lookup(key ...string) (*Element, error) {
}
switch elem.value.Type() {
case '\x03':
elem, err = elem.value.MutableDocument().Lookup(key[1:]...)
elem, err = elem.value.MutableDocument().LookupElementErr(key[1:]...)
case '\x04':
index, err := strconv.ParseUint(key[1], 10, 0)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions bson/document_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ func TestDocument(t *testing.T) {
t.Run("Lookup", func(t *testing.T) {
t.Run("empty key", func(t *testing.T) {
d := NewDocument()
_, err := d.Lookup()
_, err := d.LookupErr()
if err != ErrEmptyKey {
t.Errorf("Empty key lookup did not return expected result. got %#v; want %#v", err, ErrEmptyKey)
}
Expand Down Expand Up @@ -377,7 +377,7 @@ func TestDocument(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got, err := tc.d.Lookup(tc.key...)
got, err := tc.d.LookupElementErr(tc.key...)
if err != tc.err {
t.Errorf("Returned error does not match. got %#v; want %#v", err, tc.err)
}
Expand Down
18 changes: 9 additions & 9 deletions core/integration/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ func TestCommand(t *testing.T) {
result, err = bson.ReadDocument(rdr)
noerr(t, err)

elem, err := result.Lookup("ok")
val, err := result.LookupErr("ok")
noerr(t, err)
if got, want := elem.Value().Type(), bson.TypeDouble; got != want {
if got, want := val.Type(), bson.TypeDouble; got != want {
t.Errorf("Did not get correct type for 'ok'. got %s; want %s", got, want)
}
if got, want := elem.Value().Double(), float64(1); got != want {
if got, want := val.Double(), float64(1); got != want {
t.Errorf("Did not get correct value for 'ok'. got %f; want %f", got, want)
}

elem, err = result.Lookup("nonce")
val, err = result.LookupErr("nonce")
require.NoError(t, err)
require.Equal(t, elem.Value().Type(), bson.TypeString)
require.NotEqual(t, "", elem.Value().StringValue(), "MongoDB returned empty nonce")
require.Equal(t, val.Type(), bson.TypeString)
require.NotEqual(t, "", val.StringValue(), "MongoDB returned empty nonce")

result.Reset()
cmd.Command = bson.NewDocument(bson.EC.Int32("ping", 1))
Expand All @@ -72,10 +72,10 @@ func TestCommand(t *testing.T) {
result, err = bson.ReadDocument(rdr)
require.NoError(t, err)

elem, err = result.Lookup("ok")
val, err = result.LookupErr("ok")
require.NoError(t, err)
require.Equal(t, elem.Value().Type(), bson.TypeDouble)
require.Equal(t, float64(1), elem.Value().Double(), "Unable to ping MongoDB")
require.Equal(t, val.Type(), bson.TypeDouble)
require.Equal(t, float64(1), val.Double(), "Unable to ping MongoDB")
}

func TestWriteCommands(t *testing.T) {
Expand Down
8 changes: 4 additions & 4 deletions core/integration/list_collections_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ func TestCommandListCollections(t *testing.T) {
err = cursor.Decode(next)
noerr(t, err)

elem, err := next.Lookup("name")
val, err := next.LookupErr("name")
noerr(t, err)
if elem.Value().Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", elem.Value().Type(), bson.TypeString)
if val.Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", val.Type(), bson.TypeString)
t.FailNow()
}
names[elem.Value().StringValue()] = true
names[val.StringValue()] = true
}

for _, required := range []string{collOne, collTwo, collThree} {
Expand Down
32 changes: 16 additions & 16 deletions core/integration/list_indexes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ func TestCommandListIndexes(t *testing.T) {
err = cursor.Decode(next)
noerr(t, err)

elem, err := next.Lookup("name")
val, err := next.LookupErr("name")
noerr(t, err)
if elem.Value().Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", elem.Value().Type(), bson.TypeString)
if val.Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", val.Type(), bson.TypeString)
t.FailNow()
}
indexes = append(indexes, elem.Value().StringValue())
indexes = append(indexes, val.StringValue())
}

if len(indexes) != 0 {
Expand All @@ -70,13 +70,13 @@ func TestCommandListIndexes(t *testing.T) {
err = cursor.Decode(next)
noerr(t, err)

elem, err := next.Lookup("name")
val, err := next.LookupErr("name")
noerr(t, err)
if elem.Value().Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", elem.Value().Type(), bson.TypeString)
if val.Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", val.Type(), bson.TypeString)
t.FailNow()
}
indexes = append(indexes, elem.Value().StringValue())
indexes = append(indexes, val.StringValue())
}

if len(indexes) != 0 {
Expand Down Expand Up @@ -105,13 +105,13 @@ func TestCommandListIndexes(t *testing.T) {
err = cursor.Decode(next)
noerr(t, err)

elem, err := next.Lookup("name")
val, err := next.LookupErr("name")
noerr(t, err)
if elem.Value().Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", elem.Value().Type(), bson.TypeString)
if val.Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", val.Type(), bson.TypeString)
t.FailNow()
}
indexes = append(indexes, elem.Value().StringValue())
indexes = append(indexes, val.StringValue())
}

if len(indexes) != 5 {
Expand Down Expand Up @@ -145,13 +145,13 @@ func TestCommandListIndexes(t *testing.T) {
err = cursor.Decode(next)
noerr(t, err)

elem, err := next.Lookup("name")
val, err := next.LookupErr("name")
noerr(t, err)
if elem.Value().Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", elem.Value().Type(), bson.TypeString)
if val.Type() != bson.TypeString {
t.Errorf("Incorrect type for 'name'. got %v; want %v", val.Type(), bson.TypeString)
t.FailNow()
}
indexes = append(indexes, elem.Value().StringValue())
indexes = append(indexes, val.StringValue())
}

if len(indexes) != 4 {
Expand Down
4 changes: 2 additions & 2 deletions core/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ type OptReadConcern struct{ ReadConcern *bson.Element }

// Option implements the Optioner interface.
func (opt OptReadConcern) Option(d *bson.Document) error {
if _, err := d.Lookup(opt.ReadConcern.Key()); err == bson.ErrElementNotFound {
if _, err := d.LookupElementErr(opt.ReadConcern.Key()); err == bson.ErrElementNotFound {
d.Append(opt.ReadConcern)
}
return nil
Expand Down Expand Up @@ -704,7 +704,7 @@ type OptWriteConcern struct {

// Option implements the Optioner interface.
func (opt OptWriteConcern) Option(d *bson.Document) error {
_, err := d.Lookup(opt.WriteConcern.Key())
_, err := d.LookupElementErr(opt.WriteConcern.Key())
if err == bson.ErrElementNotFound {
d.Append(opt.WriteConcern)
return nil
Expand Down
30 changes: 15 additions & 15 deletions examples/documentation_examples/examples.go
Original file line number Diff line number Diff line change
Expand Up @@ -1410,10 +1410,10 @@ func ProjectionExamples(t *testing.T, db *mongo.Database) {
require.False(t, containsKey(keys, "size", nil))
require.True(t, containsKey(keys, "instock", nil))

instock, err := doc.Lookup("instock")
instock, err := doc.LookupErr("instock")
require.NoError(t, err)

arr := instock.Value().MutableArray()
arr := instock.MutableArray()

for i := uint(0); i < uint(arr.Len()); i++ {
elem, err := arr.Lookup(i)
Expand All @@ -1423,7 +1423,7 @@ func ProjectionExamples(t *testing.T, db *mongo.Database) {
subdoc := elem.MutableDocument()

require.Equal(t, 1, subdoc.Len())
_, err = subdoc.Lookup("qty")
_, err = subdoc.LookupErr("qty")
require.NoError(t, err)
}
}
Expand Down Expand Up @@ -1470,9 +1470,9 @@ func ProjectionExamples(t *testing.T, db *mongo.Database) {
require.False(t, containsKey(keys, "size", nil))
require.True(t, containsKey(keys, "instock", nil))

instock, err := doc.Lookup("instock")
instock, err := doc.LookupErr("instock")
require.NoError(t, err)
require.Equal(t, instock.Value().MutableArray().Len(), 1)
require.Equal(t, instock.MutableArray().Len(), 1)
}

require.NoError(t, cursor.Err())
Expand Down Expand Up @@ -1641,13 +1641,13 @@ func UpdateExamples(t *testing.T, db *mongo.Database) {
err := cursor.Decode(doc)
require.NoError(t, err)

uom, err := doc.Lookup("size", "uom")
uom, err := doc.LookupErr("size", "uom")
require.NoError(t, err)
require.Equal(t, uom.Value().StringValue(), "cm")
require.Equal(t, uom.StringValue(), "cm")

status, err := doc.Lookup("status")
status, err := doc.LookupErr("status")
require.NoError(t, err)
require.Equal(t, status.Value().StringValue(), "P")
require.Equal(t, status.StringValue(), "P")

keys, err := doc.Keys(false)
require.NoError(t, err)
Expand Down Expand Up @@ -1700,13 +1700,13 @@ func UpdateExamples(t *testing.T, db *mongo.Database) {
err := cursor.Decode(doc)
require.NoError(t, err)

uom, err := doc.Lookup("size", "uom")
uom, err := doc.LookupErr("size", "uom")
require.NoError(t, err)
require.Equal(t, uom.Value().StringValue(), "cm")
require.Equal(t, uom.StringValue(), "cm")

status, err := doc.Lookup("status")
status, err := doc.LookupErr("status")
require.NoError(t, err)
require.Equal(t, status.Value().StringValue(), "P")
require.Equal(t, status.StringValue(), "P")

keys, err := doc.Keys(false)
require.NoError(t, err)
Expand Down Expand Up @@ -1767,9 +1767,9 @@ func UpdateExamples(t *testing.T, db *mongo.Database) {
require.True(t, containsKey(keys, "item", nil))
require.True(t, containsKey(keys, "instock", nil))

instock, err := doc.Lookup("instock")
instock, err := doc.LookupErr("instock")
require.NoError(t, err)
require.Equal(t, instock.Value().MutableArray().Len(), 2)
require.Equal(t, instock.MutableArray().Len(), 2)

}

Expand Down
6 changes: 3 additions & 3 deletions mongo/change_stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TestChangeStream_firstStage(t *testing.T) {
doc := elem.MutableDocument()
require.Equal(t, 1, doc.Len())

_, err = doc.Lookup("$changeStream")
_, err = doc.LookupErr("$changeStream")
require.NoError(t, err)
}

Expand Down Expand Up @@ -121,10 +121,10 @@ func TestChangeStream_trackResumeToken(t *testing.T) {
err := changes.Decode(doc)
require.NoError(t, err)

id, err := doc.Lookup("_id")
id, err := doc.LookupErr("_id")
require.NoError(t, err)

require.Equal(t, id.Value().MutableDocument(), changes.(*changeStream).resumeToken)
require.Equal(t, id.MutableDocument(), changes.(*changeStream).resumeToken)
}
}

Expand Down
Loading

0 comments on commit ba9aede

Please sign in to comment.