app.js
function(srcUrl, targetStream, opts, callback) {
    var listenerErrorIndicator = { errored: false };
    if (typeof callback === 'undefined' && typeof opts === 'function') {
      callback = opts;
      opts = {};
    }
    if (!validateArgs(srcUrl, opts, callback)) {
      // bad args, bail
      return;
    }

    // if there is an error writing to the stream, call the completion
    // callback with the error set
    addEventListener(listenerErrorIndicator, targetStream, 'error', function(err) {
      debug('Error ' + JSON.stringify(err));
      if (callback) callback(err);
    });

    opts = Object.assign({}, defaults(), opts);

    const ee = new events.EventEmitter();

    // Set up the DB client
    const backupDB = request.client(srcUrl, opts);

    // Validate the DB exists, before proceeding to backup
    proceedIfDbValid(backupDB, function(err) {
      if (err) {
        if (err.name === 'DatabaseNotFound') {
          err.message = `${err.message} Ensure the backup source database exists.`;
        }
        // Didn't exist, or another fatal error, exit
        callback(err);
        return;
      }
      var backup = null;
      if (opts.mode === 'shallow') {
        backup = backupShallow;
      } else { // full mode
        backup = backupFull;
      }

      // If resuming write a newline as it's possible one would be missing from
      // an interruption of the previous backup. If the backup was clean this
      // will cause an empty line that will be gracefully handled by the restore.
      if (opts.resume) {
        targetStream.write('\n');
      }

      // Get the event emitter from the backup process so we can handle events
      // before passing them on to the app's event emitter if needed.
      const internalEE = backup(backupDB, opts);
      addEventListener(listenerErrorIndicator, internalEE, 'changes', function(batch) {
        ee.emit('changes', batch);
      });
      addEventListener(listenerErrorIndicator, internalEE, 'received', function(obj, q, logCompletedBatch) {
        // this may be too verbose to have as well as the "backed up" message
        // debug(' received batch', obj.batch, ' docs: ', obj.total, 'Time', obj.time);
        // Callback to emit the written event when the content is flushed
        function writeFlushed() {
          ee.emit('written', { total: obj.total, time: obj.time, batch: obj.batch });
          if (logCompletedBatch) {
            logCompletedBatch(obj.batch);
          }
          debug(' backed up batch', obj.batch, ' docs: ', obj.total, 'Time', obj.time);
        }
        // Write the received content to the targetStream
        const continueWriting = targetStream.write(JSON.stringify(obj.data) + '\n',
          'utf8',
          writeFlushed);
        if (!continueWriting) {
          // The buffer was full, pause the queue to stop the writes until we
          // get a drain event
          if (q && !q.isPaused) {
            q.pause();
            targetStream.once('drain', function() {
              q.resume();
            });
          }
        }
      });
      // For errors we expect, may or may not be fatal
      addEventListener(listenerErrorIndicator, internalEE, 'error', function(err) {
        debug('Error ' + JSON.stringify(err));
        callback(err);
      });
      addEventListener(listenerErrorIndicator, internalEE, 'finished', function(obj) {
        function emitFinished() {
          debug('Backup complete - written ' + JSON.stringify(obj));
          const summary = { total: obj.total };
          ee.emit('finished', summary);
          if (callback) callback(null, summary);
        }
        if (targetStream === process.stdout) {
          // stdout cannot emit a finish event so use a final write + callback
          targetStream.write('', 'utf8', emitFinished);
        } else {
          // If we're writing to a file, end the writes and register the
          // emitFinished function for a callback when the file stream's finish
          // event is emitted.
          targetStream.end('', 'utf8', emitFinished);
        }
      });
    });
    return ee;
  }
function(srcUrl, targetStream, opts, callback) {
    var listenerErrorIndicator = { errored: false };
    if (typeof callback === 'undefined' && typeof opts === 'function') {
      callback = opts;
      opts = {};
    }
    if (!validateArgs(srcUrl, opts, callback)) {
      // bad args, bail
      return;
    }

    // if there is an error writing to the stream, call the completion
    // callback with the error set
    addEventListener(listenerErrorIndicator, targetStream, 'error', function(err) {
      debug('Error ' + JSON.stringify(err));
      if (callback) callback(err);
    });

    opts = Object.assign({}, defaults(), opts);

    const ee = new events.EventEmitter();

    // Set up the DB client
    const backupDB = request.client(srcUrl, opts);

    // Validate the DB exists, before proceeding to backup
    proceedIfDbValid(backupDB, function(err) {
      if (err) {
        if (err.name === 'DatabaseNotFound') {
          err.message = `${err.message} Ensure the backup source database exists.`;
        }
        // Didn't exist, or another fatal error, exit
        callback(err);
        return;
      }
      var backup = null;
      if (opts.mode === 'shallow') {
        backup = backupShallow;
      } else { // full mode
        backup = backupFull;
      }

      // If resuming write a newline as it's possible one would be missing from
      // an interruption of the previous backup. If the backup was clean this
      // will cause an empty line that will be gracefully handled by the restore.
      if (opts.resume) {
        targetStream.write('\n');
      }

      // Get the event emitter from the backup process so we can handle events
      // before passing them on to the app's event emitter if needed.
      const internalEE = backup(backupDB, opts);
      addEventListener(listenerErrorIndicator, internalEE, 'changes', function(batch) {
        ee.emit('changes', batch);
      });
      addEventListener(listenerErrorIndicator, internalEE, 'received', function(obj, q, logCompletedBatch) {
        // this may be too verbose to have as well as the "backed up" message
        // debug(' received batch', obj.batch, ' docs: ', obj.total, 'Time', obj.time);
        // Callback to emit the written event when the content is flushed
        function writeFlushed() {
          ee.emit('written', { total: obj.total, time: obj.time, batch: obj.batch });
          if (logCompletedBatch) {
            logCompletedBatch(obj.batch);
          }
          debug(' backed up batch', obj.batch, ' docs: ', obj.total, 'Time', obj.time);
        }
        // Write the received content to the targetStream
        const continueWriting = targetStream.write(JSON.stringify(obj.data) + '\n',
          'utf8',
          writeFlushed);
        if (!continueWriting) {
          // The buffer was full, pause the queue to stop the writes until we
          // get a drain event
          if (q && !q.isPaused) {
            q.pause();
            targetStream.once('drain', function() {
              q.resume();
            });
          }
        }
      });
      // For errors we expect, may or may not be fatal
      addEventListener(listenerErrorIndicator, internalEE, 'error', function(err) {
        debug('Error ' + JSON.stringify(err));
        callback(err);
      });
      addEventListener(listenerErrorIndicator, internalEE, 'finished', function(obj) {
        function emitFinished() {
          debug('Backup complete - written ' + JSON.stringify(obj));
          const summary = { total: obj.total };
          ee.emit('finished', summary);
          if (callback) callback(null, summary);
        }
        if (targetStream === process.stdout) {
          // stdout cannot emit a finish event so use a final write + callback
          targetStream.write('', 'utf8', emitFinished);
        } else {
          // If we're writing to a file, end the writes and register the
          // emitFinished function for a callback when the file stream's finish
          // event is emitted.
          targetStream.end('', 'utf8', emitFinished);
        }
      });
    });
    return ee;
  }
function ( srcUrl , targetStream , opts , callback ) { var listenerErrorIndicator = { errored : false } ; if ( typeof callback === 'undefined' && typeof opts === 'function' ) { callback = opts ; opts = { } ; } if ( ! validateArgs ( srcUrl , opts , callback ) ) { // bad args, bail return ; } // if there is an error writing to the stream, call the completion // callback with the error set addEventListener ( listenerErrorIndicator , targetStream , 'error' , function ( err ) { debug ( 'Error ' + JSON . stringify ( err ) ) ; if ( callback ) callback ( err ) ; } ) ; opts = Object . assign ( { } , defaults ( ) , opts ) ; const ee = new events . EventEmitter ( ) ; // Set up the DB client const backupDB = request . client ( srcUrl , opts ) ; // Validate the DB exists, before proceeding to backup proceedIfDbValid ( backupDB , function ( err ) { if ( err ) { if ( err . name === 'DatabaseNotFound' ) { err . message = ` ${ err . message } ` ; } // Didn't exist, or another fatal error, exit callback ( err ) ; return ; } var backup = null ; if ( opts . mode === 'shallow' ) { backup = backupShallow ; } else { // full mode backup = backupFull ; } // If resuming write a newline as it's possible one would be missing from // an interruption of the previous backup. If the backup was clean this // will cause an empty line that will be gracefully handled by the restore. if ( opts . resume ) { targetStream . write ( '\n' ) ; } // Get the event emitter from the backup process so we can handle events // before passing them on to the app's event emitter if needed. const internalEE = backup ( backupDB , opts ) ; addEventListener ( listenerErrorIndicator , internalEE , 'changes' , function ( batch ) { ee . emit ( 'changes' , batch ) ; } ) ; addEventListener ( listenerErrorIndicator , internalEE , 'received' , function ( obj , q , logCompletedBatch ) { // this may be too verbose to have as well as the "backed up" message // debug(' received batch', obj.batch, ' docs: ', obj.total, 'Time', obj.time); // Callback to emit the written event when the content is flushed function writeFlushed ( ) { ee . emit ( 'written' , { total : obj . total , time : obj . time , batch : obj . batch } ) ; if ( logCompletedBatch ) { logCompletedBatch ( obj . batch ) ; } debug ( ' backed up batch' , obj . batch , ' docs: ' , obj . total , 'Time' , obj . time ) ; } // Write the received content to the targetStream const continueWriting = targetStream . write ( JSON . stringify ( obj . data ) + '\n' , 'utf8' , writeFlushed ) ; if ( ! continueWriting ) { // The buffer was full, pause the queue to stop the writes until we // get a drain event if ( q && ! q . isPaused ) { q . pause ( ) ; targetStream . once ( 'drain' , function ( ) { q . resume ( ) ; } ) ; } } } ) ; // For errors we expect, may or may not be fatal addEventListener ( listenerErrorIndicator , internalEE , 'error' , function ( err ) { debug ( 'Error ' + JSON . stringify ( err ) ) ; callback ( err ) ; } ) ; addEventListener ( listenerErrorIndicator , internalEE , 'finished' , function ( obj ) { function emitFinished ( ) { debug ( 'Backup complete - written ' + JSON . stringify ( obj ) ) ; const summary = { total : obj . total } ; ee . emit ( 'finished' , summary ) ; if ( callback ) callback ( null , summary ) ; } if ( targetStream === process . stdout ) { // stdout cannot emit a finish event so use a final write + callback targetStream . write ( '' , 'utf8' , emitFinished ) ; } else { // If we're writing to a file, end the writes and register the // emitFinished function for a callback when the file stream's finish // event is emitted. targetStream . end ( '' , 'utf8' , emitFinished ) ; } } ) ; } ) ; return ee ; }
Backup a Cloudant database to a stream.

@param {string} srcUrl - URL of database to backup.
@param {stream.Writable} targetStream - Stream to write content to.
@param {object} opts - Backup options.
@param {number} [opts.parallelism=5] - Number of parallel HTTP requests to use.
@param {number} [opts.bufferSize=500] - Number of documents per batch request.
@param {number} [opts.requestTimeout=120000] - Milliseconds to wait before retrying a HTTP request.
@param {string} [opts.iamApiKey] - IAM API key to use to access Cloudant database.
@param {string} [opts.log] - Log file name. Default uses a temporary file.
@param {boolean} [opts.resume] - Whether to resume from existing log.
@param {string} [opts.mode=full] - Use `full` or `shallow` mode.
@param {backupRestoreCallback} callback - Called on completion.
Backup a Cloudant database to a stream .