diff --git a/src/commands/cmd_string.cc b/src/commands/cmd_string.cc index 3bf99559382..b32d9db3837 100644 --- a/src/commands/cmd_string.cc +++ b/src/commands/cmd_string.cc @@ -559,10 +559,8 @@ class CommandCAS : public Commander { CommandParser parser(args, 4); std::string_view flag; while (parser.Good()) { - if (parser.EatEqICaseFlag("EX", flag)) { - ttl_ = GET_OR_RET(parser.TakeInt(TTL_RANGE)) * 1000; - } else if (parser.EatEqICaseFlag("PX", flag)) { - ttl_ = GET_OR_RET(parser.TakeInt(TTL_RANGE)); + if (auto v = GET_OR_RET(ParseTTL(parser, flag))) { + ttl_ = *v; } else { return parser.InvalidSyntax(); } diff --git a/tests/gocase/unit/type/strings/strings_test.go b/tests/gocase/unit/type/strings/strings_test.go index 1d5cea1b46e..f255228d18f 100644 --- a/tests/gocase/unit/type/strings/strings_test.go +++ b/tests/gocase/unit/type/strings/strings_test.go @@ -718,6 +718,13 @@ func TestString(t *testing.T) { require.Equal(t, "", rdb.Get(ctx, "cas_key").Val()) }) + t.Run("CAS expire EX option", func(t *testing.T) { + require.NoError(t, rdb.Del(ctx, "cas_key").Err()) + require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) + require.EqualValues(t, 1, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "ex", 10).Val()) + util.BetweenValues(t, rdb.TTL(ctx, "cas_key").Val(), 5*time.Second, 10*time.Second) + }) + t.Run("CAS expire Duplicate EX option", func(t *testing.T) { require.NoError(t, rdb.Del(ctx, "cas_key").Err()) require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) @@ -725,6 +732,13 @@ func TestString(t *testing.T) { util.BetweenValues(t, rdb.TTL(ctx, "cas_key").Val(), 5*time.Second, 10*time.Second) }) + t.Run("CAS expire PX option", func(t *testing.T) { + require.NoError(t, rdb.Del(ctx, "cas_key").Err()) + require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) + require.EqualValues(t, 1, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "px", 10000).Val()) + util.BetweenValues(t, rdb.TTL(ctx, "cas_key").Val(), 5*time.Second, 10*time.Second) + }) + t.Run("CAS expire Duplicate PX option", func(t *testing.T) { require.NoError(t, rdb.Del(ctx, "cas_key").Err()) require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) @@ -732,12 +746,45 @@ func TestString(t *testing.T) { util.BetweenValues(t, rdb.TTL(ctx, "cas_key").Val(), 5*time.Second, 10*time.Second) }) - t.Run("CAS expire PX option and EX option exist at the same time", func(t *testing.T) { + t.Run("CAS expire EXAT option", func(t *testing.T) { + require.NoError(t, rdb.Del(ctx, "cas_key").Err()) + require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) + require.NoError(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "exat", time.Now().Add(10*time.Second).Unix()).Err()) + util.BetweenValues(t, rdb.TTL(ctx, "cas_key").Val(), 5*time.Second, 10*time.Second) + }) + + t.Run("CAS Duplicate EXAT option", func(t *testing.T) { + require.NoError(t, rdb.Del(ctx, "cas_key").Err()) + require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) + require.NoError(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "exat", time.Now().Add(100*time.Second).Unix(), "exat", time.Now().Add(10*time.Second).Unix()).Err()) + util.BetweenValues(t, rdb.TTL(ctx, "cas_key").Val(), 5*time.Second, 10*time.Second) + }) + + t.Run("CAS expire PXAT option", func(t *testing.T) { + require.NoError(t, rdb.Del(ctx, "cas_key").Err()) + require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) + require.NoError(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "pxat", time.Now().Add(10*time.Second).UnixMilli()).Err()) + util.BetweenValues(t, rdb.TTL(ctx, "cas_key").Val(), 5*time.Second, 10*time.Second) + }) + + t.Run("CAS Duplicate PXAT option", func(t *testing.T) { + require.NoError(t, rdb.Del(ctx, "cas_key").Err()) + require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) + require.NoError(t, rdb.Do(ctx, "cas", "cas_key", "123", "234", "pxat", time.Now().Add(100*time.Second).UnixMilli(), "pxat", time.Now().Add(10*time.Second).UnixMilli()).Err()) + util.BetweenValues(t, rdb.TTL(ctx, "cas_key").Val(), 5*time.Second, 10*time.Second) + }) + + t.Run("CAS expire mutually exclusive options exist at the same time", func(t *testing.T) { require.NoError(t, rdb.Del(ctx, "cas_key").Err()) require.NoError(t, rdb.Set(ctx, "cas_key", "123", 0).Err()) require.ErrorContains(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "ex", 100, "px", 100000).Err(), "syntax error") require.ErrorContains(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "ex", 100, "ex", 10, "px", 10000).Err(), "syntax error") require.ErrorContains(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "px", 10000, "ex", 100, "ex", 10, "px", 10000).Err(), "syntax error") + require.ErrorContains(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "ex", 100, "exat", 100000).Err(), "syntax error") + require.ErrorContains(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "ex", 100, "pxat", 100000).Err(), "syntax error") + require.ErrorContains(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "px", 100, "exat", 100000).Err(), "syntax error") + require.ErrorContains(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "px", 100, "pxat", 100000).Err(), "syntax error") + require.ErrorContains(t, rdb.Do(ctx, "CAS", "cas_key", "123", "234", "exat", 100, "pxat", 100000).Err(), "syntax error") }) t.Run("CAD normal case", func(t *testing.T) {