Skip to content

Commit

Permalink
WIP - (pouchdb/express-pouchdb#232) - Modernize pouchdb-list
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-de-vries committed Dec 21, 2015
1 parent d135c6f commit 5bb5f98
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 37 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
dist
node_modules
dist
coverage

29 changes: 29 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
sudo: false
language: node_js

cache:
directories:
- node_modules

node_js:
- "0.10"

services:
- couchdb

before_install:
- npm i -g npm@^2.0.0

before_script:
- npm prune

script: npm run $COMMAND

env:
matrix:
- COMMAND='helper -- lint'
- COMMAND='helper -- js-test'
- COMMAND='build'

#after_success:
# - npm run helper -- semantic-release
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,45 @@
pouchdb-list
============

[![Build Status](https://travis-ci.org/pouchdb/pouchdb-list.svg?branch=master)](https://travis-ci.org/pouchdb/pouchdb-list)
[![Dependency Status](https://david-dm.org/pouchdb/pouchdb-list.svg)](https://david-dm.org/pouchdb/pouchdb-list)
[![devDependency Status](https://david-dm.org/pouchdb/pouchdb-list/dev-status.svg)](https://david-dm.org/pouchdb/pouchdb-list#info=devDependencies)

A PouchDB plug-in that allows you to re-use your CouchDB list functions
on the client side. A browser version is available.

See also [pouchdb-list's documentation](http://pythonhosted.org/Python-PouchDB/js-plugins.html#pouchdb-list-plug-in)
TODO: integrate, update & make nice:
```rst
.. _pouchdb-list-plug-in:
PouchDB List plug-in
====================
+----------------------+-----------------+
| NodeJS package name: | `pouchdb-list`_ |
+----------------------+-----------------+
| Browser object name: | ``window.List`` |
+----------------------+-----------------+
First, make sure you understand how list functions work in CouchDB. A
good start is `the CouchDB guide entry on lists`_.
.. _pouchdb-list: https://www.npmjs.org/package/pouchdb-list
.. _the CouchDB guide entry on lists: http://guide.couchdb.org/draft/transforming.html
.. js:function:: List.list(listPath[, options[, callback]])
Runs a list function on a view. Both are specified via the
``listPath`` parameter.
:param string listPath: a url of the form
``"designDocName/listFuncName/viewName"``
:param object options: this object is supplemented with defaults
until a complete `CouchDB request object`_ has been formed, which
is then passed into the list function.
:returns: When succesful, the list function's result in the form of a
`CouchDB response object`_. Otherwise, an error object with one
of the following statuses: 400, 404, 406 or 500.
[Website of this plug-in and a few others](http://python-pouchdb.marten-de-vries.nl/plugins.html)
.. _CouchDB request object: http://docs.couchdb.org/en/latest/json-structure.html#request-object
.. _CouchDB response object: http://docs.couchdb.org/en/latest/json-structure.html#response-object
```
69 changes: 35 additions & 34 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
{
"name": "pouchdb-list",
"version": "1.0.6",
"main": "index.json",
"description": "A PouchDB plug-in that allows you to re-use your CouchDB list functions on the client side.",
"repository": "pouchdb/pouchdb-list",
"homepage": "http://python-pouchdb.marten-de-vries.nl/plugins.html",
"keywords": [
"pouch",
"pouchdb",
"couch",
"couchdb",
"list",
"design"
],
"license": "Apache-2.0",
"author": "Marten de Vries",
"dependencies": {
"extend": "^1.2.1",
"couchdb-objects": "^1.0.0",
"couchdb-render": "^1.0.0",
"pouchdb-req-http-query": "^1.0.0",
"promise-nodify": "^1.0.0",
"pouchdb-promise": "^0.0.0",
"pouchdb-plugin-error": "^1.0.0"
},
"devDependencies": {
"browserify": "^4.1.8",
"uglify-js": "^2.4.13",
"es3ify": "^0.1.3"
},
"scripts": {
"build-js": "mkdir -p dist && browserify index.js -g es3ify -s List -o dist/pouchdb-list.js",
"build": "npm run build-js; cd dist; uglifyjs pouchdb-list.js -mc > pouchdb-list.min.js"
}
"name": "pouchdb-list",
"version": "1.0.6",
"main": "index.json",
"description": "A PouchDB plug-in that allows you to re-use your CouchDB list functions on the client side.",
"repository": {
"type": "git",
"url": "https://github.com/pouchdb/pouchdb-list.git"
},
"keywords": [
"pouch",
"pouchdb",
"couch",
"couchdb",
"list",
"design"
],
"license": "Apache-2.0",
"author": "Marten de Vries",
"dependencies": {
"extend": "^1.2.1",
"couchdb-objects": "^1.0.0",
"couchdb-render": "^1.0.0",
"pouchdb-req-http-query": "^1.0.0",
"promise-nodify": "^1.0.0",
"pouchdb-promise": "^0.0.0",
"pouchdb-plugin-error": "^1.0.0"
},
"devDependencies": {
"pouchdb-plugin-helper": "^2.0.0"
},
"scripts": {
"helper": "./node_modules/.bin/pouchdb-plugin-helper",
"test": "npm run helper -- test",
"build": "npm run helper -- build List"
}
}
106 changes: 106 additions & 0 deletions test/features.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {setup, teardown, listDocument, shouldThrowError} from './utils';

let db;

describe('Async list tests', () => {
beforeEach(done => {
db = setup();
function ddocCb() {
db.put({_id: 'testdoc'}, done);
}
db.put(listDocument, ddocCb);
});
afterEach(teardown);
/*
def testArgs(self):
def cb(err, resp):
head, req = json.loads(resp.body)["args"]
self.assertEqual(head["offset"], 0)
self.assertIsNone(req["id"])
self.assertEqual(req["query"]["a"], "b")
self._db.list("test/args/ids", cb, query={"a": "b"})
self.waitUntilCalled(cb)
*/
});

describe('Sync list tests with empty design docs', () => {
beforeEach(async () => {
db = setup();
await db.put({_id: '_design/test'});
});
afterEach(teardown);

it('test', async () => {
const err = await shouldThrowError(async () => {
await db.list('test/test/test');
});
err.status.should.equal(404);
err.name.should.equal('not_found');
});
});

describe('Sync list tests', () => {
beforeEach(async () => {
db = setup();
await db.put(listDocument);
await db.put({_id: 'testdoc'});
});
afterEach(teardown);

/*
def testCouchEval(self):
resp = self._db.list("test/test-coucheval/ids")
self.assertEqual(resp["code"], 200)
self.assertEqual(resp["body"], "6 - Hello World!")
def testArgs(self):
resp = self._db.list("test/args/ids", query={"a": "b"})
head, req = json.loads(resp.body)["args"]
self.assertEqual(head["offset"], 0)
self.assertEqual(head["total_rows"], 1)
self.assertIsNone(req["id"])
self.assertEqual(req["raw_path"], "/test/_design/test/_list/args/ids?a=b")
self.assertEqual(req["requested_path"], ["test", "_design", "test", "_list", "args", "ids?a=b"])
self.assertEqual(req["path"], ["test", "_design", "test", "_list", "args", "ids"])
#and one at random, to check if the rest (shared with show) is still ok.
self.assertEqual(req["peer"], "127.0.0.1")
def testUnexistingDesignDoc(self):
with self.assertRaises(pouchdb.PouchDBError) as cm:
self._db.list("unexisting/args/ids")
self.assertEqual(cm.exception["name"], "not_found")
def testUnexistingListFunc(self):
with self.assertRaises(pouchdb.PouchDBError) as cm:
self._db.list("test/unexisting/ids")
self.assertTrue(str(cm.exception))
self.assertEqual(cm.exception["name"], "not_found")
self.assertEqual(cm.exception["message"], "missing list function unexisting on design doc _design/test")
def testUnexistingView(self):
with self.assertRaises(pouchdb.PouchDBError) as cm:
self._db.list("test/args/unexisting")
self.assertEqual(cm.exception["name"], "not_found")
def testListApi(self):
resp = self._db.list("test/use-list-api/ids")
self.assertEqual(resp["headers"]["Transfer-Encoding"], "chunked")
self.assertEqual(resp["code"], 500)
row1, row2 = resp.body.split("\n")
self.assertEqual(json.loads(row1), {"id": "testdoc", "key": "testdoc", "value": "value"})
self.assertEqual(row2, "testHello World!")
def testWrongContentType(self):
"""CouchDB only supports application/json here. It's a CouchDB
restriction: probably best to emulate it...
"""
with self.assertRaises(pouchdb.PouchDBError) as cm:
self._db.list("test/args/ids", headers={"Content-Type": "application/x-www-form-urlencoded"}, body="hello=world")
self.assertEqual(cm.exception["status"], 400)
self.assertEqual(cm.exception["name"], "bad_request")
self.assertEqual(cm.exception["message"], "invalid_json")
*/
});
42 changes: 42 additions & 0 deletions test/http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {setupHTTP, teardown, listDocument, shouldThrowError, should} from './utils';

let db;

describe('http', () => {
beforeEach(async () => {
db = setupHTTP();
await db.put(listDocument);
});
afterEach(teardown);

it('list basics', async () => {
const resp = await db.list('test/args/ids', {query: {a: 'b'}});

const [head, req] = JSON.parse(resp.body).args;
head.offset.should.equal(0);
head.total_rows.should.equal(0);

should.equal(req.id, null);
req.raw_path.should.equal('/pouchdb-plugin-helper-db/_design/test/_list/args/ids?a=b');
req.requested_path.should.eql(['pouchdb-plugin-helper-db', '_design', 'test', '_list', 'args', 'ids?a=b']);
req.path.should.eql(['pouchdb-plugin-helper-db', '_design', 'test', '_list', 'args', 'ids']);
// and one at random, to check if the rest (shared with show) is still ok.
req.peer.should.equal('127.0.0.1');
});

it('wrong list content type', async () => {
// CouchDB only supports application/json here. It's a CouchDB restriction:
// this check is here in case it ever changes. - then PouchDB-List's
// simulation of it can stop.

const err = await shouldThrowError(async () => {
await db.list('test/args/ids', {
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body:'value=hello'
});
});
err.status.should.equal(400);
err.name.should.equal('bad_request');
err.message.should.equal('invalid_json');
})
});
15 changes: 15 additions & 0 deletions test/signatures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {setup, teardown} from './utils';

let db;

describe('signatures', () => {
beforeEach(() => {
db = setup();
});
afterEach(teardown);
it('list', () => {
const promise = db.list('test/test/test', () => {});
promise.then.should.be.ok;
promise.catch.should.be.ok;
});
});
36 changes: 36 additions & 0 deletions test/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import stuff from 'pouchdb-plugin-helper/testutils';
import List from '../';

stuff.PouchDB.plugin(List);

stuff.listDocument = {
_id: '_design/test',
views: {
ids: {
map: `function (doc) {
emit(doc._id, "value");
}`
}
},
lists: {
args: `function (head, req) {
return toJSON({args: [head, req]});
}`,
'use-list-api': `function (head, req) {
start({code: 500});
send(JSON.stringify(getRow()));
send("\\n");
send("test");
return "Hello World!";
}`,
'test-coucheval': `function (head, req) {
var result = sum([1, 2, 3]);
return result + " - " + require("lib/thingy").data;
}`
},
lib: {
thingy: `exports.data = 'Hello World!';`
}
};

module.exports = stuff;

0 comments on commit 5bb5f98

Please sign in to comment.