diff options
author | garren smith <garren.smith@gmail.com> | 2020-08-05 09:25:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-05 09:25:29 +0200 |
commit | 282e85814b7025da76e88e8cfc2413aacd6808b8 (patch) | |
tree | 9d688e9d83efeb71f7f32d7a9c13e136f5a69b82 | |
parent | e0bcb2a5ebbe23f4c04c9c19dbdbde692bef8fde (diff) | |
download | couchdb-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.erl | 29 | ||||
-rw-r--r-- | src/couch_views/test/couch_views_map_test.erl | 51 | ||||
-rw-r--r-- | test/elixir/test/map_test.exs | 27 |
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) |