diff --git a/null.go b/null.go index d7fcbf2..bad6ac9 100644 --- a/null.go +++ b/null.go @@ -17,15 +17,14 @@ var jsonNull = []byte("null") // NullUUID implements the SQL driver.Scanner interface so // it can be used as a scan destination: // -// var u uuid.NullUUID -// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) -// ... -// if u.Valid { -// // use u.UUID -// } else { -// // NULL value -// } -// +// var u uuid.NullUUID +// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) +// ... +// if u.Valid { +// // use u.UUID +// } else { +// // NULL value +// } type NullUUID struct { UUID UUID Valid bool // Valid is true if UUID is not NULL @@ -116,3 +115,8 @@ func (nu *NullUUID) UnmarshalJSON(data []byte) error { nu.Valid = err == nil return err } + +// IsZero determine whether the value is zero. +func (nu NullUUID) IsZero() bool { + return !nu.Valid || nu.UUID.IsZero() +} diff --git a/null_test.go b/null_test.go index fe0fe8d..e76260e 100644 --- a/null_test.go +++ b/null_test.go @@ -212,3 +212,35 @@ func TestNullUUIDUnmarshalJSON(t *testing.T) { t.Errorf("expected nil when unmarshalling null, got %s", err) } } + +func TestNullUUIDIsZero(t *testing.T) { + tests := []struct { + nullUUID NullUUID + expected bool + }{ + { + nullUUID: NullUUID{}, + expected: true, + }, + { + nullUUID: NullUUID{ + Valid: true, + UUID: UUID{}, + }, + expected: true, + }, + { + nullUUID: NullUUID{ + Valid: true, + UUID: New(), + }, + expected: false, + }, + } + + for _, test := range tests { + if test.nullUUID.IsZero() != test.expected { + t.Errorf("expected %t, got %t", test.expected, test.nullUUID.IsZero()) + } + } +} diff --git a/uuid.go b/uuid.go index dc75cee..abcdb1a 100644 --- a/uuid.go +++ b/uuid.go @@ -52,7 +52,7 @@ var ( ErrInvalidBracketedFormat = errors.New("invalid bracketed UUID format") ) -type URNPrefixError struct { prefix string } +type URNPrefixError struct{ prefix string } func (e URNPrefixError) Error() string { return fmt.Sprintf("invalid urn prefix: %q", e.prefix) @@ -215,10 +215,12 @@ func Must(uuid UUID, err error) UUID { } // Validate returns an error if s is not a properly formatted UUID in one of the following formats: -// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} +// +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} +// // It returns an error if the format is invalid, otherwise nil. func Validate(s string) error { switch len(s) { @@ -315,6 +317,11 @@ func (uuid UUID) Version() Version { return Version(uuid[6] >> 4) } +// IsZero determine whether the value is zero. +func (uuid UUID) IsZero() bool { + return uuid == Nil +} + func (v Version) String() string { if v > 15 { return fmt.Sprintf("BAD_VERSION_%d", v) @@ -391,3 +398,8 @@ func (uuids UUIDs) Strings() []string { } return uuidStrs } + +// IsZero determine whether the value is zero. +func (uuids UUIDs) IsZero() bool { + return len(uuids) == 0 +} diff --git a/uuid_test.go b/uuid_test.go index 906ecbe..1ccdea1 100644 --- a/uuid_test.go +++ b/uuid_test.go @@ -928,3 +928,47 @@ func TestVersion7MonotonicityStrict(t *testing.T) { u1 = u2 } } + +func TestUUIDIsZero(t *testing.T) { + tests := []struct { + uuid UUID + expected bool + }{ + { + uuid: UUID{}, + expected: true, + }, + { + uuid: New(), + expected: false, + }, + } + + for _, test := range tests { + if test.uuid.IsZero() != test.expected { + t.Errorf("expected %t, got %t", test.expected, test.uuid.IsZero()) + } + } +} + +func TestUUIDsIsZero(t *testing.T) { + tests := []struct { + uuids UUIDs + expected bool + }{ + { + uuids: UUIDs{}, + expected: true, + }, + { + uuids: UUIDs{New()}, + expected: false, + }, + } + + for _, test := range tests { + if test.uuids.IsZero() != test.expected { + t.Errorf("expected %t, got %t", test.expected, test.uuids.IsZero()) + } + } +}