1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
= 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.
|