summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgarren smith <garren.smith@gmail.com>2020-08-05 09:25:29 +0200
committerGitHub <noreply@github.com>2020-08-05 09:25:29 +0200
commit282e85814b7025da76e88e8cfc2413aacd6808b8 (patch)
tree9d688e9d83efeb71f7f32d7a9c13e136f5a69b82
parente0bcb2a5ebbe23f4c04c9c19dbdbde692bef8fde (diff)
downloadcouchdb-282e85814b7025da76e88e8cfc2413aacd6808b8.tar.gz
add local_seq option to views (#3043)
add local_seq option to views
-rw-r--r--src/couch_views/src/couch_views_indexer.erl29
-rw-r--r--src/couch_views/test/couch_views_map_test.erl51
-rw-r--r--test/elixir/test/map_test.exs27
3 files changed, 97 insertions, 10 deletions
diff --git a/src/couch_views/src/couch_views_indexer.erl b/src/couch_views/src/couch_views_indexer.erl
index 9183d982e..9c8be6fca 100644
--- a/src/couch_views/src/couch_views_indexer.erl
+++ b/src/couch_views/src/couch_views_indexer.erl
@@ -195,9 +195,10 @@ do_update(Db, Mrst0, State0) ->
limit := Limit,
limiter := Limiter,
view_vs := ViewVS,
- changes_done := ChangesDone0
+ changes_done := ChangesDone0,
+ design_opts := DesignOpts
} = State2,
- DocAcc1 = fetch_docs(TxDb, DocAcc),
+ DocAcc1 = fetch_docs(TxDb, DesignOpts, DocAcc),
couch_rate:in(Limiter, Count),
{Mrst1, MappedDocs} = map_docs(Mrst0, DocAcc1),
@@ -379,7 +380,7 @@ write_docs(TxDb, Mrst, Docs, State) ->
DocsNumber.
-fetch_docs(Db, Changes) ->
+fetch_docs(Db, DesignOpts, Changes) ->
{Deleted, NotDeleted} = lists:partition(fun(Doc) ->
#{deleted := Deleted} = Doc,
Deleted
@@ -407,17 +408,27 @@ fetch_docs(Db, Changes) ->
}
end, #{}, erlfdb:wait_for_all(RevFutures)),
+ AddLocalSeq = fabric2_util:get_value(<<"local_seq">>, DesignOpts, false),
+
BodyFutures = maps:keys(BodyState),
ChangesWithDocs = lists:map(fun (BodyFuture) ->
{Id, RevInfo, Change} = maps:get(BodyFuture, BodyState),
Doc = fabric2_fdb:get_doc_body_wait(Db, Id, RevInfo, BodyFuture),
- BranchCount = maps:get(branch_count, RevInfo, 1),
- Doc1 = if BranchCount == 1 -> Doc; true ->
- RevConflicts = fabric2_fdb:get_all_revs(Db, Id),
- {ok, DocWithConflicts} = fabric2_db:apply_open_doc_opts(Doc,
- RevConflicts, [conflicts]),
- DocWithConflicts
+ Doc1 = case maps:get(branch_count, RevInfo, 1) of
+ 1 when AddLocalSeq ->
+ {ok, DocWithLocalSeq} = fabric2_db:apply_open_doc_opts(Doc,
+ [RevInfo], [local_seq]),
+ DocWithLocalSeq;
+ 1 ->
+ Doc;
+ _ ->
+ RevConflicts = fabric2_fdb:get_all_revs(Db, Id),
+ DocOpts = if not AddLocalSeq -> []; true -> [local_seq] end,
+
+ {ok, DocWithConflicts} = fabric2_db:apply_open_doc_opts(Doc,
+ RevConflicts, [conflicts | DocOpts]),
+ DocWithConflicts
end,
Change#{doc => Doc1}
end, erlfdb:wait_for_all(BodyFutures)),
diff --git a/src/couch_views/test/couch_views_map_test.erl b/src/couch_views/test/couch_views_map_test.erl
index 2b679f07c..c419546e1 100644
--- a/src/couch_views/test/couch_views_map_test.erl
+++ b/src/couch_views/test/couch_views_map_test.erl
@@ -58,7 +58,8 @@ map_views_test_() ->
?TDEF(should_map_with_doc_emit),
?TDEF(should_map_update_is_false),
?TDEF(should_map_update_is_lazy),
- ?TDEF(should_map_wait_for_interactive)
+ ?TDEF(should_map_wait_for_interactive),
+ ?TDEF(should_map_local_seq)
% fun should_give_ext_size_seq_indexed_test/1
]
}
@@ -440,6 +441,36 @@ should_map_wait_for_interactive() ->
]}, Result).
+should_map_local_seq() ->
+ ExpectedTrue = [
+ {row, [{id, <<"1">>}, {key, 1}, {value, 1}]},
+ {row, [{id, <<"2">>}, {key, 2}, {value, 2}]},
+ {row, [{id, <<"3">>}, {key, 3}, {value, 3}]}
+ ],
+ check_local_seq(true, ExpectedTrue),
+
+ ExpectedFalse = [],
+ check_local_seq(false, ExpectedFalse),
+
+ Error = {bad_request,invalid_design_doc,
+ <<"`options.local_seq` field must have boolean type">>},
+ ?assertThrow(Error, check_local_seq(something_else, null)).
+
+
+check_local_seq(Val, Expected) ->
+ DbName = ?tempdb(),
+ {ok, Db} = fabric2_db:create(DbName, [{user_ctx, ?ADMIN_USER}]),
+
+ DDoc = create_local_seq_ddoc(Val),
+ Docs = make_docs(5),
+ fabric2_db:update_docs(Db, [DDoc | Docs]),
+
+ {ok, Result} = couch_views:query(Db, DDoc, <<"idx_01">>, fun default_cb/2, [],
+ #{limit => 3}),
+
+ ?assertEqual(Expected, Result).
+
+
% should_give_ext_size_seq_indexed_test(Db) ->
% DDoc = couch_doc:from_json_obj({[
% {<<"_id">>, <<"_design/seqdoc">>},
@@ -550,6 +581,24 @@ create_interactive_ddoc() ->
]}).
+create_local_seq_ddoc(Val) ->
+ couch_doc:from_json_obj({[
+ {<<"_id">>, <<"_design/ddoc_local_seq">>},
+ {<<"options">>, {[{<<"local_seq">>, Val}]}},
+ {<<"language">>, <<"javascript">>},
+ {<<"views">>, {[
+ {<<"idx_01">>, {[
+ {<<"map">>, <<
+ "function(doc) {"
+ "if (doc._local_seq) {"
+ "emit(doc.val, doc.val);"
+ "}"
+ "}">>}
+ ]}}
+ ]}}
+ ]}).
+
+
make_docs(Count) ->
[doc(I) || I <- lists:seq(1, Count)].
diff --git a/test/elixir/test/map_test.exs b/test/elixir/test/map_test.exs
index 84325659d..9254cc4c3 100644
--- a/test/elixir/test/map_test.exs
+++ b/test/elixir/test/map_test.exs
@@ -586,6 +586,33 @@ defmodule ViewMapTest do
assert get_ids(resp) == ["doc-id-1"]
end
+ test "_local_seq is supported", context do
+ db_name = context[:db_name]
+ ddoc = %{
+ _id: "_design/local_seq",
+ views: %{
+ view: %{
+ map: """
+ function (doc) {
+ emit(doc._local_seq, doc._id);
+ }
+ """
+ }
+ },
+ options: %{
+ local_seq: true
+ }
+ }
+
+ resp = Couch.post("/#{db_name}/_bulk_docs", body: %{:docs => [ddoc]})
+ assert resp.status_code == 201
+
+ url = "/#{db_name}/_design/local_seq/_view/view"
+ resp = Couch.get(url, query: %{limit: 1})
+ key = Enum.at(resp.body["rows"], 0)["key"]
+ assert key != :null
+ end
+
def update_doc_value(db_name, id, value) do
resp = Couch.get("/#{db_name}/#{id}")
doc = convert(resp.body)