couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cml...@apache.org
Subject svn commit: r643043 - in /incubator/couchdb/branches/mochiweb: configure.ac src/couchdb/couch_httpd.erl
Date Mon, 31 Mar 2008 16:15:42 GMT
Author: cmlenz
Date: Mon Mar 31 09:15:29 2008
New Revision: 643043

URL: http://svn.apache.org/viewvc?rev=643043&view=rev
Log:
mochiweb branch: build fixes and integrated parts of Damien's refactoring.

Modified:
    incubator/couchdb/branches/mochiweb/configure.ac
    incubator/couchdb/branches/mochiweb/src/couchdb/couch_httpd.erl

Modified: incubator/couchdb/branches/mochiweb/configure.ac
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/mochiweb/configure.ac?rev=643043&r1=643042&r2=643043&view=diff
==============================================================================
--- incubator/couchdb/branches/mochiweb/configure.ac (original)
+++ incubator/couchdb/branches/mochiweb/configure.ac Mon Mar 31 09:15:29 2008
@@ -214,7 +214,6 @@
 AC_CONFIG_FILES([bin/couchjs.tpl])
 AC_CONFIG_FILES([bin/couchdb.tpl])
 AC_CONFIG_FILES([bin/Makefile])
-AC_CONFIG_FILES([etc/couch_httpd.conf.tpl])
 AC_CONFIG_FILES([etc/couch.ini.tpl])
 AC_CONFIG_FILES([etc/default/couchdb.tpl])
 AC_CONFIG_FILES([etc/default/Makefile])

Modified: incubator/couchdb/branches/mochiweb/src/couchdb/couch_httpd.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/branches/mochiweb/src/couchdb/couch_httpd.erl?rev=643043&r1=643042&r2=643043&view=diff
==============================================================================
--- incubator/couchdb/branches/mochiweb/src/couchdb/couch_httpd.erl (original)
+++ incubator/couchdb/branches/mochiweb/src/couchdb/couch_httpd.erl Mon Mar 31 09:15:29 2008
@@ -19,6 +19,26 @@
     {port, 5984}
 ]).
 
+-record(doc_query_args, {
+    options = [],
+    rev = "",
+    open_revs = ""
+}).
+
+-record(view_query_args, {
+    start_key = nil,
+    end_key = <<>>,
+    count = 10000000000, % a huge huge default number. Picked so we don't have
+                         % to do different logic for when there is no count
+                         % limit
+    update = true,
+    direction = fwd,
+    start_docid = nil,
+    end_docid = <<>>,
+    skip = 0
+}).
+
+
 start_link(DocumentRoot) ->
     Loop = fun (Req) -> handle_request(Req, DocumentRoot) end,
     mochiweb_http:start([{loop, Loop} | ?DEFAULTS]).
@@ -67,6 +87,7 @@
         {"couchdb", "Welcome"},
         {"version", couch_server:get_version()}
     ]});
+
 handle_welcome_request(Req, _Method) ->
     send_error(Req, {method_not_allowed, "GET,HEAD"}).
 
@@ -77,6 +98,7 @@
         Error ->
             send_error(Req, Error)
     end;
+
 handle_all_dbs_request(Req, _Method) ->
     send_error(Req, {method_not_allowed, "GET,HEAD"}).
 
@@ -87,6 +109,7 @@
     {obj, Options} = proplists:get_value("options", Props, {obj, []}),
     {ok, JsonResults} = couch_rep:replicate(Source, Target, Options),
     send_json(Req, JsonResults);
+
 handle_replicate_request(Req, _Method) ->
     send_error(Req, {method_not_allowed, "POST"}).
 
@@ -108,6 +131,7 @@
             Msg = io_lib:format("Error creating database ~p: ~p", [DbName, Error]),
             send_error(Req, {unknown_error, Msg})
     end;
+
 handle_db_request(Req, Method, {DbName, Rest}) ->
     case couch_server:open(DbName) of
         {ok, Db} ->
@@ -121,89 +145,121 @@
     send_json(Req, 202, {obj, [
         {ok, true}
     ]});
+
 handle_db_request(Req, 'GET', {DbName, Db, []}) ->
-    {ok, DbInfo} = couch_db:get_info(Db),
+    {ok, DbInfo} = couch_db:get_db_info(Db),
     send_json(Req, {obj, [
         {"db_name", DbName},
         {"doc_count", proplists:get_value(doc_count, DbInfo)},
         {"update_seq", proplists:get_value(last_update_seq, DbInfo)}
     ]});
+
 handle_db_request(Req, 'POST', {_DbName, Db, []}) ->
+    % TODO: Etag handling
     Json = cjson:decode(Req:recv_body()),
     Doc = couch_doc:from_json_obj(Json),
     DocId = couch_util:new_uuid(),
-    case couch_db:save_doc(Db, Doc#doc{id=DocId, revs=[]}, []) of
-    {ok, NewRev} ->
-        send_json(Req, 201, {obj, [
-            {ok, true},
-            {id, DocId},
-            {rev, NewRev}
-        ]});
-    Error ->
-        send_error(Req, Error)
-    end;
+    {ok, NewRev} = couch_db:update_doc(Db, Doc#doc{id=DocId, revs=[]}, []),
+    send_json(Req, 201, {obj, [
+        {ok, true},
+        {id, DocId},
+        {rev, NewRev}
+    ]});
 
 handle_db_request(Req, _Method, {_DbName, _Db, []}) ->
     send_error(Req, {method_not_allowed, "DELETE,GET,HEAD,POST"});
 
 handle_db_request(Req, 'POST', {_DbName, Db, ["_bulk_docs"]}) ->
-    JsonArray = cjson:decode(Req:recv_body()),
+    Options = [], % put options here.
+    {obj, JsonProps} = cjson:decode(Req:recv_body()),
+    DocsArray = proplists:get_value("docs", JsonProps),
     % convert all the doc elements to native docs
-    DocsAndOptions = lists:foldl(
-        fun(Json, DocAcc) ->
-            case Json of
-            {obj, ObjProps} ->
-                Doc = couch_doc:from_json_obj(Json),
+    case proplists:get_value("new_edits", JsonProps, true) of
+    true ->
+        Docs = lists:map(
+            fun({obj, ObjProps} = JsonObj) ->
+                Doc = couch_doc:from_json_obj(JsonObj),
                 Id = case Doc#doc.id of
-                    [] -> couch_util:new_uuid();
+                    "" -> couch_util:new_uuid();
                     Id0 -> Id0
                 end,
                 Revs = case proplists:get_value("_rev", ObjProps) of
                     undefined -> [];
                     Rev  -> [Rev]
                 end,
-                [{[Doc#doc{id=Id, revs=Revs}], [new_edits]} | DocAcc];
-            _ ->
-                % when the doc is instead an array of docs, it means they
-                % are not new edits, but replicated/restored revisions
-                Docs = [couch_doc:from_json_obj(JsonDoc) ||
-                        JsonDoc <- tuple_to_list(Json)],
-                [{Docs, []} | DocAcc]
-            end
-        end,
-        [], tuple_to_list(JsonArray)),
-    % save the documents
-    {ok, Results} = couch_db:save_docs(Db, DocsAndOptions),
-    % output the results
-    DocResults = lists:zipwith(
-        fun([Result], {[Doc], _}) ->
-            case Result of
-            {ok, NewRev} ->
-                {obj, [{"ok", true}, {"id", Doc#doc.id}, {"rev", NewRev}]};
-            Error ->
-                {JsonError, _} = error_to_json(Error),
-                JsonError
-            end
-        end, Results, DocsAndOptions),
-    send_json(Req, 201, {obj, [
-        {ok, true},
-        {results, list_to_tuple(DocResults)}
-    ]});
+                Doc#doc{id=Id,revs=Revs}
+            end,
+            tuple_to_list(DocsArray)),
+        {ok, ResultRevs} = couch_db:update_docs(Db, Docs, Options),
+
+        % output the results
+        DocResults = lists:zipwith(
+            fun(Doc, NewRev) ->
+                {obj, [{"id", Doc#doc.id}, {"rev", NewRev}]}
+            end,
+            Docs, ResultRevs),
+        send_json(Req, 201, [{new_revs, list_to_tuple(DocResults)}]);
+
+    false ->
+        Docs = [couch_doc:from_json_obj(JsonObj) || JsonObj <- tuple_to_list(DocsArray)],
+        ok = couch_db:save_docs(Db, Docs, Options),
+        send_json(Req, 201)
+    end;
+
 handle_db_request(Req, _Method, {_DbName, _Db, ["_bulk_docs"]}) ->
     send_error(Req, {method_not_allowed, "POST"});
 
 % View request handlers
 
 handle_db_request(Req, 'GET', {_DbName, Db, ["_all_docs"]}) ->
-    send_all_docs(Req, Db);
+    #view_query_args{
+        start_key = StartKey,
+        start_docid = StartDocId,
+        count = Count,
+        skip = SkipCount,
+        direction = Dir
+    } = QueryArgs = parse_view_query(Req),
+    {ok, Info} = couch_db:get_db_info(Db),
+    TotalRowCount = proplists:get_value(doc_count, Info),
+
+    StartId = if is_list(StartKey) -> StartKey;
+    true -> StartDocId
+    end,
+
+    FoldlFun = make_view_fold_fun(Req, QueryArgs),
+    AdapterFun = fun(#full_doc_info{id=Id}=FullDocInfo, Offset, Acc) ->
+        case couch_doc:to_doc_info(FullDocInfo) of
+        #doc_info{deleted=false, rev=Rev} ->
+            FoldlFun(Id, Id, {obj, [{rev, Rev}]}, Offset, TotalRowCount, Acc);
+        #doc_info{deleted=true} ->
+            {ok, Acc}
+        end
+    end,
+    {ok, FoldResult} = couch_db:enum_docs(Db, StartId, Dir, AdapterFun,
+            {Count, SkipCount, undefined, []}),
+    finish_view_fold(Req, {ok, TotalRowCount, FoldResult});
+
 handle_db_request(Req, _Method, {_DbName, _Db, ["_all_docs"]}) ->
     send_error(Req, {method_not_allowed, "GET,HEAD"});
 
 handle_db_request(Req, 'GET', {DbName, Db, ["_all_docs_by_update_seq"]}) ->
     send_error(Req, not_implemented); % TODO
 
-handle_db_request(Req, 'GET', {_DbName, Db, ["_view", DocId, ViewName]}) ->
-    send_view(Req, Db, DocId, ViewName);
+handle_db_request(Req, 'GET', {DbName, _Db, ["_view", DocId, ViewName]}) ->
+    #view_query_args{
+        start_key = StartKey,
+        count = Count,
+        skip = SkipCount,
+        direction = Dir,
+        start_docid = StartDocId
+    } = QueryArgs = parse_view_query(Req),
+    View = {DbName, DocId, ViewName},
+    Start = {StartKey, StartDocId},
+    FoldlFun = make_view_fold_fun(Req, QueryArgs),
+    FoldAccInit = {Count, SkipCount, undefined, []},
+    FoldResult = couch_view:fold(View, Start, Dir, FoldlFun, FoldAccInit),
+    finish_view_fold(Req, FoldResult);
+
 handle_db_request(Req, _Method, {_DbName, _Db, ["_view", _DocId, _ViewName]}) ->
     send_error(Req, method_not_allowed, "GET,HEAD");
 
@@ -216,26 +272,8 @@
         {missing_revs, {obj, JsonResults}}
     ]});
 
-handle_db_request(Req, 'POST', {_DbName, Db, ["_temp_view"]}) ->
-    exec_temp_view(Req, Db);
-handle_db_request(Req, _Method, {_DbName, _Db, ["_temp_view"]}) ->
-    send_error(Req, {method_not_allowed, "POST"});
-
--record(query_args, {
-    start_key = nil,
-    end_key = <<>>,
-    count = 10000000000, % a huge huge default number. Picked so we don't have
-                         % to do different logic for when there is no count
-                         % limit
-    update = true,
-    direction = fwd,
-    start_docid = nil,
-    end_docid = <<>>,
-    skip = 0
-}).
-
-exec_temp_view(Req, Db) ->
-    #query_args{
+handle_db_request(Req, 'POST', {DbName, _Db, ["_temp_view"]}) ->
+    #view_query_args{
         start_key = StartKey,
         count = Count,
         skip = SkipCount,
@@ -244,75 +282,109 @@
     } = QueryArgs = parse_view_query(Req),
 
     ContentType = case Req:get_primary_header_value("content-type") of
-    undefined ->
-        "text/javascript";
-    Else ->
-        Else
+        undefined ->
+            "text/javascript";
+        Else ->
+            Else
     end,
 
-    ViewQuery = ContentType ++ "|" ++ Req:recv_body(),
-    case couch_db:update_temp_view_group_sync(Db, ViewQuery) of
-    ok -> ok;
-    Error -> send_error(Req, Error)
-    end,
+    View = {temp, DbName, ContentType, Req:recv_body()},
+    Start = {StartKey, StartDocId},
     FoldlFun = make_view_fold_fun(Req, QueryArgs),
-    FoldResult = couch_db:fold_temp_view(Db, ViewQuery, {StartKey, StartDocId},
-        Dir, FoldlFun, {Count, SkipCount, undefined, []}),
-    finish_view_fold(Req, FoldResult).
+    FoldAccInit = {Count, SkipCount, undefined, []},
+    FoldResult = couch_view:fold(View, Start, Dir, FoldlFun, FoldAccInit),
+    finish_view_fold(Req, FoldResult);
 
-send_all_docs(Req, Db) ->
-    #query_args{
-        start_key = StartKey,
-        start_docid = StartDocId,
-        count = Count,
-        skip = SkipCount,
-        direction = Dir
-    } = QueryArgs = parse_view_query(Req),
-    {ok, Info} = couch_db:get_info(Db),
-    TotalRowCount = proplists:get_value(doc_count, Info),
+handle_db_request(Req, _Method, {_DbName, _Db, ["_temp_view"]}) ->
+    send_error(Req, {method_not_allowed, "POST"});
 
-    StartId = if is_list(StartKey) -> StartKey;
-    true -> StartDocId
-    end,
+% Document request handlers
 
-    FoldlFun = make_view_fold_fun(Req, QueryArgs),
-    AdapterFun =
-    fun(#doc_info{deleted=true}, _Offset, Acc) ->
-        {ok, Acc}; % skip
-    (#doc_info{id=Id, rev=Rev}, Offset, Acc) ->
-        FoldlFun(Id, Id, {obj, [{rev, Rev}]}, Offset, TotalRowCount, Acc)
-    end,
-    RawFoldResult = couch_db:enum_docs(Db, StartId, Dir, AdapterFun,
-            {Count, SkipCount, undefined, []}),
-    case RawFoldResult of
-    {ok, FoldResult} ->
-        finish_view_fold(Req, {ok, TotalRowCount, FoldResult});
-    Else ->
-        finish_view_fold(Req, Else)
-    end.
+handle_db_request(Req, Method, {DbName, Db, Resource}) ->
+    handle_doc_request(Req, Method, DbName, Db, Resource).
 
-send_view(Req, Db, DocId, ViewName) ->
-    #query_args{
-        start_key = StartKey,
-        count = Count,
-        skip = SkipCount,
-        update = Update,
-        direction = Dir,
-        start_docid = StartDocId
-    } = QueryArgs = parse_view_query(Req),
-    case Update of
-    true ->
-        case couch_db:update_view_group_sync(Db, DocId) of
-        ok ->       ok;
-        Error ->    send_error(Req, Error)
+handle_doc_request(Req, 'DELETE', _DbName, Db, [DocId]) ->
+    % TODO: Etag handling
+    RevToDelete = proplists:get_value("rev", Req:parse_qs()),
+    {ok, NewRev} = couch_db:delete_doc(Db, DocId, [RevToDelete]),
+    send_json(Req, 202, [
+        {"id", DocId},
+        {"rev", NewRev}
+    ]);
+
+handle_doc_request(Req, 'GET', _DbName, Db, [DocId]) ->
+    #doc_query_args{
+        rev = Rev,
+        open_revs = Revs,
+        options = Options
+    } = parse_doc_query(Req),
+    case Revs of
+    [] ->
+        case Rev of
+        "" ->
+            % open most recent rev
+            case couch_db:open_doc(Db, DocId, Options) of
+            {ok, #doc{revs=[DocRev|_]}=Doc} ->
+                Etag = Req:get_header_value("if-none-match"),
+                if Options == [] andalso Etag == DocRev ->
+                    Req:respond({304, [{"etag", DocRev}], ""});
+                true ->
+                    JsonDoc = couch_doc:to_json_obj(Doc, Options),
+                    send_json(Req, 200, JsonDoc)
+                end;
+            Error ->
+                send_error(Req, Error)
+            end;
+        _ ->
+            % open a specific rev (deletions come back as stubs)
+            case couch_db:open_doc_revs(Db, DocId, [Rev], Options) of
+            {ok, [{ok, Doc}]} ->
+                send_json(Req, 200, [{"etag", Rev}],
+                                           couch_doc:to_json_obj(Doc, Options));
+            {ok, [Else]} ->
+                send_error(Req, Else)
+            end
         end;
-    false ->
-        ok
-    end,
-    FoldlFun = make_view_fold_fun(Req, QueryArgs),
-    FoldResult = couch_db:fold_view(Db, DocId, ViewName, {StartKey, StartDocId},
-        Dir, FoldlFun, {Count, SkipCount, undefined, []}),
-    finish_view_fold(Req, FoldResult).
+    _ ->
+        {ok, Results} = couch_db:open_doc_revs(Db, DocId, Revs, Options),
+        Resp = start_json_response(Req, 200),
+        Resp:write_chunk("["),
+        % We loop through the docs. The first time through the separator
+        % is whitespace, then a comma on subsequent iterations.
+        lists:foldl(
+            fun(Result, AccSeparator) ->
+                case Result of
+                {ok, Doc} ->
+                    JsonDoc = couch_doc:to_json_obj(Doc, Options),
+                    Json = lists:flatten(cjson:encode({obj, [{ok, JsonDoc}]})),
+                    Resp:write_chunk(AccSeparator ++ Json);
+                {{not_found, missing}, RevId} ->
+                    Json = {obj, [{"missing", RevId}]},
+                    Json = lists:flatten(cjson:encode(Json)),
+                    Resp:write_chunk(AccSeparator ++ Json)
+                end,
+                "," % AccSeparator now has a comma
+            end,
+            "", Results),
+        Resp:write_chunk("]"),
+        end_json_response(Resp)
+    end;
+
+handle_doc_request(Req, 'PUT', _DbName, Db, [DocId]) ->
+    % TODO: Etag handling
+    Json = cjson:decode(Req:recv_body()),
+    Doc = couch_doc:from_json_obj(Json),
+    {ok, NewRev} = couch_db:update_doc(Db, Doc#doc{id=DocId, revs=[]}, []),
+    send_json(Req, 201, {obj, [
+        {ok, true},
+        {id, DocId},
+        {rev, NewRev}
+    ]});
+
+handle_doc_request(Req, _Method, _DbName, _Db, [_DocId]) ->
+    send_error(Req, {method_not_allowed, "DELETE,GET,HEAD,PUT"}).
+
+% View request handling internals
 
 reverse_key_default(nil) -> <<>>;
 reverse_key_default(<<>>) -> nil;
@@ -326,52 +398,52 @@
             Args;
         {"key", Value} ->
             JsonKey = cjson:decode(Value),
-            Args#query_args{start_key=JsonKey,end_key=JsonKey};
+            Args#view_query_args{start_key=JsonKey,end_key=JsonKey};
         {"startkey_docid", DocId} ->
-            Args#query_args{start_docid=DocId};
+            Args#view_query_args{start_docid=DocId};
         {"startkey", Value} ->
-            Args#query_args{start_key=cjson:decode(Value)};
+            Args#view_query_args{start_key=cjson:decode(Value)};
         {"endkey", Value} ->
-            Args#query_args{end_key=cjson:decode(Value)};
+            Args#view_query_args{end_key=cjson:decode(Value)};
         {"count", Value} ->
             case (catch list_to_integer(Value)) of
             Count when is_integer(Count) ->
                 if Count < 0 ->
-                    Args#query_args {
+                    Args#view_query_args {
                         direction =
-                        if Args#query_args.direction == rev -> fwd;
+                        if Args#view_query_args.direction == rev -> fwd;
                         true -> rev
                         end,
                         count=Count,
-                        start_key = reverse_key_default(Args#query_args.start_key),
-                        start_docid = reverse_key_default(Args#query_args.start_docid),
-                        end_key = reverse_key_default(Args#query_args.end_key),
-                        end_docid =  reverse_key_default(Args#query_args.end_docid)};
+                        start_key = reverse_key_default(Args#view_query_args.start_key),
+                        start_docid = reverse_key_default(Args#view_query_args.start_docid),
+                        end_key = reverse_key_default(Args#view_query_args.end_key),
+                        end_docid =  reverse_key_default(Args#view_query_args.end_docid)};
                 true ->
-                    Args#query_args{count=Count}
+                    Args#view_query_args{count=Count}
                 end;
             _Error ->
                 Msg = io_lib:format("Bad URL query value, number expected: count=~s", [Value]),
                 throw({query_parse_error, Msg})
             end;
         {"update", "false"} ->
-            Args#query_args{update=false};
+            Args#view_query_args{update=false};
         {"descending", "true"} ->
-            case Args#query_args.direction of
+            case Args#view_query_args.direction of
             fwd ->
-                Args#query_args {
+                Args#view_query_args {
                     direction = rev,
-                    start_key = reverse_key_default(Args#query_args.start_key),
-                    start_docid = reverse_key_default(Args#query_args.start_docid),
-                    end_key = reverse_key_default(Args#query_args.end_key),
-                    end_docid =  reverse_key_default(Args#query_args.end_docid)};
+                    start_key = reverse_key_default(Args#view_query_args.start_key),
+                    start_docid = reverse_key_default(Args#view_query_args.start_docid),
+                    end_key = reverse_key_default(Args#view_query_args.end_key),
+                    end_docid =  reverse_key_default(Args#view_query_args.end_docid)};
             _ ->
                 Args %already reversed
             end;
         {"skip", Value} ->
             case (catch list_to_integer(Value)) of
             Count when is_integer(Count) ->
-                Args#query_args{skip=Count};
+                Args#view_query_args{skip=Count};
             _Error ->
                 Msg = lists:flatten(io_lib:format(
                 "Bad URL query value, number expected: skip=~s", [Value])),
@@ -382,10 +454,10 @@
                 "Bad URL query key:~s", [Key])),
             throw({query_parse_error, Msg})
         end
-    end, #query_args{}, QueryList).
+    end, #view_query_args{}, QueryList).
 
 make_view_fold_fun(Req, QueryArgs) ->
-    #query_args{
+    #view_query_args{
         end_key = EndKey,
         end_docid = EndDocId,
         direction = Dir,
@@ -395,11 +467,11 @@
     PassedEndFun = case Dir of
     fwd ->
         fun(ViewKey, ViewId) ->
-            couch_view_group:less_json({EndKey, EndDocId}, {ViewKey, ViewId})
+            couch_view:less_json({EndKey, EndDocId}, {ViewKey, ViewId})
         end;
     rev->
         fun(ViewKey, ViewId) ->
-            couch_view_group:less_json({ViewKey, ViewId}, {EndKey, EndDocId})
+            couch_view:less_json({ViewKey, ViewId}, {EndKey, EndDocId})
         end
     end,
 
@@ -407,11 +479,9 @@
                       {AccCount, AccSkip, Resp, AccRevRows}) ->
         PassedEnd = PassedEndFun(Key, Id),
         case {PassedEnd, AccCount, AccSkip, Resp} of
-        {true, _, _, _} ->
-            % The stop key has been passed, stop looping.
+        {true, _, _, _} -> % The stop key has been passed, stop looping.
             {stop, {AccCount, AccSkip, Resp, AccRevRows}};
-        {_, 0, _, _} ->
-            % we've done "count" rows, stop foldling
+        {_, 0, _, _} -> % we've done "count" rows, stop foldling
             {stop, {0, 0, Resp, AccRevRows}};
         {_, _, AccSkip, _} when AccSkip > 0 ->
             {ok, {AccCount, AccSkip - 1, Resp, AccRevRows}};
@@ -465,7 +535,7 @@
     {ok, TotalRows, {_, _, undefined, _}} ->
         % nothing found in the view, nothing has been returned
         % send empty view
-        send_json(Req, 201, {obj, [
+        send_json(Req, 200, {obj, [
             {total_rows, TotalRows},
             {rows, []}
         ]});
@@ -477,109 +547,7 @@
         throw(Error)
     end.
 
-% Document request handlers
-
-handle_db_request(Req, Method, {DbName, Db, Resource}) ->
-    handle_doc_request(Req, Method, DbName, Db, Resource).
-
-handle_doc_request(Req, 'DELETE', _DbName, Db, [DocId]) ->
-    RevToDelete = proplists:get_value("rev", Req:parse_qs()),
-    case couch_db:delete_doc(Db, DocId, [RevToDelete]) of
-    {ok, [{ok, NewRev}]} ->
-        send_json(Req, 202, {obj, [
-            {ok, true},
-            {id, DocId},
-            {rev, NewRev}
-        ]});
-    {ok, [Error]} ->
-        send_error(Req, Error);
-    Error ->
-        send_error(Req, Error)
-    end;
-
-handle_doc_request(Req, 'GET', _DbName, Db, [DocId]) ->
-    send_doc(Req, Db, DocId);
-
-handle_doc_request(Req, 'PUT', _DbName, Db, [DocId]) ->
-    Json = cjson:decode(Req:recv_body()),
-    Doc = couch_doc:from_json_obj(Json),
-    case couch_db:save_doc(Db, Doc, []) of
-    {ok, NewRev} ->
-        send_json(Req, 201, {obj, [
-            {ok, true},
-            {id, DocId},
-            {rev, NewRev}
-        ]});
-    Error ->
-        send_error(Req, Error)
-    end;
-
-handle_doc_request(Req, _Method, _DbName, _Db, [_DocId]) ->
-    send_error(Req, {method_not_allowed, "DELETE,GET,HEAD,PUT"}).
-
--record(doc_query_args, {
-    options = [],
-    rev = "",
-    open_revs = ""
-}).
-
-send_doc(Req, Db, DocId) ->
-    #doc_query_args{
-        rev = Rev,
-        open_revs = Revs,
-        options = Options
-    } = parse_doc_query(Req),
-    case Revs of
-    [] ->
-        case Rev of
-        "" ->
-            % open most recent rev
-            case couch_db:open_doc(Db, DocId, Options) of
-            {ok, #doc{revs=[DocRev|_]}=Doc} ->
-                Etag = Req:get_header_value("if-none-match"),
-                if Options == [] andalso Etag == DocRev ->
-                    Req:respond({304, [{"etag", DocRev}], ""});
-                true ->
-                    JsonDoc = couch_doc:to_json_obj(Doc, Options),
-                    send_json(Req, 200, JsonDoc)
-                end;
-            Error ->
-                send_error(Req, Error)
-            end;
-        _ ->
-            % open a specific rev (deletions come back as stubs)
-            case couch_db:open_doc_revs(Db, DocId, [Rev], Options) of
-            {ok, [{ok, Doc}]} ->
-                send_json(Req, 200, [{"etag", Rev}],
-                                           couch_doc:to_json_obj(Doc, Options));
-            {ok, [Else]} ->
-                send_error(Req, Else)
-            end
-        end;
-    _ ->
-        {ok, Results} = couch_db:open_doc_revs(Db, DocId, Revs, Options),
-        Resp = start_json_response(Req, 200),
-        Resp:write_chunk("["),
-        % We loop through the docs. The first time through the separator
-        % is whitespace, then a comma on subsequent iterations.
-        lists:foldl(
-            fun(Result, AccSeparator) ->
-                case Result of
-                {ok, Doc} ->
-                    JsonDoc = couch_doc:to_json_obj(Doc, Options),
-                    Json = lists:flatten(cjson:encode({obj, [{ok, JsonDoc}]})),
-                    Resp:write_chunk(AccSeparator ++ Json);
-                {{not_found, missing}, RevId} ->
-                    Json = {obj, [{"missing", RevId}]},
-                    Json = lists:flatten(cjson:encode(Json)),
-                    Resp:write_chunk(AccSeparator ++ Json)
-                end,
-                "," % AccSeparator now has a comma
-            end,
-            "", Results),
-        Resp:write_chunk("]"),
-        end_json_response(Resp)
-    end.
+% Document request handling internals
 
 parse_doc_query(Req) ->
     lists:foldl(fun({Key,Value}, Args) ->



Mime
View raw message