Skip to content

Commit 8655d40

Browse files
glynnbirdGlynn BirdYCsxwei123BigsonLvrocha
authored
Replace request with axios (#208)
* use new url.URL instead of url.parse/url.reslove * remove mocha tests * add jest framework. Remove tape/mocha/istanbul. * first jest tests * finished top level tests * document tests complete * design functions * multipart tests * attachment tests * tidy up * auth/session/uuids * 100% coverage * partitioned functions and tests * tidy up * standard styling of examples * only support current versions of node * stash changes * remove db.copy function - axios does not support COPY HTTP method * alter the way attachment.insertAsStream works * typescript update * combine attachment.insert attachment.insertAsStream * ensure db.head passes the test * configure default http agent, user-agent string and gzipping * added tests for gzip/user-agent headers + TypeScript defs * ensure tests run in env=node mode * typescript defs * remove cloudant-follow and replace with changesReader * added further tests * readme * removed errs dependency * resurrect logging * get changesreader to use relax * fixed suggestions from @eridal * avoid extra function wrapper in setTimeout * handle numeric sequence tokens * remove callback from wait:true mode - switch to pause()/resume() functions * ensure the response attributes are assigned to the error object thrown * add description to error messages * prevent Error message being overwritten * dependency bump * ensure Node version list matches current/supported versions * fixup readme * fix(nano.d.ts): add opts and callback for relax (#225) * fix(nano.d.ts): add opts and callback for nano.request * fix(nano.d.ts): add opts and callback for relax and dinosaur * Add FollowEmitter.stop() to typescript declaration file (#230) * Patch typescript declaration file (#231) * Add string to View.map type (#220) addresses #219 * - Addded viewWithListAsStream function (#227) - Added test case for viewWithListAsStream - Added documntation for viewWithListm and viewWithListAsStream * dependency bump * updated Node.js versions used to test to reflect current supported versions * standard fixes * added 8->9 migration guide Co-authored-by: Glynn Bird <glynnbird@apache.org> Co-authored-by: Steven Tang <steven.yc.tang@gmail.com> Co-authored-by: Leon <sxwei123@users.noreply.github.com> Co-authored-by: Luiz Victor Linhares Rocha <luizvictorlrocha@gmail.com> Co-authored-by: Luca Morandini <lmorandini@ieee.org>
1 parent 77224eb commit 8655d40

21 files changed

+3565
-4281
lines changed

.travis.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
language: "node_js"
22
node_js:
3-
- "node"
4-
- "8"
5-
- "10"
63
- "12"
4+
- "14"
75
services:
86
- docker
97
os:

README.md

Lines changed: 139 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ or save `nano` as a dependency of your project with
2323

2424
npm install --save nano
2525

26-
Note the minimum required version of Node.js is 6.
27-
28-
See [Migration Guide for switching from Nano 6.x to 7.x](migration_6_to_7.md).
26+
Note the minimum required version of Node.js is 10.
2927

3028
## Table of contents
3129

@@ -45,26 +43,25 @@ See [Migration Guide for switching from Nano 6.x to 7.x](migration_6_to_7.md).
4543
- [nano.db.replication.disable(id, [opts], [callback])](#nanodbreplicationdisableid-opts-callback)
4644
- [nano.db.changes(name, [params], [callback])](#nanodbchangesname-params-callback)
4745
- [nano.db.changesAsStream(name, [params])](#nanodbchangesasstreamname-params)
48-
- [nano.db.follow(name, [params], [callback])](#nanodbfollowname-params-callback)
4946
- [nano.db.info([callback])](#nanodbinfocallback)
5047
- [nano.use(name)](#nanousename)
5148
- [nano.request(opts, [callback])](#nanorequestopts-callback)
5249
- [nano.config](#nanoconfig)
5350
- [nano.updates([params], [callback])](#nanoupdatesparams-callback)
54-
- [nano.followUpdates([params], [callback])](#nanofollowupdatesparams-callback)
5551
- [nano.info([callback])](#nanoinfocallback)
52+
5653
- [Document functions](#document-functions)
5754
- [db.insert(doc, [params], [callback])](#dbinsertdoc-params-callback)
5855
- [db.destroy(docname, rev, [callback])](#dbdestroydocname-rev-callback)
5956
- [db.get(docname, [params], [callback])](#dbgetdocname-params-callback)
6057
- [db.head(docname, [callback])](#dbheaddocname-callback)
61-
- [db.copy(src_doc, dest_doc, opts, [callback])](#dbcopysrc_doc-dest_doc-opts-callback)
6258
- [db.bulk(docs, [params], [callback])](#dbbulkdocs-params-callback)
6359
- [db.list([params], [callback])](#dblistparams-callback)
6460
- [db.listAsStream([params])](#dblistasstreamparams)
6561
- [db.fetch(docnames, [params], [callback])](#dbfetchdocnames-params-callback)
6662
- [db.fetchRevs(docnames, [params], [callback])](#dbfetchrevsdocnames-params-callback)
6763
- [db.createIndex(indexDef, [callback])](#dbcreateindexindexdef-callback)
64+
- [db.changesReader...](##reading-changes-feed)
6865
- [Partitioned database functions](#partition-functions)
6966
- [db.partitionInfo(partitionKey, [callback])](#dbpartitioninfopartitionkey-callback))
7067
- [db.partitionedList(partitionKey, [params], [callback])](#dbpartitionedlistpartitionkey-params-callback)
@@ -220,10 +217,7 @@ You can also pass options to the require to specify further configuration option
220217
// nano parses the URL and knows this is a database
221218
const opts = {
222219
url: "http://localhost:5984/foo",
223-
requestDefaults: { "proxy" : "http://someproxy" },
224-
log: (id, args) => {
225-
console.log(id, args);
226-
}
220+
requestDefaults: { "proxy" : "http://someproxy" }
227221
};
228222
const db = require('nano')(opts);
229223
```
@@ -441,21 +435,6 @@ Same as `nano.db.changes` but returns a stream.
441435
nano.db.changes('alice').pipe(process.stdout);
442436
```
443437

444-
### nano.db.follow(name, [params], [callback])
445-
446-
Uses [Follow] to create a solid changes feed. Please consult `follow` documentation for more information as this is a very complete API on it's own:
447-
448-
```js
449-
const feed = db.follow({since: "now"});
450-
feed.on('change', (change) => {
451-
console.log("change: ", change);
452-
});
453-
feed.follow();
454-
process.nextTick( () => {
455-
db.insert({"bar": "baz"}, "bar");
456-
});
457-
```
458-
459438
### nano.db.info([callback])
460439

461440
Gets database information:
@@ -530,29 +509,6 @@ Listen to db updates, the available `params` are:
530509
* `params.timeout` – Number of seconds until CouchDB closes the connection. Default is 60.
531510
* `params.heartbeat` – Whether CouchDB will send a newline character (\n) on timeout. Default is true.
532511

533-
### nano.followUpdates([params], [callback])
534-
535-
** changed in version 6 **
536-
537-
Use [Follow] to create a solid
538-
[`_db_updates`](http://docs.couchdb.org/en/latest/api/server/common.html?highlight=db_updates#get--_db_updates) feed.
539-
Please consult follow documentation for more information as this is a very complete api on it's own
540-
541-
```js
542-
const feed = nano.followUpdates({since: "now"});
543-
feed.on('change', (change) => {
544-
console.log("change: ", change);
545-
});
546-
feed.follow();
547-
process.nextTick( () => {
548-
nano.db.create('alice');
549-
});
550-
```
551-
552-
### nano.info([callback])
553-
554-
Get meta information about database instance.
555-
556512
## Document functions
557513

558514
### db.insert(doc, [params], [callback])
@@ -624,17 +580,6 @@ alice.head('rabbit').then((headers) => {
624580

625581
*Note:* if you call `alice.head` in the callback style, the headers are returned to you as the third argument of the callback function.
626582

627-
### db.copy(src_doc, dest_doc, opts, [callback])
628-
629-
Copies the contents (and attachments) of a document
630-
to a new document, or overwrite an existing target document
631-
632-
```js
633-
alice.copy('rabbit', 'rabbit2', { overwrite: true }).then((body) => {
634-
console.log(body);
635-
});
636-
```
637-
638583
### db.bulk(docs, [params], [callback])
639584

640585
Bulk operations(update/delete/insert) on the database, refer to the
@@ -719,6 +664,103 @@ alice.createIndex(indexDef).then((result) => {
719664
});
720665
```
721666

667+
## Reading Changes Feed
668+
669+
Nano provides a low-level API for making calls to CouchDB's changes feed, or if you want a
670+
reliable, resumable changes feed follower, then you need the `changesReader`.
671+
672+
There are three ways to start listening to the changes feed:
673+
674+
1. `changesReader.start()` - to listen to changes indefinitely by repeated "long poll" requests. This mode continues to poll for changes forever.
675+
2. `changesReader.get()` - to listen to changes until the end of the changes feed is reached, by repeated "long poll" requests. Once a response with zero changes is received, the 'end' event will indicate the end of the changes and polling will stop.
676+
3. `changesReader.spool()` - listen to changes in one long HTTP request. (as opposed to repeated round trips) - spool is faster but less reliable.
677+
678+
> Note: for `.get()` & `.start()`, the sequence of API calls can be paused by calling `changesReader.pause()` and resumed by calling `changesReader.resume()`.
679+
680+
Set up your database connection and then choose `changesReader.start()` to listen to that database's changes:
681+
682+
```js
683+
const db = nano.db.use('mydb')
684+
db.changesReader.start()
685+
.on('change', (change) => { console.log(change) })
686+
.on('batch', (b) => {
687+
console.log('a batch of', b.length, 'changes has arrived');
688+
}).on('seq', (s) => {
689+
console.log('sequence token', s);
690+
}).on('error', (e) => {
691+
console.error('error', e);
692+
})
693+
```
694+
695+
> Note: you probably want to monitor *either* the `change` or `batch` event, not both.
696+
697+
If you want `changesReader` to hold off making the next `_changes` API call until you are ready, then supply `wait:true` in the options to `get`/`start`. The next request will only fire when you call `changesReader.resume()`:
698+
699+
```js
700+
db.changesReader.get({wait: true})
701+
.on('batch', (b) => {
702+
console.log('a batch of', b.length, 'changes has arrived');
703+
// do some asynchronous work here and call "changesReader.resume()"
704+
// when you're ready for the next API call to be dispatched.
705+
// In this case, wait 5s before the next changes feed request.
706+
setTimeout( () => {
707+
db.changesReader.resume()
708+
}, 5000)
709+
}).on('end', () => {
710+
console.log('changes feed monitoring has stopped');
711+
});
712+
```
713+
714+
You may supply a number of options when you start to listen to the changes feed:
715+
716+
| Parameter | Description | Default value | e.g. | |
717+
|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|---------------------------------|---|
718+
| batchSize | The maximum number of changes to ask CouchDB for per HTTP request. This is the maximum number of changes you will receive in a `batch` event. | 100 | 500 | |
719+
| since | The position in the changes feed to start from where `0` means the beginning of time, `now` means the current position or a string token indicates a fixed position in the changes feed | now | 390768-g1AAAAGveJzLYWBgYMlgTmGQ | |
720+
| includeDocs | Whether to include document bodies or not | false | e.g. true |
721+
| wait | For `get`/`start` mode, automatically pause the changes reader after each request. When the the user calls `resume()`, the changes reader will resume. | false | e.g. true |
722+
| fastChanges | Adds a seq_interval parameter to fetch changes more quickly | false | true | |
723+
| selector | Filters the changes feed with the supplied Mango selector | {"name":"fred} | null | |
724+
| timeout | The number of milliseconds a changes feed request waits for data| 60000 | 10000
725+
726+
The events it emits are as follows:s
727+
728+
| Event | Description | Data | |
729+
|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|---|
730+
| change | Each detected change is emitted individually. Only available in `get`/`start` modes. | A change object | |
731+
| batch | Each batch of changes is emitted in bulk in quantities up to `batchSize`. | An array of change objects | |
732+
| seq | Each new sequence token (per HTTP request). This token can be passed into `ChangesReader` as the `since` parameter to resume changes feed consumption from a known point. Only available in `get`/`start` modes. | String | |
733+
| error | On a fatal error, a descriptive object is returned and change consumption stops. | Error object | |
734+
| end | Emitted when the end of the changes feed is reached. `ChangesReader.get()` mode only, | Nothing | |
735+
736+
The *ChangesReader* library will handle many temporal errors such as network connectivity, service capacity limits and malformed data but it will emit an `error` event and exit when fed incorrect authentication credentials or an invalid `since` token.
737+
738+
The `change` event delivers a change object that looks like this:
739+
740+
```js
741+
{
742+
"seq": "8-g1AAAAYIeJyt1M9NwzAUBnALKiFOdAO4gpRix3X",
743+
"id": "2451be085772a9e588c26fb668e1cc52",
744+
"changes": [{
745+
"rev": "4-061b768b6c0b6efe1bad425067986587"
746+
}],
747+
"doc": {
748+
"_id": "2451be085772a9e588c26fb668e1cc52",
749+
"_rev": "4-061b768b6c0b6efe1bad425067986587",
750+
"a": 3
751+
}
752+
}
753+
```
754+
755+
N.B
756+
757+
- `doc` is only present if `includeDocs:true` is supplied
758+
- `seq` is not present for every change
759+
760+
The `id` is the unique identifier of the document that changed and the `changes` array contains the document revision tokens that were written to the database.
761+
762+
The `batch` event delivers an array of change objects.
763+
722764
## Partition Functions
723765

724766
Functions related to [partitioned databses](https://docs.couchdb.org/en/latest/partitioned-dbs/index.html).
@@ -968,16 +1010,8 @@ fs.readFile('rabbit.png', (err, data) => {
9681010

9691011
### db.attachment.insertAsStream(docname, attname, att, contenttype, [params])
9701012

971-
It may be more memory-efficient to pipe a stream of data from a source (file, network etc) to a CouchDB attachment:
972-
973-
```js
974-
const rs = fs.createReadStream('logo.png');
975-
const is = db.attachment.insertAsStream('mydoc', 'logo.png', null, 'image/png',
976-
{ rev: '12-150985a725ec88be471921a54ce91452' }).on('end', () => {
977-
console.log('done')
978-
});
979-
rs.pipe(is);
980-
```
1013+
As of Nano 9.x, the function `db.attachment.insertAsStream` is now deprecated. Now simply pass
1014+
a readable stream to `db.attachment.insert` as the third paramseter.
9811015

9821016
### db.attachment.get(docname, attname, [params], [callback])
9831017

@@ -1291,6 +1325,39 @@ and document level functions
12911325
12921326
- db.listAsStream
12931327
1328+
### Logging
1329+
1330+
When instantiating Nano, you may supply the function that will perform the logging of requests and responses. In its simplest for, simply pass `console.log` as your logger:
1331+
1332+
```js
1333+
const nano = Nano({ url: process.env.COUCH_URL, log: console.log })
1334+
// all requests and responses will be sent to console.log
1335+
```
1336+
1337+
You may supply your own logging function to format the data before output:
1338+
1339+
```js
1340+
const url = require('url')
1341+
const logger = (data) => {
1342+
// only output logging if there is an environment variable set
1343+
if (process.env.LOG === 'nano') {
1344+
// if this is a request
1345+
if (typeof data.err === 'undefined') {
1346+
const u = new url.URL(data.uri)
1347+
console.log(data.method, u.pathname, data.qs)
1348+
} else {
1349+
// this is a response
1350+
const prefix = data.err ? 'ERR' : 'OK'
1351+
console.log(prefix, data.headers.statusCode, JSON.stringify(data.body).length)
1352+
}
1353+
}
1354+
}
1355+
const nano = Nano({ url: process.env.COUCH_URL, log: logger })
1356+
// all requests and responses will be formatted by my code
1357+
// GET /cities/_all_docs { limit: 5 }
1358+
// OK 200 468
1359+
```
1360+
12941361
## Tutorials, examples in the wild & screencasts
12951362
12961363
* article: [nano - a minimalistic CouchDB client for nodejs](http://writings.nunojob.com/2011/08/nano-minimalistic-couchdb-client-for-nodejs.html)
@@ -1314,17 +1381,9 @@ To run (and configure) the test suite simply:
13141381
``` sh
13151382
cd nano
13161383
npm install
1317-
npm test
1384+
npm run test
13181385
```
13191386
1320-
After adding a new test you can run it individually (with verbose output) using:
1321-
1322-
``` sh
1323-
nano_env=testing node tests/doc/list.js list_doc_params
1324-
```
1325-
1326-
where `list_doc_params` is the test name.
1327-
13281387
## Meta
13291388
13301389
* code: `git clone git://github.com/apache/couchdb-nano.git`
@@ -1338,9 +1397,10 @@ where `list_doc_params` is the test name.
13381397
[2]: http://github.com/apache/couchdb-nano/issues
13391398
[4]: https://github.com/apache/couchdb-nano/blob/master/cfg/couch.example.js
13401399
[8]: http://webchat.freenode.net?channels=%23couchdb-dev
1341-
[follow]: https://www.npmjs.com/package/cloudant-follow
13421400
[request]: https://github.com/request/request
13431401

1402+
http://freenode.org/
1403+
13441404
## Release
13451405

13461406
To create a new release of nano. Run the following commands on the master branch

examples/bulk_transform.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ const db = require('nano')('http://localhost:5984/emails')
1414
const async = require('async')
1515

1616
function updateRow (row, cb) {
17-
var doc = row.doc
17+
const doc = row.doc
1818
delete doc.subject
1919
db.insert(doc, doc._id, function (err, data) {
2020
if (err) { console.log('err at ' + doc._id); cb(err) } else { console.log('updated ' + doc._id); cb() }
2121
})
2222
}
2323

2424
function list (offset) {
25-
var ended = false
25+
let ended = false
2626
offset = offset || 0
2727
db.list({ include_docs: true, limit: 10, skip: offset },
2828
function (err, data) {
29-
var total, offset, rows
29+
let rows
3030
if (err) { console.log('fuuuu: ' + err.message); rows = []; return }
31-
total = data.total_rows
32-
offset = data.offset
31+
const total = data.total_rows
32+
const offset = data.offset
3333
rows = data.rows
3434
if (offset === total) {
3535
ended = true

examples/lazy_creation_of_views.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,14 @@ module.exports = function () {
7171
}
7272
users.view('users', view, opts, function (e, b, h) {
7373
if (e) {
74-
var currentView = VIEWS[view]
74+
const currentView = VIEWS[view]
7575
if (!currentView) {
7676
e.message = 'View is not available'
7777
return callback(e, b, h)
7878
}
7979
if (tried.tried < tried.max_retries) {
8080
if (e.message === 'missing' || e.message === 'deleted') { // create design document
81-
var designDoc = { views: {} }
81+
const designDoc = { views: {} }
8282
designDoc.views[view] = currentView
8383
return users.insert(designDoc, '_design/users', function () {
8484
tried.tried += 1

examples/lazy_db_creation_and_replication.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function replicateWithRetry (masterUri, replicaUri, retries, callback) {
4646
}
4747
callback = callback || function () {}
4848
retries = retries || 0
49-
var master = nano(couch.master)
49+
const master = nano(couch.master)
5050
master.replicate(couch.replica, function (err, resp, head) {
5151
if (err && err.error === 'db_not_found' && retries < 1) {
5252
const replica = nano(couch.replica)

0 commit comments

Comments
 (0)