This commit is contained in:
Daniel Ziltener 2024-04-09 14:05:23 +02:00
parent 981144c743
commit 5ed8812f67
Signed by: zilti
GPG key ID: B38976E82C9DAE42
6 changed files with 138 additions and 128 deletions

View file

@ -1,2 +1,3 @@
((scheme-mode . ((flymake-chicken-command-args . ("-X" "r7rs" "-R" "r7rs")) ((org-mode . ((geiser-scheme-implementation . chicken)))
(geiser-scheme . 'chicken)))) (scheme-mode . ((flymake-chicken-command-args . ("-X" "r7rs" "-R" "r7rs"))
(geiser-scheme-implementation . chicken))))

1
.envrc Normal file
View file

@ -0,0 +1 @@
use guix chicken chicken-test chicken-r7rs chicken-srfi-34 chicken-srfi-35 chicken-srfi-69 chicken-srfi-99 chicken-srfi-113 chicken-srfi-128 chicken-srfi-133 chicken-srfi-152 chicken-srfi-158 redis

View file

@ -2,6 +2,7 @@
(import r7rs (import r7rs
(chicken base) (chicken base)
(chicken port) (chicken port)
(chicken string)
(chicken io) (chicken io)
(chicken tcp) (chicken tcp)
(srfi 34) ;; Exception Handling (srfi 34) ;; Exception Handling
@ -28,15 +29,17 @@
;; Connection Management ;; Connection Management
;; This egg currently uses a simple TCP connection without any "bells and whistles". The two ports are kept in a record of type =redis-connection= in the fields ~input~ and ~output~. ;; This egg currently uses a simple TCP connection without any "bells and whistles". The two ports are kept in a record of type =redis-connection= in the fields ~input~ and ~output~.
;; ~(redis-connect host port)~ ;; ~(redis-connect host port #!optional (protocol-version 1))~
;; Connects to a (hopefully) Redis server at =host:port=. ;; Connects to a (hopefully) Redis server at =host:port=, using the given protocol version. Defaults, like Redis itself, to version 1.
;; [[file:redis.org::*Connection Management][Connection Management:1]] ;; [[file:redis.org::*Connection Management][Connection Management:1]]
(define-record-type redis-connection #t #t input output) (define-record-type redis-connection #t #t input output)
(define (redis-connect host port) (define (redis-connect host port #!optional (protocol-version 1))
(let-values (((i o) (tcp-connect host port))) (let-values (((i o) (tcp-connect host port)))
(make-redis-connection i o))) (values (make-redis-connection i o)
(and (write-line (string-append "HELLO " (->string protocol-version)) o)
(redis-read-reply i)))))
;; Connection Management:1 ends here ;; Connection Management:1 ends here
@ -80,7 +83,7 @@
;; Supported Data Types ;; Supported Data Types
;; This Redis client supports all data types up to and including as specified in [[https://github.com/antirez/RESP3/blob/master/spec.md][RESP3]]. Setting the protocol version with the =HELLO= command, however, is the user's responsibility. ;; This Redis client supports all data types up to and including as specified in [[https://github.com/antirez/RESP3/blob/master/spec.md][RESP3]].
;; #+name: redis-read-reply ;; #+name: redis-read-reply

View file

@ -7,7 +7,7 @@
(synopsis "A Redis client library for Chicken Scheme") (synopsis "A Redis client library for Chicken Scheme")
(category db) (category db)
(license "BSD") (license "BSD")
(version "0.5") (version "0.6")
(dependencies r7rs srfi-34 srfi-35 srfi-69 srfi-99 srfi-113 srfi-128 srfi-133 srfi-152 srfi-158) (dependencies r7rs srfi-34 srfi-35 srfi-69 srfi-99 srfi-113 srfi-128 srfi-133 srfi-152 srfi-158)
(test-dependencies test) (test-dependencies test)

244
redis.org
View file

@ -79,21 +79,22 @@
#+end_src #+end_src
#+begin_src scheme :noweb yes :tangle redis-impl.scm :exports none #+begin_src scheme :noweb yes :tangle redis-impl.scm :exports none
(import r7rs (import r7rs
(chicken base) (chicken base)
(chicken port) (chicken port)
(chicken io) (chicken string)
(chicken tcp) (chicken io)
(srfi 34) ;; Exception Handling (chicken tcp)
(srfi 35) ;; Exception Types (srfi 34) ;; Exception Handling
(srfi 69) ;; Hash Tables (srfi 35) ;; Exception Types
(srfi 99) ;; Extended Records (srfi 69) ;; Hash Tables
(srfi 113) ;; Sets and Bags (srfi 99) ;; Extended Records
(srfi 128) ;; Comparators (srfi 113) ;; Sets and Bags
(srfi 133) ;; Vectors (srfi 128) ;; Comparators
(srfi 152) ;; Strings (srfi 133) ;; Vectors
(srfi 158) ;; Generators and Accumulators (srfi 152) ;; Strings
) (srfi 158) ;; Generators and Accumulators
)
#+end_src #+end_src
#+begin_src scheme :tangle tests/run.scm :exports none #+begin_src scheme :tangle tests/run.scm :exports none
@ -103,30 +104,32 @@
** Exceptions ** Exceptions
This library defines an SRFI-35 exception type ~&redis-error~ that gets raised when Redis returns an error. The exception type has a single field called ~redis-error-message~ containing the error message returned by Redis. This library defines an SRFI-35 exception type ~&redis-error~ that gets raised when Redis returns an error. The exception type has a single field called ~redis-error-message~ containing the error message returned by Redis.
#+begin_src scheme :tangle redis-impl.scm #+begin_src scheme :tangle redis-impl.scm
(define-condition-type &redis-error &error (define-condition-type &redis-error &error
redis-error? redis-error?
(redis-error-message redis-error-message)) (redis-error-message redis-error-message))
#+end_src #+end_src
** Connection Management ** Connection Management
This egg currently uses a simple TCP connection without any "bells and whistles". The two ports are kept in a record of type =redis-connection= in the fields ~input~ and ~output~. This egg currently uses a simple TCP connection without any "bells and whistles". The two ports are kept in a record of type =redis-connection= in the fields ~input~ and ~output~.
~(redis-connect host port)~ ~(redis-connect host port #!optional (protocol-version 1))~
Connects to a (hopefully) Redis server at =host:port=. Connects to a (hopefully) Redis server at =host:port=, using the given protocol version. Defaults, like Redis itself, to version 1.
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define-record-type redis-connection #t #t input output) (define-record-type redis-connection #t #t input output)
(define (redis-connect host port) (define (redis-connect host port #!optional (protocol-version 1))
(let-values (((i o) (tcp-connect host port))) (let-values (((i o) (tcp-connect host port)))
(make-redis-connection i o))) (values (make-redis-connection i o)
(and (write-line (string-append "HELLO " (->string protocol-version)) o)
(redis-read-reply i)))))
#+end_src #+end_src
~(redis-disconnect rconn)~ ~(redis-disconnect rconn)~
Disconnects from =rconn= which must be a =redis-connection=. Disconnects from =rconn= which must be a =redis-connection=.
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (redis-disconnect rconn) (define (redis-disconnect rconn)
(tcp-abandon-port (redis-connection-input rconn)) (tcp-abandon-port (redis-connection-input rconn))
(tcp-abandon-port (redis-connection-output rconn))) (tcp-abandon-port (redis-connection-output rconn)))
#+end_src #+end_src
** Running Commands ** Running Commands
@ -134,50 +137,50 @@ Disconnects from =rconn= which must be a =redis-connection=.
~(redis-run rconn command . args)~ ~(redis-run rconn command . args)~
Uses connection =rconn= to run =command= with =args=. The args will be appended to the command, space-separated. Returns the parsed reply. Uses connection =rconn= to run =command= with =args=. The args will be appended to the command, space-separated. Returns the parsed reply.
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (redis-run rconn command . args) (define (redis-run rconn command . args)
(let ((in (redis-connection-input rconn)) (let ((in (redis-connection-input rconn))
(out (redis-connection-output rconn)) (out (redis-connection-output rconn))
(comm (string-join (cons command args)))) (comm (string-join (cons command args))))
(write-line comm out) (write-line comm out)
(redis-read-reply in))) (redis-read-reply in)))
#+end_src #+end_src
~(redis-run-proc rconn proc . args)~ ~(redis-run-proc rconn proc . args)~
Calls =proc= with the output port of the =rconn= as current output port, optionally with =args=. Returns the parsed reply. Calls =proc= with the output port of the =rconn= as current output port, optionally with =args=. Returns the parsed reply.
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (redis-run-proc rconn proc . args) (define (redis-run-proc rconn proc . args)
(let ((in (redis-connection-input rconn)) (let ((in (redis-connection-input rconn))
(out (redis-connection-output rconn))) (out (redis-connection-output rconn)))
(with-output-to-port out (with-output-to-port out
(cut apply proc args)) (cut apply proc args))
(redis-read-reply in))) (redis-read-reply in)))
#+end_src #+end_src
** Supported Data Types ** Supported Data Types
This Redis client supports all data types up to and including as specified in [[https://github.com/antirez/RESP3/blob/master/spec.md][RESP3]]. Setting the protocol version with the =HELLO= command, however, is the user's responsibility. This Redis client supports all data types up to and including as specified in [[https://github.com/antirez/RESP3/blob/master/spec.md][RESP3]].
#+name: redis-read-reply #+name: redis-read-reply
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (redis-read-reply #!optional port) (define (redis-read-reply #!optional port)
(let* ((port (or port (current-input-port))) (let* ((port (or port (current-input-port)))
(sigil (read-char port))) (sigil (read-char port)))
(case sigil (case sigil
((#\+) (read-redis-simple-string port)) ((#\+) (read-redis-simple-string port))
((#\-) (raise (make-condition &redis-error 'redis-error-message (read-redis-simple-string port)))) ((#\-) (raise (make-condition &redis-error 'redis-error-message (read-redis-simple-string port))))
((#\$) (read-redis-blob-string port)) ((#\$) (read-redis-blob-string port))
((#\!) (raise (make-condition &redis-error 'redis-error-message (read-redis-blob-string port)))) ((#\!) (raise (make-condition &redis-error 'redis-error-message (read-redis-blob-string port))))
((#\=) (read-redis-blob-string port)) ((#\=) (read-redis-blob-string port))
((#\:) (read-redis-number port)) ((#\:) (read-redis-number port))
((#\,) (read-redis-number port)) ((#\,) (read-redis-number port))
((#\() (read-redis-number port)) ((#\() (read-redis-number port))
((#\#) (read-redis-bool port)) ((#\#) (read-redis-bool port))
((#\_) (read-redis-null port)) ((#\_) (read-redis-null port))
((#\*) (read-redis-array port)) ((#\*) (read-redis-array port))
((#\%) (read-redis-map port)) ((#\%) (read-redis-map port))
((#\~) (read-redis-set port)) ((#\~) (read-redis-set port))
((#\|) (read-redis-with-attributes port))))) ((#\|) (read-redis-with-attributes port)))))
#+end_src #+end_src
*** Simple Strings *** Simple Strings
@ -190,9 +193,9 @@ Simple strings start with ~+~ and are single-line.
#+name: read-redis-simple-string #+name: read-redis-simple-string
#+begin_src scheme :tangle redis-impl.scm :exports none :results silent #+begin_src scheme :tangle redis-impl.scm :exports none :results silent
(define (read-redis-simple-string #!optional port) (define (read-redis-simple-string #!optional port)
(let ((port (or port (current-input-port)))) (let ((port (or port (current-input-port))))
(read-line port))) (read-line port)))
#+end_src #+end_src
#+name: simple-string-test #+name: simple-string-test
@ -229,15 +232,15 @@ chicken
#+name: read-redis-blob-string #+name: read-redis-blob-string
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (read-redis-blob-string #!optional port) (define (read-redis-blob-string #!optional port)
(let* ((port (or port (current-input-port))) (let* ((port (or port (current-input-port)))
(charcount (string->number (read-line port))) (charcount (string->number (read-line port)))
(str (list->string (str (list->string
(generator-map->list (generator-map->list
(lambda (i) (read-char port)) (lambda (i) (read-char port))
(make-range-generator 0 charcount))))) (make-range-generator 0 charcount)))))
(read-line port) (read-line port)
str)) str))
#+end_src #+end_src
#+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output #+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output
@ -282,12 +285,12 @@ Integers are sent to the client prefixed with ~:~.
#+name: read-redis-number #+name: read-redis-number
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (read-redis-number #!optional port) (define (read-redis-number #!optional port)
(let* ((port (or port (current-input-port))) (let* ((port (or port (current-input-port)))
(elem (read-line port))) (elem (read-line port)))
(if (string=? elem "inf") (if (string=? elem "inf")
(string->number "+inf") (string->number "+inf")
(string->number elem)))) (string->number elem))))
#+end_src #+end_src
#+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output #+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output
@ -339,9 +342,9 @@ True and false values are represented as ~#t~ and ~#f~, just like in Scheme.
#+name: read-redis-bool #+name: read-redis-bool
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (read-redis-bool #!optional port) (define (read-redis-bool #!optional port)
(let ((port (or port (current-input-port)))) (let ((port (or port (current-input-port))))
(string=? (read-line port) "t"))) (string=? (read-line port) "t")))
#+end_src #+end_src
#+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output #+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output
@ -367,9 +370,9 @@ The null type is encoded simply as ~_~, and results in ~'()~.
#+name: read-redis-null #+name: read-redis-null
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (read-redis-null #!optional port) (define (read-redis-null #!optional port)
(let ((port (or port (current-input-port)))) (let ((port (or port (current-input-port))))
(read-line port) '())) (read-line port) '()))
#+end_src #+end_src
#+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output #+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output
@ -399,15 +402,15 @@ Arrays are marked with ~*~ followed by the number of entries, and get returned a
#+name: read-redis-array #+name: read-redis-array
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (read-redis-array #!optional port) (define (read-redis-array #!optional port)
(let* ((port (or port (current-input-port))) (let* ((port (or port (current-input-port)))
(elems (string->number (read-line port))) (elems (string->number (read-line port)))
(vec (make-vector elems '()))) (vec (make-vector elems '())))
(generator-for-each (generator-for-each
(lambda (i) (lambda (i)
(vector-set! vec i (redis-read-reply port))) (vector-set! vec i (redis-read-reply port)))
(make-range-generator 0 elems)) (make-range-generator 0 elems))
vec)) vec))
#+end_src #+end_src
#+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output #+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output
@ -440,15 +443,15 @@ Maps are represented exactly as arrays, but instead of using the ~*~ byte, the e
#+name: read-redis-map #+name: read-redis-map
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (read-redis-map #!optional port) (define (read-redis-map #!optional port)
(let* ((port (or port (current-input-port))) (let* ((port (or port (current-input-port)))
(elems (string->number (read-line port))) (elems (string->number (read-line port)))
(ht (make-hash-table))) (ht (make-hash-table)))
(generator-for-each (generator-for-each
(lambda (i) (lambda (i)
(hash-table-set! ht (redis-read-reply port) (redis-read-reply port))) (hash-table-set! ht (redis-read-reply port) (redis-read-reply port)))
(make-range-generator 0 elems)) (make-range-generator 0 elems))
ht)) ht))
#+end_src #+end_src
#+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output #+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output
@ -485,22 +488,22 @@ Additionally, there is a parameter defined, =redis-set-comparator=, that specifi
#+name: read-redis-set #+name: read-redis-set
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define redis-set-comparator (define redis-set-comparator
(make-parameter (make-default-comparator) (make-parameter (make-default-comparator)
(lambda (newcomp) (lambda (newcomp)
(or (and (comparator? newcomp) (or (and (comparator? newcomp)
newcomp) newcomp)
'())))) '()))))
(define (read-redis-set #!optional port) (define (read-redis-set #!optional port)
(let* ((port (or port (current-input-port))) (let* ((port (or port (current-input-port)))
(elems (string->number (read-line port))) (elems (string->number (read-line port)))
(s (set (redis-set-comparator)))) (s (set (redis-set-comparator))))
(generator-for-each (generator-for-each
(lambda (i) (lambda (i)
(set-adjoin! s (redis-read-reply port))) (set-adjoin! s (redis-read-reply port)))
(make-range-generator 0 elems)) (make-range-generator 0 elems))
s)) s))
#+end_src #+end_src
#+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output #+begin_src scheme :tangle tests/run.scm :noweb strip-tangle :exports none :post test-post(input=*this*) :results output
@ -529,10 +532,10 @@ This library returns two values in this case, the first value being the actual d
#+name: read-redis-with-attributes #+name: read-redis-with-attributes
#+begin_src scheme :tangle redis-impl.scm :exports none #+begin_src scheme :tangle redis-impl.scm :exports none
(define (read-redis-with-attributes #!optional port) (define (read-redis-with-attributes #!optional port)
(let* ((port (or port (current-input-port))) (let* ((port (or port (current-input-port)))
(attributes (read-redis-map port))) (attributes (read-redis-map port)))
(values (redis-read-reply port) attributes))) (values (redis-read-reply port) attributes)))
#+end_src #+end_src
* About this egg * About this egg
@ -567,7 +570,8 @@ Daniel Ziltener
** Version History ** Version History
#+name: version-history #+name: version-history
| 0.5 | Initial Release | | 0.6 | Easier Protocol Version Setting |
| 0.5 | Initial Release |
#+name: gen-releases #+name: gen-releases
#+begin_src emacs-lisp :var vers=version-history :results raw :exports none #+begin_src emacs-lisp :var vers=version-history :results raw :exports none

View file

@ -2,5 +2,6 @@
;; -*- Scheme -*- ;; -*- Scheme -*-
(repo git "https://gitea.lyrion.ch/Chicken/redis.git") (repo git "https://gitea.lyrion.ch/Chicken/redis.git")
(uri targz "https://gitea.lyrion.ch/Chicken/redis/archive/{egg-release}.tar.gz") (uri targz "https://gitea.lyrion.ch/Chicken/redis/archive/{egg-release}.tar.gz")
(release "0.6") ;; Easier Protocol Version Setting
(release "0.5") ;; Initial Release (release "0.5") ;; Initial Release
;; Version History:3 ends here ;; Version History:3 ends here