summaryrefslogtreecommitdiff
path: root/src/fabric_rpc.erl
diff options
context:
space:
mode:
authorAdam Kocoloski <adam@cloudant.com>2010-06-07 14:46:35 -0400
committerAdam Kocoloski <adam@cloudant.com>2010-06-07 14:46:35 -0400
commit38bde53e2429f60b3209d71c562218f3c7429945 (patch)
tree5fd5ee047eeb7a3b46cc022c0eab121a74f5e1ec /src/fabric_rpc.erl
parenta9a36b4184fae5e4078982d48c0536b8ba948391 (diff)
map views w/o keylist, BugzID 10220
Diffstat (limited to 'src/fabric_rpc.erl')
-rw-r--r--src/fabric_rpc.erl105
1 files changed, 97 insertions, 8 deletions
diff --git a/src/fabric_rpc.erl b/src/fabric_rpc.erl
index a2d42007..0eab5e6d 100644
--- a/src/fabric_rpc.erl
+++ b/src/fabric_rpc.erl
@@ -2,7 +2,7 @@
-export([get_db_info/1, get_doc_count/1, get_update_seq/1]).
-export([open_doc/3, open_revs/4, get_missing_revs/2, update_docs/3]).
--export([all_docs/2]).
+-export([all_docs/2, map_view/4]).
-include("fabric.hrl").
@@ -11,6 +11,7 @@
limit,
include_docs,
offset = nil,
+ total_rows,
reduce_fun = fun couch_db:enum_docs_reduce_to_count/1,
stop_fun,
group_level = 0
@@ -30,14 +31,46 @@ all_docs(DbName, #view_query_args{keys=nil} = QueryArgs) ->
direction = Dir
} = QueryArgs,
StartId = if is_binary(StartKey) -> StartKey; true -> StartDocId end,
+ {ok, Total} = couch_db:get_doc_count(Db),
Acc0 = #view_acc{
db = Db,
include_docs = IncludeDocs,
limit = Limit+Skip,
+ total_rows = Total,
stop_fun = all_docs_stop_fun(QueryArgs)
},
{ok, Acc} = couch_db:enum_docs(Db, StartId, Dir, fun view_fold/3, Acc0),
- final_all_docs_response(Db, Acc#view_acc.offset).
+ final_response(Total, Acc#view_acc.offset).
+
+map_view(DbName, DDoc, ViewName, #view_query_args{keys=nil} = QueryArgs) ->
+ {ok, Db} = couch_db:open(DbName, []),
+ #view_query_args{
+ start_key = StartKey,
+ start_docid = StartDocId,
+ limit = Limit,
+ skip = Skip,
+ include_docs = IncludeDocs,
+ direction = Dir,
+ stale = Stale,
+ view_type = ViewType
+ } = QueryArgs,
+ Start = {StartKey, StartDocId},
+ MinSeq = if Stale == ok -> 0; true -> couch_db:get_update_seq(Db) end,
+ Group0 = couch_view_group:design_doc_to_view_group(Db, DDoc),
+ {ok, Pid} = gen_server:call(couch_view, {get_group_server, DbName, Group0}),
+ {ok, Group} = couch_view_group:request_group(Pid, MinSeq),
+ View = extract_view(Pid, ViewName, Group#group.views, ViewType),
+ {ok, Total} = couch_view:get_row_count(View),
+ Acc0 = #view_acc{
+ db = Db,
+ include_docs = IncludeDocs,
+ limit = Limit+Skip,
+ total_rows = Total,
+ reduce_fun = fun couch_view:reduce_to_count/1,
+ stop_fun = default_stop_fun(QueryArgs)
+ },
+ {ok, Acc} = couch_view:fold(View, Start, Dir, fun view_fold/3, Acc0),
+ final_response(Total, Acc#view_acc.offset).
get_db_info(DbName) ->
with_db(DbName, [], {couch_db, get_db_info, []}).
@@ -101,10 +134,9 @@ view_fold(#full_doc_info{} = FullDocInfo, OffsetReds, Acc) ->
#doc_info{revs=[#rev_info{deleted=true}|_]} ->
{ok, Acc}
end;
-view_fold(KV, OffsetReds, #view_acc{offset=nil} = Acc) ->
+view_fold(KV, OffsetReds, #view_acc{offset=nil, total_rows=Total} = Acc) ->
% calculates the offset for this shard
- #view_acc{db=Db, reduce_fun=Reduce} = Acc,
- {ok, Total} = couch_db:get_doc_count(Db),
+ #view_acc{reduce_fun=Reduce} = Acc,
Offset = Reduce(OffsetReds),
case rexi:sync_reply({total_and_offset, Total, Offset}) of
ok ->
@@ -150,10 +182,67 @@ all_docs_stop_fun(#view_query_args{direction=rev, end_key=EndKey}) ->
couch_db_updater:less_docid(ViewKey, EndKey)
end.
-final_all_docs_response(Db, nil) ->
- {ok, Total} = couch_db:get_doc_count(Db),
+final_response(Total, nil) ->
case rexi:sync_reply({total_and_offset, Total, Total}) of ok ->
rexi:reply(complete);
stop -> ok end;
-final_all_docs_response(_Db, _Offset) ->
+final_response(_Total, _Offset) ->
rexi:reply(complete).
+
+default_stop_fun(#view_query_args{direction=fwd, inclusive_end=true} = Args) ->
+ #view_query_args{end_key=EndKey, end_docid=EndDocId} = Args,
+ fun(ViewKey, ViewId) ->
+ couch_view:less_json([EndKey, EndDocId], [ViewKey, ViewId])
+ end;
+default_stop_fun(#view_query_args{direction=fwd} = Args) ->
+ #view_query_args{end_key=EndKey, end_docid=EndDocId} = Args,
+ fun
+ (ViewKey, _ViewId) when ViewKey == EndKey ->
+ true;
+ (ViewKey, ViewId) ->
+ couch_view:less_json([EndKey, EndDocId], [ViewKey, ViewId])
+ end;
+default_stop_fun(#view_query_args{direction=rev, inclusive_end=true} = Args) ->
+ #view_query_args{end_key=EndKey, end_docid=EndDocId} = Args,
+ fun(ViewKey, ViewId) ->
+ couch_view:less_json([ViewKey, ViewId], [EndKey, EndDocId])
+ end;
+default_stop_fun(#view_query_args{direction=rev} = Args) ->
+ #view_query_args{end_key=EndKey, end_docid=EndDocId} = Args,
+ fun
+ (ViewKey, _ViewId) when ViewKey == EndKey ->
+ true;
+ (ViewKey, ViewId) ->
+ couch_view:less_json([ViewKey, ViewId], [EndKey, EndDocId])
+ end.
+
+extract_view(Pid, ViewName, [], _ViewType) ->
+ ?LOG_ERROR("missing_named_view ~p", [ViewName]),
+ exit(Pid, kill),
+ exit(missing_named_view);
+extract_view(Pid, ViewName, [View|Rest], ViewType) ->
+ case lists:member(ViewName, view_names(View, ViewType)) of
+ true ->
+ if ViewType == reduce ->
+ {index_of(ViewName, view_names(View, reduce)), View};
+ true ->
+ View
+ end;
+ false ->
+ extract_view(Pid, ViewName, Rest, ViewType)
+ end.
+
+view_names(View, Type) when Type == red_map; Type == reduce ->
+ [Name || {Name, _} <- View#view.reduce_funs];
+view_names(View, map) ->
+ View#view.map_names.
+
+index_of(X, List) ->
+ index_of(X, List, 1).
+
+index_of(_X, [], _I) ->
+ not_found;
+index_of(X, [X|_Rest], I) ->
+ I;
+index_of(X, [_|Rest], I) ->
+ index_of(X, Rest, I+1).