summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2018-02-06 22:16:28 +0000
committerGitHub <noreply@github.com>2018-02-06 22:16:28 +0000
commitbdfd1e70a060cbd2cb9a8da1dd3861950332d28a (patch)
tree3f55a0d6f2198525f9bb0c5ccd6aab6b916cc0ad
parent3b53c1c92af6dc774995fd8f1009d1306248477c (diff)
downloadcouchdb-revert-1143-issue-820-remove-queries-for_all_docs.tar.gz
-rw-r--r--src/chttpd/src/chttpd_db.erl42
-rw-r--r--src/chttpd/test/chttpd_db_test.erl85
-rw-r--r--test/javascript/tests/basics.js2
3 files changed, 120 insertions, 9 deletions
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index de5c79c66..3dc9f5794 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -520,14 +520,18 @@ db_req(#httpd{method='GET',path_parts=[_,OP]}=Req, Db) when ?IS_ALL_DOCS(OP) ->
db_req(#httpd{method='POST',path_parts=[_,OP]}=Req, Db) when ?IS_ALL_DOCS(OP) ->
chttpd:validate_ctype(Req, "application/json"),
- {Fields} = chttpd:json_body_obj(Req),
- case couch_util:get_value(<<"keys">>, Fields, nil) of
- Keys when is_list(Keys) ->
- all_docs_view(Req, Db, Keys, OP);
- nil ->
- all_docs_view(Req, Db, undefined, OP);
- _ ->
- throw({bad_request, "`keys` body member must be an array."})
+ Props = chttpd:json_body_obj(Req),
+ Keys = couch_mrview_util:get_view_keys(Props),
+ Queries = couch_mrview_util:get_view_queries(Props),
+ case {Queries, Keys} of
+ {Queries, undefined} when is_list(Queries) ->
+ multi_all_docs_view(Req, Db, OP, Queries);
+ {undefined, Keys} when is_list(Keys) ->
+ all_docs_view(Req, Db, Keys, OP);
+ {undefined, undefined} ->
+ all_docs_view(Req, Db, undefined, OP);
+ {_, _} ->
+ throw({bad_request, "`keys` and `queries` are mutually exclusive"})
end;
db_req(#httpd{path_parts=[_,OP]}=Req, _Db) when ?IS_ALL_DOCS(OP) ->
@@ -636,6 +640,28 @@ db_req(#httpd{path_parts=[_, DocId]}=Req, Db) ->
db_req(#httpd{path_parts=[_, DocId | FileNameParts]}=Req, Db) ->
db_attachment_req(Req, Db, DocId, FileNameParts).
+multi_all_docs_view(Req, Db, OP, Queries) ->
+ Args0 = couch_mrview_http:parse_params(Req, undefined),
+ Args1 = Args0#mrargs{view_type=map},
+ ArgQueries = lists:map(fun({Query}) ->
+ QueryArg1 = couch_mrview_http:parse_params(Query, undefined,
+ Args1, [decoded]),
+ QueryArgs2 = couch_mrview_util:validate_args(QueryArg1),
+ set_namespace(OP, QueryArgs2)
+ end, Queries),
+ Options = [{user_ctx, Req#httpd.user_ctx}],
+ VAcc0 = #vacc{db=Db, req=Req, prepend="\r\n"},
+ FirstChunk = "{\"results\":[",
+ {ok, Resp0} = chttpd:start_delayed_json_response(VAcc0#vacc.req, 200, [], FirstChunk),
+ VAcc1 = VAcc0#vacc{resp=Resp0},
+ VAcc2 = lists:foldl(fun(Args, Acc0) ->
+ {ok, Acc1} = fabric:all_docs(Db, Options,
+ fun couch_mrview_http:view_cb/2, Acc0, Args),
+ Acc1
+ end, VAcc1, ArgQueries),
+ {ok, Resp1} = chttpd:send_delayed_chunk(VAcc2#vacc.resp, "\r\n]}"),
+ chttpd:end_delayed_json_response(Resp1).
+
all_docs_view(Req, Db, Keys, OP) ->
Args0 = couch_mrview_http:parse_params(Req, Keys),
Args1 = Args0#mrargs{view_type=map},
diff --git a/src/chttpd/test/chttpd_db_test.erl b/src/chttpd/test/chttpd_db_test.erl
index 2071ca502..1725f87a9 100644
--- a/src/chttpd/test/chttpd_db_test.erl
+++ b/src/chttpd/test/chttpd_db_test.erl
@@ -70,6 +70,11 @@ all_test_() ->
fun should_return_409_for_put_att_nonexistent_rev/1,
fun should_return_update_seq_when_set_on_all_docs/1,
fun should_not_return_update_seq_when_unset_on_all_docs/1,
+ fun should_succeed_on_all_docs_with_queries_keys/1,
+ fun should_succeed_on_all_docs_with_queries_limit_skip/1,
+ fun should_succeed_on_all_docs_with_multiple_queries/1,
+ fun should_succeed_on_design_docs_with_multiple_queries/1,
+ fun should_fail_on_multiple_queries_with_keys_and_queries/1,
fun should_return_correct_id_on_doc_copy/1
]
}
@@ -223,6 +228,86 @@ should_not_return_update_seq_when_unset_on_all_docs(Url) ->
end).
+should_succeed_on_all_docs_with_queries_keys(Url) ->
+ ?_test(begin
+ [create_doc(Url, "testdoc" ++ ?i2l(I)) || I <- lists:seq(1, 10)],
+ QueryDoc = "{\"queries\": [{\"keys\": [ \"testdoc3\", \"testdoc8\"]}]}",
+ {ok, RC, _, RespBody} = test_request:post(Url ++ "/_all_docs/",
+ [?CONTENT_JSON, ?AUTH], QueryDoc),
+ ?assertEqual(200, RC),
+ {ResultJson} = ?JSON_DECODE(RespBody),
+ ResultJsonBody = couch_util:get_value(<<"results">>, ResultJson),
+ {InnerJson} = lists:nth(1, ResultJsonBody),
+ ?assertEqual(2, length(couch_util:get_value(<<"rows">>, InnerJson)))
+ end).
+
+
+should_succeed_on_all_docs_with_queries_limit_skip(Url) ->
+ ?_test(begin
+ [create_doc(Url, "testdoc" ++ ?i2l(I)) || I <- lists:seq(1, 10)],
+ QueryDoc = "{\"queries\": [{\"limit\": 5, \"skip\": 2}]}",
+ {ok, RC, _, RespBody} = test_request:post(Url ++ "/_all_docs/",
+ [?CONTENT_JSON, ?AUTH], QueryDoc),
+ ?assertEqual(200, RC),
+ {ResultJson} = ?JSON_DECODE(RespBody),
+ ResultJsonBody = couch_util:get_value(<<"results">>, ResultJson),
+ {InnerJson} = lists:nth(1, ResultJsonBody),
+ ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson)),
+ ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson)))
+ end).
+
+
+should_succeed_on_all_docs_with_multiple_queries(Url) ->
+ ?_test(begin
+ [create_doc(Url, "testdoc" ++ ?i2l(I)) || I <- lists:seq(1, 10)],
+ QueryDoc = "{\"queries\": [{\"keys\": [ \"testdoc3\", \"testdoc8\"]},
+ {\"limit\": 5, \"skip\": 2}]}",
+ {ok, RC, _, RespBody} = test_request:post(Url ++ "/_all_docs/",
+ [?CONTENT_JSON, ?AUTH], QueryDoc),
+ ?assertEqual(200, RC),
+ {ResultJson} = ?JSON_DECODE(RespBody),
+ ResultJsonBody = couch_util:get_value(<<"results">>, ResultJson),
+ {InnerJson1} = lists:nth(1, ResultJsonBody),
+ ?assertEqual(2, length(couch_util:get_value(<<"rows">>, InnerJson1))),
+ {InnerJson2} = lists:nth(2, ResultJsonBody),
+ ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson2)),
+ ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson2)))
+ end).
+
+
+should_succeed_on_design_docs_with_multiple_queries(Url) ->
+ ?_test(begin
+ [create_doc(Url, "_design/ddoc" ++ ?i2l(I)) || I <- lists:seq(1, 10)],
+ QueryDoc = "{\"queries\": [{\"keys\": [ \"_design/ddoc3\",
+ \"_design/ddoc8\"]}, {\"limit\": 5, \"skip\": 2}]}",
+ {ok, RC, _, RespBody} = test_request:post(Url ++ "/_design_docs/",
+ [?CONTENT_JSON, ?AUTH], QueryDoc),
+ ?assertEqual(200, RC),
+ {ResultJson} = ?JSON_DECODE(RespBody),
+ ResultJsonBody = couch_util:get_value(<<"results">>, ResultJson),
+ {InnerJson1} = lists:nth(1, ResultJsonBody),
+ ?assertEqual(2, length(couch_util:get_value(<<"rows">>, InnerJson1))),
+ {InnerJson2} = lists:nth(2, ResultJsonBody),
+ ?assertEqual(2, couch_util:get_value(<<"offset">>, InnerJson2)),
+ ?assertEqual(5, length(couch_util:get_value(<<"rows">>, InnerJson2)))
+ end).
+
+
+should_fail_on_multiple_queries_with_keys_and_queries(Url) ->
+ ?_test(begin
+ [create_doc(Url, "testdoc" ++ ?i2l(I)) || I <- lists:seq(1, 10)],
+ QueryDoc = "{\"queries\": [{\"keys\": [ \"testdoc3\", \"testdoc8\"]}],
+ \"keys\": [ \"testdoc4\", \"testdoc9\"]}",
+ {ok, RC, _, RespBody} = test_request:post(Url ++ "/_all_docs/",
+ [?CONTENT_JSON, ?AUTH], QueryDoc),
+ ?assertEqual(400, RC),
+ ?assertMatch({[
+ {<<"error">>,<<"bad_request">>},
+ {<<"reason">>,<<"`keys` and `queries` are mutually exclusive">>}]},
+ ?JSON_DECODE(RespBody))
+ end).
+
+
should_return_correct_id_on_doc_copy(Url) ->
?_test(begin
{ok, _, _, _} = create_doc(Url, "testdoc"),
diff --git a/test/javascript/tests/basics.js b/test/javascript/tests/basics.js
index a36b3035d..79599516d 100644
--- a/test/javascript/tests/basics.js
+++ b/test/javascript/tests/basics.js
@@ -268,7 +268,7 @@ couchTests.basics = function(debug) {
T(xhr.status == 400);
result = JSON.parse(xhr.responseText);
T(result.error == "bad_request");
- T(result.reason == "`keys` body member must be an array.");
+ T(result.reason == "`keys` member must be an array.");
// oops, the doc id got lost in code nirwana
xhr = CouchDB.request("DELETE", "/" + db_name + "/?rev=foobarbaz");