Permalink
Browse files

# 0.7.0

* added support for arbitrary paths in
* document paths are now EncodeURIComponent by default, use path to override
* new error handling code, hopefully more readable
* added auto db.use when a database is present in the uri that was provided
* updated to request 2.1.1 on frozen deps
  • Loading branch information...
1 parent 403949c commit ecd5b1a1d9ac3fe1255ac8d3e374dcb3a4fb4a37 @dscape committed Aug 29, 2011
Showing with 235 additions and 104 deletions.
  1. +7 −0 CHANGELOG.md
  2. +9 −9 LICENSE
  3. +1 −1 README.md
  4. +4 −0 cfg/tests.js
  5. +62 −61 error.js
  6. +29 −12 nano.js
  7. +5 −5 node_modules/request/main.js
  8. +2 −2 package.json
  9. +28 −8 tests/doc/insert.js
  10. +82 −0 tests/shared/cfg.js
  11. +6 −6 tests/shared/error.js
View
@@ -0,0 +1,7 @@
+# 0.7.0
+
+* added support for arbitrary paths in `nano.request`
+* document paths are now EncodeURIComponent by default, use path to override
+* new error handling code, hopefully more readable
+* added auto db.use when a database is present in the uri that was provided
+* updated to request 2.1.1 on frozen deps
View
@@ -1,13 +1,13 @@
-Copyright 2011 Nuno Job <nunojob.com>
+copyright 2011 nuno job <nunojob.com> (oO)--',--
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
+licensed under the apache license, version 2.0 (the "license");
+you may not use this file except in compliance with the license.
+you may obtain a copy of the license at
http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+unless required by applicable law or agreed to in writing, software
+distributed under the license is distributed on an "as is" basis,
+without warranties or conditions of any kind, either express or implied.
+see the license for the specific language governing permissions and
+limitations under the license.
View
@@ -123,7 +123,7 @@ to get a document in a specific rev an advanced user might do:
function (_,_,b) { console.log(b) }
);
-this is the same as (assuming `alice = nano.use("alice");`):
+this is the same as (assuming `alice = require('nano')('http://localhost:5984/alice')`):
alice.get("rabbit", {rev: "1-967a00dff5e02add41819138abb3284d"},
function (_,_,b) { console.log(b) }
View
@@ -30,4 +30,8 @@ cfg.url = function (){
":" + cfg.port;
}();
+cfg.db_url = function (postfix) {
+ return cfg.url + '/' + postfix;
+};
+
module.exports = exports = cfg;
View
@@ -1,55 +1,56 @@
-var STATUS_CODES = { '100': 'Continue',
- '101': 'Switching Protocols',
- '102': 'Processing',
- '200': 'OK',
- '201': 'Created',
- '202': 'Accepted',
- '203': 'Non-Authoritative Information',
- '204': 'No Content',
- '205': 'Reset Content',
- '206': 'Partial Content',
- '207': 'Multi-Status',
- '300': 'Multiple Choices',
- '301': 'Moved Permanently',
- '302': 'Moved Temporarily',
- '303': 'See Other',
- '304': 'Not Modified',
- '305': 'Use Proxy',
- '307': 'Temporary Redirect',
- '400': 'Bad Request',
- '401': 'Unauthorized',
- '402': 'Payment Required',
- '403': 'Forbidden',
- '404': 'Not Found',
- '405': 'Method Not Allowed',
- '406': 'Not Acceptable',
- '407': 'Proxy Authentication Required',
- '408': 'Request Time-out',
- '409': 'Conflict',
- '410': 'Gone',
- '411': 'Length Required',
- '412': 'Precondition Failed',
- '413': 'Request Entity Too Large',
- '414': 'Request-URI Too Large',
- '415': 'Unsupported Media Type',
- '416': 'Requested Range Not Satisfiable',
- '417': 'Expectation Failed',
- '418': 'I\'m a teapot',
- '422': 'Unprocessable Entity',
- '423': 'Locked',
- '424': 'Failed Dependency',
- '425': 'Unordered Collection',
- '426': 'Upgrade Required',
- '500': 'Internal Server Error',
- '501': 'Not Implemented',
- '502': 'Bad Gateway',
- '503': 'Service Unavailable',
- '504': 'Gateway Time-out',
- '505': 'HTTP Version not supported',
- '506': 'Variant Also Negotiates',
- '507': 'Insufficient Storage',
- '509': 'Bandwidth Limit Exceeded',
- '510': 'Not Extended' };
+var STATUS_CODES = { '100': 'Continue'
+ ,'101': 'Switching Protocols'
+ ,'102': 'Processing'
+ ,'200': 'OK'
+ ,'201': 'Created'
+ ,'202': 'Accepted'
+ ,'203': 'Non-Authoritative Information'
+ ,'204': 'No Content'
+ ,'205': 'Reset Content'
+ ,'206': 'Partial Content'
+ ,'207': 'Multi-Status'
+ ,'300': 'Multiple Choices'
+ ,'301': 'Moved Permanently'
+ ,'302': 'Moved Temporarily'
+ ,'303': 'See Other'
+ ,'304': 'Not Modified'
+ ,'305': 'Use Proxy'
+ ,'307': 'Temporary Redirect'
+ ,'400': 'Bad Request'
+ ,'401': 'Unauthorized'
+ ,'402': 'Payment Required'
+ ,'403': 'Forbidden'
+ ,'404': 'Not Found'
+ ,'405': 'Method Not Allowed'
+ ,'406': 'Not Acceptable'
+ ,'407': 'Proxy Authentication Required'
+ ,'408': 'Request Time-out'
+ ,'409': 'Conflict'
+ ,'410': 'Gone'
+ ,'411': 'Length Required'
+ ,'412': 'Precondition Failed'
+ ,'413': 'Request Entity Too Large'
+ ,'414': 'Request-URI Too Large'
+ ,'415': 'Unsupported Media Type'
+ ,'416': 'Requested Range Not Satisfiable'
+ ,'417': 'Expectation Failed'
+ ,'418': 'I\'m a teapot'
+ ,'422': 'Unprocessable Entity'
+ ,'423': 'Locked'
+ ,'424': 'Failed Dependency'
+ ,'425': 'Unordered Collection'
+ ,'426': 'Upgrade Required'
+ ,'500': 'Internal Server Error'
+ ,'501': 'Not Implemented'
+ ,'502': 'Bad Gateway'
+ ,'503': 'Service Unavailable'
+ ,'504': 'Gateway Time-out'
+ ,'505': 'HTTP Version not supported'
+ ,'506': 'Variant Also Negotiates'
+ ,'507': 'Insufficient Storage'
+ ,'509': 'Bandwidth Limit Exceeded'
+ ,'510': 'Not Extended'
+ };
/*
* generic error
*
@@ -84,18 +85,18 @@ var STATUS_CODES = { '100': 'Continue',
*
* @return an augmented error that helps you know more than the stack trace
*/
-function gen_err(error,code,request,http_code,type) {
- if(!type) { type = http_code; http_code = null; }
- if(!error) { error = new Error(STATUS_CODES[http_code] || "Unknown Error"); }
- if(typeof http_code !== "number") { http_code = 500; }
+function gen_err(scope,error,code,request,status_code) {
+ error = error || STATUS_CODES[status_code] || 'Unknown Error';
+ code = code || 'unknown';
+ status_code = typeof status_code === 'number' && status_code || 500;
+ request = request || {};
if(typeof error === 'string') { error = new Error(error); }
-
error.error = code;
- error.status_code = http_code;
- error.namespace = type;
+ error.status_code = status_code;
+ error.scope = scope;
error.request = request;
return error;
}
-exports.request_err = function (e,c,r,h) { return gen_err(e,c,r,h,"request");};
-exports.couch_err = function (e,c,r,h) { return gen_err(e,c,r,h,"couch"); };
+exports.request = function (e,c,r,h) { return gen_err('request',e,c,r,h);};
+exports.couch = function (e,c,r,h) { return gen_err('couch',e,c,r,h); };
View
@@ -18,6 +18,7 @@ var request = require('request')
, fs = require('fs')
, qs = require('querystring')
, _ = require('underscore')
+ , u = require('url')
, error = require('./error')
, default_url = "http://localhost:5984"
, nano;
@@ -32,24 +33,29 @@ var request = require('request')
* dinosaurs spaceships!
*/
module.exports = exports = nano = function database_module(cfg) {
- var public_functions = {};
+ var public_functions = {}, path, db;
if(typeof cfg === "string") {
if(/^https?:/.test(cfg)) { cfg = {url: cfg}; } // url
else {
try { cfg = require(cfg); } // file path
catch(e) { console.error("bad cfg: couldn't load file"); }
}
}
+ if(!cfg) {
+ console.error("bad cfg: you passed undefined");
+ cfg = {};
+ }
if(cfg.proxy) {
request = request.defaults({proxy: cfg.proxy}); // proxy support
}
if(!cfg.url) {
console.error("bad cfg: using default=" + default_url);
cfg = {url: default_url}; // if everything else fails, use default
}
+ path = u.parse(cfg.url);
/****************************************************************************
- * relax *
+ * relax *
****************************************************************************/
/*
* relax
@@ -71,6 +77,7 @@ module.exports = exports = nano = function database_module(cfg) {
* @param {opts:object} request options; e.g. {db: "test", method: "GET"}
* {opts.db:string} database name
* {opts.method:string:optional} http method, defaults to "GET"
+ * {opts.path:string:optional} a full path, override `doc` and `att`
* {opts.doc:string:optional} document name
* {opts.att:string:optional} attachment name
* {opts.content_type:string:optional} content type, default to json
@@ -88,10 +95,13 @@ module.exports = exports = nano = function database_module(cfg) {
, status_code
, parsed
, rh;
- if(opts.doc) {
- url += "/" + opts.doc; // add the document to the url
+ if(opts.path) {
+ url += "/" + opts.path;
+ }
+ else if(opts.doc) {
+ url += "/" + encodeURIComponent(opts.doc); // add the document to the url
if(opts.att) { url += "/" + opts.att; } // add the attachment to the url
- }
+ }
if(opts.encoding && callback) {
req.encoding = opts.encoding;
delete req.headers["content-type"];
@@ -112,15 +122,15 @@ module.exports = exports = nano = function database_module(cfg) {
request(req, function(e,h,b){
rh = (h && h.headers || {});
rh['status-code'] = status_code = (h && h.statusCode || 500);
- if(e) { return callback(error.request_err(e,"socket",req,status_code),rh,b); }
+ if(e) { return callback(error.request(e,"socket",req,status_code),rh,b); }
delete rh.server; // prevent security vunerabilities related to couchdb
delete rh["content-length"]; // prevent problems with trims and stalled responses
try { parsed = JSON.parse(b); } catch (err) { parsed = b; } // did we get json or binary?
if (status_code >= 200 && status_code < 300) {
callback(null,rh,parsed);
}
else { // proxy the error directly from couchdb
- callback(error.couch_err(parsed.reason,parsed.error,req,status_code),rh,parsed);
+ callback(error.couch(parsed.reason,parsed.error,req,status_code),rh,parsed);
}
});
}
@@ -211,7 +221,7 @@ module.exports = exports = nano = function database_module(cfg) {
callback = design_name;
design_name = null;
}
- return relax({db: db_name, doc: "_compact", att: design_name, method: "POST"},callback);
+ return relax({db: db_name, path: ("_compact" + design_name), method: "POST"},callback);
}
/*
@@ -231,7 +241,7 @@ module.exports = exports = nano = function database_module(cfg) {
callback = params;
params = {};
}
- return relax({db: db_name, doc: "_changes", params: params, method: "GET"},callback);
+ return relax({db: db_name, path: "_changes", params: params, method: "GET"},callback);
}
/*
@@ -331,7 +341,7 @@ module.exports = exports = nano = function database_module(cfg) {
callback = params;
params = {};
}
- return relax({db: db_name, doc: "_all_docs", method: "GET", params: params},callback);
+ return relax({db: db_name, path: "_all_docs", method: "GET", params: params},callback);
}
/*
@@ -344,7 +354,7 @@ module.exports = exports = nano = function database_module(cfg) {
* @see relax
*/
function bulk_docs(docs,callback) {
- return relax({db: db_name, doc: "_bulk_docs", body: docs, method: "POST"},callback);
+ return relax({db: db_name, path: "_bulk_docs", body: docs, method: "POST"},callback);
}
/**************************************************************************
@@ -458,7 +468,14 @@ module.exports = exports = nano = function database_module(cfg) {
, relax: relax // alias
, dinosaur: relax // alias
};
- return public_functions;
+
+ // does the user want a database, or nano?
+ if(!_.isEmpty(path.pathname.split('/')[1])) {
+ db = path.pathname.split('/')[1];
+ cfg.url = path.protocol + '//' + path.host; // reset url
+ return document_module(db);
+ }
+ else { return public_functions; }
};
/*
Oops, something went wrong.
View
@@ -1,10 +1,10 @@
{ "name": "nano"
, "description": "minimalistic couchdb driver for node.js"
, "homepage": "http://github.com/dscape/nano"
-, "version": "0.6.6"
+, "version": "0.7.0"
, "author": "Nuno Job <nunojobpinto@gmail.com> (http://nunojob.com)"
, "keywords": ["couchdb", "data", "request", "json", "nosql", "micro", "nano"]
-, "dependencies": {"request": "~2.0.5", "underscore": "~1.1.7"}
+, "dependencies": {"request": "~2.1.1", "underscore": "~1.1.7"}
, "devDependencies": { "async": "~0.1.9", "vows": "~0.5.10" }
, "main": "./nano.js"
, "engines" : { "node": ">=0.3.6" }
Oops, something went wrong.

0 comments on commit ecd5b1a

Please sign in to comment.