clouchdb

A Common Lisp library for interacting with CouchDb databases.

Overview

Clouchdb is a Common Lisp library for interacting with CouchDb databases. CouchDb is a document based database server. Clouchdb comes with a BSD Style License for maximum agreeableness.

Author: Peter Eddy (peter.eddy at gmail.com)

Contents

News

Download and Installation

The current download link for clouchdb can be found at Clicki.net. Clouchdb may also be installed with Quicklisp or ASDF.

Requirements:

Optional Libraries:

Quicklisp Install

I highly recommend using Quicklisp for easy, trouble-free installation

(ql:quickload "clouchdb")  

ASDF Install

Something like the following should be all that's necessary to install and load clouchdb using ASDF-INSTALL:

(asdf-install:install 'clouchdb)  
(asdf:operate 'asdf:load-op '#:clouchdb)

ASDF-INSTALL will install library dependencies, though you must of course install the CouchDb server separately.

Unit tests

The clouchdb distribution comes with a unit test suite which uses the Stefil test framework. To run the tests follow the following steps:

;; Install the Stefil test framework. This example installs Stefil using Quicklisp
(ql:quickload "stefil")

(load "tests.lisp")
(in-package :clouchdb-tests)

;; The following is only necessary if the couchdb server is not on 
;; localhost, or authenticaion is enabled, respectively.
(set-connection :host "hostname" :user "username" :password "password")

(test-all)

Examples

The distribution also includes the clouchdb examples file examples.lisp which contains ready-to-run examples and comments describing each example in detail.

Github Source

Clouchdb is now available in a git repository at https://github.com/petereddy/clouchdb

CVS Access

Note: CVS access is still available, but further development will be checked in only to the git repository at github

cvs -z3 -d :pserver:anonymous:anonymous@common-lisp.net:/project/clouchdb/cvsroot co clouchdb

Support and mailing lists

The following email lists have been provided by the common-lisp.net for clouchdb development and information:

Examples

The following clouchdb REPL sessions demonstrate various aspects of the three major functional areas of the CouchDb API: Database API, Document API and View API.

NB: If you try these examples I suggest also viewing the results via CouchDb's bulit-in HTML UI at http://localhost:5894/_utils/. Of course adjust the URL for the actual CouchDb server and port in use.

Example 1

The following example session demonstrates:

;; Create a package to try out clouchdb
CL-USER> (defpackage :clouchdb-user (:use :cl :clouchdb :parenscript))
#<PACKAGE "CLOUCHDB-USER">

CL-USER> (in-package :clouchdb-user)
#<Package "CLOUCHDB-USER">

;; View the current (default) CouchDb connection configuration
CLOUCHDB-USER> *couchdb*
#S(CLOUCHDB::DB
   :HOST "localhost"
   :PORT "5984"
   :NAME "default"
   :PROTOCOL "http"
   :USER NIL
   :PASSWORD NIL
   :DOCUMENT-FETCH-FN NIL
   :DOCUMENT-UPDATE-FN NIL)

;; The current database name is "default". Set appropriate values, for
;; example, if the CouchDb server is running on host "odeon" set that 
;; value like so:
CLOUCHDB-USER> (set-connection :host "odeon")
#S(CLOUCHDB::DB
   :HOST "odeon"
   :PORT "5984"
   :NAME "default"
   :PROTOCOL "http"
   :USER NIL
   :PASSWORD NIL
   :DOCUMENT-FETCH-FN NIL
   :DOCUMENT-UPDATE-FN NIL)

;; GetCouchDb Server Information. This is the first communication
;; with the CouchDb server.
CLOUCHDB-USER> (get-couchdb-info)
((:|couchdb| . "Welcome") (:|version| . "0.10.0a788899"))

;; Create database named "default", (as configured in *couchdb*)
CLOUCHDB-USER> (create-db)
((:|ok| . T))

;; Create a document with one field, and give it an ID of "gjc"
CLOUCHDB-USER> (create-document '((:name . "Gaius Julius Caesar")) :id "gjc")
((:|ok| . T) (:|id| . "gjc") (:|rev| . "1-1009420200"))

;; Fetch the document we just created 
CLOUCHDB-USER> (get-document "gjc")
((:|_id| . "gjc") (:|_rev| . "1-1009420200") (:NAME . "Gaius Julius Caesar"))

;; Add a field to this new document
CLOUCHDB-USER> (put-document (cons '(:lover . "Servilia Caepionis") *))
((:|ok| . T) (:|id| . "gjc") (:|rev| . "2-3501332342"))

;; Get the updated document to verify that the new field stuck
CLOUCHDB-USER> (get-document "gjc")
((:|_id| . "gjc") (:|_rev| . "2-3501332342") (:LOVER . "Servilia Caepionis")
 (:NAME . "Gaius Julius Caesar"))

Example 2

Demonstrating:

;; Create, or drop and recreate, the current database
CLOUCHDB-USER> (create-db :if-exists :recreate)
((:|ok| . T))

;; Create a document that will have it's ID assigned by the CouchDb server
CLOUCHDB-USER> (create-document '((:size . "medium") (:color . "blue")))
((:|ok| . T) (:|id| . "37173e3a844a342414272daa733e1302")
 (:|rev| . "1-3111744915"))

;; CouchDb generated IDs are too large to use easily in an
;; interactive example like this, so create another document
;; with a shorter ID to demonstrate property value updates
CLOUCHDB-USER> (create-document '((:size . "large") (:color . "blue")) 
                                :id "someid")
((:|ok| . T) (:|id| . "someid") (:|rev| . "1-2190467195"))

;; Change :color property
CLOUCHDB-USER> (put-document 
                (setf (document-property :color 
                                         (get-document "someid"))
                      "green"))
((:|ok| . T) (:|id| . "someid") (:|rev| . "2-1066530650"))

;; Show that the new property stuck
CLOUCHDB-USER> (get-document "someid")
((:|_id| . "someid") (:|_rev| . "2-1066530650") (:SIZE . "large")
 (:COLOR . "green")

;; In the following document the :tags field has an array value,
;; the :demographics field has a map value, and the :religion map 
;; key also has an associated map value.
CLOUCHDB-USER> (create-document '((:name . "Czech Republic")
                                  (:tags . ("country" "European"))
                                  ;; Field using map property value:
                                  (:demographics . ((:population . 10230000)
                                                    ;; A nested map property:
                                                    (:religion . ((:agnostic . 0.59)
                                                                  (:roman-catholic . 0.26)
                                                                  (:protestant . 2.5)))
                                                    (:political-system . "democracy"))))
                                :id "czechrepublic")
((:|ok| . T) (:|id| . "czechrepublic") (:|rev| . "1-56705403"))

;; Let's see what this document looks like
CLOUCHDB-USER> (get-document "czechrepublic")
((:|_id| . "czechrepublic") (:|_rev| . "1-56705403") (:NAME . "Czech Republic")
 (:TAGS "country" "European")
 (:DEMOGRAPHICS (:POPULATION . 10230000)
  (:RELIGION (:AGNOSTIC . 0.59) (:ROMAN-CATHOLIC . 0.26) (:PROTESTANT . 2.5))
  (:POLITICAL-SYSTEM . "democracy")))

;; Let's see all documents in this database
CLOUCHDB-USER> (get-all-documents)
((:|total_rows| . 3) (:|offset| . 0)
 (:|rows|
  ((:|id| . "37173e3a844a342414272daa733e1302")
   (:|key| . "37173e3a844a342414272daa733e1302")
   (:|value| (:|rev| . "1-3111744915")))
  ((:|id| . "czechrepublic") (:|key| . "czechrepublic")
   (:|value| (:|rev| . "1-56705403")))
  ((:|id| . "someid") (:|key| . "someid")
   (:|value| (:|rev| . "2-1066530650")))))

Example 3

Demonstrating:

;; Create current database if it doesn't already exist.
;; An (:IGNORED . T) result indicates that the create
;; was ignored because the database already existed.
CLOUCHDB-USER> (create-db :if-exists :ignore)
((:|ok| . T) (:IGNORED . T))

;; Create some documents representing various cities and their 
;; associated countries.
CLOUCHDB-USER> (create-document '((:city . "New York City")
                                  (:country . "US"))
                                :id "nyc")
((:|ok| . T) (:|id| . "nyc") (:|rev| . "1-2083466274"))

CLOUCHDB-USER> (create-document '((:city . "Amsterdam")
                                  (:country . "NL"))
                                :id "amst") 
((:|ok| . T) (:|id| . "amst") (:|rev| . "1-3092672538"))

CLOUCHDB-USER> (create-document '((:city . "Rotterdam")
                                  (:country . "NL"))
                                :id "rott") 
((:|ok| . T) (:|id| . "rott") (:|rev| . "1-2303974290"))

CLOUCHDB-USER> (create-document '((:city . "Chicago")
                                  (:country . "US"))
                                :id "chi") 
((:|ok| . T) (:|id| . "chi") (:|rev| . "1-1962544983"))

;; Make a persistent view document that can be used to find cities in the 
;; Netherlands, cities by country key, and cities by country and city.

;; Note: Expressions within the (ps) expressions are Parenscript,
;; a lispy way to generate JavaScript. Unquoted keyword symbols in Lisp 
;; field names should be referenced in Parenscript with the double
;; asterix names, as in the examples below. This is because JavaScript
;; is case sensitive and unquoted Lisp symbols are converted to upper
;; case. The double asterix syntax causes Parenscript to generate 
;; upper case JavaScript property names.

CLOUCHDB-USER> (create-ps-view "cities"
                               ;; Index of cities in the Netherlands
                               (ps-view ("nl")
                                 (defun map (doc)
                                   (with-slots (*country* *city*) doc
                                     (if (eql "NL" *country*)
                                         (emit *city* doc)))))
                               ;; Index by country
                               (ps-view ("country")
                                 (defun map (doc)
                                   (with-slots (*country*) doc
                                     (emit *country* doc))))
                               ;; Index by country and city
                               (ps-view ("multi")
                                 (defun map (doc)
                                   (with-slots (*country* *city*) doc
                                     (emit (list *country* *city*) doc))))
((:|ok| . T) (:|id| . "_design/cities") (:|rev| . "1-544897531"))

;; Invoke "nl" view to find cities in the Netherlands
CLOUCHDB-USER> (invoke-view "cities" "nl")
((:|total_rows| . 2) (:|offset| . 0)
 (:|rows|
  ((:|id| . "amst") (:|key| . "Amsterdam")
   (:|value| (:|_id| . "amst") (:|_rev| . "1-3092672538") (:CITY . "Amsterdam")
    (:COUNTRY . "NL")))
  ((:|id| . "rott") (:|key| . "Rotterdam")
   (:|value| (:|_id| . "rott") (:|_rev| . "1-2303974290") (:CITY . "Rotterdam")
    (:COUNTRY . "NL")))))

;; Use "nl" view to find a specific city in the Netherlands
CLOUCHDB-USER> (invoke-view "cities" "nl" :key "Rotterdam")
((:|total_rows| . 2) (:|offset| . 1)
 (:|rows|
  ((:|id| . "rott") (:|key| . "Rotterdam")
   (:|value| (:|_id| . "rott") (:|_rev| . "1-2303974290") (:CITY . "Rotterdam")
    (:COUNTRY . "NL")))))

;; Invoke "country" view to search for US cities
CLOUCHDB-USER> (invoke-view "cities" "country" :key "US")
((:|total_rows| . 4) (:|offset| . 2)
 (:|rows|
  ((:|id| . "chi") (:|key| . "US")
   (:|value| (:|_id| . "chi") (:|_rev| . "1-1962544983") (:CITY . "Chicago")
    (:COUNTRY . "US")))
  ((:|id| . "nyc") (:|key| . "US")
   (:|value| (:|_id| . "nyc") (:|_rev| . "1-2083466274")
    (:CITY . "New York City") (:COUNTRY . "US")))))

;; Find the US city Chicago using the "multi" index:
CLOUCHDB-USER> (invoke-view "cities" "multi" :key '("US" "Chicago"))
((:|total_rows| . 4) (:|offset| . 2)
 (:|rows|
  ((:|id| . "chi") (:|key| "US" "Chicago")
   (:|value| (:|_id| . "chi") (:|_rev| . "1-1962544983") (:CITY . "Chicago")
    (:COUNTRY . "US")))))

;; Use "multi" index to find all cities with country codes that start with "N"
CLOUCHDB-USER> (invoke-view "cities" "multi" :start-key '("N") :end-key '("O"))
((:|total_rows| . 4) (:|offset| . 0)
 (:|rows|
  ((:|id| . "amst") (:|key| "NL" "Amsterdam")
   (:|value| (:|_id| . "amst") (:|_rev| . "1-3092672538") (:CITY . "Amsterdam")
    (:COUNTRY . "NL")))
  ((:|id| . "rott") (:|key| "NL" "Rotterdam")
   (:|value| (:|_id| . "rott") (:|_rev| . "1-2303974290") (:CITY . "Rotterdam")
    (:COUNTRY . "NL")))))

Example 4

Demonstrating the use of the attachment API

;; Adding an attachment to a document, this will create the document too
;; if it does not already exist
CLOUCHDB-USER> (add-attachment "photos" 
                               (pathname "/home/peter/images/camels.jpg"))
((:|ok| . T) (:|id| . "photos") (:|rev| . "1-1883927893"))

;; Take a look at what was just created
CLOUCHDB-USER> (get-document "photos")
((:|_id| . "photos") (:|_rev| . "1-1883927893")
 (:|_attachments|
  (:|camels.jpg| (:|stub| . T) (:|content_type| . "application/octet-stream")
   (:|length| . 54271))))

;; Get just the list of attachemnts in the "photos" document
CLOUCHDB-USER> (attachment-list (get-document "photos"))
((:|camels.jpg| (:|stub| . T) (:|content_type| . "application/octet-stream")
  (:|length| . 54271)))

;; Copy the attachment from the document to /tmp directory on the local disk
;; and return the resulting file name and path.
CLOUCHDB-USER> (save-attachment "photos" "camels.jpg" (pathname "/tmp/"))
#P"/tmp/camels.jpg"

;; Copy the camels.jpg attachment from the document to a differently 
;; named file on the local disk
CLOUCHDB-USER> (save-attachment "photos" "camels.jpg" 
                                (pathname "/tmp/SomeCamels.jpg"))
#P"/tmp/SomeCamels.jpg"

;; Copy camels.jpg attachment from the "photos" document to
;; the "camels2.jpg" attachment of the "animals" document
;; The with-attachment macro returns the attachment as
;; an input stream and closes that stream before returning.
CLOUCHDB-USER> (with-attachment (in "photos" "camels.jpg")
                 (add-attachment "animals" in :name "camels2.jpg"))
((:|ok| . T) (:|id| . "animals") (:|rev| . "1-2497134014"))

;; Delete the "camels.jpg" attachment from the "photos" document
CLOUCHDB-USER> (delete-attachment "photos" "camels.jpg")
((:|ok| . T) (:|id| . "photos") (:|rev| . "2-3799224225"))

;; Delete all attachments in the "animals" document
CLOUCHDB-USER> (dolist (at (attachment-list "animals"))
                 (delete-attachment "animals" at))

API Reference

Server Connection and Database Management API

The API described in this has to do with managing CouchDb server information and the creation and deletion of databases.

[Symbol]
*couchdb*

This special variable contains an instance of the db structure which identifies the target host, port and database name for general database operations.

See (set-connection), (with-connection), (make-db)

[Function]
changes &key db feed since style heartbeat filter notify-fn include-docs

Return document change activity information for a database.

Parameter Description
:db The target database or database host information, specified either as a string or a db structure. Defaults to current database in *couchdb*.
:feed Either :normal to not poll (the default), :longpoll to block waiting for a single response from the server, or :continuous to poll for changes indefinately.
:since
:heartbeat The period, in milliseconds, after which a nil result is sent. Applies only to :longpoll and :continuous feed options. Overrides any timeout value.
:timeout Time, in milliseconds, after which the database will send an empty line. Applies only to :longpoll or :continuous feed options.
:filter
:notify-fn A function to call as change notifications arrive. If specified, the call to (changes) will block and the notify-fn function will be called as each change notification arrives. The function should take one parameter, which will be the change notification document or nil (when :heartbeat is specified). The function should return true to continue to receive change notifications or false to cancel receipt of change notifications. When the notification function returns false the open stream to the CouchDb server is closed and the call to (changes) will return.
:include-docs If true, include the associated document with each result. (CouchDb version 0.11+)

Example:

;; Changes for the current database
(changes)
=> 
((:|results|
  ((:|seq| . 4) (:|id| . "_design/example")
   (:|changes| ((:|rev| . "1-f83b5f3e154eb3c0ba2d721ad53211b3"))))
  ((:|seq| . 5) (:|id| . "_design/toast")
   (:|changes| ((:|rev| . "1-3525a1d974ba13a34d26e305116feab2")))))
 (:|last_seq| . 5))

;; Define function to be called when changes occur
(defun handle-change (change) 
  (format t "got change: ~A~%" change) 
  ;; return true to continue to receive change notifications
  t)

(changes :feed :continuous :notify-fn #'handle-change :heartbeat 1000)

got change: ((seq . 4) (id . _design/example)
             (changes ((rev . 1-f83b5f3e154eb3c0ba2d721ad53211b3))))
got change: ((seq . 5) (id . _design/toast)
             (changes ((rev . 1-3525a1d974ba13a34d26e305116feab2))))
got change: ((seq . 6) (id . biking)
             (changes ((rev . 1-7e2d4e10305a1b9cfc0ae5bd40a1b301))))
got change: ((seq . 7) (id . bought-a-cat)
             (changes ((rev . 1-8ea27c5ff15247402947864f1bafc245))))
got change: NIL
got change: NIL
got change: NIL

[Function]
compact-db &key db

Initiates database compaction. The database to compact, if unspecified, is the current value of *couchdb*. The db parameter allows an alternate database to be specified, either as a local database name string or a db structure instance.

Example:

;; Compact current database
(compact-db)
=> ((:|ok| . T))

;; Compact "default" database
(compact-db :db "default")

;; Compact "default" database
(compact-db :db (make-db :name "default"))
=> ((:|ok| . T))

[Function]
create-db &key db if-exists

Create a database. If specified, the db parameter may be either the string value of a local database name or an instance of the db structure. If the db parameter is unspecified the value of *couchdb* will be used to create the database.

The if-exists parameter defaults to :fail, which will raise an error if the database already exists. A value of :ignore will simply ignore the this error. A value of :recreate will delete the database if it exists, and then recreate it.

See (set-connection), (with-connection), (delete-db) (make-db)

Example:

;; Create the database named in the current connection settings
(set-connection :name "tvland")
(create-db)
=> ((:|ok| . T))

;; Specify name of database to create, if it already exists
;; then ignore the request (don't generate error, don't
;; recreate database), return (:ignored . T) if database did
;; exist
(create-db :db "tvland" :if-exists :ignore)
=> ((:|ok| . T) (:IGNORED . T))

;; Create named db, if it already exists, drop it and 
;; recreate it. Specify db using a db structure.
(create-db (make-db :name "tvland") :if-exists :recreate)
=> ((:|ok| . T))

[Function]
delete-db &key db if-missing

Delete a database. The db parameter, if specified, can be either a string to indicate a local database name or a db structure. If db is unspecified this function attempts to delete the database named in the current *couchdb* context See (set-connection) or (with-connection).

If :ignore is specified for the if-missing parameter, errors resulting from the attempt to delete a non-existent database are ignored.

See (set-connection), (with-connection), (make-db) (create-db)

Example:

;; Create then delete the database named in the current connection settings
(set-connection :name "tvland")
(create-db)
=> ((:|ok| . T))
(delete-db)
=> ((:|ok| . T))

;; Specify name of database to delete, if it doesn't exist
;; then ignore the request (don't generate error), return 
;; error result if database did not exist
(delete-db :db "radio" :if-missing :ignore)
=> ((:|error| . "not_found") (:|reason| . "missing"))

[Function]
get-couchdb-info &key db

Returns information about the CouchDb server specified in the *couchdb* special variable, or via the db keyword parameter if specified. The db keyword parameter may be either the string name of a database or an instance of a db structure.

(get-couchdb-info)
=> ((:|couchdb| . "Welcome") (:|version| . "0.10.0a788899"))

[Function]
get-db-info &key db

Returns database information for the connection and database in the current context, or, if the db keyword parameter is specified, for that database. The db keyword parameter may be either the string name of a database or an instance of a db structure.

Example:

(get-db-info)
=> ((:|db_name| . "default") (:|doc_count| . 0) (:|doc_del_count| . 0)
     (:|update_seq| . 0) (:|purge_seq| . 0) (:|compact_running|)
     (:|disk_size| . 79) (:|instance_start_time| . "1247095993127949")
     (:|disk_format_version| . 3))

(get-db-info :db "default")
=> ((:|db_name| . "default") (:|doc_count| . 0) (:|doc_del_count| . 0)
     (:|update_seq| . 0) (:|purge_seq| . 0) (:|compact_running|)
     (:|disk_size| . 79) (:|instance_start_time| . "1247095993127949")
     (:|disk_format_version| . 3))

(get-db-info :db *couchdb*)
=> ((:|db_name| . "default") (:|doc_count| . 0) (:|doc_del_count| . 0)
     (:|update_seq| . 0) (:|purge_seq| . 0) (:|compact_running|)
     (:|disk_size| . 79) (:|instance_start_time| . "1247095993127949")
     (:|disk_format_version| . 3))

[Function]
list-dbs

Returns a list of the databases that exist on the current database host, as specified in *couchdb*.

(list-dbs)
=> ("default" "example1" "example2" "example3")

[Function]
get-active-tasks &optional db

Get list of active tasks (compaction, replication, etc)

Parameter Description
db The target database or database host information specified as a db structure. Defaults to current database in *couchdb*.

[Function]
get-config &key db section

Get configuration data

Parameter Description
:db The target database or database host information specified as a db structure. Defaults to current database in *couchdb*. :section The configuration section

[Function]
get-stats &optional db

Get database statistics overview

Parameter Description
db The target database or database host information specified as a db structure. Defaults to current database in *couchdb*.

[Function]
make-db &key (db *couchdb*) host port name protocol user password document-fetch-fn document-update-fn

Create a new instance of a DB structure. This function uses the current values of *couchdb* to as defaults for the new instance unless an alternate source of these default values is specified is specified though the db parameter. The additional parameters override any from the default source structure.

(make-db)
=> #S(CLOUCHDB::DB
      :HOST "localhost"
      :PORT "5984"
      :NAME "default"
      :PROTOCOL "http"
      :USER NIL
      :PASSWORD NIL
      :DOCUMENT-FETCH-FN NIL
      :DOCUMENT-UPDATE-FN NIL)

(make-db :name "users" :host "www.company.com")
=> #S(CLOUCHDB::DB
      :HOST "www.company.com"
      :PORT "5984"
      :NAME "users"
      :PROTOCOL "http"
      :USER NIL
      :PASSWORD NIL
      :DOCUMENT-FETCH-FN NIL
      :DOCUMENT-UPDATE-FN NIL)

;; Temporarily set current db connection info to alternate database
(let ((*couchdb* (make-db :name "users" :host "www.company.com")))
  (get-document "someuser"))

[Function]
set-connection &key host name protocol port document-update-fn document-fetch-fn => db structure

Sets the host name, database name, protocol ("http" or "https") and port number for the top-level connection to the CouchDb server. Default connection settings are host="localhost", protocol="http", port="5984" and database="default". Note: This function destructively updates the *couchdb* special variable.

Functions may be specified that should invoked automatically each time a document is created or updated (document-update-fn) and each time a document is fetched (document-fetch-fn). These functions must take one argument, the document, and return the potentially modified document.

*couchdb*
=> #S(CLOUCHDB::DB
     :HOST "localhost"
     :PORT "5984"
     :NAME "default"
     :PROTOCOL "http"
     :USER NIL
     :PASSWORD NIL
     :DOCUMENT-FETCH-FN NIL
     :DOCUMENT-UPDATE-FN NIL)

(set-connection :host "orubus")
*couchdb*
=> #S(CLOUCHDB::DB
     :HOST "orubus"
     :PORT "5984"
     :NAME "default"
     :PROTOCOL "http"
     :USER NIL
     :PASSWORD NIL
     :DOCUMENT-FETCH-FN NIL
     :DOCUMENT-UPDATE-FN NIL)

Example of update function use:

;; Create a function that adds or updates a timestamp field in a
;; document and returns the modified document
(defun time-stamper (doc) 
  (set-document-property doc :timestamp (get-universal-time)))

;; Cause time-stamper to be invoked with each document as
;; it's updated or created
(set-connection :document-update-fn #'time-stamper)

;; Test the new time stamping feature
(create-document '((:hello . "there")) :id "test")
=> ((:|ok| . T) (:|id| . "test") (:|rev| . "3721228336"))

;; Display the new document with timestamp
(get-document "test")
=> ((:|_id| . "test") (:|_rev| . "3721228336") (:TIMESTAMP . 3422649324) 
  (:HELLO . "there"))

See (with-connection)

[Function]
replicate target &key source

Replicate source database to target. The target may be specified either with a local database name string or a DB structure. The source database defaults to the current value of *couchdb*.

If the :create-target keyword parmaeter is true the database will automatically create the replication target if necessary (requires CouchDb version 0.11+)

Example:

  ;; Replicate current database to databased named "backup" on the same server
  (replicate "backup")

  ;; Replicate current database to remotely hosted "backup" database
  (replicate (make-db :name "backup" :host "remote"))
   
  ;; Replicate one remote database to another
  (replicate (make-db :name "backup" :host "remoteB")
     :source (make-db :name "source" :host "remoteA"))

[Macro]
with-connection (&key db host name protocol port document-update-fn document-fetch-fn) &body body => value returned by evaluation of body

Executes the statements in the body in the context of the specified connection values. Sets the db, host name, database name, protocol ("http" or "https") or port number of the CouchDb server to use in the expressions in the body.

Functions that are called as documents are created or modified (document-update-fn) and when documents are fetched (document-fetch-fn) may be specified. These functions take one parameter, the document being sent to or fetched from the database, and return a potentially modified document.

Example:

;; Get document from specified host and database
(with-connection (:host "cornichon.cucumber.net" :name "rfc")
  (get-document "2616"))

;; Copy document identified by "someid" from database "otherdb" to 
;; current database, use "copy-of-someid" for copied document ID.
(put-document
  (with-connection (:name "otherdb")
    (get-document "someid"))
  :id "copy-of-someid")

See (set-connection)

[Macro]
with-temp-db (&body) => value returned by evaluation of body

Perform operations in body in newly created, temporary database. Database is created using the current connection information in *clouchdb*, with a name that should not conflict with existing database names. The database is deleted before returning.

(with-temp-db 
  *couchdb*)

=> #S(CLOUCHDB::DB
      :HOST "localhost"
      :PORT "5984"
      :NAME "temp-3456412771-3"
      :PROTOCOL "http"
      :USER NIL
      :PASSWORD NIL
      :DOCUMENT-FETCH-FN NIL
      :DOCUMENT-UPDATE-FN NIL)

Document API

The Document ID

Documents in clouchdb are identified by a document ID string which must be unique within the database that contains the document. The ID string may either be specified when the document is created or it will be provided by the CouchDb server if unspecified.

Document Content

Document content takes the form of an associative list. The car of each associative list element represents the document field name, the cdr contains the value. Field names are specified as keyword symbols. The following example demonstrates the creation of a simple document with two fields, :name and :agent, and with a specified document ID:

(create-document '((:name . "Max") (:agent . 86)) :id "agent86")
(get-document "agent86")
=> ((:|_id| . "agent86") (:|_rev| . "3674093994") (:NAME . "Max") (:AGENT . 86))
  

By giving keyword symbols their special significance as field names identifiers, clouchdb is able to distinguish between field names and field values in certain situations which would otherwise be ambiguous. For example, keyword symbols allow clocuhdb to distinguish between associative lists and lists that contain other, non-associative lists.

Field names in CouchDb are case sensitive. Field names specified with unquoted keyword symbols are normally converted to upper case by Lisp and this results in upper case field names in the CouchDb server. Use quotes in symbol names to specify mixed or lower case field names, like so:

;; Create a document with a mixed case field name. This document
;; will appear in the database as, "MixedCaseName"
(create-document '((:|MixedCaseName| . "Value")) :id "mixed-case")
(get-document "mixed-case")
=> ((:|_id| . "mixed-case") (:|_rev| . "2016717365") (:|MixedCaseName| . "Value"))
  

The native document representation in the CouchDb protocol is a JSON object. Clouchdb translates documents to and from JSON as necessary.

The value of a document field may be a string, a number, a list, or an associative list. Document field values may be nested to create arbitrarily complex document structures.

(create-document '((:string . "String Value")
                   (:number . 42.0)
                   (:list . (milk eggs "green beans"))
                   (:alist . ((:string . "Another String")
                              (:size . 3)
                              (:list . ("un" "deux" "trois"))
                              (:another-alist . ((a . "A") (b . "B")))))))

Special Properties

When a document is created CouchDb assigns special properties to that document, these properties cannot be modified by clients. The special properties include the document's ID (:|_id|) and the document revision number (:|_rev|). All special properties begin with an underscore (_) symbol. CouchDb uses lower case for these special properties therefore, as of Clouchdb version 0.0.8, they will always appear as quoted keyword symbols.

(create-document '((:name . "Maxwell Smart") (:agent . 86)) :id "max")
=> ((:|ok| . T) (:|id| . "max") (:|rev| . "3789799231"))

(get-document "max")
=> ((:|_id| . "max") (:|_rev| . "3789799231") (:NAME . "Maxwell Smart") (:AGENT . 86))

Please refer to the CouchDb Document API for general CouchDb document information.

[Function]
as-deleted-document doc

Return specified document in a format used by bulk-document-update to indicate that the document should be deleted in the bulk operation.

Example: Use of as-deleted-document to delete multiple documents at once

(bulk-document-update 
  (mapcar #'as-deleted-document (list (get-document "one")
                                       (get-document "two"))))
=>(((:|id| . "one") (:|rev| . "2-1128337663"))
   ((:|id| . "two") (:|rev| . "2-1919003983")))

[Function]
as-keyword-symbol string

Create a keyword symbol from a string, encode case information in the result. This function translates Json field names from CouchDb into the Lisp keyword symbols used in documents.

Example:

;; Lower case
(as-keyword-symbol "lowercase")
=> :|lowercase|

;; Upper case
(as-keyword-symbol "UPPER-CASE")
=> :UPPER-CASE

;; Mixed case
(as-keyword-symbol "MixedCase")
=>:|MixedCase|

See (as-field-name-string)

[Function]
as-field-name-string symbol

Convert a field name keyword symbol to a camelCase style string. This function produces the field name in the format that will be used and visible in CouchDb.

Example:

  ;; Upper case
  (as-field-name-string :case)
  => "CASE"

  ;; Lower case
  (as-field-name-string :|case|)
  => "case"

  ;; Mixed case
  (as-field-name-string :|MixedCase|)
  => "MixedCase"

See (as-keyword-symbol)

[Function]
all-docs-by-seq

Return all updated or deleted documents in the order that these actions were done.

[Function]
couchdb-document-properties doc

Return only CouchDb specific document properties, stripping off CouchDb non special properties. The doc parameter specifies the document.

See (document-properties)

(get-document "apple")
=> ((:|_id| . "apple") (:|_rev| . "1-4022626409") (:FRUIT . "Apple"))

(couchdb-document-properties (get-document "apple"))
=> ((:|_id| . "apple") (:|_rev| . "1-4022626409"))

[Function]
create-document doc &key id

Create a new document, optionally specifying the document's ID. This function simply calls (put-document) if an ID is specified, otherwise it calls (post-document).

Parameter Description
doc The document contents or nil to create empty document
:id The ID for the new document. If not specified, CouchDb will provide an ID value.
:attachments One or more document attachments

Example:

;; Create document, specifying ID of "example"
(create-document '((:string . "string") 
                   (:number . 42)
                   (:array . ("one" 2 "nine"))
                   (:map . ((:foo . "bar")
                            (:size . 3)
                            (:colors . ("red" "blue" "green")))))
                 :id "example")

;; Create a document and let CouchDb provide an ID
(create-document '((:some . "data")))

See (put-document) (post-document)

[Function]
bulk-document-update docs &key all-or-nothing

Update multiple documents in a single request. The docs parameter is a list of documents. Any document in the list that does not contain an :|_id| value is created with a CouchDb assigned ID. Documents that contain a '(:|_deleted| . t) top-level property will be deleted. Documents that contain an :|_id| property will be updated.

If all-or-nothing is true then the entire operation will fail if any individual document operation cannot be performed. The default is false.

Example: Create two simple documents in one operation using bulk-document-update. The first document is created with a CouchdDb assigned ID value, the ID for the second document is specified.

(bulk-document-update (list '((:name . "Bob"))
                            '((:name . "Ted") (:|_id| . "ted"))))
=>(((:|id| . "6df18bda590ee37927ec33cdcdd3e41b") (:|rev| . "1-2493069933"))
   ((:|id| . "ted") (:|rev| . "1-1461663065")))

[Function]
copy-document source destination &key revision

Copy source document to destination. The source parameter may be either a document ID or a document from which the ID will be obtained. The destination parameter may also be a document ID or document. If the destination document does not already exist it will be created.

If the destination document does exist and the intention is to overwrite that document, then the destination document revision must be specified. If the destination parameter is a document then the revision information will be taken from that document unless the :revision parameter is specified. The revision parameter must be the current revision of the destination document. Alternatively the revision parameter may be the keyword :current which will cause this function to fetch the current revision number from the database.

;; Copy document identified by "source" to new document "copy")
(copy-document "source" "copy")

;; Overwrite "destination" with "source" document
(copy-document "source" (get-document "destination"))

;; Overwrite "destination" with "source" document
(copy-document "source" "destination" :revision :current)

[Function]
delete-document &key doc-or-id revision if-missing

Delete the specified document. The document may be specified with either the string ID or with a document object, the latter which must include the standard CouchDb special variables :|_id| and :|_rev|. If revision is specified, either via the revision parameter or in the :|_rev| property of the document, deletes the specific revision of identified document. If no revision is specified, deletes the most current revision by fetching the document by ID and using its :|_rev| value for the deletion.

Signals a document-missing error if document does not exist, unless the :if-missing keyword parameter is set to :ignore

[Function]
document-property name doc

Get the value of the named document property or nil if property does not exist. This function can be used with setf to set property values as well. The name parameter may be either a keyword document property name or a list of such properties. If name is a list, it specifies a nested property in the document starting with the outermost property and proceeding to the most nested property.

(create-document '((:name . "Maxwell Smart") (:agent . 86)) :id "max")

(document-property :name (get-document "max"))
=> "Maxwell Smart"

;; Nested property change example
(create-document '((:a . 1)(:b . ((:c . ((:d . "New York")))))) :id "nested")
;; Change (:d . "New York") to (:d . "Boston")
(put-document
  (setf (document-property '(:b :c :d) (get-document "nested")) "Boston"))

See (set-document-property)

[Function]
get-all-documents &key key start-key start-key-docid end-key end-key-docid limit stale descending skip group group-level reduce include-docs

Return ID and current revision information for all documents, ordered by ascending document ID. If descending is non-nil, returns documents in reverse order.

[Function]
get-document id &key revision revisions revision-info if-missing conflicts

Get document by id.

If the specified document is not found in the database this function will signal an error unless if-missing is :ignore.

Note: Revision information is used by CouchDb to support database replication. You should not use revision data to build version control type systems becuase older revisions will be deleted automatically when no longer needed by the database.

Parameter Description
id The document ID
:revision The optional document revision. If not specified, returns the most recent revision.
:conflicts If true, return any existing replication conflicts for the document.
:revisions If non-nil, return brief revision information for the document.
:revision-info If non-nil, returned document will contain detailed document revision information.
:if-missing If the specified document does not exist, return the value specified instead. If the value is a function pointer, call the function with the ID of the missing document.

[Function]
get-uuids &key count

Get one or more UUIDs from the datbase. Note that the database does not guarantee that the UUIDs returned are not already used in the database.

Parameter Description
:db The target database or database host information, specified either as a string or a db structure. Defaults to current database in *couchdb*.
:count The number of UUIDS to return. Default is 1

Example:

    ;; Create a document, let server assign an ID
    (get-uuids :count 3)

    =>((:|uuids| "ff02503bc937206fa3aec576b0378fc0"
        "84b78cb82667856025929bfe30168ea3" "2c9026f46d8db4f8cc669f91c501c265"
        "289f477p587e1775a5f3f6e55cb5b76f0" "d28f7a78268d8411b53bdf4bb4d6b9f9"))
  

[Function]
document-properties doc

Return only non-CouchDb specific document properties, stripping off CouchDb special properties. The doc parameter specifies the document.

See (couchdb-document-properties)

(get-document "apple")
=> ((:|_id| . "apple") (:|_rev| . "1-4022626409") (:FRUIT . "Apple"))

(document-properties (get-document "apple"))
=> ((:FRUIT . "Apple"))

[Function]
post-document doc

Create a document and let the server assign an ID. An existing :|_id| field in the document will be ignored, the server will create a new document and assign it a new ID. This therefore is an easy way to copy documents. The return value includes the server-assigned document ID in the :|id| property.

Example:

;; Create a document, let server assign an ID
(post-document '((:field . "value")))

=> ((:|ok| . T) (:|id| . "4A0FF20F6AE5168B771BC41D4557F650") (:|rev| . "16873930"))

See (create-document) (put-document)

[Function]
put-document doc &key id

Create a new document or update an existing one. If the document is new an ID must be specified. If the document has been fetched from the server (and still retains its :|_*| CouchDb special properties) then no ID need be specified. If a parameter ID is provided and it differs from the :|_id| value in the document, then a new document is created with the provided ID and any non-special properties of the document.

Example:

;; Create document "A"
(put-document '((:name . "Laraby")) :id "A")

;; Copy to new document "B"
(put-document (get-document "A") :id "B")

;; Add field to document "B"
(put-document (cons '(:new-field . "new-value")) (get-document "B"))

See (create-document) (post-document)

[Function]
query-document query document

This function can be used to extract data from complex documents or other CouchDb data such as results returned from views. The query parameter is a list containing zero or more query expressions. A query expression can be either a keyword symbol, which simply matches the keyword field name in the document, wild card symbols, or a function.

Note that this function does not represent any CouchDb API, nor does it communicate with the database other than when functions are used in the query and these functions communicate with the database.

Query Operators
Type Description
keyword symbol Matches field name in document
:* Wild card, matches any symbol at the current level in the document
:** Recursive wild card, matches subsequent symbol at any level in the document below the current level
function The function should accept a single parameter. This parameter will contain the value matched by the previous query term, or the initial document if the function is the first element in the query list. Query operators following the function are applied to the result of the function or, if the function is the last operator in the query, the function return value is collected in the query-document results list.

Examples:

;; Secret Agent document to query
(setf *agents* '((:control
                  (((:name . "Max") (:agent . 86)) 
                   ((:name . "Ninety Nine") (:agent . 99))
                   ((:agent . 44))
                   ((:agent . 13))
                   ((:name . "Hymie"))
                   ((:name . "Larrabee"))
                   ((:name . "Fang") (:agent . "K-9"))))
                 (:kaos
                  (((:name . "Siegfried"))
                   ((:name . "Shtarker"))
                   ((:name . "The Claw"))
                   ((:name . "Colonel von Klaus"))))))

;; Get the agent values for all Control agents that have these values
(query-document '(:control :agent) *agents*)
=> ("K-9" 13 44 99 86)

;; Get names of agents that work for Control or Kaos, for agents who have names
(query-document '(:* :name) *agents*)
=> ("Colonel von Klaus" "The Claw" "Shtarker" "Siegfried" "Fang" "Larrabee" 
  "Hymie" "Ninety Nine" "Max")

;; Get a value from a deeply nested position
(query-document '(:** :value) '((:a . 
                                 ((:very . 
                                   ((:deeply . 
                                     ((:nested . 
                                       ((:value . "Deep Value")))))))))))
=> ("Deep Value")

;; Use the recursive wild card operator to retrieve values from any level
(query-document '(:** :value) 
                '((:one . 
                   ((:very . 
                     ((:deeply . 
                       ((:nested . 
                         ((:value . "Deep Value")))))))))
                  (:this . 
                    ((:value . 
                      ((:is . 
                        ((:different . "Different Deep Value")))))))))

=> (((:IS (:DIFFERENT . "Different Deep Value"))) "Deep Value")

;; Functions
;;
;; Query the results of (get-all-documents), extracting all
;; document :|id| values in the :|rows| property.
;; 
;; Use the clouchdb function (get-document) to look up the 
;; corresponding document for each value of :|id|. The form below will 
;; return the value of the :name property for all documents in the
;; current database that have one or more :name properties

(query-document `(:|rows| :|id| ,#'get-document :** :name) (get-all-documents))

See the function (example3) in examples.lisp for more information

[Function]
set-document-property doc &rest args

Modify existing named property or add property names and values to a document. This function returns a new copy of the specified document, it does not modify its document parameter.

Example:

(create-document '((:name . "Maxwell Smart") (:agent . 86)) :id "max")

(document-property :name (get-document "max"))
=> "Maxwell Smart"

;; Modify existing :name value and add :employer property
(put-document 
  (set-document-property (get-document "max")
                         :name "Maxwell Smart, Secret Agent"
                         :employer "Control"))
(get-document "max")
=> ((:|_id| . "max") (:|_rev| . "655510103") (:EMPLOYER . "Control")
    (:NAME . "Maxwell Smart, Secret Agent") (:AGENT . 86))

Attachment API

Attachments are files that are associated with documents in the database. An attachment may be a file of any type, text or binary. Files are not normally viewable as document data. Their presence in a document is indicated by a list of meta data in the document's :|_attachments| property.

;; A document with three attachments
(get-document "images")
=>((:|_id| . "images") (:|_rev| . "7-1856240461")
   (:|_attachments|
    (:|camels.jpg| (:|stub| . T) (:|content_type| . "image/jpeg")
     (:|length| . 54271))
    (:|butter.jpg| (:|stub| . T) (:|content_type| . "image/jpeg")
     (:|length| . 54271))
    (:|birds.jpg| (:|stub| . T) (:|content_type| . "application/octet-stream")
     (:|length| . 54271))))

This library implements support only for stand-alone attachment CouchDb API.

[Function]
add-attachment doc-or-id content &key name revision content-type

Adds an attachment to the document specified by doc-or-id, which may be the string identifier of the document or the document itself. If the string ID is specified but the document's revision is unspecified, this function will fetch the current document from the database in order to obtain the necessary revision information. If a document object is specified then the revision information is taken from that object, and no additional fetch is required.

The content parameter becomes the content of the attachment, and may be either a string, an open binary input stream, a pathname or a sequence of octets (clouchdb passes this value directly to Drakma, so see Drakma's content documentation for more information.)

The content-type parameter allows the document to be created and tagged as containing the specified content type. The name parameter names the attachment. If the attachment content comes from a file the attachment name will be the file name if this parameter is unspecified. If the attachment content is not from a file then the attachment must be named with this parameter.

If the doc-or-id parameter is a string value and revision is unspecified, this function will fetch the current document from the database in order to obtain the current document revision number.

;; Add file attachment with content type
(add-attachment "Moscow"
                (pathname "/home/peter/Pictures/images/Zaryadye.jpg")
                :content-type "image/jpeg")
=>((:|ok| . T) (:|id| . "Moscow") (:|rev| . "1-2164210511"))

;; Add attachment but supply an attachment name to use instead of
;; the file name
(add-attachment "Moscow"
                (pathname "/home/peter/Pictures/images/Suharevskaia.jpg")
                :name "Sukharevskaya.jpeg"
                :content-type "image/jpeg")
=>((:|ok| . T) (:|id| . "Moscow") (:|rev| . "2-2235841483"))

;; Add string value as attachment
(add-attachment "StringDoc" "Attachment Content" :name "StringAttachment")
=>((:|ok| . T) (:|id| . "StringDoc") (:|rev| . "1-2376170595"))

[Function]
attachment-list doc-or-id &key fetch

List document attachments. The document, specified by doc-or-id, may be the string identifier of the document or the document itself. If the string ID is specified this function will fetch the document from the database in order to obtain the attachment information. If a document object is specified then the attachment information is taken from that object, and no database communication is performed.

If a document is provided and parameter fetch is true this function will fetch a fresh copy of the document from the database.

(attachment-list "Moscow")
=>((:|Sukharevskaya.jpeg| (:|stub| . T) (:|content_type| . "image/jpeg")
    (:|length| . 119891))
   (:|Zaryadye.jpg| (:|stub| . T) (:|content_type| . "image/jpeg")
    (:|length| . 30057)))

[Function]
attachment-name attachment

Return the attachment name as a string. The attachment parameter maybe a symbol name, e.g. :|file.jpg|, a string, or one element of a document's attachment list.

Example: Print the names of all document attachments
(dolist (attachment (attachment-list "SomeDocument"))
  (format t "Name: ~s~%" (attachment-name attachment)))
=> Name: "Sukharevskaya.jpeg"
   Name: "Zaryadye.jpg"

[Function]
delete-attachment doc-or-id attachment &key revision

Delete an attachment. The doc-or-id parameter may be the string identifier of the document or the document itself from which the ID will be obtained.

The attachment parameter is either the string name of the attachment to remove from the document, a keyword symbol (as obtained from the car of the elements of the :|_attachments| value of a document) or it is one element of the list of attachments in a document."

If the doc-or-id parameter is a document the document revision will be taken from that object. Otherwise, the revision parameter indicates the revision of the document from which to delete the attachment. If this parameter is not supplied then a request will be made to the database to obtain the document's current revision number.

[Function]
get-attachment-stream doc-or-id attachment

Return attachment stream. The document, specified by doc-or-id, may be the string identifier of the document or the document itself. The attachment parameter is either the string name of the attachment, a keyword symbol attachment name (as it would appear in the car of the document's attachment list), or an element of the document's attachment list. Caller must always close the returned stream.

[Function]
save-attachment doc-or-id attachment path &key if-does-not-exist if-exists

Save specified document attachment to disk file. The document, specified by doc-or-id, may be the string identifier of the document or the document itself from which the ID will be obtained.

The attachment parameter is either the string name of the attachment or an element from the document's attachment list. The path parameter must be a pathname. If path identifies a directory then the target file will be created in that directory with the same name as the attachment in the document. If the path ends with a file name then the attachment will be created with that name.

;; Save an attachment to /tmp/camels.jpg. Directory name must end
;; with / 
(save-attachment "images" "camels.jpg" (pathname "/tmp/"))
=>#P"/tmp/camels.jpg"

;; Save an attachment to a different file name in /tmp/
(save-attachment "images" "camels.jpg" (pathname "/tmp/someCamels.jpg"))
=>#P"/tmp/someCamels.jpg"

[Macro]
with-attachment stream doc-or-id attachment &body body

Macro that provides the attachment as an input stream and automatically closes that stream after executing the statements in its body. The document containing the attachment, specified by doc-or-id, may be the string identifier of the document or the document itself from which the document ID will be obtained. The attachment parameter is either the string name of the attachment or a single element of the document's attachment list.

;; Use with-attachment to copy attachment "camels.jpg" from document
;; "images" to document "animals"
(with-attachment (in "images" "camels.jpg")
  (add-attachment "animals" in :name "camels.jpg"))
=>((:|ok| . T) (:|id| . "animals") (:|rev| . "1-2861475448"))

Views API

Views are the query mechanism for CouchDb. There are two types of views in CouchDb: ad hoc and persistent. As you might expect persistent views are stored in the database. Ad hoc views are not, they are sent from the client each time they're used. Native CouchDb views are expressed in JavaScript. While it is possible to use JavaScript with the Clouchdb API, it may be more natural to use the Parenscript library instead. Parenscript is library for generating JavaScript using Lisp syntax.

Note that CouchDb and JavaScript are case sensitivie. Field names in documents created using un-quoted keyword symbol field names (e.g., :name) will be converted to upper case by Lisp and result in upper case field names in CouchDb and JavaScript.

For general CouchDb View information, please see the the CouchDb View API wiki.

Field Name Case Comparison
Clouchdb Parenscript CouchDb/JavaScript
:name, :NAME, :NaMe *name*, *NAME* *NaMe* NAME
:|name| name name
:|mixedCase| mixed-case mixedCase

Please refer to CouchDb View API Documentation for general information about CouchDb views. Note: Many details of CouchDb views have yet to be documented. In the meantime, see this blog post for some useful hints.

[Function]
ad-hoc-view view &key key start-key start-key-docid end-key end-key-docid limit stale descending skip group group-level reduce include-docs language

Executes a one-time, non persistent view (query). The view is specified as a JavaScript anonymous function.

Keyword parameters

Example:

(create-document '((:name . "Laraby")))
(ad-hoc-view "function(doc) { if (doc.NAME == 'Laraby') { map(null,doc.NAME) } }")

Ok, but this is Lisp and JavaScript looks exotic and scary. To solve this problem we use Parenscript. The following expression generates the same view with a more familiar syntax:

(create-document '((:name . "Laraby")))
(ad-hoc-view (ps (lambda (doc)
                   (with-slots (*name*) doc
                     (if (eql *name* "Laraby")
                       (emit nil doc))))))

Note that it is not necessary for every document in the database to have a field called 'name'. This view will return only those documents that have a name field and where the value of that name field is "Laraby". No errors result from documents with no name field.

The (with-slots) expression above can be eliminated, if desired, like so:

(ad-hoc-view (ps (lambda (doc)
                   (if (eql doc.*name* "Laraby")
                     (emit nil doc))))))

See (create-ps-view) and Example 3

[Function]
create-ps-view {view-definition}*

Creates a view document containing one or more view definitions. The view definitions may be specified in a JavaScript string or Parenscript s-expresions.

The following example view definition is the clouchdb equivalent of the JavaScript views defined under the "Creating Views" section of the CouchDb View API wiki page.

(create-ps-view "company"
                (ps-view ("all")
                  (defun map (doc)
                    (with-slots (type) doc
                      (if (eql type "customer")
                          (emit null doc)))))
                (ps-view ("by_lastname")
                  (defun map (doc)
                    (with-slots (type last-name) doc
                      (if (eql type "customer")
                          (emit last-name doc))))
                (ps-view ("total_purchases")
                  (defun map (doc)
                    (with-slots (type customer amount)
                      (if (eql type "purchase")
                          (emit customer amount))))
                  (defun reduce (keys values)
                    (sum values)))))

See (invoke-view) (ad-hoc-view) and Example 3

[Function]
delete-view id &key rev

Delete view document identified by id. If revision is specified, delete specific revision of view document.

See (create-ps-view)

[Function]
invoke-view id view &key key start-key start-key-docid end-key end-key-docid limit stale descending skip group group-level reduce include-docs

Invoke specified view in identified view document.

Keyword parameters

Example:

;; Document to query
(create-document '((:name . "Laraby")))

;; Views defined with Parenscript
(create-ps-view "names"
  (cons "laraby"
        (ps (lambda (doc)  ;; parameter-less view
              (with-slots (name) doc
                (if (eql "Laraby" name)
                  (emit nil doc))))))
  (cons "name"
        (ps (lambda (doc)  ;; parameter view
              (with-slots (name) doc
                (emit name doc))))))

;; Find document by invoking parameter-less "laraby" view
(invoke-view "names" "laraby")

;; Find document by invoking "name" view with key parameter
(invoke-view "names" "name" :key "Laraby")

See (create-ps-view) (ad-hoc-view) and Example 3


Conditions Defined by Clouchdb

attachment-missing
Error signaled when an attachment is requested which is not found to exist in the associated document. This is a sub type of doc-error
clouchdb-error
The base type of all errors signaled by clouchdb.
db-already-exists
Signaled when an attempt is made to create a database that already exists. This is a sub type of db-existential-error
db-does-not-exist
Signaled when an attempt is made to use a database that does not exist. This is a sub type of db-existential-error
db-existential-error
The base type of all database management errors (as opposed to document, view, etc.) This is a sub type of clouchdb-error
doc-error
The base type of all document related errors. This is a sub type of clouchdb-error
document-missing
Error signaled when an attempt is made to operate on an existing document which does not exist. This is a sub type of doc-error
id-missing
Error signaled when a required document ID has not been supplied. This is a sub type of doc-error
id-or-revision-conflict
Signaled when an operation is performed on a document which does not represent the current version of the document in the database, for example, when that document has been modified by another process. This is a sub type of doc-error
illegal-database-name
Signaled when an attempt is made to create a database with an illegal name. This is a sub type of db-existential-error
invalid-type
Error raised when an invalid type was specified for a parameter. This is a sub type of clouchdb-error

Symbol Index

ad-hoc-view
add-attachment
all-docs-by-seq
as-deleted-document
as-field-name-string
as-keyword-symbol
attachment-list
attachment-missing
attachment-name
bulk-document-update
clouchdb-error
changes
compact-db
copy-document
*couchdb*
couchdb-document-properties
create-db
create-document
create-ps-view
create-temp-db
db-already-exists
db-does-not-exist
db-existential-error
delete-attachment
delete-db
delete-document
delete-view
doc-error
document-id
document-missing
document-properties
document-property
document-revision
document-to-json
encode-document
get-active-tasks
get-all-documents
get-attachment-name
get-attachment-stream
get-config
get-couchdb-info
get-db-info
get-document
get-stats
get-uuids
id-missing
id-or-revision-conflict
illegal-database-name
invalid-input
invoke-view
json-to-document
list-dbs
make-db
post-document
ps-view
put-document
query-document
replicate
save-attachment
set-connection
set-document-property
with-attachment
with-connection
with-temp-db

Issues and Bugs

Back to Common-lisp.net.

Valid XHTML 1.0 Strict

Valid XHTML 1.0 Strict