feat(): add delete, restore basic testing

This commit is contained in:
Ryan Schmukler 2017-03-21 14:59:34 -04:00
parent aab14d167e
commit f8dbe6a0db
4 changed files with 120 additions and 39 deletions

View File

@ -211,6 +211,11 @@ defmodule Rox do
The default arguments of this function is used for the `Enumerable` implementation
for `DB` and `ColumnFamily` structs.
Note: The result of stream is a cursor which is *not* meant to be shared across processes.
Iterating over the cursor will result in an internal state in RocksDB being modified.
If two processes try and use the same cursor, they will consume
each others results. This may or may not be desired.
"""
@spec stream(DB.t | ColumnFamily.t, Iterator.mode) :: Cursor.t | {:error, any}
def stream(db_or_cf, mode \\ :start)
@ -240,6 +245,22 @@ defmodule Rox do
Native.count_cf(db, cf)
end
@doc """
Deletes the specified `key` from the provided database or column family.
Optionally takes a list of `write_opts`.
"""
@spec delete(DB.t | ColumnFamily.t, key, write_options) :: :ok | {:error, any}
def delete(db_or_cf, key, write_opts \\ [])
def delete(%DB{resource: db}, key, write_opts) do
Native.delete(db, key, to_map(write_opts))
end
def delete(%ColumnFamily{db_resource: db, cf_resource: cf}, key, write_opts) do
Native.delete_cf(db, cf, key, to_map(write_opts))
end
defp to_map(map) when is_map(map), do: map
defp to_map([]), do: %{}
defp to_map(enum), do: Enum.into(enum, %{})

View File

@ -10,6 +10,8 @@ defmodule Rox.Native do
def put_cf(_, _, _, _, _), do: raise "Nif not loaded"
def get(_, _, _), do: raise "Nif not loaded"
def get_cf(_, _, _, _), do: raise "Nif not loaded"
def delete(_, _, _), do: raise "Nif not loaded"
def delete_cf(_, _, _, _), do: raise "Nif not loaded"
def iterate(_, _), do: raise "Nif not loaded"
def iterate_cf(_, _, _), do: raise "Nif not loaded"
def iterator_next(_), do: raise "Nif not loaded"

View File

@ -533,6 +533,51 @@ fn put_cf<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
Ok(atoms::ok().encode(env))
}
fn delete<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
let db_arc: ResourceArc<DBHandle> = args[0].decode()?;
let db = db_arc.deref().db.write().unwrap();
let key: &str = args[1].decode()?;
let resp =
if args[2].map_size()? > 0 {
let write_opts = decode_write_options(env, args[2])?;
db.delete_opt(key.as_bytes(), &write_opts)
} else {
db.delete(key.as_bytes())
};
handle_error!(env, resp);
Ok(atoms::ok().encode(env))
}
fn delete_cf<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
let db_arc: ResourceArc<DBHandle> = args[0].decode()?;
let db = db_arc.deref().db.write().unwrap();
let cf_arc: ResourceArc<CFHandle> = args[1].decode()?;
let cf = cf_arc.deref().cf;
let key: &str = args[2].decode()?;
let resp =
if args[3].map_size()? > 0 {
let write_opts = decode_write_options(env, args[3])?;
db.delete_cf_opt(cf, key.as_bytes(), &write_opts)
} else {
db.delete_cf(cf, key.as_bytes() )
};
handle_error!(env, resp);
Ok(atoms::ok().encode(env))
}
fn get<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
let db_arc: ResourceArc<DBHandle> = args[0].decode()?;
let db = db_arc.deref().db.read().unwrap();
@ -652,6 +697,8 @@ rustler_export_nifs!(
("cf_handle", 2, cf_handle),
("put", 4, put),
("put_cf", 5, put_cf),
("delete", 3, delete),
("delete_cf", 4, delete_cf),
("count", 1, count),
("count_cf", 2, count_cf),
("iterate", 2, iterate),

View File

@ -2,65 +2,76 @@ defmodule RoxTest do
use ExUnit.Case, async: false
doctest Rox
setup do
setup_all do
path =
Path.join(__DIR__, "test.rocksdb")
cf_path =
Path.join(__DIR__, "cf_test.rocksdb")
{:ok, db} =
Rox.open(path, create_if_missing: true)
{:ok, db} =
Rox.open(path, create_if_missing: true)
{:ok, db, %{"people" => people}} =
Rox.open(path, [create_if_missing: true, auto_create_column_families: true], ["people"])
on_exit fn ->
Rox.close(db)
File.rm_rf(path)
:ok
end
{:ok, %{db: db}}
{:ok, %{db: db, people: people}}
end
test "simple put and get", %{db: db} do
assert :not_found = Rox.get(db, "key")
:ok = Rox.put(db, "key", "val")
describe "Working with default column family" do
test "simple put and get", %{db: db} do
assert :not_found = Rox.get(db, "put_test")
assert {:ok, "val"} = Rox.get(db, "key")
assert :ok = Rox.put(db, "put_test", "val")
assert {:ok, "val"} = Rox.get(db, "put_test")
end
test "stream", %{db: db} do
assert :ok = Rox.put(db, "stream_test", "val")
count =
Rox.stream(db)
|> Enum.count
assert count > 0
end
test "delete", %{db: db} do
assert :not_found = Rox.get(db, "delete_test")
assert :ok = Rox.put(db, "delete_test", "some_val")
assert {:ok, _val} = Rox.get(db, "delete_test")
assert :ok = Rox.delete(db, "delete_test")
assert :not_found = Rox.get(db, "delete_test")
end
end
test "stream_keys", %{db: db} do
:ok = Rox.put(db, "key", "val")
describe "Working with non-default column family" do
test "simple put and get", %{people: people} do
assert :not_found = Rox.get(people, "put_test")
count = Rox.stream_keys(db)
|> Enum.count
assert :ok = Rox.put(people, "put_test", "val")
assert count == 1
end
assert {:ok, "val"} = Rox.get(people, "put_test")
end
test "stream", %{db: db} do
:ok = Rox.put(db, "key", "val")
test "stream", %{people: people} do
assert :ok = Rox.put(people, "stream_test", "val")
count = Rox.stream(db)
|> Enum.count
count =
Rox.stream(people)
|> Enum.count
assert count == 1
end
assert count > 0
end
test "partial exhaustion of a stream", %{db: db} do
:ok = Rox.put(db, "key", "val")
:ok = Rox.put(db, "alt-key", "val")
test "delete", %{people: people} do
assert :not_found = Rox.get(people, "delete_test")
assert :ok = Rox.put(people, "delete_test", "some_val")
assert {:ok, _val} = Rox.get(people, "delete_test")
assert :ok = Rox.delete(people, "delete_test")
Rox.stream_keys(db) |> Enum.take(1)
end
test "count", %{db: db} do
count =
Rox.count(db)
assert is_number(count)
assert count >= 0
assert :not_found = Rox.get(people, "delete_test")
end
end
end