diff --git a/string.go b/string.go index 769c434..87a0137 100644 --- a/string.go +++ b/string.go @@ -473,6 +473,34 @@ func execDecrBy(db *DB, args [][]byte) redis.Reply { return reply.MakeIntReply(-delta) } +// execStrLen returns len of string value bound to the given key +func execStrLen(db *DB, args [][]byte) redis.Reply { + key := string(args[0]) + bytes, err := db.getAsString(key) + if err != nil { + return err + } + if bytes == nil { + return reply.MakeIntReply(0) + } + return reply.MakeIntReply(int64(len(bytes))) +} + +// execAppend sets string value and time to live to the given key +func execAppend(db *DB, args [][]byte) redis.Reply { + key := string(args[0]) + bytes, err := db.getAsString(key) + if err != nil { + return err + } + bytes = append(bytes, args[1]...) + db.PutEntity(key, &DataEntity{ + Data: bytes, + }) + db.AddAof(makeAofCmd("append", args)) + return reply.MakeIntReply(int64(len(bytes))) +} + func init() { RegisterCommand("Set", execSet, writeFirstKey, rollbackFirstKey, -3) RegisterCommand("SetNx", execSetNX, writeFirstKey, rollbackFirstKey, 3) @@ -488,4 +516,6 @@ func init() { RegisterCommand("IncrByFloat", execIncrByFloat, writeFirstKey, rollbackFirstKey, 3) RegisterCommand("Decr", execDecr, writeFirstKey, rollbackFirstKey, 2) RegisterCommand("DecrBy", execDecrBy, writeFirstKey, rollbackFirstKey, 3) + RegisterCommand("StrLen", execStrLen, readFirstKey, nil, 2) + RegisterCommand("Append", execAppend, writeFirstKey, rollbackFirstKey, 3) } diff --git a/string_test.go b/string_test.go index bf3d9cb..90a447b 100644 --- a/string_test.go +++ b/string_test.go @@ -315,3 +315,60 @@ func TestMSetNX(t *testing.T) { result = testDB.Exec(nil, utils.ToCmdLine2("MSETNX", args[0:4]...)) asserts.AssertIntReply(t, result, 0) } + +func TestStrLen(t *testing.T) { + testDB.Flush() + key := utils.RandString(10) + testDB.Exec(nil, utils.ToCmdLine2("SET", key, key)) + + actual := testDB.Exec(nil, utils.ToCmdLine("StrLen", key)) + len, ok := actual.(*reply.IntReply) + if !ok { + t.Errorf("expect int bulk reply, get: %s", string(actual.ToBytes())) + return + } + asserts.AssertIntReply(t, len, 10) +} + +func TestStrLen_KeyNotExist(t *testing.T) { + testDB.Flush() + key := utils.RandString(10) + + actual := testDB.Exec(nil, utils.ToCmdLine("StrLen", key)) + result, ok := actual.(*reply.IntReply) + if !ok { + t.Errorf("expect null bulk reply, get: %s", string(actual.ToBytes())) + return + } + + asserts.AssertIntReply(t, result, 0) +} + +func TestAppend_KeyExist(t *testing.T) { + testDB.Flush() + key := utils.RandString(10) + key2 := utils.RandString(10) + testDB.Exec(nil, utils.ToCmdLine2("SET", key, key)) + + actual := testDB.Exec(nil, utils.ToCmdLine("Append", key, key2)) + val, ok := actual.(*reply.IntReply) + if !ok { + t.Errorf("expect nil bulk reply, get: %s", string(actual.ToBytes())) + return + } + asserts.AssertIntReply(t, val, len(key)*2) +} + +func TestAppend_KeyNotExist(t *testing.T) { + testDB.Flush() + key := utils.RandString(10) + + actual := testDB.Exec(nil, utils.ToCmdLine("Append", key, key)) + val, ok := actual.(*reply.IntReply) + if !ok { + t.Errorf("expect nil bulk reply, get: %s", string(actual.ToBytes())) + return + } + asserts.AssertIntReply(t, val, len(key)) +} +