Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mnishiguchi/dbkv
A disk-based key-value storage built on top of dets
https://github.com/mnishiguchi/dbkv
database elixir embedded key-value key-value-store nerves
Last synced: about 1 month ago
JSON representation
A disk-based key-value storage built on top of dets
- Host: GitHub
- URL: https://github.com/mnishiguchi/dbkv
- Owner: mnishiguchi
- License: mit
- Created: 2021-06-28T22:07:12.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2021-09-29T23:58:05.000Z (about 3 years ago)
- Last Synced: 2024-09-29T21:04:23.062Z (about 2 months ago)
- Topics: database, elixir, embedded, key-value, key-value-store, nerves
- Language: Elixir
- Homepage:
- Size: 78.1 KB
- Stars: 5
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# DBKV
[![Hex version](https://img.shields.io/hexpm/v/dbkv.svg "Hex version")](https://hex.pm/packages/dbkv)
[![API docs](https://img.shields.io/hexpm/v/dbkv.svg?label=docs "API docs")](https://hexdocs.pm/dbkv)
[![CI](https://github.com/mnishiguchi/dbkv/actions/workflows/ci.yml/badge.svg)](https://github.com/mnishiguchi/dbkv/actions/workflows/ci.yml)
[![Hex](https://github.com/mnishiguchi/dbkv/actions/workflows/hex.yml/badge.svg)](https://github.com/mnishiguchi/dbkv/actions/workflows/hex.yml)A disk-based embedded key-value storage built on top of [dets](https://erlang.org/doc/man/dets.html) set.
Inspired by [CubDB](https://github.com/lucaong/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](https://erlang.org/doc/man/dets.html) for more info.## Usage
Documentation can be found at [https://hexdocs.pm/dbkv](https://hexdocs.pm/dbkv).
### Open a table
```elixir
iex> {:ok, t} = DBKV.open(name: :my_table, data_dir: "tmp")
{:ok, :my_table}iex> DBKV.open?(t)
trueiex> DBKV.filename(t)
'tmp/my_table.db'
```You could omit `name` and `data_dir` options. In such a case, they will default to `DBKV` and `"tmp"` respectively.
```elixir
iex> DBKV.open()
```### Upsert an entry
```elixir
iex> DBKV.put(t, "greeting", "Hi")
:okiex> DBKV.get(t, "greeting")
"Hi"
```### Insert an entry unless the entry key already exists in the table
```elixir
iex> DBKV.put_new(t, "greeting", "Hello")
{:error, :exists}iex> DBKV.get(t, "greeting")
"Hi"iex> DBKV.put_new(t, :temperature, 32)
:okiex> DBKV.get(t, :temperature)
32
```### Update an entry in the table with a function
```elixir
iex> DBKV.update(t, "greeting", "default", &(&1 <> "!!!"))
:okiex> DBKV.get(t, "greeting")
"Hi!!!"iex> DBKV.update(t, 123, "default", &(&1 <> "!!!"))
:okiex> DBKV.get(t, 123)
"default"
```### Delete an entry
```elixir
iex> DBKV.delete(t, "greeting")
:okiex> DBKV.get(t, "greeting")
nil
```### Initialize a table with a specific dataset
A table can be initialized with a list of two-element tulpes.
```elixir
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 range**
```elixir
iex> DBKV.select_by_key_range(t, :b, :d)
[b: 1, c: 2, d: 3]
```**By value range**
```elixir
iex> DBKV.select_by_value_range(t, 2, 3)
[c: 2, d: 3]
```**By [match spec](https://erlang.org/doc/apps/erts/match_spec.html)**
The [Ex2ms.fun/2](https://hexdocs.pm/ex2ms/Ex2ms.html#fun/1) macro is useful to build a match specification.
```elixir
iex> require Ex2msiex> 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
You could mix and match with any [dets functions](https://erlang.org/doc/man/dets.html) if you wish.
```elixir
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.```elixir
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
```## Installation
`DBKV` can be installed by adding `dbkv` to your list of dependencies in mix.exs:
```elixir
def deps do
[
{:dbkv, "~> 0.2"}
]
end
```Using `Mix.install/2` in IEx:
```elixir
❯ iexiex> Mix.install([{:dbkv, "~> 0.2"}])
```## Alternatives
- [CubDB](https://github.com/lucaong/cubdb)
- [dets](https://erlang.org/doc/man/dets.html)
- etcThere was a good discussion about Erlang/Elixir key-value stores in this [Elixir Forum thread](https://elixirforum.com/t/cubdb-a-pure-elixir-embedded-key-value-database/23397?u=mnishiguchi).