From peddy at common-lisp.net Sat Jun 7 22:37:20 2008 From: peddy at common-lisp.net (peddy) Date: Sat, 7 Jun 2008 18:37:20 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/public_html Message-ID: <20080607223720.27B0A111CC@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/public_html In directory clnet:/tmp/cvs-serv6365 Modified Files: index.html Log Message: Added warning about incompatiblity with new views API --- /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/03/01 19:46:03 1.18 +++ /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/07 22:37:19 1.19 @@ -50,6 +50,11 @@
This function returns nil if no document matching ID is found.
++ 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. +
[Function]
From peddy at common-lisp.net Sun Jun 15 18:00:39 2008
From: peddy at common-lisp.net (peddy)
Date: Sun, 15 Jun 2008 14:00:39 -0400 (EDT)
Subject: [clouchdb-cvs] CVS clouchdb/src
Message-ID: <20080615180039.E89257E0AB@common-lisp.net>
Update of /project/clouchdb/cvsroot/clouchdb/src
In directory clnet:/tmp/cvs-serv869/src
Modified Files:
package.lisp clouchdb.lisp
Log Message:
Fixe bulk-document-update so it works with 7.3+ changes
--- /project/clouchdb/cvsroot/clouchdb/src/package.lisp 2008/06/14 21:31:35 1.8
+++ /project/clouchdb/cvsroot/clouchdb/src/package.lisp 2008/06/15 18:00:39 1.9
@@ -49,6 +49,7 @@
:with-connection
:document-properties
:document-property
+ :couchdb-document-properties
:document-id
:query-document
:set-document-property
@@ -65,6 +66,7 @@
:post-document
:create-document
:bulk-document-update
+ :as-deleted-document
:delete-document
:create-view
:create-ps-view
--- /project/clouchdb/cvsroot/clouchdb/src/clouchdb.lisp 2008/06/14 21:30:40 1.24
+++ /project/clouchdb/cvsroot/clouchdb/src/clouchdb.lisp 2008/06/15 18:00:39 1.25
@@ -285,15 +285,6 @@
(t (rplacd (assoc name doc) value)))
doc))
-;; (defun set-document-property (doc name value)
-;; "Set a property of a document. If the named property does not exist,
-;; add it to the document, otherwise change the existing value. Does not
-;; destructively modify input document, so be sure to use return value."
-;; (let ((doc (copy-tree doc)))
-;; (if (assoc name doc)
-;; (setf (document-property name doc) value)
-;; (cons `(,(as-keyword-symbol name) . ,value) doc))))
-
(defun set-document-property (doc &rest args)
"Set a property of a document. If the named property does not exist,
add it to the document, otherwise change the existing value. Does not
@@ -384,7 +375,7 @@
;; (format t " -> uri: ~a~%" uri)
;; (format t " -> headers: ~S~%" headers)
(cond (must-close
-;; (format t "body: ~S~%" body)
+ ;;(format t "body: ~S~%" body)
(json-to-document body))
(t nil)))))
@@ -435,11 +426,11 @@
(defun document-properties (document)
"Return the document properties, filtering out any couchdb reserved
properties (properties that start with an underscore)."
- (let ((props))
- (dolist (p document)
- (unless (equal "_" (subseq (symbol-name (car p)) 0 1))
- (push p props)))
- props))
+ (remove-if #'(lambda (e) (equal "_" (subseq (symbol-name (car e)) 0 1))) document))
+
+(defun couchdb-document-properties (document)
+ "Return only CouchDb specific document properties (opposite of document-properties)."
+ (remove-if-not #'(lambda (e) (equal "_" (subseq (symbol-name (car e)) 0 1))) document))
;;
;; CouchDB Database Management API
@@ -660,19 +651,29 @@
(put-document doc :id id :attachments attachments)
(post-document doc)))
+(defun as-deleted-document (doc)
+ "Return specified document in a special document format used by
+bulk-document-update to indicate that the document should be deleted
+in the bulk operation."
+ (set-document-property (couchdb-document-properties doc)
+ :|_deleted| t))
+
(defun bulk-document-update (docs)
"Update multiple documents in a single request. The docs parameter
-should be a list of documents."
+must be a list of documents. If the provided documents do not contain
+an :|_id| value, then a document is created with a CouchDb assigned
+ID. Any documents containing a (:|_deleted| . t) value will "
(ensure-db ()
(db-request (cat (url-encode *db-name*) "/_bulk_docs")
:method :post
- :content-type "application/xml"
+ :content-type "text/javascript"
:external-format-out +utf-8+
:content-length nil
:content
- (cat "[ "
- (string-join (mapcar #'document-to-json docs))
- " ] "))))
+ (cat "{ \"docs\": [ "
+ (string-join
+ (mapcar #'document-to-json docs))
+ " ] }"))))
(defun delete-document (&key document id revision if-missing)
"Delete a revision of a document. If the id parameter is provided
From peddy at common-lisp.net Sun Jun 15 20:34:57 2008
From: peddy at common-lisp.net (peddy)
Date: Sun, 15 Jun 2008 16:34:57 -0400 (EDT)
Subject: [clouchdb-cvs] CVS clouchdb/src
Message-ID: <20080615203457.875903D03A@common-lisp.net>
Update of /project/clouchdb/cvsroot/clouchdb/src
In directory clnet:/tmp/cvs-serv12271/src
Modified Files:
clouchdb.lisp
Log Message:
Add ps-view validation functions
--- /project/clouchdb/cvsroot/clouchdb/src/clouchdb.lisp 2008/06/15 18:00:39 1.25
+++ /project/clouchdb/cvsroot/clouchdb/src/clouchdb.lisp 2008/06/15 20:34:57 1.26
@@ -146,11 +146,12 @@
(id condition))))
(:documentation "Error raised when no document matching ID is found"))
-;; (define-condition ps-view-def-error (error)
-;; ((ps-view-def :initarg :ps-view-def :reader ps-view-def))
-;; (:report (lambda (condition stream)
-;; (format stream "Invalid parenscript ps-view-def: \"~s\"" ps-view-def)))
-;; (:documentation "Error raised for invalid ps-view definition"))
+(define-condition ps-view-def-error (error)
+ ((ps-view-def :initarg :ps-view-def :reader ps-view-def))
+ (:report (lambda (condition stream)
+ (format stream "Invalid ps-view definition: ~s"
+ (ps-view-def condition))))
+ (:documentation "Error raised for invalid ps-view definition"))
;;
;; Unexported utility functions
@@ -737,7 +738,24 @@
"Create one or more views in the specified view document ID."
(create-view id (string-join view-defs)))
+(defun validate-ps-view (defun fn-name fn-param fn-body)
+ "Validation for ps-view definition"
+ (declare (ignore fn-body))
+ (cond ((not (eq 'defun defun))
+ (error 'ps-view-def-error :ps-view-def
+ "View definition should take the form (defun
- Returns a list of database names available in the current connection. + Returns a list of databases that exist in the current database.
+ ++(list-dbs) +=> ("default" "example1" "example2" "example3") +
[Function]
@@ -621,6 +626,32 @@
See (set-connection)
+ + +The Document ID From peddy at common-lisp.net Tue Jun 17 01:13:20 2008 From: peddy at common-lisp.net (peddy) Date: Mon, 16 Jun 2008 21:13:20 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/src Message-ID: <20080617011320.DAFAE14101@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/src In directory clnet:/tmp/cvs-serv14390/src Modified Files: clouchdb.lisp Log Message: Fixed comment in source Updated docs with missing document-update-fn, document-fetch-fn and other missing information --- /project/clouchdb/cvsroot/clouchdb/src/clouchdb.lisp 2008/06/16 23:42:55 1.27 +++ /project/clouchdb/cvsroot/clouchdb/src/clouchdb.lisp 2008/06/17 01:13:20 1.28 @@ -219,7 +219,7 @@ (intern (cat "*" (string-upcase (symbol-name key)) "*"))) (defmacro ensure-db ((&key (db-name nil db-name-p)) &body body) - "Warp request in code to check for errors due to non-existant data + "Wrap request in code to check for errors due to non-existant data bases. This is necessary because in a document operation, CouchDb does not distinguish between an error due to a missing document and a missing database." From peddy at common-lisp.net Tue Jun 17 01:13:21 2008 From: peddy at common-lisp.net (peddy) Date: Mon, 16 Jun 2008 21:13:21 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/public_html Message-ID: <20080617011321.2801E191BD@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/public_html In directory clnet:/tmp/cvs-serv14390/public_html Modified Files: index.html Log Message: Fixed comment in source Updated docs with missing document-update-fn, document-fetch-fn and other missing information --- /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/16 23:42:56 1.22 +++ /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/17 01:13:20 1.23 @@ -546,7 +546,7 @@ ;; then ignore the request (don't generate error), return ;; ((:ERROR . "not_found") (:REASON . "missing")) if ;; database did not exist -(delete-db :db-name "tvland") +(delete-db :db-name "tvland" :if-missing :ignore) => ((:ERROR . "not_found") (:REASON . "missing")) @@ -574,7 +574,8 @@
+- Returns a list of databases that exist in the current database. + Returns a list of the databases that exist on the current database + host.
@@ -585,7 +586,7 @@[Function]
set-connection &key host -db-name protocol port => no value +db-name protocol port document-update-fn document-fetch-fn => no value@@ -594,12 +595,45 @@ server. Default connection settings are host="localhost", protocol="http", port="5984" and database="default".
++ 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. +
+ ++Example: +
++;; 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")) + +;; The new document should have been created with a timestamp, +;; let's see if it worked: +(get-document "test") +=> ((:|_id| . "test") (:|_rev| . "3721228336") (:TIMESTAMP . 3422649324) + (:HELLO . "there")) ++See (with-connection)
[Macro]
with-connection (&key host -db-name protocol port) &body body => value returned by body +db-name protocol port document-update-fn document-fetch-fn) +&body body => value returned by body@@ -609,6 +643,13 @@ expressions in the body.
+ Additionally 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:
@@ -853,7 +894,7 @@[Function]
+id revision if-missing
delete-document &key document -id revisionDelete the specified document, which must include the standard @@ -863,6 +904,10 @@ 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]
From peddy at common-lisp.net Tue Jun 17 23:12:26 2008 From: peddy at common-lisp.net (peddy) Date: Tue, 17 Jun 2008 19:12:26 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/src Message-ID: <20080617231226.A5B825F070@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/src In directory clnet:/tmp/cvs-serv12726 Modified Files: tests.lisp Log Message: Don't set host information in tests setup code to make it easier to test with a remote CouchDb --- /project/clouchdb/cvsroot/clouchdb/src/tests.lisp 2008/06/14 21:31:35 1.13 +++ /project/clouchdb/cvsroot/clouchdb/src/tests.lisp 2008/06/17 23:12:26 1.14 @@ -130,10 +130,7 @@ (deftestsuite clouchdb-tests () () (:dynamic-variables - (*db-name* nil) - (*host* "localhost") - (*port* "5984") - (*protocol* "http"))) + (*db-name* nil))) ;; ;; General tests that do not require a db connection From peddy at common-lisp.net Sat Jun 28 22:55:07 2008 From: peddy at common-lisp.net (peddy) Date: Sat, 28 Jun 2008 18:55:07 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/src Message-ID: <20080628225507.B06996308D@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/src In directory clnet:/tmp/cvs-serv20169/src Modified Files: clouchdb.lisp changelog.txt README.txt Log Message: Release 0.0.10 checkin --- /project/clouchdb/cvsroot/clouchdb/src/clouchdb.lisp 2008/06/17 01:13:20 1.28 +++ /project/clouchdb/cvsroot/clouchdb/src/clouchdb.lisp 2008/06/28 22:55:07 1.29 @@ -381,19 +381,6 @@ (json-to-document body)) (t nil))))) -;; (defun cached-db-request (cache uri &rest args &key parameters &allow-other-keys) -;; "If a cache is supplied try it first before reqesting from -;; server. Cache result if cache is not nil." -;; (cond (cache -;; (let ((cache-key (if parameters (cons uri parameters) uri))) -;; (format t "cache key: ~s~%" cache-key) -;; (let ((cached (get-cached cache-key cache))) -;; (cond (cached -;; cached) -;; (t -;; (setf (get-cached cache-key cache) (apply #'db-request uri args))))))) -;; (t (apply #'db-request uri args)))) - ;; ;; ;; --- /project/clouchdb/cvsroot/clouchdb/src/changelog.txt 2008/03/01 19:19:17 1.8 +++ /project/clouchdb/cvsroot/clouchdb/src/changelog.txt 2008/06/28 22:55:07 1.9 @@ -1,4 +1,13 @@ +0.0.10: + + - Views now use the new map/reduce/emit style JavaScript definitions + of CouchDb 0.8+. + - Added create-ps-view function and ps-view macro to help build the + new views + - Added document-update-fn and document-fetch-fn documentation. + - Added compact-db function + 0.0.9: - View functions now work with complex key types, e.g. --- /project/clouchdb/cvsroot/clouchdb/src/README.txt 2007/12/01 14:19:59 1.1.1.1 +++ /project/clouchdb/cvsroot/clouchdb/src/README.txt 2008/06/28 22:55:07 1.2 @@ -19,12 +19,10 @@ Clouchdb is written in generic lisp code and should run in most lisp implementations. At the time of writing it has been tested with SBCL running on Linux (Fedora 8, 32 bit) and with OpenMCL running on -Leopard (64bit, Intel). The CouchDb server version was 0.7.0a575 (very -near the final 0.7 release.) +Leopard (64bit, Intel). The CouchDb server version was 0.8-incubating. -Clouchdb relies on the cl-json, Parenscript, and Drakma libraries. The -included clouchdb-tests package also relies on the Lift unit test -framework. +Clouchdb relies on the Parenscript and Drakma libraries. The included +clouchdb-tests package also relies on the Lift unit test framework. Installation From peddy at common-lisp.net Sat Jun 28 22:55:08 2008 From: peddy at common-lisp.net (peddy) Date: Sat, 28 Jun 2008 18:55:08 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/public_html Message-ID: <20080628225508.54362710E4@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/public_html In directory clnet:/tmp/cvs-serv20169/public_html Modified Files: index.html Log Message: Release 0.0.10 checkin --- /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/17 01:13:20 1.23 +++ /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/28 22:55:07 1.24 @@ -50,6 +50,12 @@News
+
- Jun 28, 2008 Released version 0.0.10 to support CouchDb + version 0.8+ and updated this documentation to reflect those + changes. This new release is compatible only with CouchDb + 0.8.0-incubating (and hopefully later releases). For CouchDb + releases prior to 0.8 please use clouchdb release 0.0.9. +
- Jun 15, 2008 Added function create-ps-view and macro ps-view to support the new CouchDb 8.0 style views (which use map/reduce and emit). This code is checked into source control but @@ -256,29 +262,37 @@
;; Create a package to try out clouchdb -CL-USER> (defpackage :clouchdb-user (:use :cl :clouchdb :parenscript)) +CL-USER> (defpackage :clouchdb-user (:use :cl :clouchdb)) #<Package "CLOUCHDB-USER"> + CL-USER> (in-package :clouchdb-user) #<Package "CLOUCHDB-USER"> -;; Set our CouchDb host (default is "localhost"), and the database name for -;; the examples -CLOUCHDB-USER> (set-connection :host "odeon" :db-name "test-db") + +;; If necessary, set the CouchDb host name (default is "localhost"), +;; and the database name (default is "default") for the examples +CLOUCHDB-USER> (set-connection :host "odeon" :db-name "test-db") ; No value + ;; Get CouchDb Server Information by specifying a nil DB name CLOUCHDB-USER> (get-db-info :db-name nil) -((:|couchdb| . "Welcome") (:|version| . "0.7.3a")) +((:|couchdb| . "Welcome") (:|version| . "0.8.0-incubating")) + ;; Create database "test-db", which we named above 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| . "1479031852")) + ;; Fetch the document we just created CLOUCHDB-USER> (get-document "gjc") ((:|_id| . "gjc") (:|_rev| . "1479031852") (:NAME . "Gaius Julius Caesar")) + ;; Add a field to "gjc" CLOUCHDB-USER> (put-document (cons '(:lover . "Servilia Caepionis") *)) ((:|ok| . T) (:|id| . "gjc") (:|rev| . "1460552879")) + ;; Get the updated document CLOUCHDB-USER> (get-document "gjc") ((:|_id| . "gjc") (:|_rev| . "1460552879") (:LOVER . "Servilia Caepionis") @@ -300,29 +314,35 @@ ;; 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| . "C731D3A3698DA144FB35EDA9737917F2") (:|rev| . "3363852140")) + ;; 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| . "3181950830")) + ;; Change :color property CLOUCHDB-USER> (let ((doc (get-document "someid"))) (setf (document-property :color doc) "green") (put-document doc)) ((:|ok| . T) (:|id| . "someid") (:|rev| . "4275808446")) + ;; Show that the new property stuck CLOUCHDB-USER> (get-document "someid") ((:|_id| . "someid") (:|_rev| . "4275808446") (:SIZE . "large") (:COLOR . "green")) -;; Get revision information for this document (formatted for legibility) + +;; Get revision information for this document CLOUCHDB-USER> (get-document "someid" :revision-info t) ((:|_id| . "someid") (:|_rev| . "4275808446") (:SIZE . "large") (:COLOR . "green") (:|_revs_info| ((:|rev| . "4275808446") (:|status| . "disk")) ((:|rev| . "3181950830") (:|status| . "disk")))) + ;; Since the first revision is still available (i.e., :|status| == "disk") ;; we can still retrieve it: CLOUCHDB-USER> (get-document "someid" :revision "3181950830") @@ -342,14 +362,16 @@ (:political-system . "democracy")))) :id "czechrepublic") ((:|ok| . T) (:|id| . "czechrepublic") (:|rev| . "4272625130")) -;; Let's see what this document looks like (formatted for legibility) + +;; Let's see what this document looks like CLOUCHDB-USER> (get-document "czechrepublic") ((:|_id| . "czechrepublic") (:|_rev| . "3929202819") (:NAME . "Czech Republic") (:TAGS "country" "european") (:DEMOGRAPHICS (:POPULATION . 10230000) (:RELIGION (:AGNOSTIC . 0.59) (:ROMAN-CATHOLIC . 0.26) (:PROTESTANT . 2.5)) (:POLITICAL-SYSTEM . "democracy"))) -;; Get all documents, results again formatted for legibility + +;; Get all documents in current database CLOUCHDB-USER> (get-all-documents) ((:TOTAL_ROWS . 3) (:OFFSET . 0) (:ROWS @@ -400,7 +422,7 @@ ;; Netherlands, cities by country key, and cities by country ;; and city. -;; Note: Expressions within the (ps) expressions are Parenscript, +;; Note: Expressions within the (ps-view) macro 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 @@ -408,23 +430,23 @@ ;; case. The double asterix syntax causes Parenscript to generate ;; upper case JavaScript property names. -CLOUCHDB-USER> (create-view "cities" - ;; Index of cities in the Netherlands - (cons "nl" - (ps (lambda (doc) - (with-slots (*country* *city*) doc - (if (eql "NL" *country*) - (map *city* doc)))))) - ;; Index by country - (cons "country" - (ps (lambda (doc) - (with-slots (*country*) doc - (map *country* doc))))) - ;; Index by country and city - (cons "multi" - (ps (lambda (doc) - (with-slots (*country* *city*) doc - (map (list *country* *city*) doc)))))) +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| . "3690565831")) ;; Invoke "nl" view to find cities in the Netherlands @@ -520,6 +542,16 @@[Function]
+
+compact-db &key db-name +++ ++ Force a manual compaction of a database. If db-name is specified, + compacts that database, otherwise compacts the current database. +
+[Function]
delete-db &key db-name if-missing@@ -551,6 +583,51 @@
[Special Variable]
+*document-fetch-fn*
+
++ ++ A function which is called whenever a document is fetched from the + database. The function takes one argument, the document, and returns + the potentially modified document. +
+ +
[Special Variable]
+*document-update-fn*
+
+++ A function which is called whenver a document is sent to the + database via put-document, create-document or post-document + functions. The function should take one parameter, which will be the + document, and it should return one value, which should be the + potentially modified document. +
++
+;; 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 +(setf *document-fetch-fn* #'time-stamper) + +;; Test the new time stamping feature +(create-document '((:hello . "there")) :id "test") +=> ((:|ok| . T) (:|id| . "test") (:|rev| . "3721228336")) + +;; The new document should have been created with a timestamp, +;; let's see if it worked: +(get-document "test") +=> ((:|_id| . "test") (:|_rev| . "3721228336") (:TIMESTAMP . 3422649324) + (:HELLO . "there")) ++ +
[Function]
get-db-info &key db-name
- Functions may be specified that should invoked automatically each + Functions may be specified that will be 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.
- --Example: -
--;; 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")) - -;; The new document should have been created with a timestamp, -;; let's see if it worked: -(get-document "test") -=> ((:|_id| . "test") (:|_rev| . "3721228336") (:TIMESTAMP . 3422649324) - (:HELLO . "there")) --
See (with-connection)
@@ -1004,7 +1056,7 @@;; Create document "A" -(put-document '((:name . "Laraby")) :id "A") +(put-document '((:name . "Larrabee")) :id "A") ;; Copy to new document "B" (put-document (get-document "A") :id "B") @@ -1076,7 +1128,7 @@ ((:agent . 44)) ((:agent . 13)) ((:name . "Hymie")) - ((:name . "Larrabee")) + ((:name . " Larrabee")) ((:name . "Fang") (:agent . "K-9")))) (:kaos (((:name . "Siegfried")) @@ -1171,8 +1223,8 @@ 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. + instead. Parenscript is a library for generating JavaScript using + a Lisp syntax.Note that CouchDb and JavaScript are case sensitivie. Field names in @@ -1268,43 +1320,52 @@ Example:
-(create-document '((:name . "Laraby"))) -(ad-hoc-view "function(doc) { if (doc.NAME == 'Laraby') { map(null,doc.NAME) } }") +(create-document '((:name . "Larrabee"))) + +(ad-hoc-view "{'map': function(doc) { + if (doc.NAME == 'Larrabee') { + 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: + Ok, but JavaScript looks exotic and scary. To solve this problem we + use Parenscript. The following expression generates the same ad-hoc + view as above, but with a more comfortable syntax:
-(create-document '((:name . "Laraby"))) -(ad-hoc-view (ps (lambda (doc) - (with-slots (*name*) doc - (if (eql *name* "Laraby") - (map nil doc)))))) +(create-document '((:name . "Larrabee"))) + +(ad-hoc-view (ps-view () + (defun map (doc) + (with-slots (*name*) doc + (if (eql *name* "Larrabee") + (map 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. + Note that views may be defined which refer to document properties + which may not exist in all documents in the database. For example, + given the view above CouchDb will simply ignore documents that do not + contain a NAME property.
- The (with-slots) expression above can be eliminated, if desired, like so: + Because ParenScript also supports Object-Oriented style "dot" + notation, the (with-slots) expression can be replaced with the + following:
-(ad-hoc-view (ps (lambda (doc) - (if (eql doc.*name* "Laraby") - (map nil doc)))))) +(ad-hoc-view (ps-view (lambda (doc) + (if (eql doc.*name* "Larrabee") + (map nil doc))))))-See (create-view) and Example 3
+See (create-ps-view) and Example 3
[Function]
+create-ps-view {view-definition}*
-create-view {view-definition}*Creates a view document containing one or more view definitions. The @@ -1313,23 +1374,66 @@ s-expresions.
-Example: -
--;; Views defined with Parenscript -(create-view "names" - (cons "laraby" - (ps (lambda (doc) - (with-slots (name) doc - (if (eql "Laraby" name) - (map name doc)))))) - (cons "name" - (ps (lambda (doc) - (with-slots (name) doc - (map name doc)))))) ---See (invoke-view) +The following example document, taken from the +CouchDb +HttpViewAPI Wiki, represents a native JavaScript CouchDb View document +: [200 lines skipped] From peddy at common-lisp.net Sun Jun 29 15:17:52 2008 From: peddy at common-lisp.net (peddy) Date: Sun, 29 Jun 2008 11:17:52 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/src Message-ID: <20080629151752.AEAF14060@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/src In directory clnet:/tmp/cvs-serv24442/src Modified Files: tests.lisp package.lisp Log Message: - export compact-db - add compact-db tests --- /project/clouchdb/cvsroot/clouchdb/src/tests.lisp 2008/06/17 23:12:26 1.14 +++ /project/clouchdb/cvsroot/clouchdb/src/tests.lisp 2008/06/29 15:17:52 1.15 @@ -314,6 +314,18 @@ (delete-db :if-missing :ignore :db-name (create-temp-db-name))))) (addtest (clouchdb-db-admin-tests) + (:documentation "Test compact-db") + db-compact-db-1 + (ensure (setf *db-name* (create-temp-db))) + (ensure (document-property :|ok| (compact-db)))) + +(addtest (clouchdb-db-admin-tests) + (:documentation "Test named compact-db") + db-compact-db-named + (ensure (setf *db-name* (create-temp-db))) + (ensure (document-property :|ok| (compact-db :db-name *db-name*)))) + +(addtest (clouchdb-db-admin-tests) (:documentation "Creating a db that already exists is an error") db-create-existant-db (ensure (setf *db-name* (create-temp-db))) --- /project/clouchdb/cvsroot/clouchdb/src/package.lisp 2008/06/15 18:00:39 1.9 +++ /project/clouchdb/cvsroot/clouchdb/src/package.lisp 2008/06/29 15:17:52 1.10 @@ -40,6 +40,7 @@ :doc-error :id-or-revision-conflict :id-missing + :compact-db :document-missing :document-to-json :json-to-document From peddy at common-lisp.net Sun Jun 29 17:13:38 2008 From: peddy at common-lisp.net (peddy) Date: Sun, 29 Jun 2008 13:13:38 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/public_html Message-ID: <20080629171338.9CC803100@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/public_html In directory clnet:/tmp/cvs-serv26809 Added Files: index.html Log Message: trying re-add again --- /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/29 17:13:38 NONE +++ /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/29 17:13:38 1.1
clouchdb clouchdb
A Common Lisp library for interacting with CouchDb databases.Author: Peter Eddy (peter.eddy at gmail.com)
Contents
Overview
News
Download and Installation
Examples
Support and mailing lists
API Reference
Symbol Index
Issues and Bugs
Overview
Clouchdb is a Common Lisp library for interacting with CouchDb databases. CouchDb is a document based, schema-less database server.
Design Goals
The library was written with the goals that it be:
- Lightweight This library is designed to be an as lightweight as possible wrapper of the CouchDb REST API while still providing a resonable level of comfort for to the Lisp developer. In support of the latter goal, the library automatically translates between CouchDb's native Json (JavaScript) data representation language and simple Lisp data structures.
- Interoperable CouchDb is a schema-less, document-oriented database in which no two documents need share a common structure. Clouchdb does not currently provide structure or object database mapping functionality in order not to negate the unique nature of the CouchDb database and also in order not to impose any library-specific requirements on database documents. In other words, documents created with the Clouchdb library should be fully interoperable with database documents created via other means.
- Simple Clouchdb is intended to be used easily from the Lisp REPL in order to facilitate experimentation and prototyping. Towards this end the API is designed to be as expressive and economical as possible. Simple document inspection and modification functions have been provided in substitution for an object database mapping scheme. These simple tools might serve as the basis for more elaborate custom mapping schemes.
License
Clouchdb, comes with a BSD Style License for maximum agreeableness.
News
- Jun 28, 2008 Released version 0.0.10 to support CouchDb version 0.8+ and updated this documentation to reflect those changes. This new release is compatible only with CouchDb 0.8.0-incubating (and hopefully later releases). For CouchDb releases prior to 0.8 please use clouchdb release 0.0.9.
- Jun 15, 2008 Added function create-ps-view and macro ps-view to support the new CouchDb 8.0 style views (which use map/reduce and emit). This code is checked into source control but not yet in a release. See examples.lisp and test.lisp for usage examples.
- Jun 7, 2008 Note: CouchDb's views API has changed in source control, breaking this library. If you want to use CouchDb and this library, you'll have better luck sticking to the 7.2 pre-release version of CouchDb.
- Mar 1, 2008 Released version 0.0.9 with proper support for complex keys in views. The functions ad-hoc-view and invoke-view's :key, :start-end and :end-key parameters now accept s-exprs in addtion to string values. See Views API documentaion and Example 3 for details.
- Feb 16, 2008 Released version 0.0.8 with the following significant changes. Please read if you're updating from prior versions.
- Changed document field name encoding to get rid of cl-json/parenscript style * and - case encoding. Now using the less irritating CL symbol quoting, i.e.: :|MixedCase| instead of :-mixed-case (or whatever it was, I could never get it right on the first try). Note: This will break existing code wherever there is this case sensitivity, especially in standard CouchDb property names like :ID, :_ID, :REV, and :_REV, which are now :|id|, :|_id|, :|rev| and :|_rev|. Sorry about this. On the bright side you should never have to deal with field names like :*A-L-L-U-P-P-E-R-C-A-S-E again.
- Changed (set-document-property) so that it no longer modifies its document, but instead returns a copy with specified changes. Also now allows multiple properties to be set in one invocation. Be sure any existing code uses the return value from this function.
- Added query-document function to make it easier to extract data from complex documents.
- Removed dependence on cl-json.
- Dec 20, 2007 Released version 0.0.7 with fixes for what had been cl-json's inability to distinguish certain database field value types in the document associative list.
- Dec 19, 2007 Released version 0.0.6 with full support for utf-8 character encoding. This change includes support for non-Latin characters in document IDs and in document content. Additionally the encoding of spaces in document IDs has been changed from "+" to "%20", this fixes a problem where the "+" characters were not removed from document IDs when they were decoded.
- Dec 17, 2007 Released version 0.0.5 with fixes for encoding of URL parameters. This fix allows use of legal CouchDb characters for database names and document IDs which must be escaped in urls.
- Dec 9, 2007 - Version 0.0.4: Updated (invoke-view) and (ad-hoc-view) to use all options supported by corresponding CouchDb API. Somehow I'd missed these before.
- Nov 28, 2007 - CouchDb 7.2 now uses IANA assigned port 5984 instead of 8888. As of release 0.0.4, clouchdb's default has been changed to reflect this fact. If you're using pre-7.2 CouchDb versions with clouchdb 0.0.4, be sure to set your port to 8888. There should be no other compatibility issues.
Download and Installation
The current download link for clouchdb can be found at Clicki.net. Clouchdb may also be installed ASDF.
Requirements:
- Drakma
- Parenscript
- LIFT testing framework
- An available CouchDb server, minimum supported version is 0.7 (in pre-0.0.10 releases), the current release is compatible with CouchDb 0.8+ only.
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:oos 'asdf:load-op '#:clouchdb)ASDF-INSTALL will install library dependencies, though you must install a CouchDb server separately.
Unit tests
The clouchdb distribution comes with a unit test suite which uses the LIFT testing framework. To run the tests, follow the following steps:
(asdf:oos 'asdf:load-op '#:clouchdb-tests) (in-package :clouchdb-tests) ;; If CouchDb is running on a different host (set-connection :host "db-host") (run-all-tests)Examples
The distribution also includes an examples package:
(asdf:oos 'asdf:load-op '#:clouchdb-examples) (in-package :clouchdb-examples)The file examples.lisp contains comments describing each example in detail.
CVS Access
Clouchdb project hosting is graciously provided by common-lisp.net, the CVS repository may be checked out anonymously as follows:
cvs -z3 -d :pserver:anonymous:anonymous at common-lisp.net:/project/clouchdb/cvsroot co clouchdbSupport and mailing lists
The following email lists have been provided by the common-lisp.net for clouchdb development and information:
Examples
The following clouchdb SLIME 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/browse/index.html, adjust the URL host and port for the actual CouchDb server and port in use.
Example 1
The following example session demonstrates:
- Setting the CouchDb host and database name
- Finding CouchDb server version
- Creation of a database
- Creation of a document in that database
- Fetching a document and adding a new field
;; Create a package to try out clouchdb CL-USER> (defpackage :clouchdb-user (:use :cl :clouchdb)) #<Package "CLOUCHDB-USER"> CL-USER> (in-package :clouchdb-user) #<Package "CLOUCHDB-USER"> ;; If CouchDb is running on a different host set that host ;; name (default is "localhost"), also set the database name ;; to be used in this session (default database name is "default") CLOUCHDB-USER> (set-connection :host "odeon" :db-name "test-db") ; No value ;; Get CouchDb Server Information by specifying a nil DB name CLOUCHDB-USER> (get-db-info :db-name nil) ((:|couchdb| . "Welcome") (:|version| . "0.8.0-incubating")) ;; Create database "test-db", which we named above 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| . "1479031852")) ;; Fetch the document we just created CLOUCHDB-USER> (get-document "gjc") ((:|_id| . "gjc") (:|_rev| . "1479031852") (:NAME . "Gaius Julius Caesar")) ;; Add a field to "gjc" CLOUCHDB-USER> (put-document (cons '(:lover . "Servilia Caepionis") *)) ((:|ok| . T) (:|id| . "gjc") (:|rev| . "1460552879")) ;; Get the updated document CLOUCHDB-USER> (get-document "gjc") ((:|_id| . "gjc") (:|_rev| . "1460552879") (:LOVER . "Servilia Caepionis") (:NAME . "Gaius Julius Caesar"))Example 2
Demonstrating:
- Recreating a database
- Creating a document that uses a CouchDb generated ID
- Updating a document value using set-document-property
- Viewing document revision information
- Fetching an old document revision
- Creating a document with array and map field values
- Getting a list of all documents, and filtering that list
;; 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| . "C731D3A3698DA144FB35EDA9737917F2") (:|rev| . "3363852140")) ;; 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| . "3181950830")) ;; Change :color property CLOUCHDB-USER> (put-document (set-document-property (get-document "someid") :color "green") ((:|ok| . T) (:|id| . "someid") (:|rev| . "4275808446")) ;; Show that the new property stuck CLOUCHDB-USER> (get-document "someid") ((:|_id| . "someid") (:|_rev| . "4275808446") (:SIZE . "large") (:COLOR . "green")) ;; Get revision information for this document CLOUCHDB-USER> (get-document "someid" :revision-info t) ((:|_id| . "someid") (:|_rev| . "4275808446") (:SIZE . "large") (:COLOR . "green") (:|_revs_info| ((:|rev| . "4275808446") (:|status| . "available")) ((:|rev| . "3181950830") (:|status| . "available")))) ;; Since the first revision is still available we can still retrieve it: CLOUCHDB-USER> (get-document "someid" :revision "3181950830") ((:|_id| . "someid") (:|_rev| . "3181950830") (:SIZE . "large") (:COLOR . "blue")) ;; 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) [1286 lines skipped] From peddy at common-lisp.net Sun Jun 29 17:30:59 2008 From: peddy at common-lisp.net (peddy) Date: Sun, 29 Jun 2008 13:30:59 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/public_html Message-ID: <20080629173059.C6E4913017@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/public_html In directory clnet:/tmp/cvs-serv32190 Modified Files: index.html Log Message: Added (setf (set-document-property) ..) doc --- /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/29 17:13:38 1.1 +++ /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/29 17:30:59 1.2 @@ -413,7 +413,7 @@ ;; Get all documents in current database CLOUCHDB-USER> (get-all-documents) -((:TOTAL_ROWS . 3) (:OFFSET . 0) +((:|total_rows| . 3) (:|offset| . 0) (:|rows| ((:|id| . "C731D3A3698DA144FB35EDA9737917F2") (:KEY . "C731D3A3698DA144FB35EDA9737917F2") (:|value| (:|rev| . "3363852140"))) @@ -996,6 +996,21 @@ (document-property :name (get-document "max")) => "Maxwell Smart" + +;; document-property is setf-able, but note that the result is +;; not persisted automatically (use put-document for that) + +(setf (document-property :name (get-document "max")) "Max") +=>((:|_id| . "max") (:|_rev| . "1213746364") (:NAME . "Max") (:AGENT . 86)) + +(document-property :name (get-document "max")) +=> "Maxwell Smart" + +(put-document (setf (document-property :name (get-document "max")) "Max")) +=>((:|ok| . T) (:|id| . "max") (:|rev| . "1262996208")) + +(get-document "max") +=>((:|_id| . "max") (:|_rev| . "1262996208") (:NAME . "Max") (:AGENT . 86))See From peddy at common-lisp.net Mon Jun 30 00:52:47 2008 From: peddy at common-lisp.net (peddy) Date: Sun, 29 Jun 2008 20:52:47 -0400 (EDT) Subject: [clouchdb-cvs] CVS clouchdb/public_html Message-ID: <20080630005247.669A94060@common-lisp.net> Update of /project/clouchdb/cvsroot/clouchdb/public_html In directory clnet:/tmp/cvs-serv25900/public_html Modified Files: index.html Log Message: Added Lisp/JSON field type table, minor text fixes --- /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/29 17:30:59 1.2 +++ /project/clouchdb/cvsroot/clouchdb/public_html/index.html 2008/06/30 00:52:47 1.3 @@ -829,17 +829,81 @@
- 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. + The value of a document field may be a string, a number, a list, a + boolean, or an associative list. Document field values may be + nested to create arbitrarily complex document structures.
++
+ + + +Representation of Field Names and Values ++ +Description +Lisp +JSON ++ +Boolean +(:boolean . t) +
+ (:boolean . nil)"BOOLEAN" : true +
+ "BOOLEAN" : false | null+ +String +(:string . "Example") +"STRING" : "Example" ++ +Keywords ++ (:keyword . example) +
+ (:keyword . :example)
+ (:keyword . |Example|)
+ Note: Keywords are always converted to strings ++ "KEYWORD" : "EXAMPLE" +
+ "KEYWORD" : "EXAMPLE"
+ "KEYWORD" : "Example" ++ +Number +(:number . 42) +"NUMBER" : 42 ++ +Floating Point Number +(:number . 42.0) +"NUMBER" : 42.0 ++ +Lisp List/JSON Array +(:list . (1 2 3)) +
(:list 1 2 3)"LIST" : [1,2,3] ++ +Lisp Associative Array/JSON Object +(:person . ((:name . "Bruce") (:gender . m))) +"PERSON" : {"NAME": "Bruce", "GENDER": "M"} ++ Though these types are simple, lists and associative lists may + contain other lists or associative lists, permitting a rich document + structure. +
+(create-document '((:string . "String Value") (:number . 42.0) (:list . (milk eggs "green beans")) (:alist . ((:string . "Another String") (:size . 3) + (:false . t) (:list . ("un" "deux" "trois")) (:another-alist . ((a . "A") (b . "B")))))))@@ -1093,7 +1157,7 @@ ;; Create document "A" (put-document '((:name . "Larrabee")) :id "A") -;; Copy to new document "B" +;; Copy document A to new document "B" (put-document (get-document "A") :id "B") ;; Add field to document "B" @@ -1163,7 +1227,7 @@ ((:agent . 44)) ((:agent . 13)) ((:name . "Hymie")) - ((:name . " Larrabee")) + ((:name . "Larrabee")) ((:name . "Fang") (:agent . "K-9")))) (:kaos (((:name . "Siegfried")) @@ -1366,9 +1430,10 @@
- Ok, but JavaScript looks exotic and scary. To solve this problem we - use Parenscript. The following expression generates the same ad-hoc - view as above, but with a more comfortable syntax: + Ok, but JavaScript looks exotic and scary. The + following Parenscript + expression generates the same ad-hoc view as above, but with a more + comfortable syntax:
@@ -1409,9 +1474,11 @@ s-expresions.-The following example document, taken from the +The following document, taken from the CouchDb -HttpViewAPI Wiki, represents a native JavaScript CouchDb View document: +HttpViewAPI Wiki, is an example of a native JavaScript CouchDb +View document that defines three view components "all", +"by_lastname", and "total_purchases":
{ @@ -1460,7 +1527,7 @@ (return (sum values)))))- Note that the defuns in the example above create JavaScript + Note that the defuns in the example above define JavaScript functions, not Lisp functions, and that there are some capitization differences between the JavaScript and ParenScript view documents.