summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Kocoloski <adam@cloudant.com>2010-06-01 10:39:47 -0400
committerAdam Kocoloski <adam@cloudant.com>2010-06-01 10:39:47 -0400
commit9b7831dbbddc97b4134be2fa3b3ec2d2ebc9462b (patch)
treea675e52af675e626903a5a7c288d4e2cc4e24cac
parentdc28af5e331e13283ec3915e60fa0431673d1845 (diff)
RPC endpoint for all_docs w/o keylist, BugzID 10218
-rw-r--r--src/fabric_rpc.erl98
1 files changed, 93 insertions, 5 deletions
diff --git a/src/fabric_rpc.erl b/src/fabric_rpc.erl
index 2d1f6572..a8e4585b 100644
--- a/src/fabric_rpc.erl
+++ b/src/fabric_rpc.erl
@@ -2,17 +2,52 @@
-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]).
-include("fabric.hrl").
+-record (view_acc, {
+ db,
+ limit,
+ include_docs,
+ offset = nil,
+ reduce_fun = fun couch_db:enum_docs_reduce_to_count/1,
+ stop_fun,
+ group_level = 0
+}).
+
%% rpc endpoints
%% call to with_db will supply your M:F with a #db{} and then remaining args
+all_docs(DbName, #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
+ } = QueryArgs,
+ StartId = if is_binary(StartKey) -> StartKey; true -> StartDocId end,
+ Acc0 = #view_acc{
+ db = Db,
+ include_docs = IncludeDocs,
+ limit = Limit+Skip,
+ stop_fun = all_docs_stop_fun(QueryArgs)
+ },
+ {ok, Acc} = couch_db:enum_docs(Db, StartId, Dir, fun view_fold/3, Acc0),
+ if Acc#view_acc.offset == nil ->
+ Total = couch_db:get_doc_count(Db),
+ rexi:sync_reply({total_and_offset, Total, Total});
+ true -> ok end,
+ rexi:reply(complete).
+
get_db_info(DbName) ->
with_db(DbName, {couch_db, get_db_info, []}).
get_doc_count(DbName) ->
- rexi:reply(case couch_db:open(DbName) of
+ rexi:reply(case couch_db:open(DbName, []) of
{ok, Db} ->
{ok, {Count, _DelCount}} = couch_btree:full_reduce(Db#db.id_tree),
{ok, Count};
@@ -21,7 +56,7 @@ get_doc_count(DbName) ->
end).
get_update_seq(DbName) ->
- rexi:reply(case couch_db:open(DbName) of
+ rexi:reply(case couch_db:open(DbName, []) of
{ok, #db{update_seq = Seq}} ->
{ok, Seq};
Error ->
@@ -66,7 +101,60 @@ with_db(DbName, {M,F,A}) ->
rexi:reply(Error)
end.
+view_fold(#full_doc_info{} = FullDocInfo, OffsetReds, Acc) ->
+ % matches for _all_docs and translates #full_doc_info{} -> KV pair
+ case couch_doc:to_doc_info(FullDocInfo) of
+ #doc_info{revs=[#rev_info{deleted=false, rev=Rev}|_]} ->
+ Id = FullDocInfo#full_doc_info.id,
+ Value = {[{rev,couch_doc:rev_to_str(Rev)}]},
+ view_fold({{Id,Id}, Value}, OffsetReds, Acc);
+ #doc_info{revs=[#rev_info{deleted=true}|_]} ->
+ {ok, Acc}
+ end;
+view_fold(KV, OffsetReds, #view_acc{offset=nil} = Acc) ->
+ % calculates the offset for this shard
+ #view_acc{db=Db, reduce_fun=Reduce} = Acc,
+ Offset = Reduce(OffsetReds),
+ rexi:sync_reply({total_and_offset, couch_db:get_doc_count(Db), Offset}),
+ view_fold(KV, OffsetReds, Acc#view_acc{offset=Offset});
+view_fold(_KV, _Offset, #view_acc{limit=0} = Acc) ->
+ % we scanned through limit+skip local rows
+ {stop, Acc};
+view_fold({{Key,Id}, Value}, _Offset, Acc) ->
+ % the normal case
+ #view_acc{
+ db = Db,
+ limit = Limit,
+ include_docs = IncludeDocs,
+ stop_fun = PassedEnd
+ } = Acc,
+ case PassedEnd(Key, Id) of
+ true ->
+ {stop, Acc};
+ false ->
+ RowProps = case IncludeDocs of
+ true ->
+ case couch_db:open_doc(Db, Id, []) of
+ {not_found, missing} ->
+ [{id, Id}, {key, Key}, {value, Value}, {error, missing}];
+ {not_found, deleted} ->
+ [{id, Id}, {key, Key}, {value, Value}];
+ {ok, Doc} ->
+ JsonDoc = couch_doc:to_json_obj(Doc, []),
+ [{id, Id}, {key, Key}, {value, Value}, {doc, JsonDoc}]
+ end;
+ false ->
+ [{id, Id}, {key, Key}, {value, Value}]
+ end,
+ rexi:sync_reply({row, RowProps}),
+ {ok, Acc#view_acc{limit=Limit-1}}
+ end.
-%%
-%% helper funs
-%%
+all_docs_stop_fun(#view_query_args{direction=fwd, end_key=EndKey}) ->
+ fun(ViewKey, _) ->
+ couch_db_updater:less_docid(EndKey, ViewKey)
+ end;
+all_docs_stop_fun(#view_query_args{direction=rev, end_key=EndKey}) ->
+ fun(ViewKey, _) ->
+ couch_db_updater:less_docid(ViewKey, EndKey)
+ end.