summaryrefslogtreecommitdiff
path: root/src/couch_mrview
diff options
context:
space:
mode:
authorjiahuili <lijiahui702@gmail.com>2023-03-21 15:35:14 -0500
committerjiahuili <lijiahui702@gmail.com>2023-04-04 16:32:30 -0500
commit23f4e628da4c79c6da4036aa1ebe7a01ff5cc949 (patch)
treed39b5ac1838f3edce8200196aadedc01a84b6352 /src/couch_mrview
parenta9bce2f598edc8ef843baa9412c60d22157eeabf (diff)
downloadcouchdb-23f4e628da4c79c6da4036aa1ebe7a01ff5cc949.tar.gz
treat single-element keys as the key for `_view`
- Request `_view` with reduce function, treat single-element `keys` as `key` - Add treat_single_keys_as_key/2 function for POST `_view`. If we query `_all_docs` for deleted or nonexistent docs using single-element keys, we can get {deleted:true} and {error:not_found}. - Add documentation on using key, keys, start_key, and end_key
Diffstat (limited to 'src/couch_mrview')
-rw-r--r--src/couch_mrview/src/couch_mrview_http.erl37
-rw-r--r--src/couch_mrview/src/couch_mrview_util.erl9
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl16
-rw-r--r--src/couch_mrview/test/eunit/couch_mrview_http_tests.erl29
4 files changed, 81 insertions, 10 deletions
diff --git a/src/couch_mrview/src/couch_mrview_http.erl b/src/couch_mrview/src/couch_mrview_http.erl
index 9d35e873a..522884eda 100644
--- a/src/couch_mrview/src/couch_mrview_http.erl
+++ b/src/couch_mrview/src/couch_mrview_http.erl
@@ -486,7 +486,12 @@ parse_params(Props, Keys, #mrargs{} = Args0, Options) ->
Args0;
_ ->
% group_level set to undefined to detect if explicitly set by user
- Args0#mrargs{keys = Keys, group = undefined, group_level = undefined}
+ case Keys of
+ [_] ->
+ Args0#mrargs{group = undefined, group_level = undefined};
+ _ ->
+ Args0#mrargs{keys = Keys, group = undefined, group_level = undefined}
+ end
end,
lists:foldl(
fun({K, V}, Acc) ->
@@ -513,8 +518,24 @@ parse_body_and_query(Req, Keys) ->
parse_body_and_query(Req, {Props}, Keys) ->
Args = #mrargs{keys = Keys, group = undefined, group_level = undefined},
- BodyArgs = parse_params(Props, Keys, Args, [decoded]),
- parse_params(chttpd:qs(Req), Keys, BodyArgs, [keep_group_level]).
+ BodyArgs0 = parse_params(Props, Keys, Args, [decoded]),
+ BodyArgs1 =
+ case is_view(Req) of
+ true -> treat_single_keys_as_key(BodyArgs0);
+ false -> BodyArgs0
+ end,
+ parse_params(chttpd:qs(Req), Keys, BodyArgs1, [keep_group_level]).
+
+is_view(#httpd{path_parts = [_, _, _, <<"_view">> | _]}) ->
+ true;
+is_view(#httpd{}) ->
+ false.
+
+treat_single_keys_as_key(#mrargs{keys = Keys} = BodyArgs) ->
+ case Keys of
+ [_] -> BodyArgs#mrargs{keys = undefined};
+ _ -> BodyArgs
+ end.
parse_param(Key, Val, Args, IsDecoded) when is_binary(Key) ->
parse_param(binary_to_list(Key), Val, Args, IsDecoded);
@@ -530,9 +551,15 @@ parse_param(Key, Val, Args, IsDecoded) ->
JsonKey = ?JSON_DECODE(Val),
Args#mrargs{start_key = JsonKey, end_key = JsonKey};
"keys" when IsDecoded ->
- Args#mrargs{keys = Val};
+ case Val of
+ [SingleKey] -> Args#mrargs{start_key = SingleKey, end_key = SingleKey};
+ _ -> Args#mrargs{keys = Val}
+ end;
"keys" ->
- Args#mrargs{keys = ?JSON_DECODE(Val)};
+ case ?JSON_DECODE(Val) of
+ [SingleKey] -> Args#mrargs{start_key = SingleKey, end_key = SingleKey};
+ Keys -> Args#mrargs{keys = Keys}
+ end;
"startkey" when IsDecoded ->
Args#mrargs{start_key = Val};
"start_key" when IsDecoded ->
diff --git a/src/couch_mrview/src/couch_mrview_util.erl b/src/couch_mrview/src/couch_mrview_util.erl
index e1e75f34f..1f39959af 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -564,7 +564,7 @@ validate_args(Args) ->
{red, exact, _} ->
ok;
{red, _, KeyList} when is_list(KeyList) ->
- Msg = <<"Multi-key fetchs for reduce views must use `group=true`">>,
+ Msg = <<"Multi-key fetches for reduce views must use `group=true`">>,
mrverror(Msg);
_ ->
ok
@@ -581,13 +581,12 @@ validate_args(Args) ->
ok;
{[], _, _} ->
ok;
+ {[Key], Key, Key} ->
+ ok;
{[_ | _], undefined, undefined} ->
ok;
_ ->
- mrverror(<<
- "`keys` is incompatible with `key`"
- ", `start_key` and `end_key`"
- >>)
+ mrverror(<<"`keys` is incompatible with `key`, `start_key` and `end_key`">>)
end,
case Args#mrargs.start_key_docid of
diff --git a/src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl
index 1a81d4f0a..5b9db435b 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl
@@ -40,6 +40,8 @@ all_docs_test_() ->
[
fun should_query/1,
fun should_query_with_range/1,
+ fun should_query_with_range_and_same_keys/1,
+ fun raise_error_query_with_range_and_different_keys/1,
fun should_query_with_range_rev/1,
fun should_query_with_limit_and_skip/1,
fun should_query_with_include_docs/1,
@@ -79,6 +81,20 @@ should_query_with_range(Db) ->
]},
?_assertEqual(Expect, Result).
+should_query_with_range_and_same_keys(Db) ->
+ Result = run_query(Db, [{keys, [<<"3">>]}, {start_key, <<"3">>}, {end_key, <<"3">>}]),
+ Expect =
+ {ok, [
+ {meta, [{total, 11}, {offset, 0}]},
+ mk_row(<<"3">>, <<"1-7fbf84d56f8017880974402d60f5acd6">>)
+ ]},
+ ?_assertEqual(Expect, Result).
+
+raise_error_query_with_range_and_different_keys(Db) ->
+ Error = {query_parse_error, <<"`keys` is incompatible with `key`, `start_key` and `end_key`">>},
+ ?_assertThrow(Error, run_query(Db, [{keys, [<<"1">>]}, {start_key, <<"5">>}])),
+ ?_assertThrow(Error, run_query(Db, [{keys, [<<"5">>]}, {start_key, <<"5">>}])).
+
should_query_with_range_rev(Db) ->
Result = run_query(Db, [
{direction, rev},
diff --git a/src/couch_mrview/test/eunit/couch_mrview_http_tests.erl b/src/couch_mrview/test/eunit/couch_mrview_http_tests.erl
index bfa4965a4..134e27fc0 100644
--- a/src/couch_mrview/test/eunit/couch_mrview_http_tests.erl
+++ b/src/couch_mrview/test/eunit/couch_mrview_http_tests.erl
@@ -33,5 +33,34 @@ mrview_http_test_() ->
undefined,
#mrargs{}
)
+ ),
+
+ ?_assertEqual(
+ #mrargs{start_key = 1, end_key = 1, group_level = undefined, group = undefined},
+ couch_mrview_http:parse_params(
+ [{"key", "1"}],
+ undefined,
+ #mrargs{}
+ )
+ ),
+
+ ?_assertEqual(
+ #mrargs{start_key = 1, end_key = 1, group_level = undefined},
+ couch_mrview_http:parse_params(
+ [{"keys", "[1]"}],
+ undefined,
+ #mrargs{}
+ )
+ ),
+
+ ?_assertEqual(
+ #mrargs{
+ keys = [1, 2], start_key = undefined, end_key = undefined, group_level = undefined
+ },
+ couch_mrview_http:parse_params(
+ [{"keys", "[1, 2]"}],
+ undefined,
+ #mrargs{}
+ )
)
].