An LFE Redis Client Library
Dependences ↟
You will need the following installed on your system:
- Erlang
- Redis
- rebar3
Installtion and Setup ↟
Here's what you need to do:
$ git clone https://github.com/lfex/ledis.git
$ cd ledis
$ make compile
At this point, you will be able to run an LFE REPL (shell):
$ make repl
If you don't have access to a Rdis deployment, you can always do this:
$ docker run --rm -p 6379:6379 redis:latest
Usage ↟
To use ledis from the shell, just do this:
$ make repl
Note that, under the hood, this will activate the "dev" profile, so LFE and some developer rebar3 LFE plugins will be downloaded the first time it is run.
Erlang/OTP 24 [erts-12.0.2] [source] [64-bit] [smp:4:4] ...
..-~.~_~---..
( \\ ) | A Lisp-2+ on the Erlang VM
|`-.._/_\\_.-': | Type (help) for usage info.
| g |_ \ |
| n | | | Docs: http://docs.lfe.io/
| a / / | Source: http://github.com/lfe/lfe
\ l |_/ |
\ r / | LFE v2.0.1 (abort with ^G)
`-E___.-'
lfe>
lfe> (ledis:start-link)
true
lfe> (ledis:get 'foo)
#(ok undefined)
lfe> (ledis:set 'foo 'bar)
#(ok #"OK")
lfe> (ledis:get 'foo)
#(ok #"bar")
You may also provide an option to convert all results to string values:
lfe> (ledis:set 'foo 'bar '(#(return-type string)))
#(ok "OK")
lfe> (ledis:get 'foo '(#(return-type string)))
#(ok "bar")
If you would like to receive string values by default, simply update either
your project's lfe.config
or your ~/.lfe/lfe.config
file with the
following:
#(ledis
(#(client-process-name ledis-client)
#(return-type string)))
Difference from Redis CLI ↟
Since LFE is a fixed-arity language, a few differences exist between ledis and the Redis CLI. These usually are for the following scenarios:
- Optional command arguments which have been converted to LFE as options (using proplists).
- Some Redis commands conflict with LFE functions/macros, and these have been renamed.
- Some variable arity commands are converted to single-arity in LFE where the single argument is a list.
Functions which are different in these ways have been listed below with sample usage.
bitcount
↟
lfe> (ledis:bitcount 'foo)
#(ok #"10")
lfe> (ledis:bitcount 'foo '(#(start 2) #(end 4)))
#(ok #"4")
bitop
↟
lfe> (ledis:set 'key1 "foobar")
#(ok #"OK")
lfe> (ledis:set 'key2 "absdef")
#(ok #"OK")
lfe> (ledis:bitop 'AND 'dest '(key1 key2))
#(ok #"6")
lfe> (ledis:get 'dest)
#(ok #"`bc`ab")
bitpos
↟
lfe> (ledis:set 'mykey #b(#xff #xf0 #x00))
#(ok #"OK")
lfe> (ledis:bitpos 'mykey 0)
#(ok #"12")
lfe> (ledis:set 'mykey #b(#x00 #xff #xf0))
#(ok #"OK")
lfe> (ledis:bitpos 'mykey 1 '(#(start 1)))
#(ok #"8")
lfe> (ledis:bitpos 'mykey 1 '(#(start 2)))
#(ok #"16")
lfe> (ledis:set 'mykey #b(#x00 #x00 #x00))
#(ok #"OK")
lfe> (ledis:bitpos 'mykey 1)
#(ok #"-1")
blpop
↟
The following would be returned if you had previously performed the (ledis:rpush 'list1 "banana"
and (ledis:rpush 'list1 "tranbar")
calls:
lfe> (ledis:blpop 'list1 0)
#(ok (#"list1" #"banana"))
lfe> (ledis:blpop '(list2 list3 list1) 0)
#(ok (#"list1" #"tranbar"))
del
↟
lfe> (ledis:set 'mykey "Hello")
#(ok #"OK")
lfe> (ledis:del 'mykey)
#(ok #"1")
lfe> (ledis:multi-set '(key1 "val1" key2 "val2" key3 "val3"))
#(ok #"OK")
lfe> (ledis:del '(key1 key2 key3 key4))
#(ok #"3")
hmset
↟
Normally, the HMSET
Redis command is of the form
HMSET key field value [field value ...]
, but for simplicity's sake with
regard to LFE's arity, the hmset
function is called a bit differently: It
is of the form (hmset <key> '(<kv pair> ...))
. For instance:
lfe> (ledis:hmset 'foo2 '(field1 bar2))
#(ok #"OK")
lfe> (ledis:hmset 'foo2 '(field2 bizaz field3 boz field4 bleez))
#(ok #"OK")
These can then be accessed using hmget
:
lfe> (ledis:hmget 'foo2 'field4)
#(ok (#"bleez"))
lfe> (ledis:hmget 'foo2 '(field3 field2 field1))
#(ok (#"boz" #"bizaz" #"bar2"))
lrange
↟
In addition to lrange/3
and lrange/4
(which offers the same signature as
associated Redis commands, with the 4-arity function also allowing options to be
passed), ledis offers two additional arities for this function. Arity-1 and
arity-2 will return the entire list at the given key (the following will be
returned if you have previously done something like (ledis:lpush-multi 'fruits '("banana" "tranbar" "kiwi") '())
):
lfe> (ledis:lrange 'fruits)
#(ok
(#"banana"
#"tranbar"
#"kiwi"))
M*
renamed to multi-*
↟
lfe> (ledis:multi-set '(a 10 b 20 c 30))
#(ok #"OK")
lfe> (ledis:multi-get '(a b c))
#(ok (#"10" #"20" #"30"))
set
↟
lfe> (ledis:set 'mykey "athirdvalue" '(#(xx) #(px 10000)))
#(ok #"OK")
lfe> (ledis:get 'mykey)
#(ok #"athirdvalue")
lfe> (timer:sleep 10000)
ok
lfe> (ledis:get 'mykey)
#(ok undefined)
Notes for Developers ↟
You can run the meager integration tests with the following, if you have a local instance of Redis running:
$ rebar3 as test lfe ltest -tintegration
If you have an interest in making contributions to this library, you'll need to make note of how the wrappring works.
- For every n-arity function you wish to add (wrap), you'll also need to add an n+1-arity function of the same name. This is because ledis supports (requires) a version of every function that takes LFE-specific options (e.g., setting return types).
- Under most circumstances, this just means making an entry in the functions
get-api-funcs-no-opts
andget-api-funcs-with-opts
in the fileinclude/ledis.lfe
. - Non-normal circumstances include supporting Redis functions of mixed arity,
special options, and non-standard or irregular function arguments. In these
cases, you will often be able to make an entry in
get-api-funcs-no-opts
, but have to then create a custom n+1-arity function insrc/ledis.lfe
. Sometimes you won't be able to use either of the API-generating functions and macros, and will instead need to implement both the n-arity and n+1-arity functions insrc/ledis.lfe
.