diff --git a/schema/schema.go b/schema/schema.go index b50809a..0987085 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -10,11 +10,21 @@ import ( ) var ( - NilError = errors.New("Key requested returned a nil reply") + NilError = errors.New("user error: Key requested returned a nil reply") TypeError = errors.New("Invalid type, expected pointer to struct") IdFieldError = errors.New("Expected Id field of type int64 on struct") ) +type UniqueError string + +func (e UniqueError) Error() string { + return string(e) +} + +func newUniqueError(field string, value interface{}) UniqueError { + return UniqueError(fmt.Sprintf("user error: expected unique `%s`:`%v`", field, value)) +} + /* logic: input: key, *struct @@ -56,14 +66,20 @@ func Put(db *redis.Client, k *Key, s interface{}) (*Key, error) { for _, o := range prep.unique { uk := k.Unique(o.name, fmt.Sprintf("%v", *o.value)) var reply *redis.Reply - reply, e = db.Call("SETNX", uk, k.Id()) + reply, e = db.Call("GET", uk) if e != nil { goto Error } - if reply.Elem.Int() != 1 { - e = errors.New(fmt.Sprintf("expected unique `%s`:`%v`", o.name, o.value)) + if !reply.Nil() && reply.Elem.Int64() != k.Id() { + e = newUniqueError(o.name, *o.value) + goto Error + } + + reply, e = db.Call("SET", uk, k.Id()) + + if e != nil { goto Error } diff --git a/schema/schema_test.go b/schema/schema_test.go index 408b14a..297a51a 100644 --- a/schema/schema_test.go +++ b/schema/schema_test.go @@ -9,12 +9,68 @@ import ( var db *redis.Client func init() { + redis.MaxConnections = 1 db = redis.NewClient("tcp:localhost:6379", 9, "") } +type S1 struct { + Id int64 `redis:"id"` +} + +type User struct { + Id int64 `redis:"id"` + Username string `redis:"username,unique,index"` + Email string `redis:"email,unique"` +} + +type putTest struct { + s interface{} + k *Key + e error +} + +var putTests = [][]putTest{ + {{&S1{1}, NewKey("s1", 1), nil}}, + {{S1{1}, NewKey("s1", 1), TypeError}}, + {{&S1{1}, NewKey("s1", 1), nil}, {&S1{2}, NewKey("s1", 2), nil}}, + {{&S1{1}, NewKey("s1", 1), nil}, {&S1{1}, NewKey("s1", 1), nil}}, + {{&User{1, "foo", "foo@foo.com"}, NewKey("user", 1), nil}}, + { + {&User{1, "foo", "foo@foo.com"}, NewKey("user", 1), nil}, + {&User{1, "foo", "foo@foo.com"}, NewKey("user", 1), nil}, + }, + { + {&User{1, "foo", "foo@foo.com"}, NewKey("user", 1), nil}, + {&User{2, "foo", "foo@foo.com"}, NewKey("user", 2), newUniqueError("username", "foo")}, + }, + { + {&User{1, "foo", "foo@foo.com"}, NewKey("user", 1), nil}, + {&User{2, "bar", "foo@foo.com"}, NewKey("user", 2), newUniqueError("email", "foo@foo.com")}, + }, + { + {&User{1, "foo", "foo@foo.com"}, NewKey("user", 1), nil}, + {&User{2, "bar", "bar@foo.com"}, NewKey("user", 2), nil}, + }, +} + func TestPut(t *testing.T) { - _, e := db.Call("FLUSHDB") - if e != nil { - t.Fatalf(e.Error()) + for _, tests := range putTests { + _, e := db.Call("FLUSHDB") + + if e != nil { + t.Fatalf(e.Error()) + } + + for _, o := range tests { + _, e := Put(db, o.k, o.s) + + if e != o.e { + if e == nil { + t.Fatalf("expected `%s`, got e: nil", o.e.Error()) + } else { + t.Fatal(e.Error()) + } + } + } } }