DBKV
A disk-based embedded key-value storage built on top of dets set. Inspired by CubDB's intuitive API.
A table has at most one entry with a given key. If an entry with a key already present in the table is inserted, the existing entry is overwritten by the new entry. The entries are not ordered. See dets manual for more info.
Usage
Documentation can be found at https://hexdocs.pm/dbkv.
Open a table
iex> {:ok, t} = DBKV.open(name: :my_table, data_dir: "tmp")
{:ok, :my_table}
iex> DBKV.open?(t)
true
You could omit name
and data_dir
options. In such a case, they will default to DBKV
and "tmp"
respectively.
iex> DBKV.open()
Upsert an entry
iex> DBKV.put(t, "greeting", "Hi")
:ok
iex> DBKV.get(t, "greeting")
"Hi"
Insert an entry unless the entry key already exists in the table
iex> DBKV.put_new(t, "greeting", "Hello")
{:error, :exists}
iex> DBKV.get(t, "greeting")
"Hi"
iex> DBKV.put_new(t, "temperature", 32)
:ok
iex> DBKV.get(t, "temperature")
32
Update an entry in the table with a function
iex> DBKV.update(t, "greeting", "default", &(&1 <> "!!!"))
:ok
iex> DBKV.get(t, "greeting")
"Hi!!!"
iex> DBKV.update(t, "language", "default", &(&1 <> "!!!"))
:ok
iex> DBKV.get(t, "language")
"default"
Delete an entry
iex> DBKV.delete(t, "greeting")
:ok
iex> DBKV.get(t, "greeting")
nil
Initialize a table with a specific dataset
A table can be initialized with a list of two-element tulpes.
iex> DBKV.init_table(t, [{:a, 0}, {:b, 1}, {:c, 2}, {:d, 3}, {:e, 4}])
Select a range of entries from the table
By key ranges
iex> DBKV.select_by_key_range(t, :b, :d)
[b: 1, c: 2, d: 3]
By match spec
The Ex2ms.fun/2 macro is useful to build a match specification.
iex> require Ex2ms
iex> match_spec = Ex2ms.fun do {k, v} = kv when :b <= k and k <= :d -> kv end
[{{:"$1", :"$2"}, [{:andalso, {:"=<", :b, :"$1"}, {:"=<", :"$1", :d}}], [:"$_"]}]
iex> DBKV.select_by_match_spec(t, match_spec)
[b: 1, c: 2, d: 3]
Use :dets
functions
DBKV
is a thin wrapper of dets. You could mix and match with any
dets functions if you wish.
iex> :dets.info(t)
[
type: :set,
keypos: 1,
size: 0,
file_size: 5464,
filename: 'tmp/my_table.db'
]
Troubleshooting
ArgumentError
When a table is not open, a function call results in ArgumentError
.
Make sure that the table is opened with a correct name.
iex> DBKV.get(:nonexistent_table, "temperature")
** (ArgumentError) argument error
(stdlib 3.15.1) dets.erl:1259: :dets.lookup(:nonexistent_table, "temperature")
(dbkv 0.2.0) lib/dvkv.ex:131: DBKV.get/3
:invalid_objects_list
When a table is improperly initialized, a function returns {:error, :invalid_objects_list}
.
In such a case, re-opening the table will repair the database file with zero entry.
iex> DBKV.init_table(t, ["invalid entries", 0, 0])
{:error, :invalid_objects_list}
iex> DBKV.close(t)
{:error, :invalid_objects_list}
iex> {:ok, t} = DBKV.open(name: :my_table, data_dir: "tmp")
dets: file "tmp/my_table.db" not properly closed, repairing ...
{:ok, :my_table}
iex> DBKV.all(t)
[]
Installation
DBKV
can be installed by adding dbkv
to your list of dependencies in mix.exs:
def deps do
[
{:dbkv, "~> 0.2"}
]
end
Using Mix.install/2
in IEx:
❯ iex
iex> Mix.install([{:dbkv, "~> 0.2"}])