summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--etc/couchdb/default.ini.tpl.in2
-rw-r--r--share/server/main.js4
-rw-r--r--share/www/script/couch_tests.js212
-rw-r--r--src/couchdb/Makefile.am4
-rw-r--r--src/couchdb/couch_httpd_show.erl (renamed from src/couchdb/couch_httpd_form.erl)50
-rw-r--r--src/couchdb/couch_query_servers.erl7
6 files changed, 147 insertions, 132 deletions
diff --git a/etc/couchdb/default.ini.tpl.in b/etc/couchdb/default.ini.tpl.in
index 582017fd..e3600a9a 100644
--- a/etc/couchdb/default.ini.tpl.in
+++ b/etc/couchdb/default.ini.tpl.in
@@ -47,7 +47,7 @@ _restart = {couch_httpd_misc_handlers, handle_restart_req}
[httpd_db_handlers]
_view = {couch_httpd_view, handle_view_req}
_slow_view = {couch_httpd_view, handle_slow_view_req}
-_form = {couch_httpd_form, handle_form_req}
+_show = {couch_httpd_show, handle_doc_show_req}
; The external module takes an optional argument allowing you to narrow it to a
; single script. Otherwise the script name is inferred from the first path section
diff --git a/share/server/main.js b/share/server/main.js
index 0302721e..38ca326c 100644
--- a/share/server/main.js
+++ b/share/server/main.js
@@ -335,7 +335,7 @@ while (cmd = eval(readline())) {
print(toJSON(error));
}
break;
- case "form":
+ case "show_doc":
var funSrc = cmd[1];
var doc = cmd[2];
var req = cmd[3];
@@ -346,7 +346,7 @@ while (cmd = eval(readline())) {
} catch (error) {
// Available error fields:
// message, fileName, lineNumber, stack, name
- log("form function raised error: "+error.toString());
+ log("doc show function raised error: "+error.toString());
log("stacktrace: "+error.stack);
try {
print(toJSON(error));
diff --git a/share/www/script/couch_tests.js b/share/www/script/couch_tests.js
index 3263c532..81609f19 100644
--- a/share/www/script/couch_tests.js
+++ b/share/www/script/couch_tests.js
@@ -558,6 +558,11 @@ var tests = {
for(var i=0; i<numDocsToCreate; i++) {
T(results.rows[numDocsToCreate-1-i].key==i);
}
+
+ // Check _all_docs with descending=true again (now that there are many docs)
+ // this fails, see COUCHDB-109
+ // var desc = db.allDocs({descending:true});
+ // T(desc.total_rows == desc.rows.length);
},
reduce: function(debug) {
@@ -2181,7 +2186,7 @@ var tests = {
T(xhr.status == 200)
},
- forms: function(debug) {
+ show_documents: function(debug) {
var db = new CouchDB("test_suite_db");
db.deleteDb();
db.createDb();
@@ -2195,91 +2200,94 @@ var tests = {
var designDoc = {
_id:"_design/template",
language: "javascript",
- forms: {
- "hello" : stringFun(function() {
- return {
- body : "Hello World"
- };
- }),
- "just-name" : stringFun(function(doc, req) {
- return {
- body : "Just " + doc.name
- };
- }),
- "req-info" : stringFun(function(doc, req) {
- return {
- json : req
- }
- }),
- "xml-type" : stringFun(function(doc, req) {
- return {
- "headers" : {
- "Content-Type" : "application/xml"
- },
- "body" : new XML('<xml><node foo="bar"/></xml>')
- }
- }),
- "no-set-etag" : stringFun(function(doc, req) {
- return {
- headers : {
- "Etag" : "skipped"
- },
- "body" : "something"
- }
- }),
- "accept-switch" : stringFun(function(doc, req) {
- if (req.headers["Accept"].match(/image/)) {
+ show: {
+ docs: {
+ "hello" : stringFun(function() {
return {
- // a 16x16 px version of the CouchDB logo
- "base64" : ["iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAsV",
- "BMVEUAAAD////////////////////////5ur3rEBn////////////////wDBL/",
- "AADuBAe9EB3IEBz/7+//X1/qBQn2AgP/f3/ilpzsDxfpChDtDhXeCA76AQH/v7",
- "/84eLyWV/uc3bJPEf/Dw/uw8bRWmP1h4zxSlD6YGHuQ0f6g4XyQkXvCA36MDH6",
- "wMH/z8/yAwX64ODeh47BHiv/Ly/20dLQLTj98PDXWmP/Pz//39/wGyJ7Iy9JAA",
- "AADHRSTlMAbw8vf08/bz+Pv19jK/W3AAAAg0lEQVR4Xp3LRQ4DQRBD0QqTm4Y5",
- "zMxw/4OleiJlHeUtv2X6RbNO1Uqj9g0RMCuQO0vBIg4vMFeOpCWIWmDOw82fZx",
- "vaND1c8OG4vrdOqD8YwgpDYDxRgkSm5rwu0nQVBJuMg++pLXZyr5jnc1BaH4GT",
- "LvEliY253nA3pVhQqdPt0f/erJkMGMB8xucAAAAASUVORK5CYII="].join(''),
- headers : {
- "Content-Type" : "image/png",
- "Vary" : "Accept" // we set this for proxy caches
- }
+ body : "Hello World"
};
- } else {
+ }),
+ "just-name" : stringFun(function(doc, req) {
return {
- "body" : "accepting text requests",
- headers : {
- "Content-Type" : "text/html",
- "Vary" : "Accept"
- }
+ body : "Just " + doc.name
};
- }
- }),
- "respondWith" : stringFun(function(doc, req) {
- registerType("foo", "application/foo","application/x-foo");
- return respondWith(req, {
- html : function() {
- return {
- body:"Ha ha, you said \"" + doc.word + "\"."
- };
- },
- xml : function() {
- var xml = new XML('<xml><node/></xml>');
- // becase Safari can't stand to see that dastardly
- // E4X outside of a string.
- this.eval('xml.node.@foo = doc.word');
+ }),
+ "req-info" : stringFun(function(doc, req) {
+ return {
+ json : req
+ }
+ }),
+ "xml-type" : stringFun(function(doc, req) {
+ return {
+ "headers" : {
+ "Content-Type" : "application/xml"
+ },
+ "body" : new XML('<xml><node foo="bar"/></xml>')
+ }
+ }),
+ "no-set-etag" : stringFun(function(doc, req) {
+ return {
+ headers : {
+ "Etag" : "skipped"
+ },
+ "body" : "something"
+ }
+ }),
+ "accept-switch" : stringFun(function(doc, req) {
+ if (req.headers["Accept"].match(/image/)) {
return {
- body: xml
+ // a 16x16 px version of the CouchDB logo
+ "base64" :
+["iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAsV",
+"BMVEUAAAD////////////////////////5ur3rEBn////////////////wDBL/",
+"AADuBAe9EB3IEBz/7+//X1/qBQn2AgP/f3/ilpzsDxfpChDtDhXeCA76AQH/v7",
+"/84eLyWV/uc3bJPEf/Dw/uw8bRWmP1h4zxSlD6YGHuQ0f6g4XyQkXvCA36MDH6",
+"wMH/z8/yAwX64ODeh47BHiv/Ly/20dLQLTj98PDXWmP/Pz//39/wGyJ7Iy9JAA",
+"AADHRSTlMAbw8vf08/bz+Pv19jK/W3AAAAg0lEQVR4Xp3LRQ4DQRBD0QqTm4Y5",
+"zMxw/4OleiJlHeUtv2X6RbNO1Uqj9g0RMCuQO0vBIg4vMFeOpCWIWmDOw82fZx",
+"vaND1c8OG4vrdOqD8YwgpDYDxRgkSm5rwu0nQVBJuMg++pLXZyr5jnc1BaH4GT",
+"LvEliY253nA3pVhQqdPt0f/erJkMGMB8xucAAAAASUVORK5CYII="].join(''),
+ headers : {
+ "Content-Type" : "image/png",
+ "Vary" : "Accept" // we set this for proxy caches
+ }
};
- },
- foo : function() {
+ } else {
return {
- body: "foofoo"
+ "body" : "accepting text requests",
+ headers : {
+ "Content-Type" : "text/html",
+ "Vary" : "Accept"
+ }
};
- },
- fallback : "html"
- });
- })
+ }
+ }),
+ "respondWith" : stringFun(function(doc, req) {
+ registerType("foo", "application/foo","application/x-foo");
+ return respondWith(req, {
+ html : function() {
+ return {
+ body:"Ha ha, you said \"" + doc.word + "\"."
+ };
+ },
+ xml : function() {
+ var xml = new XML('<xml><node/></xml>');
+ // becase Safari can't stand to see that dastardly
+ // E4X outside of a string.
+ this.eval('xml.node.@foo = doc.word');
+ return {
+ body: xml
+ };
+ },
+ foo : function() {
+ return {
+ body: "foofoo"
+ };
+ },
+ fallback : "html"
+ });
+ })
+ }
}
};
T(db.save(designDoc).ok);
@@ -2289,35 +2297,35 @@ var tests = {
T(resp.ok);
var docid = resp.id;
- // form error
- var xhr = CouchDB.request("GET", "/test_suite_db/_form/");
+ // show error
+ var xhr = CouchDB.request("GET", "/test_suite_db/_show/");
T(xhr.status == 404);
T(JSON.parse(xhr.responseText).reason == "Invalid path.");
// hello template world
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/hello/"+docid);
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/hello/"+docid);
T(xhr.responseText == "Hello World");
- // form with doc
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/just-name/"+docid);
+ // show with doc
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid);
T(xhr.responseText == "Just Rusty");
- // form with missing doc
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/just-name/missingdoc");
+ // show with missing doc
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/missingdoc");
T(xhr.status == 404);
var resp = JSON.parse(xhr.responseText);
T(resp.error == "not_found");
T(resp.reason == "missing");
// missing design doc
- xhr = CouchDB.request("GET", "/test_suite_db/_form/missingdoc/just-name/"+docid);
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/missingdoc/just-name/"+docid);
T(xhr.status == 404);
var resp = JSON.parse(xhr.responseText);
T(resp.error == "not_found");
T(resp.reason == "missing_design_doc");
// query parameters
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/req-info/"+docid+"?foo=bar", {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/req-info/"+docid+"?foo=bar", {
headers: {
"Accept": "text/html;text/plain;*/*",
"X-Foo" : "bar"
@@ -2331,21 +2339,21 @@ var tests = {
T(equals(resp.info.db_name, "test_suite_db"));
// returning a content-type
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/xml-type/"+docid);
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/xml-type/"+docid);
T("application/xml" == xhr.getResponseHeader("Content-Type"));
T("Accept" == xhr.getResponseHeader("Vary"));
// accept header switching
// different mime has different etag
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/accept-switch/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/accept-switch/"+docid, {
headers: {"Accept": "text/html;text/plain;*/*"}
});
T("text/html" == xhr.getResponseHeader("Content-Type"));
T("Accept" == xhr.getResponseHeader("Vary"));
var etag = xhr.getResponseHeader("etag");
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/accept-switch/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/accept-switch/"+docid, {
headers: {"Accept": "image/png;*/*"}
});
T(xhr.responseText.match(/PNG/))
@@ -2354,12 +2362,12 @@ var tests = {
T(etag2 != etag);
// proper etags
- // form with doc
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/just-name/"+docid);
+ // show with doc
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid);
// extract the ETag header values
etag = xhr.getResponseHeader("etag");
// get again with etag in request
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/just-name/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
headers: {"if-none-match": etag}
});
// should be 304
@@ -2370,7 +2378,7 @@ var tests = {
resp = db.save(doc);
T(resp.ok);
// req with same etag
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/just-name/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
headers: {"if-none-match": etag}
});
// status is 200
@@ -2378,7 +2386,7 @@ var tests = {
// get new etag and request again
etag = xhr.getResponseHeader("etag");
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/just-name/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
headers: {"if-none-match": etag}
});
// should be 304
@@ -2388,21 +2396,21 @@ var tests = {
designDoc.isChanged = true;
T(db.save(designDoc).ok);
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/just-name/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
headers: {"if-none-match": etag}
});
// should be 304
T(xhr.status == 304);
// update design doc function
- designDoc.forms["just-name"] = (function(doc, req) {
+ designDoc.show.docs["just-name"] = (function(doc, req) {
return {
body : "Just old " + doc.name
};
}).toString();
T(db.save(designDoc).ok);
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/just-name/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, {
headers: {"if-none-match": etag}
});
// status is 200
@@ -2410,13 +2418,13 @@ var tests = {
// JS can't set etag
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/no-set-etag/"+docid);
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/no-set-etag/"+docid);
// extract the ETag header values
etag = xhr.getResponseHeader("etag");
T(etag != "skipped")
// test the respondWith mime matcher
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/respondWith/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, {
headers: {
"Accept": 'text/html,application/atom+xml; q=0.9'
}
@@ -2425,7 +2433,7 @@ var tests = {
T(xhr.responseText == "Ha ha, you said \"plankton\".");
// now with xml
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/respondWith/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, {
headers: {
"Accept": 'application/xml'
}
@@ -2435,7 +2443,7 @@ var tests = {
T(xhr.responseText.match(/plankton/));
// registering types works
- xhr = CouchDB.request("GET", "/test_suite_db/_form/template/respondWith/"+docid, {
+ xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, {
headers: {
"Accept": "application/x-foo"
}
diff --git a/src/couchdb/Makefile.am b/src/couchdb/Makefile.am
index 7fb2ec68..8e280c70 100644
--- a/src/couchdb/Makefile.am
+++ b/src/couchdb/Makefile.am
@@ -55,7 +55,7 @@ source_files = \
couch_httpd.erl \
couch_httpd_db.erl \
couch_httpd_external.erl \
- couch_httpd_form.erl \
+ couch_httpd_show.erl \
couch_httpd_view.erl \
couch_httpd_misc_handlers.erl \
couch_key_tree.erl \
@@ -91,7 +91,7 @@ compiled_files = \
couch_httpd.beam \
couch_httpd_db.beam \
couch_httpd_external.beam \
- couch_httpd_form.beam \
+ couch_httpd_show.beam \
couch_httpd_view.beam \
couch_httpd_misc_handlers.beam \
couch_key_tree.beam \
diff --git a/src/couchdb/couch_httpd_form.erl b/src/couchdb/couch_httpd_show.erl
index f4fa2c18..d4b4997b 100644
--- a/src/couchdb/couch_httpd_form.erl
+++ b/src/couchdb/couch_httpd_show.erl
@@ -10,9 +10,9 @@
% License for the specific language governing permissions and limitations under
% the License.
--module(couch_httpd_form).
+-module(couch_httpd_show).
--export([handle_form_req/2]).
+-export([handle_doc_show_req/2]).
-include("couch_db.hrl").
@@ -22,7 +22,7 @@
start_json_response/2,send_chunk/2,end_json_response/1,
start_chunked_response/3, send_error/4]).
-handle_form_req(#httpd{method='GET',path_parts=[_, _, DesignName, FormName, Docid]}=Req, Db) ->
+handle_doc_show_req(#httpd{method='GET',path_parts=[_, _, DesignName, ShowName, Docid]}=Req, Db) ->
DesignId = <<"_design/", DesignName/binary>>,
% Anyway we can dry up this error handling?
case (catch couch_httpd_db:couch_doc_open(Db, DesignId, [], [])) of
@@ -33,40 +33,46 @@ handle_form_req(#httpd{method='GET',path_parts=[_, _, DesignName, FormName, Doci
DesignDoc ->
#doc{body={Props}} = DesignDoc,
Lang = proplists:get_value(<<"language">>, Props, <<"javascript">>),
- case proplists:get_value(<<"forms">>, Props, nil) of
- {Forms} ->
- case proplists:get_value(FormName, Forms, nil) of
+ case proplists:get_value(<<"show">>, Props, nil) of
+ {DocAndViews} ->
+ case proplists:get_value(<<"docs">>, DocAndViews, nil) of
nil ->
- throw({not_found, missing_form});
- FormSrc ->
- case (catch couch_httpd_db:couch_doc_open(Db, Docid, [], [])) of
- {not_found, missing} ->
- throw({not_found, missing});
- {not_found, deleted} ->
- throw({not_found, deleted});
- Doc ->
- % ok we have everythign we need. let's make it happen.
- send_form_response(Lang, FormSrc, Doc, Req, Db)
+ throw({not_found, missing_show_docs});
+ {DocShows} ->
+ case proplists:get_value(ShowName, DocShows, nil) of
+ nil ->
+ throw({not_found, missing_show_doc_function});
+ ShowSrc ->
+ case (catch couch_httpd_db:couch_doc_open(
+ Db, Docid, [], [])) of
+ {not_found, missing} ->
+ throw({not_found, missing});
+ {not_found, deleted} ->
+ throw({not_found, deleted});
+ Doc ->
+ % ok we have everythign we need. let's make it happen.
+ send_doc_show_response(Lang, ShowSrc, Doc, Req, Db)
+ end
end
end;
nil ->
- throw({not_found, missing_form})
+ throw({not_found, missing_show})
end
end;
-handle_form_req(#httpd{method='GET'}=Req, _Db) ->
+handle_doc_show_req(#httpd{method='GET'}=Req, _Db) ->
send_error(Req, 404, <<"form_error">>, <<"Invalid path.">>);
-handle_form_req(Req, _Db) ->
+handle_doc_show_req(Req, _Db) ->
send_method_not_allowed(Req, "GET,HEAD").
-send_form_response(Lang, FormSrc, #doc{revs=[DocRev|_]}=Doc, #httpd{mochi_req=MReq}=Req, Db) ->
+send_doc_show_response(Lang, ShowSrc, #doc{revs=[DocRev|_]}=Doc, #httpd{mochi_req=MReq}=Req, Db) ->
% make a term with etag-effecting Req components, but not always changing ones.
Headers = MReq:get(headers),
Hlist = mochiweb_headers:to_list(Headers),
Accept = proplists:get_value('Accept', Hlist),
- <<SigInt:128/integer>> = erlang:md5(term_to_binary({Lang, FormSrc, DocRev, Accept})),
+ <<SigInt:128/integer>> = erlang:md5(term_to_binary({Lang, ShowSrc, DocRev, Accept})),
CurrentEtag = list_to_binary("\"" ++ lists:flatten(io_lib:format("form_~.36B",[SigInt])) ++ "\""),
EtagsToMatch = string:tokens(
couch_httpd:header_value(Req, "If-None-Match", ""), ", "),
@@ -77,7 +83,7 @@ send_form_response(Lang, FormSrc, #doc{revs=[DocRev|_]}=Doc, #httpd{mochi_req=MR
couch_httpd:send_response(Req, 304, [{"Etag", CurrentEtag}], <<>>);
false ->
% Run the external form renderer.
- {JsonResponse} = couch_query_servers:render_doc_form(Lang, FormSrc, Doc, Req, Db),
+ {JsonResponse} = couch_query_servers:render_doc_show(Lang, ShowSrc, Doc, Req, Db),
% Here we embark on the delicate task of replacing or creating the
% headers on the JsonResponse object. We need to control the Etag and
% Vary headers. If the external function controls the Etag, we'd have to
diff --git a/src/couchdb/couch_query_servers.erl b/src/couchdb/couch_query_servers.erl
index c4ed5c8b..8d473381 100644
--- a/src/couchdb/couch_query_servers.erl
+++ b/src/couchdb/couch_query_servers.erl
@@ -17,7 +17,7 @@
-export([init/1, terminate/2, handle_call/3, handle_cast/2, handle_info/2,code_change/3,stop/0]).
-export([start_doc_map/2, map_docs/2, stop_doc_map/1]).
--export([reduce/3, rereduce/3,validate_doc_update/5,render_doc_form/5]).
+-export([reduce/3, rereduce/3,validate_doc_update/5,render_doc_show/5]).
% -export([test/0]).
-include("couch_db.hrl").
@@ -122,11 +122,12 @@ validate_doc_update(Lang, FunSrc, EditDoc, DiskDoc, Ctx) ->
ok = ret_os_process(Lang, Pid)
end.
-render_doc_form(Lang, FormSrc, Doc, Req, Db) ->
+render_doc_show(Lang, ShowSrc, Doc, Req, Db) ->
Pid = get_os_process(Lang),
JsonDoc = couch_doc:to_json_obj(Doc, [revs]),
JsonReq = couch_httpd_external:json_req_obj(Req, Db),
- try couch_os_process:prompt(Pid, [<<"form">>, FormSrc, JsonDoc, JsonReq]) of
+ try couch_os_process:prompt(Pid,
+ [<<"show_doc">>, ShowSrc, JsonDoc, JsonReq]) of
FormResp ->
FormResp
after