Skip to content

Commit

Permalink
expiry with options
Browse files Browse the repository at this point in the history
  • Loading branch information
pascaldekloe committed Mar 11, 2024
1 parent c7a53ea commit b0fa175
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
36 changes: 35 additions & 1 deletion command.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"time"
)

// Flags For SETOptions
// Flags For SETOptions.
const (
// NX only sets the key if it does not already exist.
NX = 1 << iota
Expand All @@ -18,6 +18,14 @@ const (
PX
)

// EXPIRE flags include NX And XX.
const (
// GT sets expiry only when the new expiry is greater than current one.
GT = 32 << iota
// LT sets expiry only when the new expiry is less than current one.
LT
)

// SETOptions are extra arguments for the SET command.
type SETOptions struct {
// Composotion of NX, XX, EX or PX. The combinations
Expand Down Expand Up @@ -48,6 +56,32 @@ func (c *Client[Key, Value]) FLUSHDB(async bool) error {
return c.commandOK(r)
}

// EXPIRE executes <https://redis.io/commands/expire>.
// Flags can be any of NX, XX, GT or LT.
func (c *Client[Key, Value]) EXPIRE(k Key, seconds int64, flags uint) (bool, error) {
if unknown := flags &^ (NX | XX | GT | LT); unknown != 0 {
return false, errors.New("redis: unknown EXPIRE flags")
}

var n int64
var err error
switch flags {
case 0:
n, err = c.commandInteger(requestWithStringAndDecimal("*3\r\n$6\r\nEXPIRE\r\n$", k, seconds))
case NX:
n, err = c.commandInteger(requestWithStringAndDecimalAndString("*4\r\n$6\r\nEXPIRE\r\n$", k, seconds, "NX"))
case XX:
n, err = c.commandInteger(requestWithStringAndDecimalAndString("*4\r\n$6\r\nEXPIRE\r\n$", k, seconds, "XX"))
case GT:
n, err = c.commandInteger(requestWithStringAndDecimalAndString("*4\r\n$6\r\nEXPIRE\r\n$", k, seconds, "GT"))
case LT:
n, err = c.commandInteger(requestWithStringAndDecimalAndString("*4\r\n$6\r\nEXPIRE\r\n$", k, seconds, "LT"))
default:
return false, errors.New("redis: multiple EXPIRE flags denied")
}
return n != 0, err
}

// FLUSHALL executes <https://redis.io/commands/flushall>.
func (c *Client[Key, Value]) FLUSHALL(async bool) error {
var r *request
Expand Down
48 changes: 48 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -670,3 +670,51 @@ func TestHashAbsent(t *testing.T) {
t.Errorf("HDEL %q got true, want false", key)
}
}

func TestExpiry(t *testing.T) {
t.Parallel()
key := randomKey("test-key")

ok, err := testClient.EXPIRE(key, 2, 0)
if err != nil {
t.Errorf("EXPIRE %q 2 error: %s", key, err)
} else if ok {
t.Errorf("EXPIRE %q 2 got OK on non-existent key", key)
}
_, err = testClient.SADD(key, "foo")
if err != nil {
t.Errorf(`SADD %q "foo" error: %s`, key, err)
}
ok, err = testClient.EXPIRE(key, 2, 0)
if err != nil {
t.Errorf("EXPIRE %q 2 error: %s", key, err)
} else if !ok {
t.Errorf("EXPIRE %q 2 got not OK on existent key", key)
}

ok, err = testClient.EXPIRE(key, 2, NX)
if err != nil {
t.Errorf("EXPIRE %q 2 NX error: %s", key, err)
} else if ok {
t.Errorf("EXPIRE %q 2 NX got OK with existing expiry", key)
}
ok, err = testClient.EXPIRE(key, 2, XX)
if err != nil {
t.Errorf("EXPIRE %q 2 XX error: %s", key, err)
} else if !ok {
t.Errorf("EXPIRE %q 2 XX got not OK with existing expiry", key)
}

ok, err = testClient.EXPIRE(key, 99, LT)
if err != nil {
t.Errorf("EXPIRE %q 99 LT error: %s", key, err)
} else if ok {
t.Errorf("EXPIRE %q 99 LT got OK on 2 second expiry", key)
}
ok, err = testClient.EXPIRE(key, 99, GT)
if err != nil {
t.Errorf("EXPIRE %q 99 GT error: %s", key, err)
} else if !ok {
t.Errorf("EXPIRE %q 99 GT got not OK on 2 second expiry", key)
}
}

0 comments on commit b0fa175

Please sign in to comment.