Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

cot

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cot - npm Package Compare versions

Comparing version 0.0.4 to 0.0.5

423

cot.js

@@ -26,3 +26,6 @@ /*

var querystring = require('querystring');
var Q = require('q');
module.exports = Cot;
var viewQueryKeys = [

@@ -37,4 +40,2 @@ 'descending', 'endkey', 'endkey_docid', 'group',

module.exports = Cot;
function Cot(opts) {

@@ -53,4 +54,13 @@ this.port = opts.port;

Cot.prototype = {
reqOpts: function (method, path, headers) {
var opts = {
jsonRequest: function(method, path, body) {
var deferred = Q.defer();
var headers = {};
headers['accept'] = 'application/json';
headers['host'] = this.hostHeader;
if (body) {
headers['content-type'] = 'application/json';
}
var request = this.http.request({
hostname: this.hostname,

@@ -61,34 +71,28 @@ port: this.port,

method: method,
headers: headers || {}
};
headers: headers
});
opts.headers.host = this.hostHeader;
return opts;
},
processResponse: function (request, next) {
waitForResponse(request, onWaitForResponse);
request.on('error', deferred.reject.bind(deferred));
function onWaitForResponse(err, response) {
if (err) { next(err); return; }
request.on('response', function(response) {
response.setEncoding('utf8');
if (response.statusCode >= 300 || response.headers['content-type'] === 'application/json') {
readAllText(response, response.statusCode >= 300 ? 8192 : null, onReadAllText);
}
else {
next(null, response);
}
var buffer = '';
response.on('data', function(data) {
buffer += data;
});
function onReadAllText(err, buffer) {
if (err) { next(err); return; }
response.on('error', deferred.reject.bind(deferred));
response.on('end', function() {
var myResponse = {
statusCode: response.statusCode,
unparsedBody: buffer
};
response.body = buffer;
if (response.headers['content-type'] === 'application/json') {
try {
response.json = JSON.parse(response.body);
}
catch (err) {
next(err);
myResponse.body = JSON.parse(buffer);
} catch (err) {
deferred.reject(err);
return;

@@ -98,55 +102,16 @@ }

next(null, response);
}
}
},
GET: function (path, headers, next) {
headers = headers || {};
if (!headers.accept) {
headers.accept = 'application/json';
}
var request = this.http.request(this.reqOpts('GET', path, headers));
this.processResponse(request, next);
},
DELETE: function (path, headers, next) {
headers = headers || {};
if (!headers.accept) {
headers.accept = 'application/json';
}
var request = this.http.request(this.reqOpts('DELETE', path, headers));
this.processResponse(request, next);
},
putOrPost: function (which, path, body, headers, next) {
headers = headers || {};
if (!headers.accept) {
headers.accept = 'application/json';
}
deferred.resolve(myResponse);
});
});
if (typeof(body) === 'object' && !headers['content-type']) {
body = JSON.stringify(body);
headers['content-type'] = 'application/json';
if (body) {
request.end(JSON.stringify(body));
} else {
request.end();
}
else if (typeof(body) === 'string') {
body = new Buffer(body, 'utf8');
}
var request = this.http.request(this.reqOpts(which, path, headers));
request.write(body);
this.processResponse(request, next);
return deferred.promise;
},
PUT: function (path, body, headers, next) {
this.putOrPost('PUT', path, body, headers, next);
},
POST: function (path, body, headers, next) {
this.putOrPost('POST', path, body, headers, next);
},
db: function (name) {
db: function(name) {
return new DbHandle(this, name);

@@ -162,35 +127,47 @@ }

DbHandle.prototype = {
docUrl: function (docId) {
if (docId.indexOf('_design/') !== 0) {
docId = encodeURIComponent(docId);
docUrl: function(docId) {
if (typeof docId !== 'string' || docId.length === 0) {
throw new TypeError('doc id must be a non-empty string');
}
return '/' + this.name + '/' + docId;
return '/' + this.name + '/' + encodeURIComponent(docId);
},
info: function (next) {
this.cot.GET('/' + this.name, null, function (err, response) {
if (err) { next(err); return; }
next(null, response.json);
info: function() {
return this.cot.jsonRequest('GET', '/' + this.name)
.then(function(response) {
return response.body;
});
},
getDoc: function (docId, next) {
this.cot.GET(this.docUrl(docId), null, function (err, response) {
if (err) { next(err); return; }
if (response.statusCode === 404) { next(null, null); return; }
if (response.statusCode !== 200) { next(new Error('error getting doc ' + docId + ': ' + response.body)); return; }
next(null, response.json);
get: function(docId) {
return this.cot.jsonRequest('GET', this.docUrl(docId))
.then(function(response) {
if (response.statusCode !== 200) {
throw new Error('error getting doc ' + docId + ': ' + response.unparsedBody);
} else {
return response.body;
}
});
},
getDocWhere: function (docId, condition, next) {
this.getDoc(docId, function (err, doc) {
if (err) { next(err); return; }
if (doc !== null && condition(doc)) {
next(null, doc);
exists: function(docId) {
return this.cot.jsonRequest('GET', this.docUrl(docId))
.then(function(response) {
if (response.statusCode === 404) {
return null;
} else if (response.statusCode !== 200) {
throw new Error('error getting doc ' + docId + ': ' + response.unparsedBody);
} else {
return response.body;
}
else {
next(null, null);
});
},
put: function(doc) {
return this.cot.jsonRequest('PUT', this.docUrl(doc._id), doc)
.then(function(response) {
if (response.statusCode === 201 || response.statusCode === 409) {
return response.body;
} else {
throw new Error('error putting doc ' + doc._id + ': ' + response.unparsedBody);
}

@@ -200,21 +177,24 @@ });

putDoc: function (doc, opts, next) {
if (typeof next === 'undefined') {
next = opts;
opts = null;
}
var url = this.docUrl(doc._id);
if (opts && opts.batch) {
url += '?batch=ok';
}
this.cot.PUT(url, doc, null, function (err, response) {
if (err) { next(err); return; }
if (response.statusCode === 201 || response.statusCode === 202 || (response.statusCode === 409 && opts && opts.conflictOk)) {
next(null, response.json);
post: function(doc) {
return this.cot.jsonRequest('POST', '/' + this.name, doc)
.then(function(response) {
if (response.statusCode === 201) {
return response.body;
} else if (doc._id) {
throw new Error('error posting doc ' + doc._id + ': ' + response.unparsedBody);
} else {
throw new Error('error posting new doc: ' + response.unparsedBody);
}
else {
next(new Error('error putting doc ' + doc._id + ': ' + response.body));
});
},
batch: function(doc) {
return this.cot.jsonRequest('POST', '/' + this.name + '?batch=ok', doc)
.then(function(response) {
if (response.statusCode === 202) {
return response.body;
} else if (doc._id) {
throw new Error('error batch posting doc ' + doc._id + ': ' + response.unparsedBody);
} else {
throw new Error('error batch posting new doc: ' + response.unparsedBody);
}

@@ -224,53 +204,46 @@ });

updateDoc: function (docId, fn, next) {
update: function(docId, fn) {
var db = this;
tryIt();
return tryIt();
function tryIt() {
db.getDoc(docId, onGot);
return db.exists(docId)
.then(function(doc) {
return fn(doc || {_id: docId});
})
.then(function(doc) {
return db.put(doc);
})
.then(function(response) {
if (response.ok) {
return response
} else {
return tryIt();
}
});
}
function onGot(err, doc) {
if (err) { next(err); return; }
if (doc === null) {
doc = {_id: docId};
}
fn(doc, onApplied);
}
function onApplied(err, doc) {
if (err) { next(err); return; }
db.putDoc(doc, {conflictOk: true}, onPut);
}
function onPut(err, response) {
if (err) { next(err); return; }
if (response.ok) {
next(null, response);
}
else {
tryIt();
}
}
},
deleteDoc: function (docId, rev, opts, next) {
if (typeof next === 'undefined') {
next = opts;
opts = null;
}
delete: function(docId, rev) {
var url = this.docUrl(docId) + '?rev=' + encodeURIComponent(rev);
this.cot.DELETE(url, null, function (err, response) {
if (err) { next(err); return; }
if (response.statusCode === 200 || (response.statusCode === 409 && opts && opts.conflictOk)) {
next(null, response.json);
return this.cot.jsonRequest('DELETE', url)
.then(function(response) {
if (response.statusCode === 200) {
return response.body;
} else {
throw new Error('error deleting doc ' + docId + ': ' + response.unparsedBody);
}
else {
next(new Error('error deleting doc ' + docId + ': ' + response.body));
});
},
bulk: function(docs) {
var url = '/' + this.name + '/_bulk_docs';
return this.cot.jsonRequest('POST', url, {docs: docs})
.then(function(response) {
if (response.statusCode !== 201) {
throw new Error('error posting to _bulk_docs:' + response.unparsedBody);
} else {
return response.body;
}

@@ -280,17 +253,11 @@ });

viewQuery: function (path, query, next) {
if (typeof next === 'undefined') {
next = query;
query = null;
}
viewQuery: function(path, query) {
query = query || {};
var url = '/' + this.name + '/' + path;
var q = {};
viewQueryKeys.forEach(function (key) {
viewQueryKeys.forEach(function(key) {
if (typeof query[key] !== 'undefined') {
if (key === 'startkey_docid' || key === 'endkey_docid') {
q[key] = query[key];
}
else {
} else {
q[key] = JSON.stringify(query[key]);

@@ -301,69 +268,41 @@ }

this.cot.GET(url + '?' + querystring.stringify(q), null, function (err, response) {
if (err) { next(err); return; }
return this.cot.jsonRequest('GET', url + '?' + querystring.stringify(q))
.then(function(response) {
if (response.statusCode !== 200) {
next(new Error('error reading view ' + path + ': ' + response.body));
throw new Error('error reading view ' + path + ': ' + response.unparsedBody);
} else {
return response.body;
}
else {
next(null, response.json);
}
});
},
view: function (designName, viewName, query, next) {
this.viewQuery('_design/' + designName + '/_view/' + viewName, query, next);
view: function(designName, viewName, query) {
return this.viewQuery('_design/' + designName + '/_view/' + viewName, query);
},
allDocs: function (query, next) {
this.viewQuery('_all_docs', query, next);
allDocs: function(query) {
return this.viewQuery('_all_docs', query);
},
viewKeysQuery: function (path, keys, next) {
viewKeysQuery: function(path, keys) {
var url = '/' + this.name + '/' + path;
this.cot.POST(url, {keys: keys}, null, function (err, response) {
if (err) { next(err); return; }
return this.cot.jsonRequest('POST', url, {keys: keys})
.then(function(response) {
if (response.statusCode !== 200) {
next(new Error('error reading view ' + path + ': ' + response.body));
throw new Error('error reading view ' + path + ': ' + response.unparsedBody);
} else {
return response.body;
}
else {
next(null, response.json);
}
});
},
viewKeys: function (designName, viewName, keys, next) {
this.viewKeysQuery('_design/' + designName + '/_view/' + viewName, keys, next);
viewKeys: function(designName, viewName, keys) {
return this.viewKeysQuery('_design/' + designName + '/_view/' + viewName, keys);
},
allDocsKeys: function (keys, next) {
this.viewKeysQuery('_all_docs', keys, next);
allDocsKeys: function(keys) {
return this.viewKeysQuery('_all_docs', keys);
},
postBulkDocs: function (docs, allOrNothing, next) {
if (typeof next === 'undefined') {
next = allOrNothing;
allOrNothing = false;
}
var url = '/' + this.name + '/_bulk_docs';
this.cot.POST(url, {docs: docs, all_or_nothing: allOrNothing}, null, function (err, response) {
if (err) { next(err); return; }
if (response.statusCode !== 201) {
next(new Error('error posting to _bulk_docs:' + response.body));
}
else {
next(null, response.json);
}
});
},
changes: function (query, next) {
if (typeof next === 'undefined') {
next = query;
query = null;
}
changes: function(query) {
query = query || {};

@@ -381,53 +320,11 @@ var q = {};

this.cot.GET('/' + this.name + '/_changes?' + querystring.stringify(q), null, function (err, response) {
if (err) { next(err); return; }
return this.cot.jsonRequest('GET', '/' + this.name + '/_changes?' + querystring.stringify(q))
.then(function(response) {
if (response.statusCode !== 200) {
next(new Error('error reading _changes: ' + response.body));
throw new Error('error reading _changes: ' + response.unparsedBody);
} else {
return response.body;
}
else {
next(null, response.json);
}
});
}
};
function waitForResponse(request, next) {
next = once(next);
request.on('error', next);
request.on('response', function (response) {
next(null, response);
});
request.end();
}
function readAllText(stream, limit, next) {
next = once(next);
var buffer = '';
stream.encoding = 'utf8';
stream.on('data', function (chunk) {
if (!limit || buffer.length < limit) {
buffer += chunk;
}
});
stream.on('error', next);
stream.on('end', function () {
next(null, buffer);
});
}
function once(f) {
var called = false;
return function() {
if (!called) {
called = true;
return f.apply(this, arguments);
}
};
}
{
"name": "cot",
"description": "bare-bones couchdb interface for node",
"keywords": ["couch", "couchdb"],
"version": "0.0.4",
"description": "promise-based CouchDB library for node with no surprises (in a good way)",
"keywords": ["couch", "couchdb", "promise", "promises"],
"version": "0.0.5",
"main": "cot",
"dependencies": {},
"dependencies": {
"q": "0.9.x"
},
"author": {

@@ -9,0 +11,0 @@ "name": "Will Conant",

# What is Cot? #
Cot is a rather simple but quite pleasant interface for CouchDB. It doesn't attempt to implement everything, but it covers the important stuff for using couch as an effective database.
Cot is a CouchDB library for nodejs with the following benefits:
- It produces promises using the excellent Q module.
- It has clear method names that map almost directly to CouchDB's HTTP API.
- It elminates redundancies in CouchDB's API when there is a clear advantage.
For instance, `post()` treats conflicts as errors, but `put()` treats
conflicts as a normal state that callers can test for.
- It supports view and `_all_docs` queries.
- It supports regular changes queries and long-poll changes queries.
- It doesn't have any weird ORM-like behavior or caching. Documents are just
plain old javascript objects. Revs don't get updated on documents you pass
in.
- It doesn't implement the whole CouchDB API, but it has a generic method adequate
for interacting with any CouchDB URL that expects JSON as input and produces
JSON as output.
# Installing #
npm install cot
# Examples #
Here's a silly example that creates a new document and then updates it:
var Cot = require('cot');
var cot = new Cot({port: 5984, hostname: 'localhost'});
var db = cot.db('my-db');
var db = new Cot({hostname: 'localhost', port: 5984}).db('my-db');
db.getDoc('counter', onGet);
var doc = {
title: 'So yeah, Cot is definitely another CouchDB library'
};
function onGet(err, doc) {
if (err) throw err;
if (doc === null) {
doc = {
_id: 'counter',
count: 0
};
}
doc.count += 1;
db.putDoc(doc, {conflictOk: true}, onPut);
db.post(doc)
.then(function(response) {
doc._id = response.id;
doc._rev = response.rev;
doc.update = 'Time to update this document and save it again!';
return db.post(doc);
})
.then(function(response) {
// let's print out the rev because that would be cool
console.log(response.rev);
})
.fail(function(err) {
// if anything goes wrong, we'll end up here
console.log('errors are lame in examples');
});
Here's an example that increments a counter and is aware of conflicts:
function incrementCounter(docId) {
return db.get(docId)
.then(function(doc) {
doc.counter += 1;
return db.put(doc);
})
.then(function(response) {
if (response.ok) {
return response;
} else {
// there was a conflict... try again
return incrementCounter(docId);
}
})
}
function onPut(err, response) {
if (err) throw err;
if (response.conflict) {
db.getDoc('counter', onGet);
}
else {
console.log('done!');
}
}
There's actually a utility function for an optimistic update loop:
This pattern is very common in CouchDB, so Cot comes with a quicker way to do it:
db.updateDoc('counter', mutate, onUpdate);
function mutate(doc, next) {
doc.count = (doc.count || 0) + 1;
next();
function incrementCounter(docId) {
return db.update(docId, function(doc) {
doc.counter += 1;
return doc;
});
}
function onUpdate(err) {
if (err) throw err;
console.log('done!');
}

@@ -69,36 +97,99 @@ # API Reference #

## db.info(next(err, info)) ##
Queries database info and calls next when done.
## promise = db.info() ##
## db.getDoc(docId, next(err, doc))
`GET /<dbName>`
Gets a doc out of the database. If the doc is missing, err will be null and doc will be null.
## db.getDocWhere(docId, condition(doc), next(err, doc))
## promise = db.get(docId)
Gets a doc out of the database and passes it to condition. If condition returns false, next will be called with doc === null as if the doc did not exist. This is useful for avoiding the easy mistake of writing code that allows access to your entire database:
`GET /<dbName>/<docId>`
db.getDocWhere(query.docId, function(doc) { return doc.isPublic }, onGet);
Missing documents are treated as an error.
## db.putDoc(doc, [opts,] next(err, response))
Attempts to put doc into database. The doc must have an `_id` field. If you expect to handle update conflicts, send {conflictOk: true} in opts. Otherwise, conflicts will be treated as errors. In any case, the response from couch is passed to next so you can retrieve the new rev or detect a conflict if `conflictOk: true`. Response may be something like:
## promise = db.exists(docId)
{ok: true, rev: '2-whatever'}
`GET /<dbName>/<docId>`
Or, in case of a conflict where `conflictOk: true`:
Returns whole document if docId exists and null if docId is missing
{error: 'conflict'}
## db.updateDoc(doc, fn, next(err, response))
## promise = db.post(doc)
Reads doc from the database and calls `fn(doc, cb)`. `fn` may directly mutate doc and call `cb` when done. Then updateDoc will attempt to put the modified document back in the database. If there is an update conflict, the process will start over and repeat until success.
`POST /<dbName>`
## db.deleteDoc(docId, rev, [opts,] next)
Creates a new document or updates an existing document. If `doc._id` is undefined, CouchDB will
generate a new ID for you.
Attempts to delete the document with the specified docId and rev. As with putDoc, you may pass `{conflictOk: true}` in opts.
On 201, returns result from CouchDB which looks like: `{"ok":true, "id":"<docId>", "rev":"<docRev>"}`
## db.view(designName, viewName, query, next(err, response))
All other status codes (including 409, conflict) are treated as errors
## promise = db.put(doc)
`PUT /<dbName>/<doc._id>`
On 409 (conflict) returns result from CouchDB which looks like: `{"error":"conflict"}`
On 201, returns result from CouchDB which looks like: `{"ok":true, "id":"<docId>", "rev":"<docRev>"}`
All other status codes are treated as errors.
## promise = db.batch(doc)
`POST /<dbName>?batch=ok`
Creates or updates a document but doesn't wait for success. Conflicts will not be detected.
On 202, returns result from CouchDB which looks like: `{"ok":true, "id":"<docId>"}`
The rev isn't returned because CouchDB returns before checking for conflicts. If there is a conflict,
the update will be silently lost.
All other status codes are treated as errors.
## promise = db.delete(docId, rev)
`DELETE /<dbName>/<docId>?rev=<rev>`
On 200, returns result from CouchDB which looks like: `{"ok":true, "id":"<docId>", "rev":"<docRev>"}`
All othe status codes are treated as errors.
If you wish to gracefully handle update conflicts while deleting, use `db.put()` on a document with
`_deleted` set to `true`:
doc._deleted = true;
db.put(doc).then(function(response) {
if (!response.ok) {
// there was a conflict
}
});
## promise = db.update(docId, updateFunction)
Gets the specified document, passes it to `updateFunction`, and then saves the results of `updateFunction`
over the document
The process loops if there is an update conflict.
If `updateFunction` needs to do asynchronous work, it may return a promise.
## promise = db.bulk(arrayOfDocs)
`POST /<dbName>/_bulk_docs`
See CouchDB documentation for more information
## promise = db.view(designName, viewName, query)
`GET /<dbName>/_desgin/<designName>/_view/<viewName>?<properly encoded query>`
Queries a view with the given name in the given design doc. `query` should be an object with any of the following keys:

@@ -124,20 +215,22 @@

## db.allDocs(query, next(err, response))
Queries the _all_docs view. `query` supports the same keys as in `db.view`.
## promise = db.allDocs(query)
## db.viewKeys(designName, viewName, keys, next(err, response))
`GET /<dbName>/_all_docs?<properly encoded query>`
Queries the `_all_docs` view. `query` supports the same keys as in `db.view`.
## promise = db.viewKeys(designName, viewName, keys)
Queries the specified keys from the specified view. Keys should be an array of keys.
## db.allDocsKeys(keys, next(err, response))
## promise = db.allDocsKeys(keys)
Loads documents with the specified keys.
## db.postBulkDocs(docs, allOrNothing, next(err, response))
Posts multiple updates to the database in one request. `docs` should be an array of documents. `allOrNothing` should be a boolean. See http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API for more information.
## promise = db.changes(query)
## db.changes(query, next)
Queries the changes feed given the specified query. `query` may contain the following keys:

@@ -144,0 +237,0 @@

@@ -24,34 +24,17 @@ var chai = require('chai');

beforeEach(function(done) {
cot.DELETE('/' + config.dbName, {}, onDelete);
function onDelete(err) {
if (err) {
done(err);
}
else {
cot.PUT('/' + config.dbName, '', {}, onPut);
}
}
function onPut(err) {
if (err) {
done(err);
}
else {
db.putDoc({_id: 'person-1', type: 'person', name: 'Will Conant'}, onPutDoc);
}
}
function onPutDoc(err) {
if (err) {
done(err);
}
else {
db.putDoc({_id: '_design/test', views: {
testView: {
map: 'function(d) { emit(d.name, null) }'
}
}}, done);
}
}
cot.jsonRequest('DELETE', '/' + config.dbName)
.then(function() {
return cot.jsonRequest('PUT', '/' + config.dbName);
})
.then(function() {
return db.post({_id: 'person-1', type: 'person', name: 'Will Conant'});
})
.then(function() {
return db.post({_id: '_design/test', views: {
testView: {
map: 'function(d) { emit(d.name, null) }'
}
}});
})
.nodeify(done);
});

@@ -61,83 +44,95 @@

it('should return database info', function(done) {
db.info(onInfo);
function onInfo(err, info) {
if (err) {
done(err);
}
else {
expect(info).to.be.a('object');
expect(info.doc_count).to.equal(2);
done();
}
}
db.info()
.then(function(info) {
expect(info).to.be.a('object');
expect(info.doc_count).to.equal(2);
})
.nodeify(done);
});
});
describe('#getDoc', function() {
describe('#get', function() {
it('should return test document from database', function(done) {
db.getDoc('person-1', onGet);
function onGet(err, doc) {
if (err) {
done(err);
}
else {
expect(doc).to.be.a('object');
expect(doc.name).to.equal('Will Conant');
done();
}
}
db.get('person-1')
.then(function(doc) {
expect(doc).to.be.a('object');
expect(doc.name).to.equal('Will Conant');
})
.nodeify(done);
});
});
describe('#getDocWhere', function() {
it('should return null when condition does not match', function(done) {
db.getDocWhere('person-1', function(doc) { return doc.type === 'clown' }, onGetDoc)
function onGetDoc(err, doc) {
if (err) {
done(err);
}
else {
expect(doc).to.be.null;
done();
}
}
describe('#view', function() {
it('should return a single row', function(done) {
db.view('test', 'testView', {})
.then(function(response) {
expect(response).to.be.object;
expect(response.rows).to.be.array;
expect(response.rows.length).to.equal(1);
expect(response.rows[0].key).to.equal('Will Conant');
})
.nodeify(done);
});
it('should return doc when condition matches', function(done) {
db.getDocWhere('person-1', function(doc) { return doc.type === 'person' }, onGetDoc)
function onGetDoc(err, doc) {
if (err) {
done(err);
}
else {
expect(doc).to.be.a('object');
expect(doc.name).to.equal('Will Conant');
done();
}
}
});
describe('#put', function() {
it('should treat conflicts as expected', function(done) {
var doc = {_id: 'put-test'};
db.put(doc)
.then(function(response) {
return db.put(doc);
})
.then(function(response) {
expect(response.error).to.equal('conflict');
})
.nodeify(done);
});
});
describe('#view', function() {
it('should return a single row', function(done) {
db.view('test', 'testView', {}, onView);
function onView(err, response) {
if (err) {
done(err)
}
else {
expect(response).to.be.object;
expect(response.rows).to.be.array;
expect(response.rows.length).to.equal(1);
expect(response.rows[0].key).to.equal('Will Conant');
done();
}
}
describe('#post', function() {
it('should treat conflicts as errors', function(done) {
var doc = {_id: 'post-test'};
db.post(doc)
.then(function(response) {
return db.post(doc);
})
.then(function(response) {
done(new Error('should not have resolved'));
})
.fail(function() {
done();
})
.done();
});
});
describe('#batch', function() {
it('should ignore conflicts', function(done) {
var doc = {_id: 'batch-test'};
var origRev;
db.post(doc)
.then(function(response) {
origRev = response.rev;
return db.batch(doc);
})
.delay(100)
.then(function(response) {
return db.get(doc._id);
})
.then(function(response) {
expect(response._rev).to.equal(origRev);
})
.nodeify(done);
});
});
describe('#exists', function() {
it('should return null for nonexistent doc', function(done) {
db.exists('does-not-exist')
.then(function(doc) {
expect(doc).to.be.null;
})
.nodeify(done);
});
});
});

@@ -5,2 +5,3 @@ var chai = require('chai');

var config = require('./config');
var Q = require('q');

@@ -12,33 +13,22 @@ describe('DbHandle', function() {

beforeEach(function(done) {
cot.DELETE('/' + config.dbName, {}, thenPutDB);
function thenPutDB(err) {
if (err) {
done(err);
cot.jsonRequest('DELETE', '/' + config.dbName)
.then(function() {
return cot.jsonRequest('PUT', '/' + config.dbName);
})
.then(function() {
var docPromises = [];
for (var i = 1; i < 10; i++) {
docPromises.push(db.post({_id: 'doc-' + i, key: 'key-' + i}));
}
else {
cot.PUT('/' + config.dbName, '', {}, thenPutDoc);
}
}
var docNumber = 0;
function thenPutDoc(err) {
if (err) {
done(err);
}
else {
docNumber += 1;
if (docNumber === 10) {
db.putDoc({_id: '_design/test', views: {
testView: {
map: 'function(d) { emit(d.key, null); emit("z", null); }'
}
}}, done);
}
else {
db.putDoc({_id: 'doc-' + docNumber, key: 'key-' + docNumber}, thenPutDoc);
}
}
}
var designDoc = {_id: '_design/test', views: {
testView: {
map: 'function(d) { emit(d.key, null); emit("z", null); }'
}
}};
docPromises.push(db.post(designDoc));
return Q.all(docPromises);
})
.nodeify(done);
});

@@ -48,19 +38,13 @@

it('should return doc-3 thru doc-6 using startkey_docid and endkey_docid', function(done) {
db.view('test', 'testView', {key: 'z', startkey_docid: 'doc-3', endkey_docid: 'doc-6'}, onView);
function onView(err, response) {
if (err) {
done(err)
}
else {
expect(response.rows.length).to.equal(4);
expect(response.rows[0].id).to.equal('doc-3');
expect(response.rows[1].id).to.equal('doc-4');
expect(response.rows[2].id).to.equal('doc-5');
expect(response.rows[3].id).to.equal('doc-6');
done();
}
}
db.view('test', 'testView', {key: 'z', startkey_docid: 'doc-3', endkey_docid: 'doc-6'})
.then(function(response) {
expect(response.rows.length).to.equal(4);
expect(response.rows[0].id).to.equal('doc-3');
expect(response.rows[1].id).to.equal('doc-4');
expect(response.rows[2].id).to.equal('doc-5');
expect(response.rows[3].id).to.equal('doc-6');
})
.nodeify(done);
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc