From 04b2acac82d8b0ad60be485b8b1321c2fcbe6f57 Mon Sep 17 00:00:00 2001 From: John Christopher Anderson Date: Sun, 5 Oct 2008 18:54:36 +0000 Subject: include_docs option adds a doc member to view rows with the latest _rev of the document (or the _rev specified in the row value) git-svn-id: https://svn.apache.org/repos/asf/incubator/couchdb/trunk@701847 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_db.hrl | 3 +- src/couchdb/couch_httpd_db.erl | 12 +++--- src/couchdb/couch_httpd_view.erl | 82 ++++++++++++++++++++++++++++++---------- 3 files changed, 69 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/couchdb/couch_db.hrl b/src/couchdb/couch_db.hrl index f5f4a0f1..bf98e182 100644 --- a/src/couchdb/couch_db.hrl +++ b/src/couchdb/couch_db.hrl @@ -124,7 +124,8 @@ end_docid = {}, skip = 0, group_level = 0, - reduce = true + reduce = true, + include_docs = false }). diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl index 20805c85..240b2730 100644 --- a/src/couchdb/couch_httpd_db.erl +++ b/src/couchdb/couch_httpd_db.erl @@ -13,7 +13,7 @@ -module(couch_httpd_db). -include("couch_db.hrl"). --export([handle_request/1, db_req/2]). +-export([handle_request/1, db_req/2, couch_doc_open/4]). -import(couch_httpd, [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2, @@ -179,8 +179,8 @@ db_req(#httpd{method='GET',path_parts=[_,<<"_all_docs_by_seq">>]}=Req, Db) -> {ok, Info} = couch_db:get_db_info(Db), TotalRowCount = proplists:get_value(doc_count, Info), - FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, TotalRowCount, - fun couch_db:enum_docs_since_reduce_to_count/1), + FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, Db, + TotalRowCount, fun couch_db:enum_docs_since_reduce_to_count/1), StartKey2 = case StartKey of nil -> 0; <<>> -> 100000000000; @@ -247,7 +247,7 @@ all_docs_view(Req, Db, Keys) -> count = Count, skip = SkipCount, direction = Dir - } = QueryArgs = couch_httpd_view:parse_view_query(Req, Keys), + } = QueryArgs = couch_httpd_view:parse_view_query(Req, Keys), {ok, Info} = couch_db:get_db_info(Db), TotalRowCount = proplists:get_value(doc_count, Info), StartId = if is_binary(StartKey) -> StartKey; @@ -257,7 +257,7 @@ all_docs_view(Req, Db, Keys) -> case Keys of nil -> - FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, + FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, Db, TotalRowCount, fun couch_db:enum_docs_reduce_to_count/1), AdapterFun = fun(#full_doc_info{id=Id}=FullDocInfo, Offset, Acc) -> case couch_doc:to_doc_info(FullDocInfo) of @@ -271,7 +271,7 @@ all_docs_view(Req, Db, Keys) -> AdapterFun, FoldAccInit), couch_httpd_view:finish_view_fold(Req, TotalRowCount, {ok, FoldResult}); _ -> - FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, + FoldlFun = couch_httpd_view:make_view_fold_fun(Req, QueryArgs, Db, TotalRowCount, fun(Offset) -> Offset end), KeyFoldFun = case Dir of fwd -> diff --git a/src/couchdb/couch_httpd_view.erl b/src/couchdb/couch_httpd_view.erl index de6a6af7..d281b82b 100644 --- a/src/couchdb/couch_httpd_view.erl +++ b/src/couchdb/couch_httpd_view.erl @@ -15,7 +15,7 @@ -export([handle_view_req/2,handle_temp_view_req/2]). --export([parse_view_query/1,parse_view_query/2,make_view_fold_fun/4,finish_view_fold/3]). +-export([parse_view_query/1,parse_view_query/2,make_view_fold_fun/5,finish_view_fold/3]). -import(couch_httpd, [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2, @@ -26,7 +26,7 @@ design_doc_view(Req, Db, Id, ViewName, Keys) -> <<"_design/", Id/binary>>, ViewName}) of {ok, View} -> QueryArgs = parse_view_query(Req, Keys), - output_map_view(Req, View, QueryArgs, Keys); + output_map_view(Req, View, Db, QueryArgs, Keys); {not_found, Reason} -> case couch_view:get_reduce_view({couch_db:name(Db), <<"_design/", Id/binary>>, ViewName}) of @@ -37,7 +37,7 @@ design_doc_view(Req, Db, Id, ViewName, Keys) -> case Reduce of false -> {reduce, _N, _Lang, MapView} = View, - output_map_view(Req, MapView, QueryArgs, Keys); + output_map_view(Req, MapView, Db, QueryArgs, Keys); _ -> output_reduce_view(Req, View, QueryArgs, Keys) end; @@ -72,7 +72,7 @@ handle_temp_view_req(#httpd{method='POST'}=Req, Db) -> case proplists:get_value(<<"reduce">>, Props, null) of null -> {ok, View} = couch_view:get_map_view({temp, couch_db:name(Db), Language, MapSrc}), - output_map_view(Req, View, QueryArgs, Keys); + output_map_view(Req, View, Db, QueryArgs, Keys); RedSrc -> {ok, View} = couch_view:get_reduce_view( {temp, couch_db:name(Db), Language, MapSrc, RedSrc}), @@ -82,7 +82,7 @@ handle_temp_view_req(#httpd{method='POST'}=Req, Db) -> handle_temp_view_req(Req, _Db) -> send_method_not_allowed(Req, "POST"). -output_map_view(Req, View, QueryArgs, nil) -> +output_map_view(Req, View, Db, QueryArgs, nil) -> #view_query_args{ count = Count, direction = Dir, @@ -92,13 +92,13 @@ output_map_view(Req, View, QueryArgs, nil) -> } = QueryArgs, {ok, RowCount} = couch_view:get_row_count(View), Start = {StartKey, StartDocId}, - FoldlFun = make_view_fold_fun(Req, QueryArgs, RowCount, + FoldlFun = make_view_fold_fun(Req, QueryArgs, Db, RowCount, fun couch_view:reduce_to_count/1), FoldAccInit = {Count, SkipCount, undefined, []}, FoldResult = couch_view:fold(View, Start, Dir, FoldlFun, FoldAccInit), finish_view_fold(Req, RowCount, FoldResult); -output_map_view(Req, View, QueryArgs, Keys) -> +output_map_view(Req, View, Db, QueryArgs, Keys) -> #view_query_args{ count = Count, direction = Dir, @@ -114,7 +114,7 @@ output_map_view(Req, View, QueryArgs, Keys) -> QueryArgs#view_query_args{ start_key = Key, end_key = Key - }, RowCount, fun couch_view:reduce_to_count/1), + }, Db, RowCount, 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). @@ -305,6 +305,23 @@ parse_view_query(Req, Keys, IsReduce) -> Args#view_query_args{reduce=true}; {"reduce", "false"} -> Args#view_query_args{reduce=false}; + {"include_docs", Value} -> + case IsReduce of + true -> + Msg = lists:flatten(io_lib:format("Bad URL query key for reduce operation: ~s", [Key])), + throw({query_parse_error, Msg}); + _ -> + ok + end, + case Value of + "true" -> + Args#view_query_args{include_docs=true}; + "false" -> + Args#view_query_args{include_docs=false}; + _ -> + Msg1 = "Bad URL query value for 'include_docs' expected \"true\" or \"false\".", + throw({query_parse_error, Msg1}) + end; _ -> % unknown key Msg = lists:flatten(io_lib:format( "Bad URL query key:~s", [Key])), @@ -331,10 +348,11 @@ parse_view_query(Req, Keys, IsReduce) -> end. -make_view_fold_fun(Req, QueryArgs, TotalViewCount, ReduceCountFun) -> +make_view_fold_fun(Req, QueryArgs, Db, TotalViewCount, ReduceCountFun) -> #view_query_args{ end_key = EndKey, end_docid = EndDocId, + include_docs = IncludeDocs, direction = Dir } = QueryArgs, @@ -367,26 +385,48 @@ make_view_fold_fun(Req, QueryArgs, TotalViewCount, ReduceCountFun) -> {ok, Resp2} = start_json_response(Req, 200), JsonBegin = io_lib:format("{\"total_rows\":~w,\"offset\":~w,\"rows\":[\r\n", [TotalViewCount, Offset]), - JsonObj = case DocId of - error -> - {[{key, Key}, {error, Value}]}; - _ -> - {[{id, DocId}, {key, Key}, {value, Value}]} - end, + JsonObj = view_row_obj(Db, {{Key, DocId}, Value}, IncludeDocs), send_chunk(Resp2, JsonBegin ++ ?JSON_ENCODE(JsonObj)), {ok, {AccCount - 1, 0, Resp2, AccRevRows}}; {_, AccCount, _, Resp} when (AccCount > 0) -> - JsonObj = case DocId of - error -> - {[{key, Key}, {error, Value}]}; - _ -> - {[{id, DocId}, {key, Key}, {value, Value}]} - end, + JsonObj = view_row_obj(Db, {{Key, DocId}, Value}, IncludeDocs), send_chunk(Resp, ",\r\n" ++ ?JSON_ENCODE(JsonObj)), {ok, {AccCount - 1, 0, Resp, AccRevRows}} end end. +view_row_obj(Db, {{Key, DocId}, Value}, IncludeDocs) -> + case DocId of + error -> + {[{key, Key}, {error, Value}]}; + _ -> + case IncludeDocs of + true -> + Rev = case Value of + {Props} -> + case is_list(Props) of + true -> + proplists:get_value(<<"_rev">>, Props, []); + _ -> + [] + end; + _ -> + [] + end, + ?LOG_DEBUG("Include Doc: ~p ~p", [DocId, Rev]), + case (catch couch_httpd_db:couch_doc_open(Db, DocId, + Rev, [])) of + {{not_found, missing}, _} -> + {[{id, DocId}, {key, Key}, {value, Value}, {error, missing}]}; + Doc -> + JsonDoc = couch_doc:to_json_obj(Doc, []), + {[{id, DocId}, {key, Key}, {value, Value}, {doc, JsonDoc}]} + end; + _ -> + {[{id, DocId}, {key, Key}, {value, Value}]} + end + end. + finish_view_fold(Req, TotalRows, FoldResult) -> case FoldResult of {ok, {_, _, undefined, _}} -> -- cgit v1.2.3