Current section

Files

Jump to
radish src radish.gleam
Raw

src/radish.gleam

import gleam/list
import gleam/float
import gleam/option
import gleam/result
import radish/tcp
import radish/error
import radish/resp
import radish/command
import radish/decoder.{decode}
pub fn connect(host: String, port: Int) {
tcp.connect(host, port, 1024)
|> result.map(fn(socket) {
command.hello(3)
|> execute(socket, _)
socket
})
}
pub fn get(socket, key: String) {
command.get(key)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.SimpleString(str) | resp.BulkString(str) -> Ok(str)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
pub fn set(socket, key: String, value: String, ttl: option.Option(Int)) {
case ttl {
option.None -> command.set(key, value, [])
option.Some(ttl) -> command.set(key, value, [command.PX(ttl)])
}
command.set(key, value, [])
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.SimpleString(str) | resp.BulkString(str) -> Ok(str)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
/// only sets a key if it does not already exist
pub fn set_new(socket, key: String, value: String, ttl: option.Option(Int)) {
case ttl {
option.None -> command.set(key, value, [command.NX])
option.Some(ttl) -> command.set(key, value, [command.NX, command.PX(ttl)])
}
command.set(key, value, [command.NX])
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.SimpleString(str) | resp.BulkString(str) -> Ok(str)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
/// only sets a key if it already exists, returns the old value
pub fn set_existing(socket, key: String, value: String, ttl: option.Option(Int)) {
case ttl {
option.None -> command.set(key, value, [command.XX, command.GET])
option.Some(ttl) ->
command.set(key, value, [command.XX, command.GET, command.PX(ttl)])
}
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.SimpleString(str) | resp.BulkString(str) -> Ok(str)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
pub fn del(socket, keys: List(String)) {
command.del(keys)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.Integer(n) -> Ok(n)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
/// adds 1 to an integer and returns the new value
pub fn incr(socket, key: String) {
command.incr(key)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.Integer(new) -> Ok(new)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
/// adds an arbitrary value to an integer and returns the new value
pub fn incr_by(socket, key: String, value: Int) {
command.incr_by(key, value)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.Integer(new) -> Ok(new)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
/// adds an arbitrary float value to a number and returns the new value
pub fn incr_by_float(socket, key: String, value: Float) {
command.incr_by_float(key, value)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.BulkString(new) ->
float.parse(new)
|> result.replace_error(error.RESPError)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
/// subtracts 1 from an integer and returns the new value
pub fn decr(socket, key: String) {
command.incr(key)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.Integer(new) -> Ok(new)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
/// subtracts an arbitrary value from an integer and returns the new value
pub fn decr_by(socket, key: String, value: Int) {
command.incr_by(key, value)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.Integer(new) -> Ok(new)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
pub fn exists(socket, keys: List(String)) {
command.exists(keys)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.Integer(n) -> Ok(n)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
pub fn keys(socket, pattern: String) {
command.keys(pattern)
|> execute(socket, _)
|> result.map(fn(value) {
case value {
resp.Array(array) ->
list.try_map(
array,
fn(item) {
case item {
resp.BulkString(value) -> Ok(value)
_ -> Error(error.RESPError)
}
},
)
_ -> Error(error.RESPError)
}
})
|> result.flatten
}
fn execute(socket, cmd: BitArray) {
cmd
|> tcp.execute(socket, _, 1024)
|> result.map_error(fn(tcp_error) { error.TCPError(tcp_error) })
|> result.map(decode)
|> result.flatten
|> result.map(fn(value) {
case value {
resp.SimpleError(error) | resp.BulkError(error) ->
Error(error.ServerError(error))
value -> Ok(value)
}
})
|> result.flatten
}