3 Commits

Author SHA1 Message Date
hellerve fafa2b40d2 use new sockets lib 2026-04-11 11:20:25 +02:00
hellerve 692fe51728 update docs 2026-04-03 11:37:12 +02:00
hellerve d88b0631a6 clarify redis version 2026-04-03 11:07:53 +02:00
6 changed files with 129 additions and 25 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ A Redis client library for Carp, supporting Redis 7.x.
## Installation ## Installation
```clojure ```clojure
(load "https://git.veitheller.de/carpentry/redis.git@master") (load "https://git.veitheller.de/carpentry/redis.git@0.2.0")
``` ```
## Usage ## Usage
+19
View File
@@ -40,6 +40,25 @@ Protocol</a>. You can create all types,
stringify the built types into strings using <a href="#str"><code>str</code></a>, and decode from stringify the built types into strings using <a href="#str"><code>str</code></a>, and decode from
the string protocol using <a href="#from-string"><code>from-string</code></a>. Arrays are fully the string protocol using <a href="#from-string"><code>from-string</code></a>. Arrays are fully
supported, including nested arrays.</p> supported, including nested arrays.</p>
<pre><code>; decoding
(RESP.from-string &quot;+OK\r\n&quot;) ; =&gt; (Success (Str @&quot;OK&quot;))
(RESP.from-string &quot;:42\r\n&quot;) ; =&gt; (Success (Integer 42))
(RESP.from-string &quot;$-1\r\n&quot;) ; =&gt; (Success (Null))
; encoding
(str &amp;(RESP.Str @&quot;hi&quot;)) ; =&gt; &quot;$2\r\nhi\r\n&quot;
(str &amp;(RESP.Integer 42)) ; =&gt; &quot;:42\r\n&quot;
; pattern matching on responses
(match (Redis.get &amp;r @&quot;key&quot;)
(Result.Success resp)
(match resp
(RESP.Str s) (println* &quot;got: &quot; &amp;s)
(RESP.Null) (println* &quot;not found&quot;)
(RESP.Arr items) (println* &quot;array of &quot; &amp;(Int.str (Array.length &amp;items)))
_ (println* &quot;other&quot;))
(Result.Error e) (println* &quot;error: &quot; &amp;e))
</code></pre>
<p>If you want your types to be supported when encoding, youll have to implement <p>If you want your types to be supported when encoding, youll have to implement
the interface <code>to-redis</code>, the signature of which is <code>(Fn [a] RESP))</code>.</p> the interface <code>to-redis</code>, the signature of which is <code>(Fn [a] RESP))</code>.</p>
+15 -7
View File
@@ -38,8 +38,16 @@
<p>is a wrapper around Redis connections. It supports opening a <p>is a wrapper around Redis connections. It supports opening a
connection using <a href="#open"><code>open</code></a> or <a href="#open-on"><code>open-on</code></a>, reading from and connection using <a href="#open"><code>open</code></a> or <a href="#open-on"><code>open-on</code></a>, reading from and
sending to the connection (using <a href="#read"><code>read</code></a> and <a href="#send"><code>send</code></a>, sending to the connection (using <a href="#read"><code>read</code></a> and <a href="#send"><code>send</code></a>,
respectively), and contains thin wrappers around all Redis commands (everything respectively), and contains thin wrappers around all Redis commands through 7.2.</p>
else).</p> <pre><code>(match (Redis.open &quot;127.0.0.1&quot;)
(Result.Success r)
(do
(println* &amp;(Redis.set &amp;r @&quot;key&quot; @&quot;val&quot;))
(println* &amp;(Redis.get &amp;r @&quot;key&quot;))
(println* &amp;(Redis.lrange &amp;r @&quot;list&quot; @&quot;0&quot; @&quot;-1&quot;))
(Redis.close r))
(Result.Error err) (IO.errorln &amp;err))
</code></pre>
</div> </div>
<div class="binder"> <div class="binder">
@@ -3095,7 +3103,7 @@ else).</p>
instantiate instantiate
</div> </div>
<p class="sig"> <p class="sig">
(Fn [Socket] Redis) (Fn [TcpStream] Redis)
</p> </p>
<span> <span>
@@ -4980,7 +4988,7 @@ else).</p>
instantiate instantiate
</div> </div>
<p class="sig"> <p class="sig">
(Fn [Redis, Socket] Redis) (Fn [Redis, TcpStream] Redis)
</p> </p>
<span> <span>
@@ -5000,7 +5008,7 @@ else).</p>
instantiate instantiate
</div> </div>
<p class="sig"> <p class="sig">
(Fn [(Ref Redis a), Socket] ()) (Fn [(Ref Redis a), TcpStream] ())
</p> </p>
<span> <span>
@@ -5314,7 +5322,7 @@ else).</p>
instantiate instantiate
</div> </div>
<p class="sig"> <p class="sig">
(Fn [(Ref Redis a)] (Ref Socket a)) (Fn [(Ref Redis a)] (Ref TcpStream a))
</p> </p>
<span> <span>
@@ -5816,7 +5824,7 @@ else).</p>
instantiate instantiate
</div> </div>
<p class="sig"> <p class="sig">
(Fn [Redis, (Ref (Fn [Socket] Socket a) b)] Redis) (Fn [Redis, (Ref (Fn [TcpStream] TcpStream a) b)] Redis)
</p> </p>
<span> <span>
+21 -2
View File
@@ -30,8 +30,27 @@
<h1> <h1>
redis redis
</h1> </h1>
<p>is a Redis client library for Carp.</p> <p>is a Redis client library for Carp, supporting Redis 7.x.</p>
<pre><code>(load &quot;https://git.veitheller.de/carpentry/redis.git@master&quot;) <h2>Installation</h2>
<pre><code>(load &quot;https://git.veitheller.de/carpentry/redis.git@0.2.0&quot;)
</code></pre>
<h2>Example</h2>
<pre><code>(defn main []
(match (Redis.open &quot;127.0.0.1&quot;)
(Result.Success r)
(do
(println* &amp;(Redis.set &amp;r @&quot;key&quot; @&quot;value&quot;))
(println* &amp;(Redis.get &amp;r @&quot;key&quot;))
(println* &amp;(Redis.lrange &amp;r @&quot;mylist&quot; @&quot;0&quot; @&quot;-1&quot;))
(match (Redis.get &amp;r @&quot;key&quot;)
(Result.Success resp)
(match resp
(RESP.Str s) (println* &quot;got: &quot; &amp;s)
(RESP.Null) (println* &quot;not found&quot;)
_ (println* &quot;unexpected type&quot;))
(Result.Error e) (println* &quot;error: &quot; &amp;e))
(Redis.close r))
(Result.Error err) (IO.errorln &amp;err)))
</code></pre> </code></pre>
</div> </div>
+25 -2
View File
@@ -5,10 +5,33 @@
(Project.config "docs-logo" "") (Project.config "docs-logo" "")
(Project.config "docs-url" "https://git.veitheller.de/carpentry/redis") (Project.config "docs-url" "https://git.veitheller.de/carpentry/redis")
(Project.config "docs-styling" "../style.css") (Project.config "docs-styling" "../style.css")
(Project.config "docs-prelude" "is a Redis client library for Carp. (Project.config "docs-prelude" "is a Redis client library for Carp, supporting Redis 7.x.
## Installation
``` ```
(load \"https://git.veitheller.de/carpentry/redis.git@master\") (load \"https://git.veitheller.de/carpentry/redis.git@0.2.0\")
```
## Example
```
(defn main []
(match (Redis.open \"127.0.0.1\")
(Result.Success r)
(do
(println* &(Redis.set &r @\"key\" @\"value\"))
(println* &(Redis.get &r @\"key\"))
(println* &(Redis.lrange &r @\"mylist\" @\"0\" @\"-1\"))
(match (Redis.get &r @\"key\")
(Result.Success resp)
(match resp
(RESP.Str s) (println* \"got: \" &s)
(RESP.Null) (println* \"not found\")
_ (println* \"unexpected type\"))
(Result.Error e) (println* \"error: \" &e))
(Redis.close r))
(Result.Error err) (IO.errorln &err)))
``` ```
") ")
+48 -13
View File
@@ -1,4 +1,4 @@
(load "git@github.com:carpentry-org/sockets@0.0.2") (load "git@github.com:carpentry-org/socket@0.1.1")
(deftype RESP (deftype RESP
(Null []) (Null [])
@@ -117,18 +117,17 @@
) )
(deftype Redis [ (deftype Redis [
sock Socket sock TcpStream
]) ])
(defmodule Redis (defmodule Redis
(use-all Array Result Socket) (use-all Array Result)
(doc open-on "opens the connection to Redis on port `port`.") (doc open-on "opens the connection to Redis on port `port`.")
(defn open-on [host port] (defn open-on [host port]
(let [s (setup-client host port)] (match (TcpStream.connect host port)
(if (valid? &s) (Result.Success s) (Success (init s))
(Success (init s)) (Result.Error e) (Error (fmt "Couldnt connect to %s:%d: %s" host port &e))))
(Error (fmt "Couldnt connect to %s:%d" host port)))))
(doc open "opens the connection to Redis on port 6379. (doc open "opens the connection to Redis on port 6379.
@@ -136,14 +135,19 @@ For variable port numbers please check out [`open-on`](#open-on).")
(defn open [host] (open-on host 6379)) (defn open [host] (open-on host 6379))
(doc read "reads a `RESP` object from Redis.") (doc read "reads a `RESP` object from Redis.")
(defn read [r] (RESP.from-string &(Socket.read (sock r)))) (defn read [r]
(match (the (Result String String) (TcpStream.read (sock r)))
(Result.Success s) (RESP.from-string &s)
(Result.Error e) (Error e)))
(doc send "sends the command `cmd` with the arguments `args` to Redis.") (doc send "sends the command `cmd` with the arguments `args` to Redis.")
(defn send [r cmd args] (defn send [r cmd args]
(let [cmd-parts (copy-map &(fn [x] (Box.init (to-redis @x))) &(Pattern.split #" " &cmd))] (let [cmd-parts (copy-map &(fn [x] (Box.init (to-redis @x))) &(Pattern.split #" " &cmd))
(Socket.send (sock r) &(str &(RESP.Arr (concat &[cmd-parts (copy-map &(fn [x] (Box.init @x)) args)])))))) msg (str &(RESP.Arr (concat &[cmd-parts (copy-map &(fn [x] (Box.init @x)) args)])))]
(ignore (TcpStream.send (sock r) &msg))))
(doc close "closes the connection to Redis.") (doc close "closes the connection to Redis.")
(defn close [r] (Socket.close @(sock &r))) (defn close [r] (TcpStream.close @(sock &r)))
) )
(defndynamic rtreat- [s] (defndynamic rtreat- [s]
@@ -503,13 +507,44 @@ It takes the same arguments as the [Redis command](https://redis.io/commands/"
(doc Redis "is a wrapper around Redis connections. It supports opening a (doc Redis "is a wrapper around Redis connections. It supports opening a
connection using [`open`](#open) or [`open-on`](#open-on), reading from and connection using [`open`](#open) or [`open-on`](#open-on), reading from and
sending to the connection (using [`read`](#read) and [`send`](#send), sending to the connection (using [`read`](#read) and [`send`](#send),
respectively), and contains thin wrappers around all Redis commands (everything respectively), and contains thin wrappers around all Redis commands through 7.2.
else).")
```
(match (Redis.open \"127.0.0.1\")
(Result.Success r)
(do
(println* &(Redis.set &r @\"key\" @\"val\"))
(println* &(Redis.get &r @\"key\"))
(println* &(Redis.lrange &r @\"list\" @\"0\" @\"-1\"))
(Redis.close r))
(Result.Error err) (IO.errorln &err))
```")
(doc RESP "is a wrapper around the [Redis Serialization (doc RESP "is a wrapper around the [Redis Serialization
Protocol](https://redis.io/topics/protocol). You can create all types, Protocol](https://redis.io/topics/protocol). You can create all types,
stringify the built types into strings using [`str`](#str), and decode from stringify the built types into strings using [`str`](#str), and decode from
the string protocol using [`from-string`](#from-string). Arrays are fully the string protocol using [`from-string`](#from-string). Arrays are fully
supported, including nested arrays. supported, including nested arrays.
```
; decoding
(RESP.from-string \"+OK\\r\\n\") ; => (Success (Str @\"OK\"))
(RESP.from-string \":42\\r\\n\") ; => (Success (Integer 42))
(RESP.from-string \"$-1\\r\\n\") ; => (Success (Null))
; encoding
(str &(RESP.Str @\"hi\")) ; => \"$2\\r\\nhi\\r\\n\"
(str &(RESP.Integer 42)) ; => \":42\\r\\n\"
; pattern matching on responses
(match (Redis.get &r @\"key\")
(Result.Success resp)
(match resp
(RESP.Str s) (println* \"got: \" &s)
(RESP.Null) (println* \"not found\")
(RESP.Arr items) (println* \"array of \" &(Int.str (Array.length &items)))
_ (println* \"other\"))
(Result.Error e) (println* \"error: \" &e))
```
If you want your types to be supported when encoding, youll have to implement If you want your types to be supported when encoding, youll have to implement
the interface `to-redis`, the signature of which is `(Fn [a] RESP))`.") the interface `to-redis`, the signature of which is `(Fn [a] RESP))`.")