diff options
author | jiahuili <lijiahui702@gmail.com> | 2023-03-21 15:35:14 -0500 |
---|---|---|
committer | jiahuili <lijiahui702@gmail.com> | 2023-04-04 16:32:30 -0500 |
commit | 23f4e628da4c79c6da4036aa1ebe7a01ff5cc949 (patch) | |
tree | d39b5ac1838f3edce8200196aadedc01a84b6352 /src/couch_mrview | |
parent | a9bce2f598edc8ef843baa9412c60d22157eeabf (diff) | |
download | couchdb-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.erl | 37 | ||||
-rw-r--r-- | src/couch_mrview/src/couch_mrview_util.erl | 9 | ||||
-rw-r--r-- | src/couch_mrview/test/eunit/couch_mrview_all_docs_tests.erl | 16 | ||||
-rw-r--r-- | src/couch_mrview/test/eunit/couch_mrview_http_tests.erl | 29 |
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{} + ) ) ]. |