/emacs-db

very simple database for emacslisp, can also wrap other databases.

Primary LanguageEmacs Lisp

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.