= Emacs Db - Key/Values stores for Emacs =

An EmacsLisp interface to key/value stores (Mongo, Postgresql Hstore,
etc..) with a simple default implementation based on EmacsLisp Hashtables.

== The interface ==

The idea behind this is to make an interface for interacting with
simple key/value database stores that is portable across all such
stores. So you can make code once but swap out the database with
relative ease.

The interface includes the following functions:

=== db-make reference ===

Make a DB based on the //reference//.

=== db-get key db ===

Get the value from the //db// with the //key//.

=== db-put key value db ===

Put a new //value// into the //db// with the specified //key//.

Return the //value// as it has been put into the //db//.

=== db-map func db &optional query filter ===

Call //func// for every record in //db// optionally //query// filter.

//query//, if specified, should be a list of query terms.

//func// should take 2 arguments:

{{{
  key db-value
}}}

where the DB-VALUE is whatever the //db// has attached to the
specified KEY.

This returns an alist of the KEY and the value the function
returned.  If //filter// is [[t]] then only pairs with a value are
returned.

=== db-query db query ===

Do //query// on //db// and return the result.

This is [[db-map]] with an identity function.


== Query language ==

{{{db}}} uses the query language provided by the {{{kv}}} library,
which is implemented as a mapping function test on ever value by the
persistent hashtable implementation.

The language should be translatable to just about any database query
language (Mongo, SQL, etc...).

There are only 3 constructs currently, {{{|}}}, {{{&}}} and {{{=}}}.

An expression could be:

{{{
(= field-name value)
}}}

To select any record where {{{field-name}}} has the {{{value}}}

{{{
(|(= field-name value)(= other-field other-value))
}}}

To select any record where {{{field-name}}} has the {{{value}}} 
or {{{other-field}}} has the value {{{other-value}}}

{{{
(&(= field-name value)(= other-field other-value))
}}}

To select any record where {{{field-name}}} has the {{{value}}} 
and {{{other-field}}} has the value {{{other-value}}}.

Logical combinations of {{{|}}} and {{{&}}} are also possible.


== Hashtable implementation ==

{{{db}}} comes with a simple implementation which can store any
EmacsLisp object (though alists would most usually be preferred).

To make a {{{db}}} with the hash implementation:

{{{
(db-make 
  `(db-hash 
     :filename ,(format "/var/cache/some-file")))
}}}

Obviously, most often you will assign the db to a global variable.

{{{
(defvar my-db 
  (db-make 
   `(db-hash 
     :filename ,(format "/var/cache/some-file"))))

(db-put "001" '(("a" . 10)("b" . 20)) my-db)
(db-put "002" '(("a" . 17)("b" . "hello")("xyz" . "well!")) my-db)
(db-get "002" my-db)
}}}

results in:

{{{
(("a" . 17)("b" . "hello")("xyz" . "well!"))
}}}

=== Testing ===

Hash Db's are tied to filenames so to test them you often have to
manage that persistence:

{{{
(unwind-protect
     (let ((mydb (db-make `(db-hash :filename "/tmp/mydb")))
           (json 
             (with-temp-buffer
              (insert-file-contents "~/work/elmarmalade/users-mongo.json")
              (goto-char (point-min))
              (json-read))))
       (--each json (db-put (car it) (cdr it) mydb))
       (list (db-get 'triss mydb)
             (db-get 'nicferrier mydb)))
  (delete-file "/tmp/mydb.elc"))
}}}

Note the deleting of the {{{elc}}} file. That's how the hash db is
stored. 

Alternately one could use {{{fakir-file}}} (see the fakir package) to
mock the file system. But that's harder than just creating and
throwing away the file.
