README.org
September 22, 2020 ยท View on GitHub
[[mango2.jpg]]
Mango is a client library for CouchDB 2.x (it also happens to be the name of CouchDB's alternate query language)
- Configuration
#+BEGIN_SRC lisp -n +i (eval-when (:compile-toplevel :load-toplevel :execute) (setf cl-mango:host "127.0.0.1") (setf cl-mango:port 5984) (setf cl-mango:scheme :http) ;; or :https (setf cl-mango:username "user") (setf cl-mango:password "password")) #+END_SRC
-
(defmango ...)
(defmango) macro that generates an orm-ish interface to a class.
#+BEGIN_SRC lisp -n +i
(defmango person people ((name :json-type :string :json-key "name" :initarg :name :accessor person-name) (role :json-type :string :json-key "role" :initform "pleb" :initarg :role :accessor person-role)) =>
(progn (defclass person () ((cl-mango::-id :initarg :-id :json-type :string :json-key "_id" :accessor person--id) (cl-mango::-rev :initarg :-rev :json-type :string :json-key "_rev" :accessor person-rev) (type :initarg :type :json-type :string :json-key "type" :initform (string-downcase "person")) (name :json-type :string :json-key "name" :initarg :name :accessor person-name) (role :json-type :string :json-key "role" :initform "pleb" :accessor person-role)) (:metaclass json-mop:json-serializable-class))
;; ;; Important notes about this defclass expansion: ;; ;; - type is special as it tells defmodel what class query results ;; are supposed to be. It's filled in automatically. Unless you ;; want to see things explode spectacularly, don't change it. ;; ;; - person--id and person-rev are special to CouchDB. When ;; creating a new record, don't fill in "_rev" as CouchDB ;; assigns it a new revision tag on insert and update. The only ;; time I ever find myself reading the rev slot in practice is ;; when I need to delete a record, in which you provide an _id and ;; _rev. ;;
(defun person-get-all ())
;; ;; Doesn't actually get all, only the first 100 as it uses ;; couchdb/database/_all_docs?include_docs=true if you truly want ;; all, I would suggest fetching only the "_id" of all with ;; (person-find) and then iterating over that list. ie. ;; ;; (person-find (list (cons "name" (alist-hash-table ;; this selector can b ;; (list (cons "$exists" 't))))) ;; :limit 1000000 ;; or some similarly large number. ;; :fields (list "_id"))
(defun person-get (id))
;; Fetch a single person record from the database with the given id. ;; CouchDB enforces that all "_id" values are unique, so there will ;; only ever be a single result from this call.
(defun person-put (cl-mango::object)) (defun person-update (cl-mango::object))
;; These two calls are identical in their implementation, however ;; there are two to help with the differences in adding a record and ;; updating a record in CouchDB. ;; - Adding a record without a value for "_rev" adds a new record to ;; the database. ;; - Adding a record with a value in "_rev" means, in CouchDB terms, ;; "This is a new revision of that document." Note that if you ;; update a record (ie. you have a value for "_rev") and it's not ;; the latest and greatest version in the database at that time, ;; you'll get a document update conflict and cl-mango will throw ;; the dreaded "unexpected-http-response" condition. So, yes, ;; it's a bit redundant, but it helps me, so it's staying. ;;
(defmacro person-find (cl-mango::query &rest cl-mango::query-args))
;;
;; This is the main interface for querying objects of your class.
;; It takes the same arguments as (make-selector) above and
;; transparently adds (cons "type" "
(person-find (list (cons "name" "bob"))) (person-find (list (cons "role" "admin")) :limit 1 :skip 100 :stable t :update t :use-index "index-name" :r 2 :fields (list "_id" "_rev") :sort (list (alexandria:alist-hash-table (list (cons "name" "desc")))))
;;
(defun person-delete (cl-mango::object))
;; ;; Removes the object from the database. ;;
(defmacro person-create (&rest cl-mango::args))
;; Make a new object and add it to the database. ;; There's nothing special about this, and there's nothing preventing you from ;; using (make-instance).
(person-put (make-instance 'person :name "bob"))
#+END_SRC
-
Lower level api
(defmango) is defined in terms of the following functions.
-
make-selector selector &key limit fields sort skip
Builds a selector for doc-find.
[[https://docs.couchdb.org/en/2.2.0/api/database/find.html#find-selectors][Docs]]
#+BEGIN_SRC lisp -n +i (make-selector (list (cons "name" "mango")) :limit 10 :fields (list "_id" "_rev") :sort '(cons "name" "desc") :skip 100) #+END_SRC
-
doc-find database selector
[[https://docs.couchdb.org/en/2.2.0/api/database/find.html][Docs]]
Execute a query against
.
#+BEGIN_SRC lisp -n +i (doc-find "test" (make-selector (list (cons "name" "me"))) #+END_SRC
-
doc-get database document-id
Get a single document by the
_id.
#+BEGIN_SRC lisp -n +i
(doc-get "test" "
-
doc-delete database document-id document-rev
Delete a single document.
-
doc-put database json-string
Insert a single document.
#+BEGIN_SRC lisp -n +i ;; Assuming you use yason, but as long as the ;; string is well formed JSON, you can use ;; whatever library you want. (doc-put "test" (with-output-to-string (sink) (yason:encode (list (cons "name" "me") (cons "something" "something else")) sink))) #+END_SRC
- query-view database view index &key parameters
[[https://docs.couchdb.org/en/2.2.0/ddocs/views/index.html?highlight=views][Docs]]
#+BEGIN_SRC lisp (query-view "test" "reports" "by-person" (list (cons "uid" 12"))) #+END_SRC
- Issues, Project Page, etc.
[[https://github.com/cmoore/cl-mango][See github]]