From 6111341a3c36a596d9c1506fab2297e6fd36bffa Mon Sep 17 00:00:00 2001 From: Nikita Tokarchuk Date: Tue, 24 Mar 2020 21:26:28 +0100 Subject: [PATCH] Check for nil interface correctly --- mongox/base/getid.go | 3 ++- mongox/database/deleteone.go | 3 ++- mongox/query/compose.go | 3 ++- mongox/utils/isnil.go | 21 +++++++++++++++++++++ mongox/utils/isnil_test.go | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 mongox/utils/isnil.go create mode 100644 mongox/utils/isnil_test.go diff --git a/mongox/base/getid.go b/mongox/base/getid.go index 6209db6..f5f4bd8 100644 --- a/mongox/base/getid.go +++ b/mongox/base/getid.go @@ -6,6 +6,7 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "github.com/mainnika/mongox-go-driver/v2/mongox" + "github.com/mainnika/mongox-go-driver/v2/mongox/utils" ) // GetID returns source document id @@ -62,7 +63,7 @@ func getObjectOrPanic(source mongox.JSONBased) (id primitive.D) { func getInterfaceOrPanic(source mongox.InterfaceBased) (id interface{}) { id = source.GetID() - if id != nil { + if !utils.IsNil(id) { return id } diff --git a/mongox/database/deleteone.go b/mongox/database/deleteone.go index 95b360e..76462fb 100644 --- a/mongox/database/deleteone.go +++ b/mongox/database/deleteone.go @@ -10,6 +10,7 @@ import ( "github.com/mainnika/mongox-go-driver/v2/mongox" "github.com/mainnika/mongox-go-driver/v2/mongox/base" "github.com/mainnika/mongox-go-driver/v2/mongox/query" + "github.com/mainnika/mongox-go-driver/v2/mongox/utils" ) // DeleteOne removes a document from a database and then returns it into target @@ -22,7 +23,7 @@ func (d *Database) DeleteOne(target interface{}, filters ...interface{}) error { opts.Sort = composed.Sorter() - if target != nil { + if !utils.IsNil(target) { composed.And(primitive.M{"_id": base.GetID(target)}) } diff --git a/mongox/query/compose.go b/mongox/query/compose.go index afa5d3d..382f463 100644 --- a/mongox/query/compose.go +++ b/mongox/query/compose.go @@ -7,6 +7,7 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "github.com/mainnika/mongox-go-driver/v2/mongox/base/protection" + "github.com/mainnika/mongox-go-driver/v2/mongox/utils" ) // Compose is a function to compose filters into a single query @@ -26,7 +27,7 @@ func Compose(filters ...interface{}) *Query { // Push applies single filter to a query func Push(q *Query, f interface{}) bool { - if f == nil { + if utils.IsNil(f) { return true } diff --git a/mongox/utils/isnil.go b/mongox/utils/isnil.go new file mode 100644 index 0000000..9c32162 --- /dev/null +++ b/mongox/utils/isnil.go @@ -0,0 +1,21 @@ +package utils + +import ( + "unsafe" +) + +// IsNil function evaluates the interface value to nil +func IsNil(i interface{}) bool { + + type iface struct { + _ *interface{} + ptr unsafe.Pointer + } + + unpacked := (*iface)(unsafe.Pointer(&i)) + if unpacked.ptr == nil { + return true + } + + return *(*unsafe.Pointer)(unpacked.ptr) == nil +} diff --git a/mongox/utils/isnil_test.go b/mongox/utils/isnil_test.go new file mode 100644 index 0000000..a6d1ced --- /dev/null +++ b/mongox/utils/isnil_test.go @@ -0,0 +1,32 @@ +package utils + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsNil(t *testing.T) { + + testvalues := []struct { + i interface{} + isnil bool + }{ + {nil, true}, + {(*string)(nil), true}, + {([]string)(nil), true}, + {(map[string]string)(nil), true}, + {(func() bool)(nil), true}, + {(chan func() bool)(nil), true}, + {"", true}, + {0, true}, + {append(([]string)(nil), ""), false}, + {[]string{}, false}, + {1, false}, + {"1", false}, + } + + for _, tt := range testvalues { + assert.Equal(t, tt.isnil, IsNil(tt.i)) + } +}