Created
October 21, 2009 19:17
-
-
Save brandon-beacher/215361 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; | |
| }, | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); | |
| }); | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); | |
| }); | |
| }); | |
| }); | |
| }); | |
| }); | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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