Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 4.0.0 - 2025-08-15

- Update `lpop` and `rpop` to return string arrays. Previously they would error if a
count higher than 1 was provided.

## 3.0.0 - 2025-06-29

- Update `mug` and add support for IPv6 connections.
Expand Down
2 changes: 1 addition & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "valkyrie"
version = "3.0.0"
version = "4.0.0"

description = "A Gleam client for Valkey, KeyDB, Redis, Dragonfly and other Redis-compatible databases."
gleam = ">= 1.11.0"
Expand Down
31 changes: 5 additions & 26 deletions src/valkyrie.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ fn expect_bulk_string_array(
)
}
})
[resp.Null] -> Error(NotFound)
_ -> Error(RespError(resp.error_string(expected: "array", got: value)))
}
}
Expand Down Expand Up @@ -1593,21 +1594,10 @@ pub fn lpop(
key: String,
count: Int,
timeout: Int,
) -> Result(String, Error) {
) -> Result(List(String), Error) {
["LPOP", key, int.to_string(count)]
|> execute(conn, _, timeout)
|> result.try(fn(value) {
case value {
// When count is provided, Redis returns an array
[resp.Array([resp.BulkString(str)])] -> Ok(str)
[resp.Array([])] -> Error(NotFound)
[resp.Null] -> Error(NotFound)
_ ->
Error(
RespError(resp.error_string(expected: "string or array", got: value)),
)
}
})
|> result.try(expect_bulk_string_array)
}

/// Remove and return elements from the right (tail) of a list.
Expand All @@ -1620,21 +1610,10 @@ pub fn rpop(
key: String,
count: Int,
timeout: Int,
) -> Result(String, Error) {
) -> Result(List(String), Error) {
["RPOP", key, int.to_string(count)]
|> execute(conn, _, timeout)
|> result.try(fn(value) {
case value {
// When count is provided, Redis returns an array
[resp.Array([resp.BulkString(str)])] -> Ok(str)
[resp.Array([])] -> Error(NotFound)
[resp.Null] -> Error(NotFound)
_ ->
Error(
RespError(resp.error_string(expected: "string or array", got: value)),
)
}
})
|> result.try(expect_bulk_string_array)
}

/// Get an element from a list by its index.
Expand Down
31 changes: 29 additions & 2 deletions test/valkyrie_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -822,11 +822,38 @@ pub fn lpop_rpop_test() {

let assert Ok(_) = valkyrie.rpush(conn, "test:pop", ["a", "b", "c"], 1000)

let assert Ok("a") = valkyrie.lpop(conn, "test:pop", 1, 1000)
let assert Ok("c") = valkyrie.rpop(conn, "test:pop", 1, 1000)
let assert Ok(["a"]) = valkyrie.lpop(conn, "test:pop", 1, 1000)
let assert Ok(["c"]) = valkyrie.rpop(conn, "test:pop", 1, 1000)
let assert Ok(1) = valkyrie.llen(conn, "test:pop", 1000)
}

pub fn lpop_rpop_multiple_test() {
use conn <- get_test_conn()

let assert Ok(_) =
valkyrie.rpush(conn, "test:pop_multiple", ["a", "b", "c", "d", "e"], 1000)

// Pop multiple from left
let assert Ok(["a", "b"]) = valkyrie.lpop(conn, "test:pop_multiple", 2, 1000)
let assert Ok(3) = valkyrie.llen(conn, "test:pop_multiple", 1000)

// Pop multiple from right
let assert Ok(["e", "d"]) = valkyrie.rpop(conn, "test:pop_multiple", 2, 1000)
let assert Ok(1) = valkyrie.llen(conn, "test:pop_multiple", 1000)

let assert Ok(["c"]) = valkyrie.lpop(conn, "test:pop_multiple", 3, 1000)
let assert Ok(0) = valkyrie.llen(conn, "test:pop_multiple", 1000)

let assert Error(valkyrie.NotFound) =
valkyrie.lpop(conn, "test:pop_multiple", 1, 1000)
let assert Error(valkyrie.NotFound) =
valkyrie.lpop(conn, "test:pop_multiple", 2, 1000)
let assert Error(valkyrie.NotFound) =
valkyrie.rpop(conn, "test:pop_multiple", 1, 1000)
let assert Error(valkyrie.NotFound) =
valkyrie.rpop(conn, "test:pop_multiple", 2, 1000)
}

pub fn lindex_test() {
use conn <- get_test_conn()

Expand Down