Skip to content

Instantly share code, notes, and snippets.

@brandon-beacher
Created October 21, 2009 19:17
Show Gist options
  • Select an option

  • Save brandon-beacher/215361 to your computer and use it in GitHub Desktop.

Select an option

Save brandon-beacher/215361 to your computer and use it in GitHub Desktop.
var http = require('/http.js');
var utils = require('/utils.js');
include('../config.js');
var databases = {};
var designs = {};
var httpClients = {};
var servers = {};
var views = {};
var duplicateSlashes = /^\/{2,}|([^:])\/{2,}/g;
var arrayify = function(args) {
return Array.prototype.slice.call(args);
};
var combine = function() {
return arrayify(arguments).join('/').replace(duplicateSlashes, '$1/');
};
var createCouchResource = function(url) {
var couchResource = {},
uri = http.parseUri(url),
httpClient = fetchHttpClient(uri);
var assembleArgs = function(method, arguments) {
args = {};
for (var i = 0; i < arguments.length; i++) {
var argument = arguments[i];
if (isServerRequest(argument)) { args.streamRequest = argument }
else if (isServerResponse(argument)) { args.streamResponse = argument }
else if (isAssureCallback(argument)) { args.assureCallback = argument }
else if (isBufferCallback(argument)) { args.bufferCallback = argument }
else if (isParams(argument)) { args.params = argument }
else if (isPath(argument)) { args.path = argument }
else {
throw new Error('got unexpected argument: ' + JSON.stringify(argument));
}
}
if (!args.path) { args.path = '/' };
args.path = combine(uri.directory, args.path);
switch (method) {
case 'del':
case 'get':
args.path += toQueryString(args.params);
break;
case 'post':
case 'put':
args.body = JSON.stringify(args.params);
break;
default:
throw new Error('got unexpected method: ' + method);
}
return args;
};
var assure = function(method, path, body, callback) {
buffer(method, path, body, function(response, json) {
if (response.statusCode >= 200 && response.statusCode < 300) {
callback.call(response, json);
} else {
throw new Error('got unexpected status code ' + response.statusCode + ' with body ' + response.body);
}
});
};
var buffer = function(method, path, body, callback) {
var request = httpClient[method](path),
responseBody = '';
if (body) { request.sendBody(body) };
request.finish(function(response) {
response.addListener('body', function(chunk) { responseBody += chunk; });
response.addListener('complete', function() {
response.body = responseBody;
callback.call(request, response, JSON.parse(responseBody));
});
});
};
var isAssureCallback = function(object) {
return typeof object === 'function' && object.length === 1;
};
var isBufferCallback = function(object) {
return typeof object === 'function' && object.length === 2;
};
var isParams = function(object) {
return typeof object === 'object';
};
var isPath = function(object) {
return typeof object === 'string';
};
var isServerRequest = function(object) {
return typeof object.pause === 'function';
};
var isServerResponse = function(object) {
return typeof object.finish === 'function';
};
var stream = function(method, path, streamRequest, streamResponse) {
// any reason to forward streamRequest.headers as the second param here?
var request = httpClient[method](path /*, streamRequest.headers */);
streamRequest.addListener('body', function(chunk) {
request.sendBody(chunk);
});
request.finish(function (response) {
// any reason to forward the response.headers as the second param here?
streamResponse.sendHeader(response.statusCode /*, response.headers */);
response.addListener('body', function (chunk) {
streamResponse.sendBody(chunk);
});
response.addListener('complete', function () {
streamResponse.finish();
});
});
};
var toQueryString = function(params) {
var parts = [];
var queryString = '';
for (var key in params) {
parts.push(encodeURIComponent(key) + '=' + JSON.stringify(params[key]));
}
return parts.length > 0 ? '?' + parts.join('&') : '';
};
var del = function() {
var args = assembleArgs('del', arguments);
request('del', args);
};
var get = function() {
var args = assembleArgs('get', arguments);
request('get', args);
};
var post = function() {
var args = assembleArgs('post', arguments);
request('post', args);
};
var put = function() {
var args = assembleArgs('put', arguments);
request('put', args);
};
var request = function(method, args) {
if (args.streamRequest) {
stream(method, args.path, args.streamRequest, args.streamResponse);
} else if (args.bufferCallback) {
buffer(method, args.path, args.body, args.bufferCallback);
} else if (args.assureCallback) {
assure(method, args.path, args.body, args.assureCallback);
} else {
throw new Error('got unexpected args: ' + JSON.stringify(args) + '\n');
}
};
couchResource.del = del;
couchResource.get = get;
couchResource.post = post;
couchResource.put = put;
couchResource.uri = uri;
return couchResource;
};
var fetchHttpClient = function(uri) {
var httpClient = httpClients[uri.authority];
if (!httpClient) {
httpClient = http.createClient(uri.port, uri.host);
httpClient.addListener('error', function () {
throw new Error('received generic http client error for uri ' + uri);
});
httpClients[uri.authority] = httpClient;
}
return httpClient;
};
var mixinCouchDatabase = function(couchResource) {
var couchResource = couchResource;
var _all_designs = function() {
_all_docs({ startkey: "_design/", endkey: "_design0" });
};
var _all_docs = function() {
couchResource.get.apply(this, arrayify(arguments).concat('_all_docs'));
};
var design = function(designName) {
var url = combine(couchResource.uri, '_design', designName);
var design = Couch.design(url);
return design;
};
var info = function() {
couchResource.get.apply(this, arrayify(arguments).concat('/'));
};
couchResource._all_designs = _all_designs;
couchResource._all_docs = _all_docs;
couchResource.design = design;
couchResource.info = info;
return couchResource;
};
var mixinCouchDesign = function(couchResource) {
var couchResource = couchResource;
var view = function(viewName) {
var url = combine(couchResource.uri, '_view', viewName);
var view = Couch.view(url);
return view;
};
couchResource.view = view;
return couchResource;
};
var mixinCouchServer = function(couchResource) {
var couchResource = couchResource;
var _all_dbs = function() {
couchResource.get.apply(this, arrayify(arguments).concat('_all_dbs'));
};
var _uuids = function() {
couchResource.get.apply(this, arrayify(arguments).concat('_uuids'));
};
var database = function(dbName) {
var url = combine(couchResource.uri, dbName);
var db = Couch.database(url);
return db;
};
couchResource._all_dbs = _all_dbs;
couchResource._uuids = _uuids;
couchResource.database = database;
return couchResource;
};
var mixinCouchView = function(couchResource) {
var couchResource = couchResource;
return couchResource;
};
exports.Couch = {
database: function(url) {
var database = databases[url];
if (!database) {
database = createCouchResource(url);
mixinCouchDatabase(database);
databases[url] = database;
}
return database;
},
design: function(url) {
var design = designs[url];
if (!design) {
design = createCouchResource(url);
mixinCouchDesign(design);
designs[url] = design;
}
return design;
},
server: function(url) {
var server = servers[url];
if (!server) {
server = createCouchResource(url);
mixinCouchServer(server);
servers[url] = server;
}
return server;
},
view: function(url) {
var view = views[url];
if (!view) {
view = createCouchResource(url);
mixinCouchView(view);
views[url] = view;
}
return view;
},
};
include("/mjsunit.js");
include("/utils.js");
include("../../config.js");
include("../../lib/couch.js");
var db = Couch.database('http://localhost:5984/test_suite_db');
var assertInfoResponse = function(response, json) {
assertEquals(200, response.statusCode);
assertEquals('test_suite_db', json.db_name);
};
db.get('/', assertInfoResponse);
db.info(assertInfoResponse);
include("/mjsunit.js");
include("/utils.js");
include("../../config.js");
include("../../lib/couch.js");
var server = Couch.server('http://localhost:5984');
// create database
server.put('test_couch_designs', function(response, json) {
var db = server.database('test_couch_designs');
var designDoc = {
_id: '_design/test_design',
views: {
test_view: {
map: 'function(doc) { log(doc) }'
}
}
};
// create design
db.put(designDoc._id, designDoc, function(response, json) {
assertEquals(201, response.statusCode);
assertTrue(json.ok);
var design = db.design('test_design');
var view = design.view('test_view');
view.get(function(response, json) {
assertEquals(200, response.statusCode);
assertEquals(0, json.total_rows);
});
// drop database
db.del(function(response, json) {
assertEquals(200, response.statusCode);
assertTrue(json.ok);
});
});
});
include("/mjsunit.js");
include("/utils.js");
include("../../config.js");
include("../../lib/couch.js");
var server = Couch.server('http://localhost:5984');
// create database
server.put('test_couch_documents', function(response, json) {
var db = server.database('test_couch_documents');
var createdDoc = { status: 'created' };
// create doc
db.post(createdDoc, function(response, json) {
assertEquals(201, response.statusCode);
assertTrue(json.ok);
var createdDocId = json.id;
// open doc
db.get(createdDocId, function(response, json) {
assertEquals(200, response.statusCode);
assertEquals(createdDocId, json._id);
assertEquals('created', json.status);
var openedDoc = json;
openedDoc.status = 'updated';
// update doc
db.put(openedDoc._id, openedDoc, function(response, json) {
assertEquals(201, response.statusCode);
assertTrue(json.ok);
var updatedDocId = json.id;
// reopen doc
db.get(updatedDocId, function(response, json) {
assertEquals(200, response.statusCode);
assertEquals(updatedDocId, json._id);
assertEquals('updated', json.status);
var rev = json._rev;
// delete doc
db.del(updatedDocId, { rev: rev }, function(response, json) {
assertEquals(200, response.statusCode);
assertTrue(json.ok);
// drop database
db.del(function(response, json) {
assertEquals(200, response.statusCode);
assertTrue(json.ok);
});
});
});
});
});
});
});
include("/mjsunit.js");
include("/utils.js");
include("../../config.js");
include("../../lib/couch.js");
var server = Couch.server('http://localhost:5984');
server.get('/', function(response, json) {
assertEquals(200, response.statusCode);
assertEquals('Welcome', json.couchdb);
});
// path defaults to / if not specified
server.get(function(response, json) {
assertEquals(200, response.statusCode);
assertEquals('Welcome', json.couchdb);
});
// pass the path as a string
server.get('_all_dbs', function(response, json) {
assertEquals(200, response.statusCode);
assertInstanceof(json, Array);
});
// or use the convenience function
server._all_dbs(function(response, json) {
assertEquals(200, response.statusCode);
assertInstanceof(json, Array);
});
// manually examine the response to a bad request
server.get('bogus', function(response, json) {
assertEquals(404, response.statusCode);
assertEquals('not_found', json.error);
});
// pass some parameters
server._uuids({ count: 10 }, function(response, json) {
assertEquals(200, response.statusCode);
assertInstanceof(json.uuids, Array);
assertEquals(10, json.uuids.length);
});
// create a database
server.put('test_database', function(response, json) {
assertEquals(201, response.statusCode);
assertTrue(json.ok);
// drop a database
server.del('test_database', function(response, json) {
assertEquals(200, response.statusCode);
assertTrue(json.ok);
});
});
include("/mjsunit.js");
include("/utils.js");
include("../../config.js");
include("../../lib/couch.js");
var assertAllDocs = function(response, json) {
assertEquals(200, response.statusCode);
assertInstanceof(json.rows, Array);
};
var assertDatabaseInfo = function(response, json) {
assertEquals(200, response.statusCode);
assertEquals('test_suite_db', json.db_name);
};
var assertServerInfo = function(response, json) {
assertEquals(200, response.statusCode);
assertEquals('Welcome', json.couchdb);
};
var assertUuids = function(response, json) {
assertEquals(200, response.statusCode);
assertInstanceof(json.uuids, Array);
};
var testDatabase = function(db) {
db.get(assertDatabaseInfo);
db.get('/', assertDatabaseInfo);
db.get('_all_docs', assertAllDocs);
db.get('_all_docs/', assertAllDocs);
db.get('/_all_docs', assertAllDocs);
db.get('/_all_docs/', assertAllDocs);
};
var testServer = function(server) {
server.get(assertServerInfo);
server.get('/', assertServerInfo);
server.get('_uuids', assertUuids);
server.get('_uuids/', assertUuids);
server.get('/_uuids', assertUuids);
server.get('/_uuids/', assertUuids);
};
[ 'http://localhost:5984',
'http://localhost:5984/' ].forEach(function(url) {
var server = Couch.server(url);
testServer(server);
[ 'test_suite_db',
'test_suite_db/',
'/test_suite_db',
'/test_suite_db/' ].forEach(function(dbName) {
var db = server.database(dbName);
testDatabase(db);
})
});
[ 'http://localhost:5984/test_suite_db',
'http://localhost:5984/test_suite_db/' ].forEach(function(url) {
var db = Couch.database(url);
testDatabase(db);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment