add fold_keys, and funs for getting keys and values via cursors

Change cursor_{next,prev} to return {ok, Key, Value}. Add
cursor_{next,prev}_{key,value} functions to allow cursor movement
followed by fetch of either key or value. Add fold_keys function. Add
unit tests for these changes. Also specify "inorder" on the unit test
generator functions, since the tests they specified are intended to be
run that way.
This commit is contained in:
Steve Vinoski 2012-02-19 20:20:38 -05:00
parent 085e703a32
commit 6c0f14da6e
2 changed files with 282 additions and 145 deletions

View file

@ -52,22 +52,31 @@ typedef char Uri[128]; // object names
static ERL_NIF_TERM ATOM_ERROR; static ERL_NIF_TERM ATOM_ERROR;
static ERL_NIF_TERM ATOM_OK; static ERL_NIF_TERM ATOM_OK;
typedef ERL_NIF_TERM (*CursorRetFun)(ErlNifEnv* env, WT_CURSOR* cursor, int rc);
// Prototypes // Prototypes
static ERL_NIF_TERM wterl_conn_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_conn_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_conn_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_conn_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_key_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc);
static ERL_NIF_TERM wterl_cursor_kv_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc);
static ERL_NIF_TERM wterl_cursor_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_np_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int next); static ERL_NIF_TERM wterl_cursor_next_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_next_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_np_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[],
CursorRetFun cursor_ret_fun, int next);
static ERL_NIF_TERM wterl_cursor_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_prev_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_prev_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_remove(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_remove(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_reset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_reset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc);
static ERL_NIF_TERM wterl_cursor_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_search_near(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_search_near(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int near); static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int near);
static ERL_NIF_TERM wterl_cursor_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_cursor_value_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc);
static ERL_NIF_TERM wterl_session_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_session_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_session_create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_session_create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM wterl_session_delete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_session_delete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@ -89,8 +98,12 @@ static ErlNifFunc nif_funcs[] =
{"cursor_close", 1, wterl_cursor_close}, {"cursor_close", 1, wterl_cursor_close},
{"cursor_insert", 3, wterl_cursor_insert}, {"cursor_insert", 3, wterl_cursor_insert},
{"cursor_next", 1, wterl_cursor_next}, {"cursor_next", 1, wterl_cursor_next},
{"cursor_next_key", 1, wterl_cursor_next_key},
{"cursor_next_value", 1, wterl_cursor_next_value},
{"cursor_open", 2, wterl_cursor_open}, {"cursor_open", 2, wterl_cursor_open},
{"cursor_prev", 1, wterl_cursor_prev}, {"cursor_prev", 1, wterl_cursor_prev},
{"cursor_prev_key", 1, wterl_cursor_prev_key},
{"cursor_prev_value", 1, wterl_cursor_prev_value},
{"cursor_remove", 3, wterl_cursor_remove}, {"cursor_remove", 3, wterl_cursor_remove},
{"cursor_reset", 1, wterl_cursor_reset}, {"cursor_reset", 1, wterl_cursor_reset},
{"cursor_search", 2, wterl_cursor_search}, {"cursor_search", 2, wterl_cursor_search},
@ -492,7 +505,48 @@ static ERL_NIF_TERM wterl_cursor_close(ErlNifEnv* env, int argc, const ERL_NIF_T
return enif_make_badarg(env); return enif_make_badarg(env);
} }
static ERL_NIF_TERM wterl_cursor_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc) static ERL_NIF_TERM wterl_cursor_key_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc)
{
if (rc == 0)
{
WT_ITEM raw_key;
rc = cursor->get_key(cursor, &raw_key);
if (rc == 0)
{
ErlNifBinary key;
enif_alloc_binary(raw_key.size, &key);
memcpy(key.data, raw_key.data, raw_key.size);
return enif_make_tuple2(env, ATOM_OK, enif_make_binary(env, &key));
}
}
return wterl_strerror(env, rc);
}
static ERL_NIF_TERM wterl_cursor_kv_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc)
{
if (rc == 0)
{
WT_ITEM raw_key, raw_value;
rc = cursor->get_key(cursor, &raw_key);
if (rc == 0)
{
rc = cursor->get_value(cursor, &raw_value);
if (rc == 0)
{
ErlNifBinary key, value;
enif_alloc_binary(raw_key.size, &key);
memcpy(key.data, raw_key.data, raw_key.size);
enif_alloc_binary(raw_value.size, &value);
memcpy(value.data, raw_value.data, raw_value.size);
return enif_make_tuple3(env, ATOM_OK,
enif_make_binary(env, &key), enif_make_binary(env, &value));
}
}
}
return wterl_strerror(env, rc);
}
static ERL_NIF_TERM wterl_cursor_value_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc)
{ {
if (rc == 0) if (rc == 0)
{ {
@ -509,25 +563,46 @@ static ERL_NIF_TERM wterl_cursor_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc)
return wterl_strerror(env, rc); return wterl_strerror(env, rc);
} }
static ERL_NIF_TERM wterl_cursor_np_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int prev) static ERL_NIF_TERM wterl_cursor_np_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[],
CursorRetFun cursor_ret, int prev)
{ {
wterl_cursor_handle *cursor_handle; wterl_cursor_handle *cursor_handle;
if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle)) if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle))
{ {
WT_CURSOR* cursor = cursor_handle->cursor; WT_CURSOR* cursor = cursor_handle->cursor;
return wterl_cursor_ret(env, cursor, prev == 0 ? cursor->next(cursor) : cursor->prev(cursor)); return cursor_ret(env, cursor, prev == 0 ? cursor->next(cursor) : cursor->prev(cursor));
} }
return enif_make_badarg(env); return enif_make_badarg(env);
} }
static ERL_NIF_TERM wterl_cursor_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM wterl_cursor_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{ {
return wterl_cursor_np_worker(env, argc, argv, 0); return wterl_cursor_np_worker(env, argc, argv, wterl_cursor_kv_ret, 0);
}
static ERL_NIF_TERM wterl_cursor_next_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return wterl_cursor_np_worker(env, argc, argv, wterl_cursor_key_ret, 0);
}
static ERL_NIF_TERM wterl_cursor_next_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return wterl_cursor_np_worker(env, argc, argv, wterl_cursor_value_ret, 0);
} }
static ERL_NIF_TERM wterl_cursor_prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) static ERL_NIF_TERM wterl_cursor_prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{ {
return wterl_cursor_np_worker(env, argc, argv, 1); return wterl_cursor_np_worker(env, argc, argv, wterl_cursor_kv_ret, 1);
}
static ERL_NIF_TERM wterl_cursor_prev_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return wterl_cursor_np_worker(env, argc, argv, wterl_cursor_key_ret, 1);
}
static ERL_NIF_TERM wterl_cursor_prev_value(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return wterl_cursor_np_worker(env, argc, argv, wterl_cursor_value_ret, 1);
} }
static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int near) static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int near)
@ -546,9 +621,9 @@ static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const E
// We currently ignore the less-than, greater-than or equals-to return information // We currently ignore the less-than, greater-than or equals-to return information
// from the cursor.search_near method. // from the cursor.search_near method.
return wterl_cursor_ret(env, cursor, return wterl_cursor_value_ret(env, cursor,
near == 1 ? near == 1 ?
cursor->search_near(cursor, &exact) : cursor->search(cursor)); cursor->search_near(cursor, &exact) : cursor->search(cursor));
} }
return enif_make_badarg(env); return enif_make_badarg(env);
} }

View file

@ -27,8 +27,12 @@
cursor_close/1, cursor_close/1,
cursor_insert/3, cursor_insert/3,
cursor_next/1, cursor_next/1,
cursor_next_key/1,
cursor_next_value/1,
cursor_open/2, cursor_open/2,
cursor_prev/1, cursor_prev/1,
cursor_prev_key/1,
cursor_prev_value/1,
cursor_remove/3, cursor_remove/3,
cursor_reset/1, cursor_reset/1,
cursor_search/2, cursor_search/2,
@ -55,7 +59,8 @@
session_upgrade/3, session_upgrade/3,
session_verify/2, session_verify/2,
session_verify/3, session_verify/3,
config_to_bin/1]). config_to_bin/1,
fold_keys/3]).
-on_load(init/0). -on_load(init/0).
@ -150,9 +155,21 @@ cursor_close(_Cursor) ->
cursor_next(_Cursor) -> cursor_next(_Cursor) ->
?nif_stub. ?nif_stub.
cursor_next_key(_Cursor) ->
?nif_stub.
cursor_next_value(_Cursor) ->
?nif_stub.
cursor_prev(_Cursor) -> cursor_prev(_Cursor) ->
?nif_stub. ?nif_stub.
cursor_prev_key(_Cursor) ->
?nif_stub.
cursor_prev_value(_Cursor) ->
?nif_stub.
cursor_search(_Cursor, _Key) -> cursor_search(_Cursor, _Key) ->
?nif_stub. ?nif_stub.
@ -162,15 +179,23 @@ cursor_search_near(_Cursor, _Key) ->
cursor_reset(_Cursor) -> cursor_reset(_Cursor) ->
?nif_stub. ?nif_stub.
cursor_insert(_Ref, _Key, _Value) -> cursor_insert(_Cursor, _Key, _Value) ->
?nif_stub. ?nif_stub.
cursor_update(_Ref, _Key, _Value) -> cursor_update(_Cursor, _Key, _Value) ->
?nif_stub. ?nif_stub.
cursor_remove(_Ref, _Key, _Value) -> cursor_remove(_Cursor, _Key, _Value) ->
?nif_stub. ?nif_stub.
fold_keys(Cursor, Fun, Acc0) ->
fold_keys(Cursor, Fun, Acc0, cursor_next_key(Cursor)).
fold_keys(_Cursor, _Fun, Acc, not_found) ->
Acc;
fold_keys(Cursor, Fun, Acc, {ok, Key}) ->
fold_keys(Cursor, Fun, Fun(Key, Acc), cursor_next_key(Cursor)).
%% %%
%% Configuration type information. %% Configuration type information.
%% %%
@ -194,7 +219,8 @@ config_types() ->
config_encode(integer, Value) -> config_encode(integer, Value) ->
try try
list_to_binary(integer_to_list(Value)) list_to_binary(integer_to_list(Value))
catch _:_ -> catch
_:_ ->
invalid invalid
end; end;
config_encode(string, Value) -> config_encode(string, Value) ->
@ -209,7 +235,7 @@ config_encode(_Type, _Value) ->
config_to_bin(Opts) -> config_to_bin(Opts) ->
config_to_bin(Opts, []). config_to_bin(Opts, []).
config_to_bin([], Acc) -> config_to_bin([], Acc) ->
iolist_to_binary([Acc, <<"\0">>]); iolist_to_binary([Acc, ?EMPTY_CONFIG]);
config_to_bin([{Key, Value} | Rest], Acc) -> config_to_bin([{Key, Value} | Rest], Acc) ->
case lists:keysearch(Key, 1, config_types()) of case lists:keysearch(Key, 1, config_types()) of
{value, {Key, Type}} -> {value, {Key, Type}} ->
@ -263,17 +289,18 @@ session_test_() ->
ok = conn_close(ConnRef) ok = conn_close(ConnRef)
end, end,
fun(ConnRef) -> fun(ConnRef) ->
[{"open/close a session", {inorder,
fun() -> [{"open/close a session",
{ok, SRef} = session_open(ConnRef), fun() ->
?assertMatch(ok, session_close(SRef)) {ok, SRef} = session_open(ConnRef),
end}, ?assertMatch(ok, session_close(SRef))
{"create and drop a table", end},
fun() -> {"create and drop a table",
SRef = open_test_session(ConnRef), fun() ->
?assertMatch(ok, session_drop(SRef, "table:test")), SRef = open_test_session(ConnRef),
?assertMatch(ok, session_close(SRef)) ?assertMatch(ok, session_drop(SRef, "table:test")),
end}] ?assertMatch(ok, session_close(SRef))
end}]}
end}. end}.
insert_delete_test() -> insert_delete_test() ->
@ -305,58 +332,59 @@ various_session_test_() ->
fun init_test_table/0, fun init_test_table/0,
fun stop_test_table/1, fun stop_test_table/1,
fun({_, SRef}) -> fun({_, SRef}) ->
[{"session verify", {inorder,
fun() -> [{"session verify",
?assertMatch(ok, session_verify(SRef, "table:test")), fun() ->
?assertMatch({ok, <<"apple">>}, ?assertMatch(ok, session_verify(SRef, "table:test")),
session_get(SRef, "table:test", <<"a">>)) ?assertMatch({ok, <<"apple">>},
end}, session_get(SRef, "table:test", <<"a">>))
{"session sync", end},
fun() -> {"session sync",
?assertMatch(ok, session_sync(SRef, "table:test")), fun() ->
?assertMatch({ok, <<"apple">>}, ?assertMatch(ok, session_sync(SRef, "table:test")),
session_get(SRef, "table:test", <<"a">>)) ?assertMatch({ok, <<"apple">>},
end}, session_get(SRef, "table:test", <<"a">>))
{"session salvage", end},
fun() -> {"session salvage",
%% =============================================================== fun() ->
%% KEITH: SKIP SALVAGE FOR NOW, THERE IS SOMETHING WRONG. %% ===============================================================
%% =============================================================== %% KEITH: SKIP SALVAGE FOR NOW, THERE IS SOMETHING WRONG.
%% ok = session_salvage(SRef, "table:test"), %% ===============================================================
%% {ok, <<"apple">>} = session_get(SRef, "table:test", <<"a">>), %% ok = session_salvage(SRef, "table:test"),
ok %% {ok, <<"apple">>} = session_get(SRef, "table:test", <<"a">>),
end}, ok
{"session upgrade", end},
fun() -> {"session upgrade",
?assertMatch(ok, session_upgrade(SRef, "table:test")), fun() ->
?assertMatch({ok, <<"apple">>}, ?assertMatch(ok, session_upgrade(SRef, "table:test")),
session_get(SRef, "table:test", <<"a">>)) ?assertMatch({ok, <<"apple">>},
end}, session_get(SRef, "table:test", <<"a">>))
{"session rename", end},
fun() -> {"session rename",
?assertMatch(ok, fun() ->
session_rename(SRef, "table:test", "table:new")), ?assertMatch(ok,
?assertMatch({ok, <<"apple">>}, session_rename(SRef, "table:test", "table:new")),
session_get(SRef, "table:new", <<"a">>)), ?assertMatch({ok, <<"apple">>},
?assertMatch(ok, session_get(SRef, "table:new", <<"a">>)),
session_rename(SRef, "table:new", "table:test")), ?assertMatch(ok,
?assertMatch({ok, <<"apple">>}, session_rename(SRef, "table:new", "table:test")),
session_get(SRef, "table:test", <<"a">>)) ?assertMatch({ok, <<"apple">>},
end}, session_get(SRef, "table:test", <<"a">>))
{"session truncate", end},
fun() -> {"session truncate",
?assertMatch(ok, session_truncate(SRef, "table:test")), fun() ->
?assertMatch(not_found, session_get(SRef, "table:test", <<"a">>)) ?assertMatch(ok, session_truncate(SRef, "table:test")),
end}] ?assertMatch(not_found, session_get(SRef, "table:test", <<"a">>))
end}]}
end}. end}.
cursor_open_close_test() -> cursor_open_close_test() ->
{ConnRef, SRef} = init_test_table(), {ConnRef, SRef} = init_test_table(),
{ok, Cursor1} = cursor_open(SRef, "table:test"), {ok, Cursor1} = cursor_open(SRef, "table:test"),
?assertMatch({ok, <<"apple">>}, cursor_next(Cursor1)), ?assertMatch({ok, <<"a">>, <<"apple">>}, cursor_next(Cursor1)),
?assertMatch(ok, cursor_close(Cursor1)), ?assertMatch(ok, cursor_close(Cursor1)),
{ok, Cursor2} = cursor_open(SRef, "table:test"), {ok, Cursor2} = cursor_open(SRef, "table:test"),
?assertMatch({ok, <<"gooseberry">>}, cursor_prev(Cursor2)), ?assertMatch({ok, <<"g">>, <<"gooseberry">>}, cursor_prev(Cursor2)),
?assertMatch(ok, cursor_close(Cursor2)), ?assertMatch(ok, cursor_close(Cursor2)),
stop_test_table({ConnRef, SRef}). stop_test_table({ConnRef, SRef}).
@ -365,79 +393,113 @@ various_cursor_test_() ->
fun init_test_table/0, fun init_test_table/0,
fun stop_test_table/1, fun stop_test_table/1,
fun({_, SRef}) -> fun({_, SRef}) ->
[{"move a cursor back and forth", {inorder,
fun() -> [{"move a cursor back and forth, getting key",
{ok, Cursor} = cursor_open(SRef, "table:test"), fun() ->
?assertMatch({ok, <<"apple">>}, cursor_next(Cursor)), {ok, Cursor} = cursor_open(SRef, "table:test"),
?assertMatch({ok, <<"banana">>}, cursor_next(Cursor)), ?assertMatch({ok, <<"a">>}, cursor_next_key(Cursor)),
?assertMatch({ok, <<"cherry">>}, cursor_next(Cursor)), ?assertMatch({ok, <<"b">>}, cursor_next_key(Cursor)),
?assertMatch({ok, <<"date">>}, cursor_next(Cursor)), ?assertMatch({ok, <<"c">>}, cursor_next_key(Cursor)),
?assertMatch({ok, <<"cherry">>}, cursor_prev(Cursor)), ?assertMatch({ok, <<"d">>}, cursor_next_key(Cursor)),
?assertMatch({ok, <<"date">>}, cursor_next(Cursor)), ?assertMatch({ok, <<"c">>}, cursor_prev_key(Cursor)),
?assertMatch({ok, <<"gooseberry">>}, cursor_next(Cursor)), ?assertMatch({ok, <<"d">>}, cursor_next_key(Cursor)),
?assertMatch(not_found, cursor_next(Cursor)), ?assertMatch({ok, <<"g">>}, cursor_next_key(Cursor)),
?assertMatch(ok, cursor_close(Cursor)) ?assertMatch(not_found, cursor_next_key(Cursor)),
end}, ?assertMatch(ok, cursor_close(Cursor))
{"search for an item", end},
fun() -> {"move a cursor back and forth, getting value",
{ok, Cursor} = cursor_open(SRef, "table:test"), fun() ->
?assertMatch({ok, <<"banana">>}, cursor_search(Cursor, <<"b">>)), {ok, Cursor} = cursor_open(SRef, "table:test"),
?assertMatch(ok, cursor_close(Cursor)) ?assertMatch({ok, <<"apple">>}, cursor_next_value(Cursor)),
end}, ?assertMatch({ok, <<"banana">>}, cursor_next_value(Cursor)),
{"range search for an item", ?assertMatch({ok, <<"cherry">>}, cursor_next_value(Cursor)),
fun() -> ?assertMatch({ok, <<"date">>}, cursor_next_value(Cursor)),
{ok, Cursor} = cursor_open(SRef, "table:test"), ?assertMatch({ok, <<"cherry">>}, cursor_prev_value(Cursor)),
?assertMatch({ok, <<"gooseberry">>}, ?assertMatch({ok, <<"date">>}, cursor_next_value(Cursor)),
cursor_search_near(Cursor, <<"z">>)), ?assertMatch({ok, <<"gooseberry">>}, cursor_next_value(Cursor)),
?assertMatch(ok, cursor_close(Cursor)) ?assertMatch(not_found, cursor_next_value(Cursor)),
end}, ?assertMatch(ok, cursor_close(Cursor))
{"check cursor reset", end},
fun() -> {"move a cursor back and forth, getting key and value",
{ok, Cursor} = cursor_open(SRef, "table:test"), fun() ->
?assertMatch({ok, <<"apple">>}, cursor_next(Cursor)), {ok, Cursor} = cursor_open(SRef, "table:test"),
?assertMatch(ok, cursor_reset(Cursor)), ?assertMatch({ok, <<"a">>, <<"apple">>}, cursor_next(Cursor)),
?assertMatch({ok, <<"apple">>}, cursor_next(Cursor)), ?assertMatch({ok, <<"b">>, <<"banana">>}, cursor_next(Cursor)),
?assertMatch(ok, cursor_close(Cursor)) ?assertMatch({ok, <<"c">>, <<"cherry">>}, cursor_next(Cursor)),
end}, ?assertMatch({ok, <<"d">>, <<"date">>}, cursor_next(Cursor)),
{"insert/overwrite an item using a cursor", ?assertMatch({ok, <<"c">>, <<"cherry">>}, cursor_prev(Cursor)),
fun() -> ?assertMatch({ok, <<"d">>, <<"date">>}, cursor_next(Cursor)),
{ok, Cursor} = cursor_open(SRef, "table:test"), ?assertMatch({ok, <<"g">>, <<"gooseberry">>}, cursor_next(Cursor)),
?assertMatch(ok, ?assertMatch(not_found, cursor_next(Cursor)),
cursor_insert(Cursor, <<"h">>, <<"huckleberry">>)), ?assertMatch(ok, cursor_close(Cursor))
?assertMatch({ok, <<"huckleberry">>}, end},
cursor_search(Cursor, <<"h">>)), {"fold keys",
?assertMatch(ok, fun() ->
cursor_insert(Cursor, <<"g">>, <<"grapefruit">>)), {ok, Cursor} = cursor_open(SRef, "table:test"),
?assertMatch({ok, <<"grapefruit">>}, ?assertMatch([<<"g">>, <<"d">>, <<"c">>, <<"b">>, <<"a">>],
cursor_search(Cursor, <<"g">>)), fold_keys(Cursor, fun(Key, Acc) -> [Key | Acc] end, [])),
?assertMatch(ok, cursor_close(Cursor)), ?assertMatch(ok, cursor_close(Cursor))
?assertMatch({ok, <<"grapefruit">>}, end},
session_get(SRef, "table:test", <<"g">>)), {"search for an item",
?assertMatch({ok, <<"huckleberry">>}, fun() ->
session_get(SRef, "table:test", <<"h">>)) {ok, Cursor} = cursor_open(SRef, "table:test"),
end}, ?assertMatch({ok, <<"banana">>}, cursor_search(Cursor, <<"b">>)),
{"update an item using a cursor", ?assertMatch(ok, cursor_close(Cursor))
fun() -> end},
{ok, Cursor} = cursor_open(SRef, "table:test"), {"range search for an item",
?assertMatch(ok, fun() ->
cursor_update(Cursor, <<"g">>, <<"goji berries">>)), {ok, Cursor} = cursor_open(SRef, "table:test"),
?assertMatch(not_found, ?assertMatch({ok, <<"gooseberry">>},
cursor_update(Cursor, <<"k">>, <<"kumquat">>)), cursor_search_near(Cursor, <<"z">>)),
?assertMatch(ok, cursor_close(Cursor)), ?assertMatch(ok, cursor_close(Cursor))
?assertMatch({ok, <<"goji berries">>}, end},
session_get(SRef, "table:test", <<"g">>)) {"check cursor reset",
end}, fun() ->
{"remove an item using a cursor", {ok, Cursor} = cursor_open(SRef, "table:test"),
fun() -> ?assertMatch({ok, <<"apple">>}, cursor_next_value(Cursor)),
{ok, Cursor} = cursor_open(SRef, "table:test"), ?assertMatch(ok, cursor_reset(Cursor)),
?assertMatch(ok, ?assertMatch({ok, <<"apple">>}, cursor_next_value(Cursor)),
cursor_remove(Cursor, <<"g">>, <<"goji berries">>)), ?assertMatch(ok, cursor_close(Cursor))
?assertMatch(not_found, end},
cursor_remove(Cursor, <<"l">>, <<"lemon">>)), {"insert/overwrite an item using a cursor",
?assertMatch(ok, cursor_close(Cursor)), fun() ->
?assertMatch(not_found, {ok, Cursor} = cursor_open(SRef, "table:test"),
session_get(SRef, "table:test", <<"g">>)) ?assertMatch(ok,
end}] cursor_insert(Cursor, <<"h">>, <<"huckleberry">>)),
?assertMatch({ok, <<"huckleberry">>},
cursor_search(Cursor, <<"h">>)),
?assertMatch(ok,
cursor_insert(Cursor, <<"g">>, <<"grapefruit">>)),
?assertMatch({ok, <<"grapefruit">>},
cursor_search(Cursor, <<"g">>)),
?assertMatch(ok, cursor_close(Cursor)),
?assertMatch({ok, <<"grapefruit">>},
session_get(SRef, "table:test", <<"g">>)),
?assertMatch({ok, <<"huckleberry">>},
session_get(SRef, "table:test", <<"h">>))
end},
{"update an item using a cursor",
fun() ->
{ok, Cursor} = cursor_open(SRef, "table:test"),
?assertMatch(ok,
cursor_update(Cursor, <<"g">>, <<"goji berries">>)),
?assertMatch(not_found,
cursor_update(Cursor, <<"k">>, <<"kumquat">>)),
?assertMatch(ok, cursor_close(Cursor)),
?assertMatch({ok, <<"goji berries">>},
session_get(SRef, "table:test", <<"g">>))
end},
{"remove an item using a cursor",
fun() ->
{ok, Cursor} = cursor_open(SRef, "table:test"),
?assertMatch(ok,
cursor_remove(Cursor, <<"g">>, <<"goji berries">>)),
?assertMatch(not_found,
cursor_remove(Cursor, <<"l">>, <<"lemon">>)),
?assertMatch(ok, cursor_close(Cursor)),
?assertMatch(not_found,
session_get(SRef, "table:test", <<"g">>))
end}]}
end}. end}.
-endif. -endif.