Mohegan SkunkWorks

Wed, 23 Jun 2010 16:20:59 EST

key-value pairs in cl-mongo

In a key-value database like mongodb the fundamental data element is the key value pair. Key-value pairs in languages like javascript or python as have a seperate representation like :

 
{ key : value }

In lisp a natural enough equivalent is the association list or alternatively the dotted list. Since the javascript expression also creates a key-value object, I wanted to mimick the same semantics in lisp. In order to stay a close as possible to the java script syntax, and to also create a disticnt type I could switch on when dispatching generic function calls, I created the two types.

The first type is the a pair structure :

(defstruct (pair
         (:conc-name pair-)
         (:constructor pair (key value)))
 key value)

In addition I created a pair container :

 (defclass kv-container () 
      ((container :initform (make-array 2 :fill-pointer 0 :adjustable t) :accessor container)))

The interface is the kv generic function defined below :

(defgeneric kv (a &rest rest) 
     (:documentation " This a helper function for key-value pairs and sets of key-value pairs.  
       In a key-value pair like (kv key value) the key has to be a string and the
       value something which is serializable. 
       key-value pairs can be combined using kv as well : (kv (kv key1 val1) (kv key2 val2)).
       This combination of key-value pairs is equivalent to a document without a unique id.
        The server will assign a unique is if a list of key-value pairs is saved."))

In addition, the following macro provides an even shorter name :

(defmacro $ (&rest args)
      `(kv ,@args))

The generic function kv or the $ macro provides the interface to create sets of key-value pairs. For example, to find all items with a particular key-value pais , I'd use :

(db.find "foo" (kv "key" "value") :limit 0)

Looking for an element value with a value for "key" larger than 30 I'd use :

(pp (db.find "foo" (kv "key" (kv "$gt" 3))))