Skip to content

Commit

Permalink
Add EXPIRETIME command (#356)
Browse files Browse the repository at this point in the history
* Add EXPIRETIME command

Redis documentation: https://redis.io/commands/expiretime/

Closes: #294

Signed-off-by: Wojciech Szarański <wojciech.szaranski@gmail.com>

* two more testcases

---------

Signed-off-by: Wojciech Szarański <wojciech.szaranski@gmail.com>
Co-authored-by: Wojciech Szarański <wojciech.szaranski@gmail.com>
Co-authored-by: Harmen <alicebob@lijzij.de>
  • Loading branch information
3 people committed Mar 6, 2024
1 parent f96a5fa commit 47eba53
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 0 deletions.
45 changes: 45 additions & 0 deletions cmd_generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ import (
"github.com/alicebob/miniredis/v2/server"
)

const (
// expiretimeReplyNoExpiration is returned by [Miniredis.cmdExpireTime] if the key exists but has no associated expiration time
expiretimeReplyNoExpiration = -1
// expiretimeReplyMissingKey is returned by [Miniredis.cmdExpireTime] if the key does not exist
expiretimeReplyMissingKey = -2
)

// commandsGeneric handles EXPIRE, TTL, PERSIST, &c.
func commandsGeneric(m *Miniredis) {
m.srv.Register("COPY", m.cmdCopy)
Expand All @@ -20,6 +27,7 @@ func commandsGeneric(m *Miniredis) {
m.srv.Register("EXISTS", m.cmdExists)
m.srv.Register("EXPIRE", makeCmdExpire(m, false, time.Second))
m.srv.Register("EXPIREAT", makeCmdExpire(m, true, time.Second))
m.srv.Register("EXPIRETIME", m.cmdExpireTime)
m.srv.Register("KEYS", m.cmdKeys)
// MIGRATE
m.srv.Register("MOVE", m.cmdMove)
Expand Down Expand Up @@ -145,6 +153,43 @@ func makeCmdExpire(m *Miniredis, unix bool, d time.Duration) func(*server.Peer,
}
}

// cmdExpireTime returns the absolute Unix timestamp (since January 1, 1970) in seconds at which the given key will expire.
// See [redis documentation].
//
// [redis documentation]: https://redis.io/commands/expiretime/
func (m *Miniredis) cmdExpireTime(c *server.Peer, cmd string, args []string) {
if len(args) != 1 {
setDirty(c)
c.WriteError(errWrongNumber(cmd))
return
}

if !m.handleAuth(c) {
return
}
if m.checkPubsub(c, cmd) {
return
}

key := args[0]
withTx(m, c, func(c *server.Peer, ctx *connCtx) {
db := m.db(ctx.selectedDB)

if _, ok := db.keys[key]; !ok {
c.WriteInt(expiretimeReplyMissingKey)
return
}

ttl, ok := db.ttl[key]
if !ok {
c.WriteInt(expiretimeReplyNoExpiration)
return
}

c.WriteInt(int(m.effectiveNow().Add(ttl).Unix()))
})
}

// TOUCH
func (m *Miniredis) cmdTouch(c *server.Peer, cmd string, args []string) {
if !m.handleAuth(c) {
Expand Down
26 changes: 26 additions & 0 deletions cmd_generic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,32 @@ func TestType(t *testing.T) {
})
}

func TestExpireTime(t *testing.T) {
s, err := Run()
ok(t, err)
defer s.Close()
c, err := proto.Dial(s.Addr())
ok(t, err)
defer c.Close()

t.Run("nosuch", func(t *testing.T) {
mustDo(t, c, "EXPIRETIME", "nosuch", proto.Int(-2))
})

t.Run("noexpire", func(t *testing.T) {
s.Set("noexpire", "")
mustDo(t, c, "EXPIRETIME", "noexpire", proto.Int(-1))
})

t.Run("", func(t *testing.T) {
s.Set("foo", "")
must1(t, c, "EXPIREAT", "foo", "10413792000") // Mon Jan 01 2300 00:00:00 GMT+0000
mustDo(t, c, "EXPIRETIME", "foo",
proto.Int(10413792000),
)
})
}

func TestExists(t *testing.T) {
s, err := Run()
ok(t, err)
Expand Down
8 changes: 8 additions & 0 deletions integration/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,18 @@ func TestStringSetnx(t *testing.T) {
func TestExpire(t *testing.T) {
skip(t)
testRaw(t, func(c *client) {
c.Do("EXPIRETIME", "missing")

c.Do("SET", "foo", "bar")
c.Do("EXPIRETIME", "foo")

c.Do("EXPIRE", "foo", "12")
c.Do("TTL", "foo")
c.Do("TTL", "nosuch")
c.Do("SET", "foo", "bar")
c.Do("PEXPIRE", "foo", "999999")
c.Do("EXPIREAT", "foo", "2234567890")
c.Do("EXPIRETIME", "foo")
c.Do("PEXPIREAT", "foo", "2234567890000")
// c.Do("PTTL", "foo")
c.Do("PTTL", "nosuch")
Expand Down Expand Up @@ -221,6 +226,9 @@ func TestExpire(t *testing.T) {
c.Error("wrong number", "PEXPIREAT")
c.Error("wrong number", "PTTL")
c.Error("wrong number", "PTTL", "too", "many")

c.Error("wrong number", "EXPIRETIME")
c.Error("wrong number", "EXPIRETIME", "too", "many")
})
}

Expand Down

0 comments on commit 47eba53

Please sign in to comment.