A Clojure library designed to utilise a clojure Ref, and the filesytem as a simple "database".
NOTE: This project is really just an experiment. You probably shouldn't run it in production.
refdb artifacts are released to Clojars.
If you are using Maven, add the following repository definition to your pom.xml:
<repository>
<id>clojars.org</id>
<url>http://clojars.org/repo</url>
</repository>With Leiningen:
[com.andrewmcveigh/refdb "0.6.4"]The most recent release can be found on Clojars.
The complete API documentation is also available (marginalia generated).
All RefDB API functions need a db-spec passed to them as the first argument.
You can create a db-spec with the macro #'refdb.core/db-spec. db-spec
takes a map of opts, & collections. opts must contain either
:path or :no-write must be truthy. :path can be a
java.net.URI, a java.io.File, or a String, and it must point to
an existing file collections should be passed as keywords which name
the collections. E.G.,
(require '[refdb.core :as db])
(db-spec {:path "data"} :cats :dogs)Once you have a db-spec, if you want to load anything into it, you should
init! it...
(db/init! db-spec)... to initialize all collections in the db-spec, or...
(db/init! db-spec :only #{:cats})... to only initialize some of them.
You can wipe out a collection with destroy!. Be careful, this operation
will destroy the data, in memory and from durable storage.
(db/destroy! db-spec :dogs) ; don't hurt the catsYou can get an item by its ID. IDs can be anything.
(db/get db-spec :cats 1000)
=> {:id 1000 :name "Cedric" :breed "Tabby"}Or you can find items(s) matching a predicate map. If the predicate is
an empty map {} or nil, returns all items.
(db/find db-spec :cats {:color "orange" :name "Reg"})
=> ({:id 457 :breed "Tabby" :color "orange" :name "Reg"}, ...)Predicates can match by literal? values, regexes and functions.
(db/find db-spec :cats {:color #"(orange)|(brown)"})
(db/find db-spec :cats {:color #(or (= % "brown") (= % "orange))"})
=> ({:id 457 :breed "Tabby" :color "orange" :name "Reg"}, ...)Predicates can have sub-maps, and sets can be used to partially match collections.
(db/find db-spec :cats {:friends #{"Tom"}})
=> ({:id 457 :breed "Persian" :color "Grey" :name "Bosco" :friends ["Tom", "Dick", "Harry"]}, ...)You can also search deeper into a match using a vector as a key.
(db/find db-spec :cats {[:skills :jumping :max-height] 20})By default a predicate's matching behavior for key-vals is AND. E.G.,
(db/find db-spec :cats {:color "orange" :name "Reg"})finds cats with :color "orange" AND :name "Reg". It's possible
to specify that the predicate should use OR matching behavior, or a
combination. E.G.,
(require '[refdb.core :as db :refer [?and ?or]])
(db/find db-spec :cats (?or (?and {:name "Timmy"
:color "Orange"})
(?and {:friends #{"Timmy"}})))#'refdb.core/save! writes data to the "database", and #'refdb.core/update!
updates the data in the "database" by applying a function and args,
much like #'clojure.core/swap! works.
(db/save! db-spec :cats {:key val ...})
(db/update! db-spec :cats assoc-in [0 :key1] {:key val ...})
(db/update! db-spec :cats update-in [0 :key2] inc)Adds a :refdb.core/deleted true key-val to the data, and so by default
will not be matched by find or get. The data is not actually deleted.
Copyright © 2013 Andrew Mcveigh
Distributed under the Eclipse Public License, the same as Clojure.
