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 cats
You 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.