summaryrefslogtreecommitdiff
path: root/src/couchdb/couch_httpd_view.erl
diff options
context:
space:
mode:
authorDamien F. Katz <damien@apache.org>2009-09-11 23:23:07 +0000
committerDamien F. Katz <damien@apache.org>2009-09-11 23:23:07 +0000
commit45796298231349dadf650e9ddefd7a6ff32e1302 (patch)
tree4de5543e9584a2c8a91f0b27b5b8f9e43de3fe46 /src/couchdb/couch_httpd_view.erl
parent773a23353b9101620ebb91183cb67240c17aa2c9 (diff)
Refactoring of endkey code in views and btrees. End key functionaility is now handled inside the btree code, simplfying calling code and making it trivial to add new collation options
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@814078 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/couchdb/couch_httpd_view.erl')
-rw-r--r--src/couchdb/couch_httpd_view.erl142
1 files changed, 46 insertions, 96 deletions
diff --git a/src/couchdb/couch_httpd_view.erl b/src/couchdb/couch_httpd_view.erl
index 884402da..35484823 100644
--- a/src/couchdb/couch_httpd_view.erl
+++ b/src/couchdb/couch_httpd_view.erl
@@ -16,7 +16,7 @@
-export([handle_view_req/2,handle_temp_view_req/2,handle_db_view_req/2]).
-export([get_stale_type/1, get_reduce_type/1, parse_view_params/3]).
--export([make_view_fold_fun/6, finish_view_fold/3, view_row_obj/3]).
+-export([make_view_fold_fun/6, finish_view_fold/4, view_row_obj/3]).
-export([view_group_etag/2, view_group_etag/3, make_reduce_fold_funs/5]).
-export([design_doc_view/5, parse_bool_param/1]).
@@ -150,11 +150,11 @@ output_map_view(Req, View, Group, Db, QueryArgs, nil) ->
CurrentEtag = view_group_etag(Group, Db),
couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
{ok, RowCount} = couch_view:get_row_count(View),
- Start = {StartKey, StartDocId},
FoldlFun = make_view_fold_fun(Req, QueryArgs, CurrentEtag, Db, RowCount, #view_fold_helper_funs{reduce_count=fun couch_view:reduce_to_count/1}),
- FoldAccInit = {Limit, SkipCount, undefined, [], nil},
- FoldResult = couch_view:fold(View, Start, Dir, FoldlFun, FoldAccInit),
- finish_view_fold(Req, RowCount, FoldResult)
+ FoldAccInit = {Limit, SkipCount, undefined, []},
+ {ok, LastReduce, FoldResult} = couch_view:fold(View, FoldlFun, FoldAccInit,
+ [{dir, Dir}, {start_key, {StartKey, StartDocId}} | make_end_key_option(QueryArgs)]),
+ finish_view_fold(Req, RowCount, couch_view:reduce_to_count(LastReduce), FoldResult)
end);
output_map_view(Req, View, Group, Db, QueryArgs, Keys) ->
@@ -167,21 +167,21 @@ output_map_view(Req, View, Group, Db, QueryArgs, Keys) ->
CurrentEtag = view_group_etag(Group, Db, Keys),
couch_httpd:etag_respond(Req, CurrentEtag, fun() ->
{ok, RowCount} = couch_view:get_row_count(View),
- FoldAccInit = {Limit, SkipCount, undefined, [], nil},
- FoldResult = lists:foldl(
- fun(Key, {ok, FoldAcc}) ->
- Start = {Key, StartDocId},
+ FoldAccInit = {Limit, SkipCount, undefined, []},
+ {LastReduce, FoldResult} = lists:foldl(
+ fun(Key, {_, FoldAcc}) ->
FoldlFun = make_view_fold_fun(Req,
QueryArgs#view_query_args{
- start_key = Key,
- end_key = Key
}, CurrentEtag, Db, RowCount,
#view_fold_helper_funs{
reduce_count = fun couch_view:reduce_to_count/1
}),
- couch_view:fold(View, Start, Dir, FoldlFun, FoldAcc)
- end, {ok, FoldAccInit}, Keys),
- finish_view_fold(Req, RowCount, FoldResult)
+ {ok, LastReduce, FoldResult} = couch_view:fold(View, FoldlFun, FoldAcc,
+ [{dir, Dir},{start_key, {Key, StartDocId}} | make_end_key_option(
+ QueryArgs#view_query_args{end_key=Key})]),
+ {LastReduce, FoldResult}
+ end, {{[],[]}, FoldAccInit}, Keys),
+ finish_view_fold(Req, RowCount, couch_view:reduce_to_count(LastReduce), FoldResult)
end).
output_reduce_view(Req, Db, View, Group, QueryArgs, nil) ->
@@ -401,58 +401,37 @@ validate_view_query(extra, _Value, Args) ->
Args.
make_view_fold_fun(Req, QueryArgs, Etag, Db, TotalViewCount, HelperFuns) ->
- #view_query_args{
- end_key = EndKey,
- end_docid = EndDocId,
- inclusive_end = InclusiveEnd,
- direction = Dir
- } = QueryArgs,
-
#view_fold_helper_funs{
- passed_end = PassedEndFun,
start_response = StartRespFun,
send_row = SendRowFun,
reduce_count = ReduceCountFun
- } = apply_default_helper_funs(HelperFuns,
- {Dir, EndKey, EndDocId, InclusiveEnd}),
+ } = apply_default_helper_funs(HelperFuns),
#view_query_args{
include_docs = IncludeDocs
} = QueryArgs,
-
- fun({{Key, DocId}, Value}, OffsetReds, {AccLimit, AccSkip, Resp, RowFunAcc,
- OffsetAcc}) ->
- PassedEnd = PassedEndFun(Key, DocId),
- case {PassedEnd, AccLimit, AccSkip, Resp} of
- {true, _, _, _} ->
- % The stop key has been passed, stop looping.
- % We may need offset so calcluate it here.
- % Checking Resp is an optimization that tells
- % us its already been calculated (and sent).
- NewOffset = case Resp of
- undefined -> ReduceCountFun(OffsetReds);
- _ -> nil
- end,
- {stop, {AccLimit, AccSkip, Resp, RowFunAcc, NewOffset}};
- {_, 0, _, _} ->
+
+ fun({{Key, DocId}, Value}, OffsetReds, {AccLimit, AccSkip, Resp, RowFunAcc}) ->
+ case {AccLimit, AccSkip, Resp} of
+ {0, _, _} ->
% we've done "limit" rows, stop foldling
- {stop, {0, 0, Resp, RowFunAcc, OffsetAcc}};
- {_, _, AccSkip, _} when AccSkip > 0 ->
+ {stop, {0, 0, Resp, RowFunAcc}};
+ {_, AccSkip, _} when AccSkip > 0 ->
% just keep skipping
- {ok, {AccLimit, AccSkip - 1, Resp, RowFunAcc, OffsetAcc}};
- {_, _, _, undefined} ->
+ {ok, {AccLimit, AccSkip - 1, Resp, RowFunAcc}};
+ {_, _, undefined} ->
% rendering the first row, first we start the response
Offset = ReduceCountFun(OffsetReds),
{ok, Resp2, RowFunAcc0} = StartRespFun(Req, Etag,
TotalViewCount, Offset, RowFunAcc),
{Go, RowFunAcc2} = SendRowFun(Resp2, Db, {{Key, DocId}, Value},
IncludeDocs, RowFunAcc0),
- {Go, {AccLimit - 1, 0, Resp2, RowFunAcc2, Offset}};
- {_, AccLimit, _, Resp} when (AccLimit > 0) ->
+ {Go, {AccLimit - 1, 0, Resp2, RowFunAcc2}};
+ {AccLimit, _, Resp} when (AccLimit > 0) ->
% rendering all other rows
{Go, RowFunAcc2} = SendRowFun(Resp, Db, {{Key, DocId}, Value},
IncludeDocs, RowFunAcc),
- {Go, {AccLimit - 1, 0, Resp, RowFunAcc2, OffsetAcc}}
+ {Go, {AccLimit - 1, 0, Resp, RowFunAcc2}}
end
end.
@@ -515,14 +494,9 @@ make_reduce_fold_funs(Req, GroupLevel, _QueryArgs, Etag, HelperFuns) ->
{ok, GroupRowsFun, RespFun}.
apply_default_helper_funs(#view_fold_helper_funs{
- passed_end = PassedEnd,
start_response = StartResp,
send_row = SendRow
-}=Helpers, {Dir, EndKey, EndDocId, InclusiveEnd}) ->
- PassedEnd2 = case PassedEnd of
- undefined -> make_passed_end_fun(Dir, EndKey, EndDocId, InclusiveEnd);
- _ -> PassedEnd
- end,
+}=Helpers) ->
StartResp2 = case StartResp of
undefined -> fun json_view_start_resp/5;
@@ -535,10 +509,10 @@ apply_default_helper_funs(#view_fold_helper_funs{
end,
Helpers#view_fold_helper_funs{
- passed_end = PassedEnd2,
start_response = StartResp2,
send_row = SendRow2
- }.
+ };
+
apply_default_helper_funs(#reduce_fold_helper_funs{
start_response = StartResp,
@@ -559,35 +533,17 @@ apply_default_helper_funs(#reduce_fold_helper_funs{
send_row = SendRow2
}.
-make_passed_end_fun(fwd, EndKey, EndDocId, InclusiveEnd) ->
- case InclusiveEnd of
- true ->
- fun(ViewKey, ViewId) ->
- couch_view:less_json([EndKey, EndDocId], [ViewKey, ViewId])
- end;
- false ->
- fun
- (ViewKey, _ViewId) when ViewKey == EndKey ->
- true;
- (ViewKey, ViewId) ->
- couch_view:less_json([EndKey, EndDocId], [ViewKey, ViewId])
- end
- end;
-
-make_passed_end_fun(rev, EndKey, EndDocId, InclusiveEnd) ->
- case InclusiveEnd of
- true ->
- fun(ViewKey, ViewId) ->
- couch_view:less_json([ViewKey, ViewId], [EndKey, EndDocId])
- end;
- false->
- fun
- (ViewKey, _ViewId) when ViewKey == EndKey ->
- true;
- (ViewKey, ViewId) ->
- couch_view:less_json([ViewKey, ViewId], [EndKey, EndDocId])
- end
- end.
+make_end_key_option(
+ #view_query_args{end_key = EndKey,
+ end_docid = EndDocId,
+ inclusive_end = true}) ->
+ [{end_key_inclusive, {EndKey, EndDocId}}];
+make_end_key_option(
+ #view_query_args{
+ end_key = EndKey,
+ end_docid = EndDocId,
+ inclusive_end = false}) ->
+ [{end_key, {EndKey,reverse_key_default(EndDocId)}}].
json_view_start_resp(Req, Etag, TotalViewCount, Offset, _Acc) ->
{ok, Resp} = start_json_response(Req, 200, [{"Etag", Etag}]),
@@ -651,26 +607,20 @@ view_row_with_doc(Db, {{Key, DocId}, Value}, Rev) ->
{[{id, DocId}, {key, Key}, {value, Value}, {doc, JsonDoc}]}
end.
-finish_view_fold(Req, TotalRows, FoldResult) ->
+finish_view_fold(Req, TotalRows, Offset, FoldResult) ->
case FoldResult of
- {ok, {_, _, undefined, _, Offset}} ->
- % nothing found in the view, nothing has been returned
+ {_, _, undefined, _} ->
+ % nothing found in the view or keys, nothing has been returned
% send empty view
- NewOffset = case Offset of
- nil -> TotalRows;
- _ -> Offset
- end,
send_json(Req, 200, {[
{total_rows, TotalRows},
- {offset, NewOffset},
+ {offset, Offset},
{rows, []}
]});
- {ok, {_, _, Resp, _, _}} ->
+ {_, _, Resp, _} ->
% end the view
send_chunk(Resp, "\r\n]}"),
- end_json_response(Resp);
- Error ->
- throw(Error)
+ end_json_response(Resp)
end.
finish_reduce_fold(Req, Resp) ->