Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xLEN-like commands have either incorrect or misleading return value types #854

Closed
rgohol opened this issue Mar 24, 2024 · 0 comments · Fixed by #873
Closed

xLEN-like commands have either incorrect or misleading return value types #854

rgohol opened this issue Mar 24, 2024 · 0 comments · Fixed by #873

Comments

@rgohol
Copy link

rgohol commented Mar 24, 2024

Checked with the following commands: strLen, hLen, hStrLen, but likely other len-returning commands may suffer from the same issue.

Actual behavior

All the commands above have return values of type Option[Long].
However, neither of them under any condition returns None.

Consider an example (expand):

import cats.effect.std.Console
import cats.effect.*
import dev.profunktor.redis4cats.*
import dev.profunktor.redis4cats.effect.Log.Stdout.given

object XLenApp extends IOApp.Simple:
  override def run: IO[Unit] =
    Redis[IO]
      .utf8(redisHost)
      .use: (redis: RedisCommands[IO, String, String]) =>
        for
          // INIT: make sure the DB is empty.
          _ <- redis.flushAll
          //
          // STRLEN command example
          //
          // Call STRLEN for a nonexistent key.
          strlen1 <- redis.strLen("string-key")
          _ <- Console[IO].println(
            s"""string result #1 (key does not exist):
               |  len: $strlen1
               |""".stripMargin
          )
          // Set the key to an empty string.
          _ <- redis.set("string-key", "")
          strlen2 <- redis.strLen("string-key")
          _ <- Console[IO].println(
            s"""string result #2 (key is set to an empty string):
               |  len: $strlen2
               |""".stripMargin
          )
          //
          // HLEN and HSTRLEN example
          //
          // Call HLEN and HSTRLEN for a nonexistent hash entity.
          hlen1 <- redis.hLen("hash-key")
          hstrlenA1 <- redis.hStrLen("hash-key", "hash-field-a")
          _ <- Console[IO].println(
            s"""hash result #1 (hash does not exist):
               |  hlen:     $hlen1
               |  hstrlenA: $hstrlenA1
               |""".stripMargin
          )
          // Create a new hash entity "hash-key" by setting "hash-field-a" to an empty value.
          // Note: "hash-field-b" still does not exist.
          _ <- redis.hSet("hash-key", "hash-field-a", "")
          hlen2 <- redis.hLen("hash-key")
          hstrlenA2 <- redis.hStrLen("hash-key", "hash-field-a")
          hstrlenB2 <- redis.hStrLen("hash-key", "hash-field-b")
          _ <- Console[IO].println(
            s"""hash result #2 (hash contains the 'hash-field-a' field only set to an empty string):
               |  hlen:     $hlen2
               |  hstrlenA: $hstrlenA2
               |  hstrlenB: $hstrlenB2
               |""".stripMargin
          )
        //
        yield ()
        end for

The example above emits the following output (expand):

string result #1 (key does not exist):
  len: Some(0)

string result #2 (key is set to an empty string):
  len: Some(0)

hash result #1 (hash does not exist):
  hlen:     Some(0)
  hstrlenA: Some(0)

hash result #2 (hash contains the 'hash-field-a' field only set to an empty string):
  hlen:     Some(1)
  hstrlenA: Some(0)
  hstrlenB: Some(0)

Notice that in all the cases return values from *Len commands are Some(...) and never None.

Expected behavior:

Either of two, actually:

  1. The commands should return None if a key they are asked about does not exist (preferrable, but...).
  2. If the former behavior is unfeasible, then their return value type is supposed to be just Long rather than Option[Long].

More details

According to both - the upstream library source code and Redis docs, p.2 might be the only feasible option though.

Here is an API definition for strlen in Lettuce:

    /**
     * Get the length of the value stored in a key.
     *
     * @param key the key.
     * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist.
     */
    RedisFuture<Long> strlen(K key);

And here is API docs in Redis:

RESP2/RESP3 Reply

Integer reply: the length of the string stored at key, or 0 when the key

Note, neither of them mentions anything about Nil or Null or anything that could support the None return value. Therefore, most likely Option does not make any sense out there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant