You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by gl...@apache.org on 2020/02/12 11:25:55 UTC
[couchdb-nano] 07/15: design functions
This is an automated email from the ASF dual-hosted git repository.
glynnbird pushed a commit to branch jest
in repository https://gitbox.apache.org/repos/asf/couchdb-nano.git
commit 47c985b042fb80c4fd05ba318b99d794c2ba0edd
Author: Glynn Bird <gl...@gmail.com>
AuthorDate: Fri Feb 7 10:18:49 2020 +0000
design functions
---
lib/nano.js | 53 ++++++++++--
test/design.atomic.test.js | 94 +++++++++++++++++++++
test/design.createIndex.test.js | 82 +++++++++++++++++++
test/design.find.test.js | 83 +++++++++++++++++++
test/design.findAsStream.test.js | 56 +++++++++++++
test/design.search.test.js | 72 ++++++++++++++++
test/design.searchAsStream.test.js | 46 +++++++++++
test/design.show.test.js | 66 +++++++++++++++
test/design.view.test.js | 164 +++++++++++++++++++++++++++++++++++++
test/design.viewAsStream.test.js | 43 ++++++++++
10 files changed, 753 insertions(+), 6 deletions(-)
diff --git a/lib/nano.js b/lib/nano.js
index 7b63bc3..6af0e37 100644
--- a/lib/nano.js
+++ b/lib/nano.js
@@ -677,8 +677,8 @@ module.exports = exports = function dbScope (cfg) {
const { opts, callback } = getCallback(qs0, callback0)
if (!docNames || typeof docNames !== 'object' ||
- !docNames.keys || !Array.isArray(docNames.keys) ||
- docNames.keys.length === 0) {
+ !docNames.keys || !Array.isArray(docNames.keys) ||
+ docNames.keys.length === 0) {
const e = new Error('Invalid keys')
if (callback) {
return callback(e, null)
@@ -698,6 +698,15 @@ module.exports = exports = function dbScope (cfg) {
function view (ddoc, viewName, meta, qs0, callback0) {
const { opts, callback } = getCallback(qs0, callback0)
+ if (!ddoc || !viewName) {
+ const e = new Error('Invalid view')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
+
if (typeof meta.stream !== 'boolean') {
meta.stream = false
}
@@ -776,6 +785,14 @@ module.exports = exports = function dbScope (cfg) {
// http://docs.couchdb.org/en/latest/api/ddoc/render.html#get--db-_design-ddoc-_show-func
function showDoc (ddoc, viewName, docName, qs, callback) {
+ if (!ddoc || !viewName || !docName) {
+ const e = new Error('Invalid show')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
return view(ddoc, viewName + '/' + docName, { type: 'show' }, qs, callback)
}
@@ -785,6 +802,14 @@ module.exports = exports = function dbScope (cfg) {
callback = body
body = undefined
}
+ if (!ddoc || !viewName || !docName) {
+ const e = new Error('Invalid update')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
return view(ddoc, viewName + '/' + encodeURIComponent(docName), {
type: 'update',
method: 'PUT',
@@ -925,26 +950,42 @@ module.exports = exports = function dbScope (cfg) {
}, callback)
}
- function find (selector, callback) {
+ function find (query, callback) {
+ if (!query || typeof query !== 'object') {
+ const e = new Error('Invalid query')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
return relax({
db: dbName,
path: '_find',
method: 'POST',
- body: selector
+ body: query
}, callback)
}
- function findAsStream (selector) {
+ function findAsStream (query) {
return relax({
db: dbName,
path: '_find',
method: 'POST',
- body: selector,
+ body: query,
stream: true
})
}
function createIndex (indexDef, callback) {
+ if (!indexDef || typeof indexDef !== 'object') {
+ const e = new Error('Invalid index definition')
+ if (callback) {
+ return callback(e, null)
+ } else {
+ return Promise.reject(e)
+ }
+ }
return relax({
db: dbName,
path: '_index',
diff --git a/test/design.atomic.test.js b/test/design.atomic.test.js
new file mode 100644
index 0000000..95c37fa
--- /dev/null
+++ b/test/design.atomic.test.js
@@ -0,0 +1,94 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to use an update function - PUT /db/_design/ddoc/_update/updatename/docid - db.atomic', async () => {
+ const updateFunction = function (doc, req) {
+ if (doc) {
+ doc.ts = new Date().getTime()
+ }
+ return [doc, { json: { status: 'ok' } }]
+ }
+ const response = updateFunction({})[1].json
+
+ // mocks
+ const scope = nock(COUCH_URL)
+ .put('/db/_design/ddoc/_update/updatename/docid')
+ .reply(200, response)
+
+ // test POST /db/_find
+ const db = nano.db.use('db')
+ const p = await db.atomic('ddoc', 'updatename', 'docid')
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to use an update function with body - PUT /db/_design/ddoc/_update/updatename/docid - db.atomic', async () => {
+ const updateFunction = function (doc, req) {
+ if (doc) {
+ doc.ts = new Date().getTime()
+ }
+ return [doc, { json: { status: 'ok' } }]
+ }
+ const body = { a: 1, b: 2 }
+ const response = updateFunction({})[1].json
+
+ // mocks
+ const scope = nock(COUCH_URL)
+ .put('/db/_design/ddoc/_update/updatename/docid', body)
+ .reply(200, response)
+
+ // test POST /db/_find
+ const db = nano.db.use('db')
+ const p = await db.atomic('ddoc', 'updatename', 'docid', body)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 404 - db.atomic', async () => {
+ // mocks
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const body = { a: 1, b: 2 }
+ const scope = nock(COUCH_URL)
+ .put('/db/_design/ddoc/_update/updatename/docid', body)
+ .reply(404, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ await expect(db.atomic('ddoc', 'updatename', 'docid', body)).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing parameters - db.update', async () => {
+ const db = nano.db.use('db')
+ await expect(db.atomic()).rejects.toThrow('Invalid update')
+ await expect(db.atomic('ddoc')).rejects.toThrow('Invalid update')
+ await expect(db.atomic('ddoc', 'updatename')).rejects.toThrow('Invalid update')
+ await expect(db.atomic('', 'updatename', 'docid')).rejects.toThrow('Invalid update')
+})
+
+test('should detect missing parameters (callback) - db.update', async () => {
+ const db = nano.db.use('db')
+ return new Promise((resolve, reject) => {
+ db.atomic('', '', '', {}, (err, data) => {
+ expect(err).not.toBeNull()
+ resolve()
+ })
+ })
+})
diff --git a/test/design.createIndex.test.js b/test/design.createIndex.test.js
new file mode 100644
index 0000000..1c7e7a5
--- /dev/null
+++ b/test/design.createIndex.test.js
@@ -0,0 +1,82 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to create an index - POST /db/_index - db.index', async () => {
+ // mocks
+ const indexDef = {
+ index: {
+ fields: ['town', 'surname']
+ },
+ type: 'json',
+ name: 'townsurnameindex',
+ partitioned: false
+ }
+ const response = {
+ result: 'created',
+ id: '_design/a5f4711fc9448864a13c81dc71e660b524d7410c',
+ name: 'foo-index'
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_index', indexDef)
+ .reply(200, response)
+
+ // test POST /db/_index
+ const db = nano.db.use('db')
+ const p = await db.createIndex(indexDef)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should handle 404 - POST /db/_index - db.index', async () => {
+ // mocks
+ const indexDef = {
+ index: {
+ fields: ['town', 'surname']
+ },
+ type: 'json',
+ name: 'townsurnameindex',
+ partitioned: false
+ }
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_index', indexDef)
+ .reply(404, response)
+
+ // test POST /db/_index
+ const db = nano.db.use('db')
+ await expect(db.createIndex(indexDef)).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing index - db.createIndex', async () => {
+ const db = nano.db.use('db')
+ await expect(db.createIndex()).rejects.toThrow('Invalid index definition')
+ await expect(db.createIndex('myindex')).rejects.toThrow('Invalid index definition')
+})
+
+test('should detect missing index (callback) - db.createIndex', async () => {
+ const db = nano.db.use('db')
+ return new Promise((resolve, reject) => {
+ db.createIndex('', (err, data) => {
+ expect(err).not.toBeNull()
+ resolve()
+ })
+ })
+})
diff --git a/test/design.find.test.js b/test/design.find.test.js
new file mode 100644
index 0000000..39bf9d3
--- /dev/null
+++ b/test/design.find.test.js
@@ -0,0 +1,83 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to query an index - POST /db/_find - db.find', async () => {
+ // mocks
+ const query = {
+ selector: {
+ $and: {
+ date: {
+ $gt: '2018'
+ },
+ name: 'Susan'
+ }
+ },
+ fields: ['name', 'date', 'orderid']
+ }
+ const response = {
+ docs: [
+ { name: 'Susan', date: '2019-01-02', orderid: '4411' },
+ { name: 'Susan', date: '2019-01-03', orderid: '8523' }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_find', query)
+ .reply(200, response)
+
+ // test POST /db/_find
+ const db = nano.db.use('db')
+ const p = await db.find(query)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should handle 404 - POST /db/_find - db.find', async () => {
+ // mocks
+ const query = {
+ selector: {
+ name: 'Susan'
+ }
+ }
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_find', query)
+ .reply(404, response)
+
+ // test POST /db/_find
+ const db = nano.db.use('db')
+ await expect(db.find(query)).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing query - db.find', async () => {
+ const db = nano.db.use('db')
+ await expect(db.find()).rejects.toThrow('Invalid query')
+ await expect(db.find('susan')).rejects.toThrow('Invalid query')
+})
+
+test('should detect missing query (callback) - db.find', async () => {
+ const db = nano.db.use('db')
+ return new Promise((resolve, reject) => {
+ db.find('', (err, data) => {
+ expect(err).not.toBeNull()
+ resolve()
+ })
+ })
+})
diff --git a/test/design.findAsStream.test.js b/test/design.findAsStream.test.js
new file mode 100644
index 0000000..b330779
--- /dev/null
+++ b/test/design.findAsStream.test.js
@@ -0,0 +1,56 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to query an index as a stream- POST /db/_find - db.findAsStream', async () => {
+ // mocks
+ const query = {
+ selector: {
+ $and: {
+ date: {
+ $gt: '2018'
+ },
+ name: 'Susan'
+ }
+ },
+ fields: ['name', 'date', 'orderid']
+ }
+ const response = {
+ docs: [
+ { name: 'Susan', date: '2019-01-02', orderid: '4411' },
+ { name: 'Susan', date: '2019-01-03', orderid: '8523' }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_find', query)
+ .reply(200, response)
+
+ return new Promise((resolve, reject) => {
+ // test POST /db/_find
+ const db = nano.db.use('db')
+ const s = db.findAsStream(query)
+ expect(typeof s).toBe('object')
+ let buffer = ''
+ s.on('data', (chunk) => {
+ buffer += chunk.toString()
+ })
+ s.on('end', () => {
+ expect(buffer).toBe(JSON.stringify(response))
+ expect(scope.isDone()).toBe(true)
+ resolve()
+ })
+ })
+})
diff --git a/test/design.search.test.js b/test/design.search.test.js
new file mode 100644
index 0000000..92be672
--- /dev/null
+++ b/test/design.search.test.js
@@ -0,0 +1,72 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to access a search index - GET /db/_design/ddoc/_search/searchname - db.search', async () => {
+ // mocks
+ const response = {
+ total_rows: 100000,
+ bookmark: 'g123',
+ rows: [
+ { a: 1, b: 2 }
+ ]
+ }
+ const params = { q: '*:*' }
+ const scope = nock(COUCH_URL)
+ .post('/db/_design/ddoc/_search/searchname', params)
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.search('ddoc', 'searchname', params)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 404 - db.search', async () => {
+ // mocks
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const params = { q: '*:*' }
+ const scope = nock(COUCH_URL)
+ .post('/db/_design/ddoc/_search/searchname', params)
+ .reply(404, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ await expect(db.search('ddoc', 'searchname', params)).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing parameters - db.search', async () => {
+ const db = nano.db.use('db')
+ await expect(db.search()).rejects.toThrow('Invalid view')
+ await expect(db.search('susan')).rejects.toThrow('Invalid view')
+ await expect(db.search('susan', '')).rejects.toThrow('Invalid view')
+ await expect(db.search('', 'susan')).rejects.toThrow('Invalid view')
+})
+
+test('should detect missing parameters (callback) - db.search', async () => {
+ const db = nano.db.use('db')
+ return new Promise((resolve, reject) => {
+ db.search('', '', (err, data) => {
+ expect(err).not.toBeNull()
+ resolve()
+ })
+ })
+})
diff --git a/test/design.searchAsStream.test.js b/test/design.searchAsStream.test.js
new file mode 100644
index 0000000..d86f35d
--- /dev/null
+++ b/test/design.searchAsStream.test.js
@@ -0,0 +1,46 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to access a search index as a stream - POST /db/_design/ddoc/_search/searchname - db.searchAsStream', async () => {
+ // mocks
+ const response = {
+ total_rows: 100000,
+ bookmark: 'g123',
+ rows: [
+ { a: 1, b: 2 }
+ ]
+ }
+ const params = { q: '*:*' }
+ const scope = nock(COUCH_URL)
+ .post('/db/_design/ddoc/_search/searchname', params)
+ .reply(200, response)
+
+ return new Promise((resolve, reject) => {
+ const db = nano.db.use('db')
+ const s = db.searchAsStream('ddoc', 'searchname', params)
+ expect(typeof s).toBe('object')
+ let buffer = ''
+ s.on('data', (chunk) => {
+ buffer += chunk.toString()
+ })
+ s.on('end', () => {
+ expect(buffer).toBe(JSON.stringify(response))
+ expect(scope.isDone()).toBe(true)
+ resolve()
+ })
+ })
+})
diff --git a/test/design.show.test.js b/test/design.show.test.js
new file mode 100644
index 0000000..258f1bb
--- /dev/null
+++ b/test/design.show.test.js
@@ -0,0 +1,66 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to use a show function - GET /db/_design/ddoc/_show/showname/docid - db.show', async () => {
+ const showFunction = function (doc, req) {
+ return 'Hello, world!'
+ }
+ // mocks
+ const scope = nock(COUCH_URL)
+ .get('/db/_design/ddoc/_show/showname/docid')
+ .reply(200, showFunction(), { 'Content-type': 'text/plain' })
+
+ // test POST /db/_find
+ const db = nano.db.use('db')
+ const p = await db.show('ddoc', 'showname', 'docid')
+ expect(p).toStrictEqual(showFunction())
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 404 - db.show', async () => {
+ // mocks
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_design/ddoc/_show/showname/docid')
+ .reply(404, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ await expect(db.show('ddoc', 'showname', 'docid')).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing parameters - db.show', async () => {
+ const db = nano.db.use('db')
+ await expect(db.show()).rejects.toThrow('Invalid show')
+ await expect(db.show('ddoc')).rejects.toThrow('Invalid show')
+ await expect(db.show('ddoc', 'showname')).rejects.toThrow('Invalid show')
+ await expect(db.show('', 'showname', 'docid')).rejects.toThrow('Invalid show')
+})
+
+test('should detect missing parameters (callback) - db.show', async () => {
+ const db = nano.db.use('db')
+ return new Promise((resolve, reject) => {
+ db.show('', '', '', {}, (err, data) => {
+ expect(err).not.toBeNull()
+ resolve()
+ })
+ })
+})
diff --git a/test/design.view.test.js b/test/design.view.test.js
new file mode 100644
index 0000000..767b4f9
--- /dev/null
+++ b/test/design.view.test.js
@@ -0,0 +1,164 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to access a MapReduce view - GET /db/_design/ddoc/_view/viewname - db.view', async () => {
+ // mocks
+ const response = {
+ rows: [
+ { key: null, value: 23515 }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_design/ddoc/_view/viewname')
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.view('ddoc', 'viewname')
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to access a MapReduce view with opts - GET /db/_design/ddoc/_view/viewname - db.view', async () => {
+ // mocks
+ const response = {
+ rows: [
+ { key: 'BA', value: 21 },
+ { key: 'BB', value: 1 },
+ { key: 'BD', value: 98 },
+ { key: 'BE', value: 184 },
+ { key: 'BF', value: 32 },
+ { key: 'BG', value: 55 },
+ { key: 'BH', value: 8 },
+ { key: 'BI', value: 10 },
+ { key: 'BJ', value: 29 },
+ { key: 'BL', value: 1 },
+ { key: 'BM', value: 1 },
+ { key: 'BN', value: 4 },
+ { key: 'BO', value: 27 },
+ { key: 'BQ', value: 1 }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_design/ddoc/_view/viewname?group=true&startkey="BA"&endkey="BQ"')
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.view('ddoc', 'viewname', { group: true, startkey: 'BA', endkey: 'BQ' })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to access a MapReduce view with keys - POST /db/_design/ddoc/_view/viewname - db.view', async () => {
+ // mocks
+ const keys = ['BA', 'BD']
+ const response = {
+ rows: [
+ { key: 'BA', value: 21 },
+ { key: 'BB', value: 1 }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_design/ddoc/_view/viewname', { keys: keys })
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.view('ddoc', 'viewname', { keys: keys })
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to access a MapReduce view with queries - POST /db/_design/ddoc/_view/viewname - db.view', async () => {
+ // mocks
+ const opts = {
+ queries: [
+ {
+ keys: [
+ 'BA',
+ 'BD'
+ ]
+ },
+ {
+ limit: 1,
+ skip: 2,
+ reduce: false
+ }
+ ]
+ }
+ const response = {
+ results: [
+ {
+ rows: [
+ { key: 'BA', value: 21 },
+ { key: 'BB', value: 1 }
+ ]
+ },
+ {
+ total_rows: 23515,
+ offset: 2,
+ rows: [
+ { id: '290594', key: 'AE', value: 1 }
+ ]
+ }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .post('/db/_design/ddoc/_view/viewname', { queries: opts.queries })
+ .reply(200, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ const p = await db.view('ddoc', 'viewname', opts)
+ expect(p).toStrictEqual(response)
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should be able to handle 404 - db.view', async () => {
+ // mocks
+ const response = {
+ error: 'not_found',
+ reason: 'missing'
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_design/ddoc/_view/viewname?group=true&startkey="BA"&endkey="BQ"')
+ .reply(404, response)
+
+ // test GET /db
+ const db = nano.db.use('db')
+ await expect(db.view('ddoc', 'viewname', { group: true, startkey: 'BA', endkey: 'BQ' })).rejects.toThrow('missing')
+ expect(scope.isDone()).toBe(true)
+})
+
+test('should detect missing parameters - db.view', async () => {
+ const db = nano.db.use('db')
+ await expect(db.view()).rejects.toThrow('Invalid view')
+ await expect(db.view('susan')).rejects.toThrow('Invalid view')
+ await expect(db.view('susan', '')).rejects.toThrow('Invalid view')
+ await expect(db.view('', 'susan')).rejects.toThrow('Invalid view')
+})
+
+test('should detect missing parameters (callback) - db.view', async () => {
+ const db = nano.db.use('db')
+ return new Promise((resolve, reject) => {
+ db.view('', '', (err, data) => {
+ expect(err).not.toBeNull()
+ resolve()
+ })
+ })
+})
diff --git a/test/design.viewAsStream.test.js b/test/design.viewAsStream.test.js
new file mode 100644
index 0000000..e332897
--- /dev/null
+++ b/test/design.viewAsStream.test.js
@@ -0,0 +1,43 @@
+// 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.
+
+const Nano = require('..')
+const COUCH_URL = 'http://localhost:5984'
+const nano = Nano(COUCH_URL)
+const nock = require('nock')
+
+test('should be able to access a MapReduce view as a stream - GET /db/_design/ddoc/_view/viewname - db.viewAsStream', async () => {
+ // mocks
+ const response = {
+ rows: [
+ { key: null, value: 23515 }
+ ]
+ }
+ const scope = nock(COUCH_URL)
+ .get('/db/_design/ddoc/_view/viewname')
+ .reply(200, response)
+
+ return new Promise((resolve, reject) => {
+ const db = nano.db.use('db')
+ const s = db.viewAsStream('ddoc', 'viewname')
+ expect(typeof s).toBe('object')
+ let buffer = ''
+ s.on('data', (chunk) => {
+ buffer += chunk.toString()
+ })
+ s.on('end', () => {
+ expect(buffer).toBe(JSON.stringify(response))
+ expect(scope.isDone()).toBe(true)
+ resolve()
+ })
+ })
+})