You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by Apache Wiki <wi...@apache.org> on 2008/06/12 18:21:00 UTC

[Couchdb Wiki] Update of "Cl-CouchDb" by NickAllen

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Couchdb Wiki" for change notification.

The following page has been changed by NickAllen:
http://wiki.apache.org/couchdb/Cl-CouchDb

------------------------------------------------------------------------------
- ["Cl-CouchDb"] is a very young library, and it doesn't have its own webpage yet. You can download it using darcs:
+ = Overview =
+ 
+ ["Cl-CouchDb"] is a Common Lisp library for interacting with CouchDB databases.
+ 
+ It defines three systems: 
+ 
+  * {{{cl-couchdb-client}}} -- a client server for making requests to a CouchDB database from Common Lisp
+  * {{{cl-couchdb-view-server}}} -- a view server for programming CouchDB ["Views"] with Common Lisp
+  * {{{cl-couchdb-object-layer}}} -- a simple object layer for making {{{cl-couchdb-client}}} easier to work with
+ 
+ 
+ = Getting =
+ 
+ There are no official releases of ["Cl-CouchDB"] yet.
+ 
+ Check out the latest version from the [http://darcs.net/ darcs] repo:
  
  {{{
  darcs get http://www.common-lisp.net/project/submarine/darcs/cl-couchdb
  }}}
  
+ or [http://common-lisp.net/cgi-bin/darcsweb/darcsweb.cgi?r=submarine-cl-couchdb;a=tree browse] the source code online.
- = Installation =
- 
- Put symlinks to the .asd files in some place where ASDF can see them
- and configure CouchDB (see below). Then load the systems you need using ASDF.
- 
- = Tutorial =
- 
- 
- Cl-CouchDB consists of three main components:
- 
-  * {{{cl-couchdb-client}}}
-  * {{{cl-couchdb-view-server}}}
-  * {{{cl-couchdb-object-layer}}}---a simple object layer (in fact a thin wrapper over json
-   objects/association lists)
  
  == Cl-CouchDB-client ==
  
+ {{{Cl-CouchDB-client}}} allows the user to make requests to the running CouchDB server from lisp. It's main entry point is the macro {{{R}}}.
- Allows to make requests to the running CouchDB server. The main entry
- points are {{{r}}} and {{{r*}}}. {{{r}}} is a macro for doing comfortably requests
- from the REPL, {{{r*}}} is the functional interface to {{{r}}}.
  
- Some examples:
+ === R ===
+ 
+ {{{R}}} takes specifiers for a request to a CouchDB database and returns a Lisp object. HTTP PUT requests with {{{R}}} take Lisp objects as well, thus enabling the programmer to black-box the JSON layer completely.
+ 
+ ==== Examples ====
+ 
+ Using {{{R}}} to make a GET request to {{{http://localhost:5984/blog/150fedd5d14f0771eb5e44d071a1df5d}}}:
+ 
  {{{
- COUCHDB-CLIENT> (r :get (blog "150fedd5d14f0771eb5e44d071a1df5d")) ;a GET request to http://localhost:5984/blog/150fedd5d14f0771eb5e44d071a1df5d
+ COUCHDB-CLIENT> (r :get (blog "150fedd5d14f0771eb5e44d071a1df5d"))
  ((:_ID . "150fedd5d14f0771eb5e44d071a1df5d") (:_REV . "253381451")
   (:AUTHOR . "foo") (:BODY . "Zażółć") (:POST . "third") (:TYPE . "comment")
   (:N . 66))
+ }}}
  
- COUCHDB-CLIENT> (r :get (blog _all_docs :count 2)) ; GET http://localhost:5984/blog/_all_docs?count=2
+ Using {{{R}}} to make a GET request to {{{http://localhost:5984/blog/_all_docs?count=2}}}:
+ 
+ {{{
+ COUCHDB-CLIENT> (r :get (blog _all_docs :count 2))
  ((:TOTAL-ROWS . 48) (:OFFSET . 0)
   (:ROWS
    ((:ID . "06672346ffc093ce68a07692a5f12db5")
@@ -42, +53 @@

    ((:ID . "14328cab564dfec5eac0ff0a44d2083d")
     (:KEY . "14328cab564dfec5eac0ff0a44d2083d") (:VALUE (:REV . "1258191009")))))
  }}}
- As you can see, {{{r}}} (and {{{r*}}}) return lisp objects (alists) and take lisp
- objects, which are translated to JSON without bothering the programmer
- (of course, there's a lower level interface if you prefer to do the
- json things yourself).
  
- An important utility function is {{{@}}}. This allows you to access data
- stored in alists (this is what json objects get translated into) in
- the JavaScript dot style. For example,
+ === R* ===
+ 
+ {{{R*}}} is the functional equivalent to the macro {{{R}}}.
+ 
+ === @ ===
+ 
+ {{{@}}} is a utility function that enables you to access Lisp data in the JavaScript dot style. For example,
  {{{(@ doc :friend :id)}}} is equivalent to js {{{doc.friend.id}}}.
  
+ When looking into lists, {{{@}}} does an alist lookup by default. Since it's a generic function, however, it's behavior can be extended for any type of object (eg, those created from CouchDB documents by {{{cl-CouchDB-object-layer}}}).
+ 
  == Cl-CouchDB-View-Server ==
  
+ {{{Cl-CouchDB-View-Server}}} enables you to write views with Common Lisp instead of having to use JavaScript. It supports {{{mapreduce}}} and should also be able to deal with a {{{rereduce}}}.
- This is a view-server implementation. It supports mapreduce and should
- be also able to deal with a rereduce.
  
- As you may know, a lisp image is rather heavy, so you shouldn't be
- starting every now and then. This means that I had to take a slightly
- different approach to allow communicating CouchDB with lisp. A lisp
- image that has started a view-server will be listening to port
- 5477. So, you need to put something like 
+ Writing views with Common Lisp has several advantages:
+ 
+  * Common Lisp compiles to fast code.
+  * Views are compiled (even ad hoc views) since CouchDB just sends symbols naming functions, rather than their source.
+  * You can do all sorts of weird tricks with the running Lisp image, such as maintaining an in-memory database for faster indexed lookup, making requests to the CouchDB server itself, or well... any of the weird things you can do with Lisp...
+ 
+ === Starting the Lisp View Server ===
+ 
+ ==== From the CouchDB side ====
+ 
+ A Lisp image that with a running view server will be listening to port 5477. So, you need to add something like 
+ 
  {{{
  common-lisp=/usr/bin/socat -TCP4:localhost:5477
  }}}
-  to the {{{[Couch Query Servers]}}} section of your
- {{{couch.ini}}} (you can substitute socat for any program that will allow a
+ 
+ to the {{{[Couch Query Servers]}}} section of your {{{couch.ini}}} (you can substitute socat for any program that will allow a
- socket open on port 5477 look like a program with standard input and
+ socket open on port 5477 look like a program with standard input and standard output).
- standard output).
  
+ ==== From the Lisp Side ====
+ 
+ The Lisp image just needs to open a client server (we need to be able to speak with couchdb through HTTP) and a view server and it's ready for action.
+ 
- This approach has some advantages, however. First of all, you can use
- all the goodness a running lisp image provides, specially its loaded
- libraries. This allows for example to have an SQLite db in memory and
- use it in views to calculate stuff that otherwise would very difficult
- to do in CouchDB. Second, views can make requests to the couchdb
- server itself (though I am not sure this is always a good
- idea). Finally, views are compiled (even ad hoc views) instead of
- being interpreted, and CouchDB sends just the symbols naming the
- functions to call rather than the source.
  {{{
- COUCHDB-SERVER> (open-server ) ; we need to be able to speak with couchdb through http
+ COUCHDB-SERVER> (open-server)
  *COUCHDB-SERVER*
  
  COUCHDB-SERVER> (start-view-server)
  #<view-server :host "127.0.0.1" :port 5477>
+ }}}
  
+ === Creating Design Documents ===
+ 
+ The {{{DEFDESIGN}}} macro creates a design document and saves it to the database.
+ 
+ This example creates a design document "test" with one view ({{{by-author-type}}}) and saves it to the database "blog":
+ 
+ {{{
  COUCHDB-SERVER> (defdesign test
  		    ((by-author-type :map (doc)
  				     (emit (list (@ doc :author) (@ doc :type)) doc)))
@@ -93, +114 @@

  		  (:sync blog))
  #<design-document :name TEST :revision NIL :views (#<view BY-AUTHOR-TYPE :map "#'CL-COUCHDB-VIEW-SERVER::BY-AUTHOR-TYPE-MAP" :reduce NIL>)>
  }}}
- This creates a design document "test" with one view: by-author-type,
- and saves it automatically to the database "blog" (it assumes that a
- server is already running).
  
- Now, you can easily query this view:
+ 
+ === Querying the View Server ===
+ 
+ You can query views with the function{{{query-view}}}:
+ 
  {{{
  COUCHDB-SERVER> (query-view 'by-author-type :startkey '("foobar") :endkey '("foobar" #()))
  (((:ID . "first") (:KEY "foobar" "blogPost")
@@ -115, +137 @@

  47
  39
  }}}
- It is also easy to query an ad-hoc view using `query':
+ 
+ You can query ad-hoc views with the function {{{query}}}:
  {{{
  COUCHDB-SERVER> (query 'blog '(lambda (doc) (emit (@ doc :author) (@ doc :body))) :count 2)
  (((:ID . "06672346ffc093ce68a07692a5f12db5") (:KEY . "foo")
@@ -125, +148 @@

  47
  0
  }}}
+ 
  == Cl-CouchDB-Object-Layer ==
  
  The objects (which are called {{{docs}}}) are in fact a thin layer over