Updated Branches: refs/heads/1993-bigcouch-couch-mrview 05f446c04 -> 6dcd0f191
WIP: remove chttpd_view functions replaced by couch_mrview Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/6dcd0f19 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/6dcd0f19 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/6dcd0f19 Branch: refs/heads/1993-bigcouch-couch-mrview Commit: 6dcd0f191c35b2574b2c18b67581d9ea486a6b4b Parents: 05f446c Author: Russell Branca <[email protected]> Authored: Wed Feb 12 16:29:42 2014 -0800 Committer: Russell Branca <[email protected]> Committed: Wed Feb 12 16:29:42 2014 -0800 ---------------------------------------------------------------------- src/chttpd_view.erl | 348 +++++------------------------------------------ 1 file changed, 37 insertions(+), 311 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/6dcd0f19/src/chttpd_view.erl ---------------------------------------------------------------------- diff --git a/src/chttpd_view.erl b/src/chttpd_view.erl index e9a2796..057962a 100644 --- a/src/chttpd_view.erl +++ b/src/chttpd_view.erl @@ -14,42 +14,40 @@ -include_lib("couch/include/couch_db.hrl"). -include_lib("couch_mrview/include/couch_mrview.hrl"). --export([handle_view_req/3, handle_temp_view_req/2, get_reduce_type/1, - parse_view_params/3, view_group_etag/2, view_group_etag/3, - parse_bool_param/1, extract_view_type/3]). - - -multi_query_view(Req, Db, DDoc, ViewName, Queries) -> - Group = couch_view_group:design_doc_to_view_group(DDoc), - IsReduce = get_reduce_type(Req), - ViewType = extract_view_type(ViewName, couch_view_group:get_views(Group), - IsReduce), - % TODO proper calculation of etag - % Etag = view_group_etag(ViewGroup, Db, Queries), - Etag = couch_uuids:new(), - DefaultParams = lists:flatmap(fun({K,V}) -> parse_view_param(K,V) end, - chttpd:qs(Req)), - [couch_stats_collector:increment({httpd, view_reads}) || _I <- Queries], - chttpd:etag_respond(Req, Etag, fun() -> - FirstChunk = "{\"results\":[", - {ok, Resp} = chttpd:start_delayed_json_response(Req, 200, [{"Etag",Etag}], FirstChunk), - {_, Resp1} = lists:foldl(fun({QueryProps}, {Chunk, RespAcc}) -> - if Chunk =/= nil -> chttpd:send_delayed_chunk(Resp, Chunk); true -> ok end, - ThisQuery = lists:flatmap(fun parse_json_view_param/1, QueryProps), - FullParams = lists:ukeymerge(1, ThisQuery, DefaultParams), - {ok, RespAcc1} = fabric:query_view( - Db, - DDoc, - ViewName, - fun couch_mrview_http:view_cb/2, - {nil, RespAcc}, - parse_view_params(FullParams, nil, ViewType) - ), - {",\n", RespAcc1} - end, {nil,Resp}, Queries), - chttpd:send_delayed_chunk(Resp1, "]}"), - chttpd:end_delayed_json_response(Resp1) - end). +-export([handle_view_req/3, handle_temp_view_req/2, get_reduce_type/1]). + +%% TODO: fix multi_query_view +%% multi_query_view(Req, Db, DDoc, ViewName, Queries) -> +%% Group = couch_view_group:design_doc_to_view_group(DDoc), +%% IsReduce = get_reduce_type(Req), +%% ViewType = extract_view_type(ViewName, couch_view_group:get_views(Group), +%% IsReduce), +%% % TODO proper calculation of etag +%% % Etag = view_group_etag(ViewGroup, Db, Queries), +%% Etag = couch_uuids:new(), +%% DefaultParams = lists:flatmap(fun({K,V}) -> parse_view_param(K,V) end, +%% chttpd:qs(Req)), +%% [couch_stats_collector:increment({httpd, view_reads}) || _I <- Queries], +%% chttpd:etag_respond(Req, Etag, fun() -> +%% FirstChunk = "{\"results\":[", +%% {ok, Resp} = chttpd:start_delayed_json_response(Req, 200, [{"Etag",Etag}], FirstChunk), +%% {_, Resp1} = lists:foldl(fun({QueryProps}, {Chunk, RespAcc}) -> +%% if Chunk =/= nil -> chttpd:send_delayed_chunk(Resp, Chunk); true -> ok end, +%% ThisQuery = lists:flatmap(fun parse_json_view_param/1, QueryProps), +%% FullParams = lists:ukeymerge(1, ThisQuery, DefaultParams), +%% {ok, RespAcc1} = fabric:query_view( +%% Db, +%% DDoc, +%% ViewName, +%% fun couch_mrview_http:view_cb/2, +%% {nil, RespAcc}, +%% parse_view_params(FullParams, nil, ViewType) +%% ), +%% {",\n", RespAcc1} +%% end, {nil,Resp}, Queries), +%% chttpd:send_delayed_chunk(Resp1, "]}"), +%% chttpd:end_delayed_json_response(Resp1) +%% end). design_doc_view(Req, Db, DDoc, ViewName, Keys) -> Args0 = couch_mrview_http:parse_qs(Req, Keys), @@ -66,19 +64,6 @@ design_doc_view(Req, Db, DDoc, ViewName, Keys) -> _ -> {ok, Resp} end. -extract_view_type(_ViewName, [], _IsReduce) -> - throw({not_found, missing_named_view}); -extract_view_type(ViewName, [View|Rest], IsReduce) -> - case lists:member(ViewName, [Name || {Name, _} <- View#mrview.reduce_funs]) of - true -> - if IsReduce -> reduce; true -> red_map end; - false -> - case lists:member(ViewName, View#mrview.map_names) of - true -> map; - false -> extract_view_type(ViewName, Rest, IsReduce) - end - end. - handle_view_req(#httpd{method='GET', path_parts=[_, _, _, _, ViewName]}=Req, Db, DDoc) -> Keys = chttpd:qs_json_value(Req, "keys", undefined), @@ -90,8 +75,8 @@ handle_view_req(#httpd{method='POST', Queries = couch_util:get_value(<<"queries">>, Fields), Keys = couch_util:get_value(<<"keys">>, Fields), case {Queries, Keys} of - {Queries, undefined} when is_list(Queries) -> - multi_query_view(Req, Db, DDoc, ViewName, Queries); + %% {Queries, undefined} when is_list(Queries) -> + %% multi_query_view(Req, Db, DDoc, ViewName, Queries); {undefined, Keys} when is_list(Keys) -> design_doc_view(Req, Db, DDoc, ViewName, Keys); {undefined, undefined} -> @@ -111,10 +96,7 @@ handle_temp_view_req(Req, _Db) -> Msg = <<"Temporary views are not supported in CouchDB">>, chttpd:send_error(Req, 403, forbidden, Msg). -reverse_key_default(?MIN_STR) -> ?MAX_STR; -reverse_key_default(?MAX_STR) -> ?MIN_STR; -reverse_key_default(Key) -> Key. - +%% TODO: remove this once chttpd_show has been updated to use couch_mrview get_reduce_type(Req) -> case chttpd:qs_value(Req, "reduce", "true") of "true" -> @@ -124,259 +106,3 @@ get_reduce_type(Req) -> _Error -> throw({bad_request, "`reduce` qs param must be `true` or `false`"}) end. - -parse_view_params(Req, Keys, ViewType) when not is_list(Req) -> - QueryParams = lists:flatmap(fun({K,V}) -> parse_view_param(K,V) end, - chttpd:qs(Req)), - parse_view_params(QueryParams, Keys, ViewType); -parse_view_params(QueryParams, Keys, ViewType) -> - IsMultiGet = (Keys =/= nil), - Args = #mrargs{ - view_type=ViewType, - multi_get=IsMultiGet, - keys=Keys - }, - QueryArgs = lists:foldl(fun({K, V}, Args2) -> - validate_view_query(K, V, Args2) - end, Args, QueryParams), - - GroupLevel = QueryArgs#mrargs.group_level, - case {ViewType, GroupLevel, IsMultiGet} of - {reduce, exact, true} -> - QueryArgs; - {reduce, _, false} -> - QueryArgs; - {reduce, _, _} -> - Msg = <<"Multi-key fetchs for reduce " - "view must include `group=true`">>, - throw({query_parse_error, Msg}); - _ -> - QueryArgs - end, - QueryArgs. - -parse_json_view_param({<<"key">>, V}) -> - [{start_key, V}, {end_key, V}]; -parse_json_view_param({<<"startkey_docid">>, V}) -> - [{start_key_docid, V}]; -parse_json_view_param({<<"endkey_docid">>, V}) -> - [{end_key_docid, V}]; -parse_json_view_param({<<"startkey">>, V}) -> - [{start_key, V}]; -parse_json_view_param({<<"endkey">>, V}) -> - [{end_key, V}]; -parse_json_view_param({<<"limit">>, V}) when is_integer(V), V > 0 -> - [{limit, V}]; -parse_json_view_param({<<"stale">>, <<"ok">>}) -> - [{stale, ok}]; -parse_json_view_param({<<"stale">>, <<"update_after">>}) -> - [{stale, update_after}]; -parse_json_view_param({<<"descending">>, V}) when is_boolean(V) -> - [{descending, V}]; -parse_json_view_param({<<"skip">>, V}) when is_integer(V) -> - [{skip, V}]; -parse_json_view_param({<<"group">>, true}) -> - [{group_level, exact}]; -parse_json_view_param({<<"group">>, false}) -> - [{group_level, 0}]; -parse_json_view_param({<<"group_level">>, V}) when is_integer(V), V > 0 -> - [{group_level, V}]; -parse_json_view_param({<<"inclusive_end">>, V}) when is_boolean(V) -> - [{inclusive_end, V}]; -parse_json_view_param({<<"reduce">>, V}) when is_boolean(V) -> - [{reduce, V}]; -parse_json_view_param({<<"include_docs">>, V}) when is_boolean(V) -> - [{include_docs, V}]; -parse_json_view_param({<<"conflicts">>, V}) when is_boolean(V) -> - [{conflicts, V}]; -parse_json_view_param({<<"list">>, V}) -> - [{list, couch_util:to_binary(V)}]; -parse_json_view_param({<<"sorted">>, V}) when is_boolean(V) -> - [{sorted, V}]; -parse_json_view_param({K, V}) -> - [{extra, {K, V}}]. - -parse_view_param("", _) -> - []; -parse_view_param("key", Value) -> - JsonKey = ?JSON_DECODE(Value), - [{start_key, JsonKey}, {end_key, JsonKey}]; -parse_view_param("startkey_docid", Value) -> - [{start_key_docid, ?l2b(Value)}]; -parse_view_param("endkey_docid", Value) -> - [{end_key_docid, ?l2b(Value)}]; -parse_view_param("startkey", Value) -> - [{start_key, ?JSON_DECODE(Value)}]; -parse_view_param("endkey", Value) -> - [{end_key, ?JSON_DECODE(Value)}]; -parse_view_param("limit", Value) -> - [{limit, parse_positive_int_param(Value)}]; -parse_view_param("count", _Value) -> - throw({query_parse_error, <<"Query parameter 'count' is now 'limit'.">>}); -parse_view_param("stale", "ok") -> - [{stale, ok}]; -parse_view_param("stale", "update_after") -> - [{stale, update_after}]; -parse_view_param("stale", _Value) -> - throw({query_parse_error, - <<"stale only available as stale=ok or as stale=update_after">>}); -parse_view_param("update", _Value) -> - throw({query_parse_error, <<"update=false is now stale=ok">>}); -parse_view_param("descending", Value) -> - [{descending, parse_bool_param(Value)}]; -parse_view_param("skip", Value) -> - [{skip, parse_int_param(Value)}]; -parse_view_param("group", Value) -> - case parse_bool_param(Value) of - true -> [{group_level, exact}]; - false -> [{group_level, 0}] - end; -parse_view_param("group_level", Value) -> - [{group_level, parse_positive_int_param(Value)}]; -parse_view_param("inclusive_end", Value) -> - [{inclusive_end, parse_bool_param(Value)}]; -parse_view_param("reduce", Value) -> - [{reduce, parse_bool_param(Value)}]; -parse_view_param("include_docs", Value) -> - [{include_docs, parse_bool_param(Value)}]; -parse_view_param("conflicts", Value) -> - [{conflicts, parse_bool_param(Value)}]; -parse_view_param("list", Value) -> - [{list, ?l2b(Value)}]; -parse_view_param("callback", _) -> - []; % Verified in the JSON response functions -parse_view_param("sorted", Value) -> - [{sorted, parse_bool_param(Value)}]; -parse_view_param(Key, Value) -> - [{extra, {Key, Value}}]. - -validate_view_query(start_key, Value, Args) -> - case Args#mrargs.multi_get of - true -> - Msg = <<"Query parameter `start_key` is " - "not compatiible with multi-get">>, - throw({query_parse_error, Msg}); - _ -> - Args#mrargs{start_key=Value} - end; -validate_view_query(start_key_docid, Value, Args) -> - Args#mrargs{start_key_docid=Value}; -validate_view_query(end_key, Value, Args) -> - case Args#mrargs.multi_get of - true-> - Msg = <<"Query paramter `end_key` is " - "not compatibile with multi-get">>, - throw({query_parse_error, Msg}); - _ -> - Args#mrargs{end_key=Value} - end; -validate_view_query(end_key_docid, Value, Args) -> - Args#mrargs{end_key_docid=Value}; -validate_view_query(limit, Value, Args) -> - Args#mrargs{limit=Value}; -validate_view_query(list, Value, Args) -> - Args#mrargs{list=Value}; -validate_view_query(stale, Value, Args) -> - Args#mrargs{stale=Value}; -validate_view_query(descending, true, Args) -> - case Args#mrargs.direction of - rev -> Args; % Already reversed - fwd -> - Args#mrargs{ - direction = rev, - start_key_docid = - reverse_key_default(Args#mrargs.start_key_docid), - end_key_docid = - reverse_key_default(Args#mrargs.end_key_docid) - } - end; -validate_view_query(descending, false, Args) -> - Args; % Ignore default condition -validate_view_query(skip, Value, Args) -> - Args#mrargs{skip=Value}; -validate_view_query(group_level, Value, Args) -> - case Args#mrargs.view_type of - reduce -> - Args#mrargs{group_level=Value}; - _ -> - Msg = <<"Invalid URL parameter 'group' or " - " 'group_level' for non-reduce view.">>, - throw({query_parse_error, Msg}) - end; -validate_view_query(inclusive_end, Value, Args) -> - Args#mrargs{inclusive_end=Value}; -validate_view_query(reduce, false, Args) -> - Args; -validate_view_query(reduce, _, Args) -> - case Args#mrargs.view_type of - map -> - Msg = <<"Invalid URL parameter `reduce` for map view.">>, - throw({query_parse_error, Msg}); - _ -> - Args - end; -validate_view_query(include_docs, true, Args) -> - case Args#mrargs.view_type of - reduce -> - Msg = <<"Query paramter `include_docs` " - "is invalid for reduce views.">>, - throw({query_parse_error, Msg}); - _ -> - Args#mrargs{include_docs=true} - end; -validate_view_query(include_docs, _Value, Args) -> - Args; -validate_view_query(conflicts, true, Args) -> - case Args#mrargs.view_type of - reduce -> - Msg = <<"Query parameter `conflicts` " - "is invalid for reduce views.">>, - throw({query_parse_error, Msg}); - _ -> - Args#mrargs{extra = [conflicts|Args#mrargs.extra]} - end; -validate_view_query(conflicts, _Value, Args) -> - Args; -validate_view_query(sorted, false, Args) -> - Args#mrargs{sorted=false}; -validate_view_query(sorted, _Value, Args) -> - Args; -validate_view_query(extra, _Value, Args) -> - Args. - -view_group_etag(Group, Db) -> - view_group_etag(Group, Db, nil). - -view_group_etag(Group, _Db, Extra) -> - Sig = couch_view_group:get_signature(Group), - CurrentSeq = couch_view_group:get_current_seq(Group), - % This is not as granular as it could be. - % If there are updates to the db that do not effect the view index, - % they will change the Etag. For more granular Etags we'd need to keep - % track of the last Db seq that caused an index change. - chttpd:make_etag({Sig, CurrentSeq, Extra}). - -parse_bool_param("true") -> true; -parse_bool_param("false") -> false; -parse_bool_param(Val) -> - Msg = io_lib:format("Invalid value for boolean paramter: ~p", [Val]), - throw({query_parse_error, ?l2b(Msg)}). - -parse_int_param(Val) -> - case (catch list_to_integer(Val)) of - IntVal when is_integer(IntVal) -> - IntVal; - _ -> - Msg = io_lib:format("Invalid value for integer parameter: ~p", [Val]), - throw({query_parse_error, ?l2b(Msg)}) - end. - -parse_positive_int_param(Val) -> - case parse_int_param(Val) of - IntVal when IntVal >= 0 -> - IntVal; - _ -> - Fmt = "Invalid value for positive integer parameter: ~p", - Msg = io_lib:format(Fmt, [Val]), - throw({query_parse_error, ?l2b(Msg)}) - end.
