%%% -*- erlang -*- %%% %%% This file is part of couchbeam released under the MIT license. %%% See the NOTICE for more information. -module(couchbeam_doc). -author('Benoit Chesneau'). -include("couchbeam.hrl"). -export([set_value/3, get_value/2, get_value/3, take_value/2, take_value/3, delete_value/2, extend/2, extend/3]). -export([get_id/1, get_rev/1, get_idrev/1, is_saved/1]). -spec get_id(doc()) -> binary(). %% @doc get document id. get_id(Doc) -> get_value(<<"_id">>, Doc). -spec get_rev(doc()) -> binary(). %% @doc get document revision. get_rev(Doc) -> get_value(<<"_rev">>, Doc). -spec get_idrev(doc()) -> {binary(), binary()}. %% @doc get a tuple containing docucment id and revision. get_idrev(Doc) -> DocId = get_value(<<"_id">>, Doc), DocRev = get_value(<<"_rev">>, Doc), {DocId, DocRev}. -spec is_saved(doc()) -> boolean(). %% @doc If document have been saved (revision is defined) return true, %% else, return false. is_saved(Doc) -> case get_value(<<"_rev">>, Doc) of undefined -> false; _ -> true end. -spec set_value(binary() | list(), term(), doc()) -> doc(). %% @doc set a value for a key in jsonobj. If key exists it will be updated. set_value(Key, Value, JsonObj) when is_list(Key)-> set_value(list_to_binary(Key), Value, JsonObj); set_value(Key, Value, JsonObj) when is_binary(Key), is_map(JsonObj) -> maps:put(Key, Value, JsonObj). -spec get_value(binary() | list(), doc()) -> term(). %% @doc Returns the value of a simple key/value property in json object %% Equivalent to get_value(Key, JsonObj, undefined). get_value(Key, JsonObj) -> get_value(Key, JsonObj, undefined). -spec get_value(binary() | list(), doc(), term()) -> term(). %% @doc Returns the value of a simple key/value property in json object get_value(Key, JsonObj, Default) when is_list(Key) -> get_value(list_to_binary(Key), JsonObj, Default); get_value(Key, JsonObj, Default) when is_binary(Key), is_map(JsonObj) -> maps:get(Key, JsonObj, Default). -spec take_value(binary() | list(), doc()) -> {term(), doc()}. %% @doc Returns the value of a simple key/value property in json object and deletes %% it form json object %% Equivalent to take_value(Key, JsonObj, undefined). take_value(Key, JsonObj) -> take_value(Key, JsonObj, undefined). -spec take_value(binary() | list(), doc(), term()) -> {term(), doc()}. %% @doc Returns the value of a simple key/value property in json object and deletes %% it from json object take_value(Key, JsonObj, Default) when is_list(Key) -> take_value(list_to_binary(Key), JsonObj, Default); take_value(Key, JsonObj, Default) when is_binary(Key), is_map(JsonObj) -> case maps:is_key(Key, JsonObj) of true -> {maps:get(Key, JsonObj), maps:remove(Key, JsonObj)}; false -> {Default, JsonObj} end. -spec delete_value(binary() | list(), doc()) -> doc(). %% @doc Deletes all entries associated with Key in json object. delete_value(Key, JsonObj) when is_list(Key) -> delete_value(list_to_binary(Key), JsonObj); delete_value(Key, JsonObj) when is_binary(Key), is_map(JsonObj) -> maps:remove(Key, JsonObj). -spec extend(binary(), ejson_term(), doc()) -> doc(). %% @doc extend a jsonobject by key, value extend(Key, Value, JsonObj) -> extend({Key, Value}, JsonObj). -spec extend(term(), doc()) -> doc(). %% @doc extend a jsonobject by a property, list of property or another jsonobject extend([], JsonObj) -> JsonObj; extend({List}, JsonObj) when is_list(List) -> extend(List, JsonObj); extend([Prop|R], JsonObj)-> NewObj = extend(Prop, JsonObj), extend(R, NewObj); extend({Key, Value}, JsonObj) -> set_value(Key, Value, JsonObj). -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). get_value_test() -> Doc = #{<<"a">> => 1}, ?assertEqual(1, couchbeam_doc:get_value(<<"a">>, Doc)), ?assertEqual(1, couchbeam_doc:get_value(<<"a">>, Doc)), ?assertEqual(undefined, couchbeam_doc:get_value(<<"b">>, Doc)), ?assertEqual(nil, couchbeam_doc:get_value(<<"b">>, Doc, nil)), ok. set_value_test() -> Doc = #{<<"a">> => 1}, ?assertEqual(undefined, couchbeam_doc:get_value(<<"b">>, Doc)), Doc1 = couchbeam_doc:set_value(<<"b">>, 1, Doc), ?assertEqual(1, couchbeam_doc:get_value(<<"b">>, Doc1)), Doc2 = couchbeam_doc:set_value(<<"b">>, 0, Doc1), ?assertEqual(0, couchbeam_doc:get_value(<<"b">>, Doc2)), ok. delete_value_test() -> Doc = #{<<"a">> => 1, <<"b">> => 1}, Doc1 = couchbeam_doc:delete_value("b", Doc), ?assertEqual(undefined, couchbeam_doc:get_value(<<"b">>, Doc1)), ok. extend_test() -> Doc = #{<<"a">> => 1}, ?assertEqual(1, couchbeam_doc:get_value(<<"a">>, Doc)), ?assertEqual(undefined, couchbeam_doc:get_value(<<"b">>, Doc)), ?assertEqual(undefined, couchbeam_doc:get_value(<<"c">>, Doc)), Doc1 = couchbeam_doc:extend([{<<"b">>, 1}, {<<"c">>, 1}], Doc), ?assertEqual(1, couchbeam_doc:get_value(<<"b">>, Doc1)), ?assertEqual(1, couchbeam_doc:get_value(<<"c">>, Doc1)), Doc2 = couchbeam_doc:extend([{<<"b">>, 3}, {<<"d">>, 1}], Doc1), ?assertEqual(3, couchbeam_doc:get_value(<<"b">>, Doc2)), ?assertEqual(1, couchbeam_doc:get_value(<<"d">>, Doc2)), ok. id_rev_test() -> Doc = #{<<"a">> => 1}, ?assertEqual(undefined, couchbeam_doc:get_id(Doc)), ?assertEqual(undefined, couchbeam_doc:get_rev(Doc)), ?assertEqual({undefined, undefined}, couchbeam_doc:get_idrev(Doc)), Doc1 = couchbeam_doc:extend([{<<"_id">>, 1}, {<<"_rev">>, 1}], Doc), ?assertEqual(1, couchbeam_doc:get_id(Doc1)), ?assertEqual(1, couchbeam_doc:get_rev(Doc1)), ?assertEqual({1, 1}, couchbeam_doc:get_idrev(Doc1)), ok. is_saved_test() -> Doc = #{<<"a">> => 1}, ?assertEqual(false, couchbeam_doc:is_saved(Doc)), Doc1 = couchbeam_doc:set_value(<<"_rev">>, <<"x">>, Doc), ?assertEqual(true, couchbeam_doc:is_saved(Doc1)), ok. take_value_test() -> Doc = #{<<"a">> => 1, <<"b">> => 2}, ?assertEqual({undefined, Doc}, couchbeam_doc:take_value(<<"c">>, Doc)), ?assertEqual({1, #{<<"b">> => 2}}, couchbeam_doc:take_value(<<"a">>, Doc)), ok. -endif.