diff --git a/77-cloudant-cf.html b/77-cloudant-cf.html
index 5ac85f7..1cea0af 100644
--- a/77-cloudant-cf.html
+++ b/77-cloudant-cf.html
@@ -88,10 +88,8 @@
diff --git a/77-cloudant-cf.js b/77-cloudant-cf.js
index 58a3af4..aa4ff2c 100644
--- a/77-cloudant-cf.js
+++ b/77-cloudant-cf.js
@@ -1,416 +1,434 @@
-/**
- * Copyright 2014,2016 IBM Corp.
- *
- * 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.
- **/
-module.exports = function(RED) {
- "use strict";
- var url = require('url');
- var querystring = require('querystring');
- var cfEnv = require("cfenv");
- var Cloudant = require("cloudant");
-
- var MAX_ATTEMPTS = 3;
-
- var appEnv = cfEnv.getAppEnv();
- var services = [];
-
- // load the services bound to this application
- for (var i in appEnv.services) {
- if (appEnv.services.hasOwnProperty(i)) {
- // filter the services to include only the Cloudant ones
- if (i.match(/^(cloudant)/i)) {
- services = services.concat(appEnv.services[i].map(function(v) {
- return { name: v.name, label: v.label };
- }));
- }
- }
- }
-
- //
- // HTTP endpoints that will be accessed from the HTML file
- //
- RED.httpAdmin.get('/cloudant/vcap', function(req,res) {
- res.send(JSON.stringify(services));
- });
-
- //
- // Create and register nodes
- //
- function CloudantNode(n) {
- RED.nodes.createNode(this, n);
- this.name = n.name;
- this.host = n.host;
- this.url = n.host;
-
- // remove unnecessary parts from host value
- var parsedUrl = url.parse(this.host);
- if (parsedUrl.host) {
- this.host = parsedUrl.host;
- }
- if (this.host.indexOf("cloudant.com")!==-1) {
- // extract only the account name
- this.account = this.host.substring(0, this.host.indexOf('.'));
- delete this.url;
- }
- var credentials = this.credentials;
- if ((credentials) && (credentials.hasOwnProperty("username"))) { this.username = credentials.username; }
- if ((credentials) && (credentials.hasOwnProperty("pass"))) { this.password = credentials.pass; }
- }
- RED.nodes.registerType("cloudant", CloudantNode, {
- credentials: {
- pass: {type:"password"},
- username: {type:"text"}
- }
- });
-
-
- function CloudantOutNode(n) {
- RED.nodes.createNode(this,n);
-
- this.operation = n.operation;
- this.payonly = n.payonly || false;
- this.outputMsg = n.outputmsg || "none";
- this.database = _cleanDatabaseName(n.database, this);
- this.cloudantConfig = _getCloudantConfig(n);
-
- var node = this;
- var credentials = {
- account: node.cloudantConfig.account,
- key: node.cloudantConfig.username,
- password: node.cloudantConfig.password,
- url: node.cloudantConfig.url
- };
-
- Cloudant(credentials, function(err, cloudant) {
- if (err) { node.error(err.description, err); }
- else {
- // check if the database exists and create it if it doesn't
- createDatabase(cloudant, node);
- }
-
- node.on("input", function(msg) {
- if (err) {
- return node.error(err.description, err);
- }
-
- handleMessage(cloudant, node, msg);
- });
- });
-
- function createDatabase(cloudant, node) {
- cloudant.db.list(function(err, all_dbs) {
- if (err) {
- if (err.status_code === 403) {
- // if err.status_code is 403 then we are probably using
- // an api key, so we can assume the database already exists
- return;
- }
- node.error("Failed to list databases: " + err.description, err);
- }
- else {
- if (all_dbs && all_dbs.indexOf(node.database) < 0) {
- cloudant.db.create(node.database, function(err, body) {
- if (err) {
- node.error(
- "Failed to create database: " + err.description,
- err
- );
- }
- });
- }
- }
- });
- }
-
- function handleMessage(cloudant, node, msg) {
- var origMsgId = msg._msgid ;
- delete msg._msgid;
- if (node.operation === "insert") {
- var origMsg = msg ;
- var msg = node.payonly ? msg.payload : msg;
- var root = node.payonly ? "payload" : "msg";
- var doc = parseMessage(msg, root);
-
- insertDocument(cloudant, node, doc, MAX_ATTEMPTS, function(err, body) {
- if (err) {
- console.trace();
- console.log(node.error.toString());
- node.error("Failed to insert document: " + err.description, msg);
- if (node.outputMsg && (node.outputMsg == "error"
- || node.outputMsg == "all")) {
- //send original message on error
- origMsg._msgid = origMsgId ;
- origMsg.dbError = {} ;
-
- origMsg.dbError.statusCode = err.statusCode;
- origMsg.dbError.description = err.description;
- origMsg.dbError.message = err.message;
- origMsg.dbError.reason = err.reason;
- origMsg.dbError.scope = err.scope;
- node.send([origMsg]);
- }
- }
- else if (node.outputMsg && (node.outputMsg == "success"
- || node.outputMsg == "all")) {
- // send message with updated id and rev on success
- origMsg._msgid = origMsgId ;
- delete origMsg.dbError; // just in case original message came from error path
- if (node.payonly) {
- origMsg.payload._id = body.id;
- origMsg.payload._rev = body.rev;
- }
- else {
- origMsg._id = body.id;
- origMsg._rev = body.rev;
- }
-
- node.send([origMsg]);
- }
- });
- }
- else if (node.operation === "delete") {
- var doc = parseMessage(msg.payload || msg, "");
-
- if ("_rev" in doc && "_id" in doc) {
- var db = cloudant.use(node.database);
- db.destroy(doc._id, doc._rev, function(err, body) {
- if (err) {
- node.error("Failed to delete document: " + err.description, msg);
- }
- });
- } else {
- var err = new Error("_id and _rev are required to delete a document");
- node.error(err.message, msg);
- }
- }
- }
-
- function parseMessage(msg, root) {
- if (typeof msg !== "object") {
- try {
- msg = JSON.parse(msg);
- // JSON.parse accepts numbers, so make sure that an
- // object is return, otherwise create a new one
- if (typeof msg !== "object") {
- msg = JSON.parse('{"' + root + '":"' + msg + '"}');
- }
- } catch (e) {
- // payload is not in JSON format
- msg = JSON.parse('{"' + root + '":"' + msg + '"}');
- }
- }
- return cleanMessage(msg);
- }
-
- // fix field values that start with _
- // https://wiki.apache.org/couchdb/HTTP_Document_API#Special_Fields
- function cleanMessage(msg) {
- for (var key in msg) {
- if (msg.hasOwnProperty(key) && !isFieldNameValid(key)) {
- // remove _ from the start of the field name
- var newKey = key.substring(1, msg.length);
- msg[newKey] = msg[key];
- delete msg[key];
- node.warn("Property '" + key + "' renamed to '" + newKey + "'.");
- }
- }
- return msg;
- }
-
- function isFieldNameValid(key) {
- var allowedWords = [
- '_id', '_rev', '_attachments', '_deleted', '_revisions',
- '_revs_info', '_conflicts', '_deleted_conflicts', '_local_seq'
- ];
- return key[0] !== '_' || allowedWords.indexOf(key) >= 0;
- }
-
- // Inserts a document +doc+ in a database +db+ that migh not exist
- // beforehand. If the database doesn't exist, it will create one
- // with the name specified in +db+. To prevent loops, it only tries
- // +attempts+ number of times.
- function insertDocument(cloudant, node, doc, attempts, callback) {
- var db = cloudant.use(node.database);
- db.insert(doc, function(err, body) {
- if (err && err.status_code === 404 && attempts > 0) {
- // status_code 404 means the database was not found
- return cloudant.db.create(db.config.db, function() {
- insertDocument(cloudant, node, doc, attempts-1, callback);
- });
- }
-
- callback(err, body);
- });
- }
- };
- RED.nodes.registerType("cloudant out", CloudantOutNode);
-
-
- function CloudantInNode(n) {
- RED.nodes.createNode(this,n);
-
- this.cloudantConfig = _getCloudantConfig(n);
- this.database = _cleanDatabaseName(n.database, this);
- this.search = n.search;
- this.design = n.design;
- this.index = n.index;
- this.inputId = "";
-
- var node = this;
- var credentials = {
- account: node.cloudantConfig.account,
- key: node.cloudantConfig.username,
- password: node.cloudantConfig.password,
- url: node.cloudantConfig.url
- };
-
- Cloudant(credentials, function(err, cloudant) {
- if (err) { node.error(err.description, err); }
-
- node.on("input", function(msg) {
- if (err) {
- return node.error(err.description, err);
- }
-
- var db = cloudant.use(node.database);
- var options = (typeof msg.payload === "object") ? msg.payload : {};
-
- if (node.search === "_id_") {
- var id = getDocumentId(msg.payload);
- node.inputId = id;
-
- db.get(id, function(err, body) {
- sendDocumentOnPayload(err, body, msg);
- });
- }
- else if (node.search === "_idx_") {
- options.query = options.query || options.q || formatSearchQuery(msg.payload);
- options.include_docs = options.include_docs || true;
- options.limit = options.limit || 200;
-
- db.search(node.design, node.index, options, function(err, body) {
- sendDocumentOnPayload(err, body, msg);
- });
- }
- else if (node.search === "_all_") {
- options.include_docs = options.include_docs || true;
-
- db.list(options, function(err, body) {
- sendDocumentOnPayload(err, body, msg);
- });
- }
- });
- });
-
- function getDocumentId(payload) {
- if (typeof payload === "object") {
- if ("_id" in payload || "id" in payload) {
- return payload.id || payload._id;
- }
- }
-
- return payload;
- }
-
- function formatSearchQuery(query) {
- if (typeof query === "object") {
- // useful when passing the query on HTTP params
- if ("q" in query) { return query.q; }
-
- var queryString = "";
- for (var key in query) {
- queryString += key + ":" + query[key] + " ";
- }
-
- return queryString.trim();
- }
- return query;
- }
-
- function sendDocumentOnPayload(err, body, msg) {
- if (!err) {
- msg.cloudant = body;
-
- if ("rows" in body) {
- msg.payload = body.rows.
- map(function(el) {
- if (el.doc._id.indexOf("_design/") < 0) {
- return el.doc;
- }
- }).
- filter(function(el) {
- return el !== null && el !== undefined;
- });
- } else {
- msg.payload = body;
- }
- }
- else {
- msg.payload = null;
-
- if (err.description === "missing") {
- node.warn(
- "Document '" + node.inputId +
- "' not found in database '" + node.database + "'.",
- err
- );
- } else {
- node.error(err.description, err);
- }
- }
-
- node.send(msg);
- }
- }
- RED.nodes.registerType("cloudant in", CloudantInNode);
-
- // must return an object with, at least, values for account, username and
- // password for the Cloudant service at the top-level of the object
- function _getCloudantConfig(n) {
- if (n.service === "_ext_") {
- return RED.nodes.getNode(n.cloudant);
-
- } else if (n.service !== "") {
- var service = appEnv.getService(n.service);
- var cloudantConfig = { };
-
- var host = service.credentials.host;
-
- cloudantConfig.username = service.credentials.username;
- cloudantConfig.password = service.credentials.password;
- cloudantConfig.account = host.substring(0, host.indexOf('.'));
-
- return cloudantConfig;
- }
- }
-
- // remove invalid characters from the database name
- // https://wiki.apache.org/couchdb/HTTP_database_API#Naming_and_Addressing
- function _cleanDatabaseName(database, node) {
- var newDatabase = database;
-
- // caps are not allowed
- newDatabase = newDatabase.toLowerCase();
- // remove trailing underscore
- newDatabase = newDatabase.replace(/^_/, '');
- // remove spaces and slashed
- newDatabase = newDatabase.replace(/[\s\\/]+/g, '-');
-
- if (newDatabase !== database) {
- node.warn("Database renamed as '" + newDatabase + "'.");
- }
-
- return newDatabase;
- }
-};
+/**
+ * Copyright 2014,2016 IBM Corp.
+ *
+ * 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.
+ **/
+module.exports = function (RED) {
+ "use strict";
+ var url = require('url');
+ var querystring = require('querystring');
+ var cfEnv = require("cfenv");
+ var Cloudant = require("cloudant");
+
+ var MAX_ATTEMPTS = 3;
+
+ var appEnv = cfEnv.getAppEnv();
+ var services = [];
+
+ // load the services bound to this application
+ for (var i in appEnv.services) {
+ if (appEnv.services.hasOwnProperty(i)) {
+ // filter the services to include only the Cloudant ones
+ if (i.match(/^(cloudant)/i)) {
+ services = services.concat(appEnv.services[i].map(function (v) {
+ return {
+ name: v.name,
+ label: v.label
+ };
+ }));
+ }
+ }
+ }
+
+ //
+ // HTTP endpoints that will be accessed from the HTML file
+ //
+ RED.httpAdmin.get('/cloudant/vcap', function (req, res) {
+ res.send(JSON.stringify(services));
+ });
+
+ //
+ // Create and register nodes
+ //
+ function CloudantNode(n) {
+ RED.nodes.createNode(this, n);
+ this.name = n.name;
+ this.host = n.host;
+ this.url = n.host;
+
+ // remove unnecessary parts from host value
+ var parsedUrl = url.parse(this.host);
+ if (parsedUrl.host) {
+ this.host = parsedUrl.host;
+ }
+ if (this.host.indexOf("cloudant.com") !== -1) {
+ // extract only the account name
+ this.account = this.host.substring(0, this.host.indexOf('.'));
+ delete this.url;
+ }
+ var credentials = this.credentials;
+ if ((credentials) && (credentials.hasOwnProperty("username"))) {
+ this.username = credentials.username;
+ }
+ if ((credentials) && (credentials.hasOwnProperty("pass"))) {
+ this.password = credentials.pass;
+ }
+ }
+ RED.nodes.registerType("cloudant", CloudantNode, {
+ credentials: {
+ pass: {
+ type: "password"
+ },
+ username: {
+ type: "text"
+ }
+ }
+ });
+
+ function CloudantOutNode(n) {
+ RED.nodes.createNode(this, n);
+
+ this.operation = n.operation;
+ this.payonly = n.payonly || false;
+ this.outputMsg = n.outputmsg || "none";
+ this.database = _cleanDatabaseName(n.database, this);
+ this.cloudantConfig = _getCloudantConfig(n);
+
+ var node = this;
+ var credentials = {
+ account: node.cloudantConfig.account,
+ key: node.cloudantConfig.username,
+ password: node.cloudantConfig.password,
+ url: node.cloudantConfig.url
+ };
+
+ Cloudant(credentials, function (err, cloudant) {
+ if (err) {
+ node.error(err.description, err);
+ } else {
+ // check if the database exists and create it if it doesn't
+ createDatabase(cloudant, node);
+ }
+
+ node.on("input", function (msg) {
+ if (err) {
+ _attachDbError(err, msg);
+ return node.error(err, msg);
+ }
+
+ handleMessage(cloudant, node, msg);
+ });
+ });
+
+ function createDatabase(cloudant, node) {
+ cloudant.db.list(function (err, all_dbs) {
+ if (err) {
+ if (err.status_code === 403) {
+ // if err.status_code is 403 then we are probably using
+ // an api key, so we can assume the database already exists
+ return;
+ }
+ node.error("Failed to list databases: " + err.description, err);
+ } else {
+ if (all_dbs && all_dbs.indexOf(node.database) < 0) {
+ cloudant.db.create(node.database, function (err, body) {
+ if (err) {
+ node.error(
+ "Failed to create database: " + err.description,
+ err);
+ }
+ });
+ }
+ }
+ });
+ }
+
+
+
+ function handleMessage(cloudant, node, msg) {
+
+ if (node.operation === "insert") {
+
+ var doc = node.payonly ? msg.payload : msg;
+ var root = node.payonly ? "payload" : "msg";
+
+ doc = cleanMessage(
+ parseMessage(doc, root)
+ );
+
+
+ insertDocument(cloudant, node, doc, MAX_ATTEMPTS, function (err, body) {
+ if (err) {
+
+ console.trace();
+ console.log(node.error.toString());
+
+ _attachDbError(err, msg);
+ node.error(err, msg);
+
+ } else if (node.outputMsg && (node.outputMsg == "yes")) {
+ // send message with updated id and rev on success
+
+ if (node.payonly
+ && msg.payload !== undefined
+ && (typeof msg.payload === "object")) {
+ msg.payload._id = body.id;
+ msg.payload._rev = body.rev;
+ } else {
+ msg._id = body.id;
+ msg._rev = body.rev;
+ }
+
+ node.send(msg);
+ }
+ });
+
+ } else if (node.operation === "delete") {
+ var doc = cleanMessage(
+ parseMessage(msg.payload || msg, "")
+ );
+
+ if ("_rev" in doc && "_id" in doc) {
+ var db = cloudant.use(node.database);
+ db.destroy(doc._id, doc._rev, function (err, body) {
+ if (err) {
+ _attachDbError(err, msg);
+ node.error(err, msg);
+ }
+ });
+ } else {
+ var err = new Error("_id and _rev are required to delete a document");
+ _attachDbError(err, msg);
+ node.error(err, msg);
+ }
+ }
+ }
+
+ function parseMessage(msg, root) {
+ var doc;
+ if (typeof msg !== "object") {
+ try {
+ doc = JSON.parse(msg);
+ // JSON.parse accepts numbers, so make sure that an
+ // object is return, otherwise create a new one
+ if (typeof doc !== "object") {
+ doc = JSON.parse('{"' + root + '":"' + msg + '"}');
+ }
+ } catch (e) {
+ // payload is not in JSON format
+ doc = JSON.parse('{"' + root + '":"' + msg + '"}');
+ }
+ } else {
+ // clone so we don't change the original message
+ doc = JSON.parse(JSON.stringify(msg));
+ }
+ return doc;
+ }
+
+ // fix field values that start with _
+ // https://wiki.apache.org/couchdb/HTTP_Document_API#Special_Fields
+ function cleanMessage(msg) {
+ delete msg._msgid;
+
+ for (var key in msg) {
+ if (msg.hasOwnProperty(key) && !isFieldNameValid(key)) {
+ // remove _ from the start of the field name
+ var newKey = key.substring(1, msg.length);
+ msg[newKey] = msg[key];
+ delete msg[key];
+ node.warn("Property '" + key + "' renamed to '" + newKey + "'.");
+ }
+ }
+ return msg;
+ }
+
+ function isFieldNameValid(key) {
+ var allowedWords = [
+ '_id', '_rev', '_attachments', '_deleted', '_revisions',
+ '_revs_info', '_conflicts', '_deleted_conflicts', '_local_seq'
+ ];
+ return key[0] !== '_' || allowedWords.indexOf(key) >= 0;
+ }
+
+ // Inserts a document +doc+ in a database +db+ that migh not exist
+ // beforehand. If the database doesn't exist, it will create one
+ // with the name specified in +db+. To prevent loops, it only tries
+ // +attempts+ number of times.
+ function insertDocument(cloudant, node, doc, attempts, callback) {
+ var db = cloudant.use(node.database);
+ db.insert(doc, function (err, body) {
+ if (err && err.status_code === 404 && attempts > 0) {
+ // status_code 404 means the database was not found
+ return cloudant.db.create(db.config.db, function () {
+ insertDocument(cloudant, node, doc, attempts - 1, callback);
+ });
+ }
+
+ callback(err, body);
+ });
+ }
+ };
+ RED.nodes.registerType("cloudant out", CloudantOutNode);
+
+ function CloudantInNode(n) {
+ RED.nodes.createNode(this, n);
+
+ this.cloudantConfig = _getCloudantConfig(n);
+ this.database = _cleanDatabaseName(n.database, this);
+ this.search = n.search;
+ this.design = n.design;
+ this.index = n.index;
+ this.inputId = "";
+
+ var node = this;
+ var credentials = {
+ account: node.cloudantConfig.account,
+ key: node.cloudantConfig.username,
+ password: node.cloudantConfig.password,
+ url: node.cloudantConfig.url
+ };
+
+ Cloudant(credentials, function (err, cloudant) {
+ if (err) {
+ node.error(err.description, err);
+ }
+
+ node.on("input", function (msg) {
+ if (err) {
+ _attachDbError(err, msg);
+ return node.error(err.description, msg);
+ }
+
+ var db = cloudant.use(node.database);
+ var options = (typeof msg.payload === "object") ? msg.payload : {};
+
+ if (node.search === "_id_") {
+ var id = getDocumentId(msg.payload);
+ node.inputId = id;
+
+ db.get(id, function (err, body) {
+ sendDocumentOnPayload(err, body, msg);
+ });
+ } else if (node.search === "_idx_") {
+ options.query = options.query || options.q || formatSearchQuery(msg.payload);
+ options.include_docs = options.include_docs || true;
+ options.limit = options.limit || 200;
+
+ db.search(node.design, node.index, options, function (err, body) {
+ sendDocumentOnPayload(err, body, msg);
+ });
+ } else if (node.search === "_all_") {
+ options.include_docs = options.include_docs || true;
+
+ db.list(options, function (err, body) {
+ sendDocumentOnPayload(err, body, msg);
+ });
+ }
+ });
+ });
+
+
+ function getDocumentId(payload) {
+ if (typeof payload === "object") {
+ if ("_id" in payload || "id" in payload) {
+ return payload.id || payload._id;
+ }
+ }
+
+ return payload;
+ }
+
+ function formatSearchQuery(query) {
+ if (typeof query === "object") {
+ // useful when passing the query on HTTP params
+ if ("q" in query) {
+ return query.q;
+ }
+
+ var queryString = "";
+ for (var key in query) {
+ queryString += key + ":" + query[key] + " ";
+ }
+
+ return queryString.trim();
+ }
+ return query;
+ }
+
+ function sendDocumentOnPayload(err, body, msg) {
+ if (!err) {
+ //msg.cloudant = body;
+
+ if ("rows" in body) {
+ msg.payload = body.rows.
+ map(function (el) {
+ if (el.doc._id.indexOf("_design/") < 0) {
+ return el.doc;
+ }
+ }).
+ filter(function (el) {
+ return el !== null && el !== undefined;
+ });
+ } else {
+ msg.payload = body;
+ }
+ node.send(msg);
+ } else {
+ _attachDbError(err, msg);
+ node.error(err, msg);
+ }
+
+ }
+ }
+ RED.nodes.registerType("cloudant in", CloudantInNode);
+
+ // must return an object with, at least, values for account, username and
+ // password for the Cloudant service at the top-level of the object
+ function _getCloudantConfig(n) {
+ if (n.service === "_ext_") {
+ return RED.nodes.getNode(n.cloudant);
+
+ } else if (n.service !== "") {
+ var service = appEnv.getService(n.service);
+ var cloudantConfig = {};
+
+ var host = service.credentials.host;
+
+ cloudantConfig.username = service.credentials.username;
+ cloudantConfig.password = service.credentials.password;
+ cloudantConfig.account = host.substring(0, host.indexOf('.'));
+
+ return cloudantConfig;
+ }
+ }
+
+ // remove invalid characters from the database name
+ // https://wiki.apache.org/couchdb/HTTP_database_API#Naming_and_Addressing
+ function _cleanDatabaseName(database, node) {
+ var newDatabase = database;
+
+ // caps are not allowed
+ newDatabase = newDatabase.toLowerCase();
+ // remove trailing underscore
+ newDatabase = newDatabase.replace(/^_/, '');
+ // remove spaces and slashed
+ newDatabase = newDatabase.replace(/[\s\\/]+/g, '-');
+
+ if (newDatabase !== database) {
+ node.warn("Database renamed as '" + newDatabase + "'.");
+ }
+
+ return newDatabase;
+ }
+
+ function _attachDbError(err, msg){
+ delete msg.dbError;
+ msg.dbError = {};
+
+ msg.dbError.statusCode = err.statusCode !== undefined ? err.statusCode : null;
+ msg.dbError.description = err.description !== undefined ? err.description : null;
+ msg.dbError.message = err.message !== undefined ? err.message : null;
+ msg.dbError.reason = err.reason !== undefined ? err.reason : null;
+ msg.dbError.scope = err.scope !== undefined ? err.scope : null;
+ }
+};
diff --git a/README.md b/README.md
index 5a5edb9..00a92ba 100644
--- a/README.md
+++ b/README.md
@@ -23,10 +23,9 @@ in JSON format, it will be transformed before being stored.
For **update** and **delete**, you must pass the `_id` and the `_rev`as part
of the input `msg` object.
-For **insert** and **update**, you can specify that an output message is generated - either
-always (all) or for success or error. In the event of an error the message output will be the original
-message with a dbError field showing the error. For successful inserts or updates, the message output
-will be the original message with the _id and _rev fields updated in either the message body or in the payload.
+For **insert** and **update**, you can specify that an output message is generated.
+For successful inserts or updates, the message output will be the original message
+with the _id and _rev fields updated in either the message body or in the payload.
To **search** for a document you have two options: get a document directly by
its `_id` or use an existing [search index](https://cloudant.com/for-developers/search/)
@@ -36,6 +35,10 @@ from the database. For both cases, the query should be passed in the
When getting documents by id, the `payload` will be the desired `_id` value.
For `search indexes`, the query should follow the format `indexName:value`.
+Errors are returned via node.error(err, msg) calls and can be caught by Catch nodes present
+on the same tab, msg objects are returned and available to the Catch nodes.
+Additional database error details are added to msg.dbError.
+
Authors
-------
* Luiz Gustavo Ferraz Aoqui - [laoqui@ca.ibm.com](mailto:laoqui@ca.ibm.com)