From commits-return-1981-apmail-couchdb-commits-archive=couchdb.apache.org@couchdb.apache.org Mon Mar 09 19:53:23 2009 Return-Path: Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: (qmail 35509 invoked from network); 9 Mar 2009 19:53:23 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 9 Mar 2009 19:53:23 -0000 Received: (qmail 81508 invoked by uid 500); 9 Mar 2009 19:53:23 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 81475 invoked by uid 500); 9 Mar 2009 19:53:23 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 81466 invoked by uid 99); 9 Mar 2009 19:53:23 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 09 Mar 2009 12:53:23 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 09 Mar 2009 19:53:17 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id A8DF023888F1; Mon, 9 Mar 2009 19:52:56 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r751813 - in /couchdb/trunk: ./ etc/couchdb/ etc/default/ share/www/script/ share/www/script/test/ src/couchdb/ Date: Mon, 09 Mar 2009 19:52:55 -0000 To: commits@couchdb.apache.org From: jchris@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090309195256.A8DF023888F1@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: jchris Date: Mon Mar 9 19:52:54 2009 New Revision: 751813 URL: http://svn.apache.org/viewvc?rev=751813&view=rev Log: merge design doc resource branch. breaking changes to _view query paths. closes COUCHDB-280 Modified: couchdb/trunk/ (props changed) couchdb/trunk/CHANGES couchdb/trunk/etc/couchdb/default.ini.tpl.in couchdb/trunk/etc/default/couchdb (props changed) couchdb/trunk/share/www/script/couch.js couchdb/trunk/share/www/script/jquery.couch.js couchdb/trunk/share/www/script/test/etags_views.js couchdb/trunk/share/www/script/test/list_views.js couchdb/trunk/share/www/script/test/show_documents.js couchdb/trunk/src/couchdb/couch_db.hrl couchdb/trunk/src/couchdb/couch_httpd.erl couchdb/trunk/src/couchdb/couch_httpd_db.erl couchdb/trunk/src/couchdb/couch_httpd_show.erl couchdb/trunk/src/couchdb/couch_httpd_view.erl Propchange: couchdb/trunk/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Mon Mar 9 19:52:54 2009 @@ -1 +1,2 @@ +/couchdb/branches/design_resources:751716-751803 /couchdb/branches/form:729440-730015 Modified: couchdb/trunk/CHANGES URL: http://svn.apache.org/viewvc/couchdb/trunk/CHANGES?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/CHANGES (original) +++ couchdb/trunk/CHANGES Mon Mar 9 19:52:54 2009 @@ -17,6 +17,13 @@ * Added pagination to the database listing page. * Implemented attachment uploading from the document page. +Design Document Resource Paths: + + * Added httpd_design_handlers config section. + * Moved _view to httpd_design_handlers. + * Added ability to render documents as non-JSON content-types with _show and + _list functions, which are also httpd_design_handlers. + Version 0.8.1-incubating ------------------------ Modified: couchdb/trunk/etc/couchdb/default.ini.tpl.in URL: http://svn.apache.org/viewvc/couchdb/trunk/etc/couchdb/default.ini.tpl.in?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/etc/couchdb/default.ini.tpl.in (original) +++ couchdb/trunk/etc/couchdb/default.ini.tpl.in Mon Mar 9 19:52:54 2009 @@ -52,13 +52,16 @@ _stats = {couch_httpd_stats_handlers, handle_stats_req} [httpd_db_handlers] -_view = {couch_httpd_view, handle_view_req} +_design = {couch_httpd_db, handle_design_req} _temp_view = {couch_httpd_view, handle_temp_view_req} -_show = {couch_httpd_show, handle_doc_show_req} -_list = {couch_httpd_show, handle_view_list_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 ; after _external's own path. ; _mypath = {couch_httpd_external, handle_external_req, <<"mykey">>} ; _external = {couch_httpd_external, handle_external_req} + +[httpd_design_handlers] +_view = {couch_httpd_view, handle_view_req} +_show = {couch_httpd_show, handle_doc_show_req} +_list = {couch_httpd_show, handle_view_list_req} Propchange: couchdb/trunk/etc/default/couchdb ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Mon Mar 9 19:52:54 2009 @@ -1,2 +1,3 @@ +/couchdb/branches/design_resources/etc/default/couchdb:751716-751803 /couchdb/branches/form/etc/default/couchdb:729440-730015 /incubator/couchdb/trunk/etc/default/couchdb:642419-694440 Modified: couchdb/trunk/share/www/script/couch.js URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch.js?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/share/www/script/couch.js [utf-8] (original) +++ couchdb/trunk/share/www/script/couch.js [utf-8] Mon Mar 9 19:52:54 2009 @@ -142,12 +142,13 @@ } this.view = function(viewname, options, keys) { + var viewParts = viewname.split('/'); + var viewPath = this.uri + "_design/" + viewParts[0] + "/_view/" + + viewParts[1] + encodeOptions(options); if(!keys) { - this.last_req = this.request("GET", this.uri + "_view/" + - viewname + encodeOptions(options)); + this.last_req = this.request("GET", viewPath); } else { - this.last_req = this.request("POST", this.uri + "_view/" + - viewname + encodeOptions(options), { + this.last_req = this.request("POST", viewPath, { headers: {"Content-Type": "application/json"}, body: JSON.stringify({keys:keys}) }); Modified: couchdb/trunk/share/www/script/jquery.couch.js URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/jquery.couch.js?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/share/www/script/jquery.couch.js [utf-8] (original) +++ couchdb/trunk/share/www/script/jquery.couch.js [utf-8] Mon Mar 9 19:52:54 2009 @@ -191,9 +191,9 @@ appName = appName.join('/'); index = ddoc.couchapp && ddoc.couchapp.index; if (index) { - appPath = ['', name, index[0], appName, index[1]].join('/'); + appPath = ['', name, ddoc._id, index].join('/'); } else if (ddoc._attachments && ddoc._attachments["index.html"]) { - appPath = ['', name, '_design', appName, "index.html"].join('/'); + appPath = ['', name, ddoc._id, "index.html"].join('/'); } if (appPath) options.eachApp(appName, appPath, ddoc); } @@ -298,8 +298,9 @@ }, view: function(name, options) { options = options || {}; + name = name.split('/'); $.ajax({ - type: "GET", url: this.uri + "_view/" + name + encodeOptions(options), + type: "GET", url: this.uri + "_design/" + name[0] + "/_view/" + name[1] + encodeOptions(options), dataType: "json", complete: function(req) { var resp = $.httpData(req, "json"); Modified: couchdb/trunk/share/www/script/test/etags_views.js URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/etags_views.js?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/share/www/script/test/etags_views.js (original) +++ couchdb/trunk/share/www/script/test/etags_views.js Mon Mar 9 19:52:54 2009 @@ -46,20 +46,20 @@ T(saveResult.ok); // verify get w/Etag on map view - xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/basicView"); + xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView"); T(xhr.status == 200); var etag = xhr.getResponseHeader("etag"); - xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/basicView", { + xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/basicView", { headers: {"if-none-match": etag} }); T(xhr.status == 304); // TODO GET with keys (when that is available) // reduce view - xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/withReduce"); + xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce"); T(xhr.status == 200); var etag = xhr.getResponseHeader("etag"); - xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/withReduce", { + xhr = CouchDB.request("GET", "/test_suite_db/_design/etags/_view/withReduce", { headers: {"if-none-match": etag} }); T(xhr.status == 304); Modified: couchdb/trunk/share/www/script/test/list_views.js URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/list_views.js?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/share/www/script/test/list_views.js (original) +++ couchdb/trunk/share/www/script/test/list_views.js Mon Mar 9 19:52:54 2009 @@ -144,8 +144,8 @@ T(view.total_rows == 10); // standard get - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView"); - T(xhr.status == 200); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView"); + T(xhr.status == 200, "standard get should be 200"); T(/Total Rows/.test(xhr.responseText)); T(/Key: 1/.test(xhr.responseText)); T(/LineNo: 0/.test(xhr.responseText)); @@ -159,14 +159,14 @@ // test that etags are available var etag = xhr.getResponseHeader("etag"); - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView", { + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView", { headers: {"if-none-match": etag} }); T(xhr.status == 304); // get with query params - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView?startkey=3"); - T(xhr.status == 200); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView?startkey=3"); + T(xhr.status == 200, "with query params"); T(/Total Rows/.test(xhr.responseText)); T(!(/Key: 1/.test(xhr.responseText))); T(/FirstKey: 3/.test(xhr.responseText)); @@ -174,33 +174,33 @@ // with 0 rows - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView?startkey=30"); - T(xhr.status == 200); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/basicView?startkey=30"); + T(xhr.status == 200, "0 rows"); T(/Total Rows/.test(xhr.responseText)); T(/Offset: null/.test(xhr.responseText)); // reduce with 0 rows - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?startkey=30"); - T(xhr.status == 200); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?startkey=30"); + T(xhr.status == 200, "reduce 0 rows"); T(/Total Rows/.test(xhr.responseText)); T(/Offset: undefined/.test(xhr.responseText)); // when there is a reduce present, but not used - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?reduce=false"); - T(xhr.status == 200); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?reduce=false"); + T(xhr.status == 200, "reduce false"); T(/Total Rows/.test(xhr.responseText)); T(/Key: 1/.test(xhr.responseText)); // when there is a reduce present, and used - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?group=true"); - T(xhr.status == 200); + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true"); + T(xhr.status == 200, "group reduce"); T(/Key: 1/.test(xhr.responseText)); // there should be etags on reduce as well var etag = xhr.getResponseHeader("etag"); T(etag, "Etags should be served with reduce lists"); - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?group=true", { + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true", { headers: {"if-none-match": etag} }); T(xhr.status == 304); @@ -210,13 +210,13 @@ var saveResult = db.bulkSave(docs); T(saveResult.ok); - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?group=true", { + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=true", { headers: {"if-none-match": etag} }); - T(xhr.status == 200); + T(xhr.status == 200, "reduce etag"); // with accept headers for HTML - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/acceptSwitch/basicView", { + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", { headers: { "Accept": 'text/html' } @@ -226,7 +226,7 @@ T(xhr.responseText.match(/Value/)); // now with xml - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/acceptSwitch/basicView", { + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/acceptSwitch/basicView", { headers: { "Accept": 'application/xml' } @@ -236,49 +236,40 @@ T(xhr.responseText.match(/entry/)); // now with extra qs params - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/qsParams/basicView?foo=blam"); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/qsParams/basicView?foo=blam"); T(xhr.responseText.match(/blam/)); // aborting iteration - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter/basicView"); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/basicView"); T(xhr.responseText.match(/^head 0 1 2 tail$/)); - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter2/basicView"); + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/basicView"); T(xhr.responseText.match(/^head 0 1 2 tail$/)); // aborting iteration with reduce - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter/withReduce?group=true"); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter/withReduce?group=true"); T(xhr.responseText.match(/^head 0 1 2 tail$/)); - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter2/withReduce?group=true"); + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/stopIter2/withReduce?group=true"); T(xhr.responseText.match(/^head 0 1 2 tail$/)); // empty list - var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/emptyList/basicView"); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/basicView"); T(xhr.responseText.match(/^$/)); - xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/emptyList/withReduce?group=true"); + xhr = CouchDB.request("GET", "/test_suite_db/_design/lists/_list/emptyList/withReduce?group=true"); T(xhr.responseText.match(/^$/)); // multi-key fetch - var xhr = CouchDB.request("POST", "/test_suite_db/_list/lists/simpleForm/basicView", { + var xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/basicView", { body: '{"keys":[2,4,5,7]}' }); - T(xhr.status == 200); + T(xhr.status == 200, "multi key"); T(/Total Rows/.test(xhr.responseText)); T(!(/Key: 1/.test(xhr.responseText))); T(/Key: 2/.test(xhr.responseText)); T(/FirstKey: 2/.test(xhr.responseText)); T(/LastKey: 7/.test(xhr.responseText)); - xhr = CouchDB.request("POST", "/test_suite_db/_list/lists/simpleForm/withReduce?group=true", { - body: '{"keys":[2,4,5,7]}' - }); - T(xhr.status == 200); - T(/Total Rows/.test(xhr.responseText)); - T(!(/Key: 1/.test(xhr.responseText))); - T(/Key: 2/.test(xhr.responseText)); - T(/FirstKey: 2/.test(xhr.responseText)); - T(/LastKey: 7/.test(xhr.responseText)); - + // no multi-key fetch allowed when group=false - xhr = CouchDB.request("POST", "/test_suite_db/_list/lists/simpleForm/withReduce?group=false", { + xhr = CouchDB.request("POST", "/test_suite_db/_design/lists/_list/simpleForm/withReduce?group=false", { body: '{"keys":[2,4,5,7]}' }); T(xhr.status == 400); Modified: couchdb/trunk/share/www/script/test/show_documents.js URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/show_documents.js?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/share/www/script/test/show_documents.js (original) +++ couchdb/trunk/share/www/script/test/show_documents.js Mon Mar 9 19:52:54 2009 @@ -33,9 +33,16 @@ } }), "just-name" : stringFun(function(doc, req) { - return { - body : "Just " + doc.name - }; + if (doc) { + return { + body : "Just " + doc.name + }; + } else { + return { + body : "No such doc", + code : 404 + }; + } }), "req-info" : stringFun(function(doc, req) { return { @@ -123,68 +130,72 @@ var docid = resp.id; // show error - var xhr = CouchDB.request("GET", "/test_suite_db/_show/"); - T(xhr.status == 404); + var xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/"); + T(xhr.status == 404, 'Should be missing'); T(JSON.parse(xhr.responseText).reason == "Invalid path."); // hello template world - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/hello/"+docid); + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello/"+docid); T(xhr.responseText == "Hello World"); // hello template world (no docid) - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/hello/"); + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello"); T(xhr.responseText == "Empty World"); // // hello template world (non-existing docid) - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/hello/nonExistingDoc"); + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/hello/nonExistingDoc"); T(xhr.responseText == "New World"); // show with doc - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid); + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid); T(xhr.responseText == "Just Rusty"); + // show with missing doc + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/missingdoc"); + console.log(xhr) + T(xhr.status == 404, 'Doc should be missing'); + T(xhr.responseText == "No such doc"); // show with missing func - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/missing/"+docid); - T(xhr.status == 404); - + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/missing/"+docid); + T(xhr.status == 404, "function is missing"); + // missing design doc - xhr = CouchDB.request("GET", "/test_suite_db/_show/missingdoc/just-name/"+docid); + xhr = CouchDB.request("GET", "/test_suite_db/_design/missingddoc/_show/just-name/"+docid); T(xhr.status == 404); var resp = JSON.parse(xhr.responseText); T(resp.error == "not_found"); // query parameters - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/req-info/"+docid+"?foo=bar", { - headers: { - "Accept": "text/html;text/plain;*/*", - "X-Foo" : "bar" - } + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/req-info/"+docid+"?foo=bar", { + headers: { + "Accept": "text/html;text/plain;*/*", + "X-Foo" : "bar" + } }); var resp = JSON.parse(xhr.responseText); T(equals(resp.headers["X-Foo"], "bar")); T(equals(resp.query, {foo:"bar"})); T(equals(resp.verb, "GET")); - T(equals(resp.path[4], docid)); + T(equals(resp.path[5], docid)); T(equals(resp.info.db_name, "test_suite_db")); // returning a content-type - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/xml-type/"+docid); + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/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/_show/template/accept-switch/"+docid, { - headers: {"Accept": "text/html;text/plain;*/*"} + // different mime has different etag + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/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/_show/template/accept-switch/"+docid, { - headers: {"Accept": "image/png;*/*"} + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/accept-switch/"+docid, { + headers: {"Accept": "image/png;*/*"} }); T(xhr.responseText.match(/PNG/)) T("image/png" == xhr.getResponseHeader("Content-Type")); @@ -193,12 +204,12 @@ // proper etags // show with doc - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid); + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/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/_show/template/just-name/"+docid, { - headers: {"if-none-match": etag} + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, { + headers: {"if-none-match": etag} }); // should be 304 T(xhr.status == 304); @@ -208,16 +219,16 @@ resp = db.save(doc); T(resp.ok); // req with same etag - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, { - headers: {"if-none-match": etag} + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, { + headers: {"if-none-match": etag} }); // status is 200 T(xhr.status == 200); // get new etag and request again etag = xhr.getResponseHeader("etag"); - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, { - headers: {"if-none-match": etag} + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, { + headers: {"if-none-match": etag} }); // should be 304 T(xhr.status == 304); @@ -225,9 +236,9 @@ // update design doc (but not function) designDoc.isChanged = true; T(db.save(designDoc).ok); - - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, { - headers: {"if-none-match": etag} + + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, { + headers: {"if-none-match": etag} }); // should be 304 T(xhr.status == 304); @@ -240,49 +251,49 @@ }).toString(); T(db.save(designDoc).ok); - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/just-name/"+docid, { - headers: {"if-none-match": etag} + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/just-name/"+docid, { + headers: {"if-none-match": etag} }); // status is 200 T(xhr.status == 200); // JS can't set etag - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/no-set-etag/"+docid); + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/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/_show/template/respondWith/"+docid, { - headers: { - "Accept": 'text/html,application/atom+xml; q=0.9' - } + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/respondWith/"+docid, { + headers: { + "Accept": 'text/html,application/atom+xml; q=0.9' + } }); T(xhr.getResponseHeader("Content-Type") == "text/html"); T(xhr.responseText == "Ha ha, you said \"plankton\"."); // now with xml - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, { - headers: { - "Accept": 'application/xml' - } + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/respondWith/"+docid, { + headers: { + "Accept": 'application/xml' + } }); T(xhr.getResponseHeader("Content-Type") == "application/xml"); T(xhr.responseText.match(/node/)); T(xhr.responseText.match(/plankton/)); // registering types works - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, { - headers: { - "Accept": "application/x-foo" - } + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/respondWith/"+docid, { + headers: { + "Accept": "application/x-foo" + } }); T(xhr.getResponseHeader("Content-Type") == "application/x-foo"); T(xhr.responseText.match(/foofoo/)); // test the respondWith mime matcher without - xhr = CouchDB.request("GET", "/test_suite_db/_show/template/respondWith/"+docid, { + xhr = CouchDB.request("GET", "/test_suite_db/_design/template/_show/respondWith/"+docid, { headers: { "Accept": 'text/html,application/atom+xml; q=0.9' } Modified: couchdb/trunk/src/couchdb/couch_db.hrl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db.hrl?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_db.hrl (original) +++ couchdb/trunk/src/couchdb/couch_db.hrl Mon Mar 9 19:52:54 2009 @@ -61,7 +61,8 @@ path_parts, db_url_handlers, user_ctx, - req_body = undefined + req_body = undefined, + design_url_handlers }). Modified: couchdb/trunk/src/couchdb/couch_httpd.erl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd.erl?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_httpd.erl (original) +++ couchdb/trunk/src/couchdb/couch_httpd.erl Mon Mar 9 19:52:54 2009 @@ -13,7 +13,7 @@ -module(couch_httpd). -include("couch_db.hrl"). --export([start_link/0, stop/0, handle_request/3]). +-export([start_link/0, stop/0, handle_request/4]). -export([header_value/2,header_value/3,qs_value/2,qs_value/3,qs/1,path/1,absolute_uri/2]). -export([verify_is_server_admin/1,unquote/1,quote/1,recv/2,recv_chunked/4]). @@ -44,11 +44,18 @@ fun({UrlKey, SpecStr}) -> {?l2b(UrlKey), make_arity_2_fun(SpecStr)} end, couch_config:get("httpd_db_handlers")), + + DesignUrlHandlersList = lists:map( + fun({UrlKey, SpecStr}) -> + {?l2b(UrlKey), make_arity_2_fun(SpecStr)} + end, couch_config:get("httpd_design_handlers")), + UrlHandlers = dict:from_list(UrlHandlersList), DbUrlHandlers = dict:from_list(DbUrlHandlersList), + DesignUrlHandlers = dict:from_list(DesignUrlHandlersList), Loop = fun(Req)-> apply(?MODULE, handle_request, - [Req, UrlHandlers, DbUrlHandlers]) + [Req, UrlHandlers, DbUrlHandlers, DesignUrlHandlers]) end, % and off we go @@ -101,7 +108,7 @@ mochiweb_http:stop(?MODULE). -handle_request(MochiReq, UrlHandlers, DbUrlHandlers) -> +handle_request(MochiReq, UrlHandlers, DbUrlHandlers, DesignUrlHandlers) -> statistics(runtime), % prepare request_time counter, see end of function AuthenticationFun = make_arity_1_fun( couch_config:get("httpd", "authentication_handler")), @@ -147,7 +154,8 @@ method = Method, path_parts = [list_to_binary(couch_httpd:unquote(Part)) || Part <- string:tokens(Path, "/")], - db_url_handlers = DbUrlHandlers + db_url_handlers = DbUrlHandlers, + design_url_handlers = DesignUrlHandlers }, DefaultFun = fun couch_httpd_db:handle_request/1, HandlerFun = couch_util:dict_find(HandlerKey, UrlHandlers, DefaultFun), Modified: couchdb/trunk/src/couchdb/couch_httpd_db.erl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_db.erl?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_httpd_db.erl (original) +++ couchdb/trunk/src/couchdb/couch_httpd_db.erl Mon Mar 9 19:52:54 2009 @@ -13,7 +13,7 @@ -module(couch_httpd_db). -include("couch_db.hrl"). --export([handle_request/1, db_req/2, couch_doc_open/4]). +-export([handle_request/1, handle_design_req/2, db_req/2, couch_doc_open/4]). -import(couch_httpd, [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2, @@ -41,6 +41,16 @@ do_db_req(Req, Handler) end. +handle_design_req(#httpd{ + path_parts=[_DbName,_Design,_DesName, <<"_",_/binary>> = Action | _Rest], + design_url_handlers = DesignUrlHandlers + }=Req, Db) -> + Handler = couch_util:dict_find(Action, DesignUrlHandlers, fun db_req/2), + Handler(Req, Db); + +handle_design_req(Req, Db) -> + db_req(Req, Db). + create_db_req(#httpd{user_ctx=UserCtx}=Req, DbName) -> ok = couch_httpd:verify_is_server_admin(Req), case couch_server:create(DbName, [{user_ctx, UserCtx}]) of Modified: couchdb/trunk/src/couchdb/couch_httpd_show.erl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_show.erl?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_httpd_show.erl (original) +++ couchdb/trunk/src/couchdb/couch_httpd_show.erl Mon Mar 9 19:52:54 2009 @@ -24,7 +24,7 @@ handle_doc_show_req(#httpd{ method='GET', - path_parts=[_, _, DesignName, ShowName, DocId] + path_parts=[_DbName, _Design, DesignName, _Show, ShowName, DocId] }=Req, Db) -> DesignId = <<"_design/", DesignName/binary>>, #doc{body={Props}} = couch_httpd_db:couch_doc_open(Db, DesignId, [], []), @@ -39,7 +39,7 @@ handle_doc_show_req(#httpd{ method='GET', - path_parts=[_, _, DesignName, ShowName] + path_parts=[_DbName, _Design, DesignName, _Show, ShowName] }=Req, Db) -> DesignId = <<"_design/", DesignName/binary>>, #doc{body={Props}} = couch_httpd_db:couch_doc_open(Db, DesignId, [], []), @@ -53,7 +53,8 @@ handle_doc_show_req(Req, _Db) -> send_method_not_allowed(Req, "GET,HEAD"). -handle_view_list_req(#httpd{method='GET',path_parts=[_, _, DesignName, ListName, ViewName]}=Req, Db) -> +handle_view_list_req(#httpd{method='GET', + path_parts=[_DbName, _Design, DesignName, _List, ListName, ViewName]}=Req, Db) -> DesignId = <<"_design/", DesignName/binary>>, #doc{body={Props}} = couch_httpd_db:couch_doc_open(Db, DesignId, [], []), Lang = proplists:get_value(<<"language">>, Props, <<"javascript">>), @@ -63,7 +64,8 @@ handle_view_list_req(#httpd{method='GET'}=Req, _Db) -> send_error(Req, 404, <<"list_error">>, <<"Invalid path.">>); -handle_view_list_req(#httpd{method='POST',path_parts=[_, _, DesignName, ListName, ViewName]}=Req, Db) -> +handle_view_list_req(#httpd{method='POST', + path_parts=[_DbName, _Design, DesignName, _List, ListName, ViewName]}=Req, Db) -> DesignId = <<"_design/", DesignName/binary>>, #doc{body={Props}} = couch_httpd_db:couch_doc_open(Db, DesignId, [], []), Lang = proplists:get_value(<<"language">>, Props, <<"javascript">>), Modified: couchdb/trunk/src/couchdb/couch_httpd_view.erl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_view.erl?rev=751813&r1=751812&r2=751813&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_httpd_view.erl (original) +++ couchdb/trunk/src/couchdb/couch_httpd_view.erl Mon Mar 9 19:52:54 2009 @@ -49,13 +49,15 @@ couch_stats_collector:increment({httpd, view_reads}), Result. -handle_view_req(#httpd{method='GET',path_parts=[_,_, Id, ViewName]}=Req, Db) -> - design_doc_view(Req, Db, Id, ViewName, nil); +handle_view_req(#httpd{method='GET', + path_parts=[_Db, _Design, DName, _View, ViewName]}=Req, Db) -> + design_doc_view(Req, Db, DName, ViewName, nil); -handle_view_req(#httpd{method='POST',path_parts=[_,_, Id, ViewName]}=Req, Db) -> +handle_view_req(#httpd{method='POST', + path_parts=[_Db, _Design, DName, _View, ViewName]}=Req, Db) -> {Props} = couch_httpd:json_body(Req), Keys = proplists:get_value(<<"keys">>, Props, nil), - design_doc_view(Req, Db, Id, ViewName, Keys); + design_doc_view(Req, Db, DName, ViewName, Keys); handle_view_req(Req, _Db) -> send_method_not_allowed(Req, "GET,POST,HEAD").