adding actions
diff --git a/actions/account-actions/create-database.js b/actions/account-actions/create-database.js
new file mode 100755
index 0000000..eeda689
--- /dev/null
+++ b/actions/account-actions/create-database.js
@@ -0,0 +1,65 @@
+ /**
+ * Create database in Cloudant account:
+ * https://docs.cloudant.com/database.html#get-databases
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ if (!dbName) {
+ return whisk.error('dbname is required.');
+ }
+
+ var promise = createDatabase(cloudant, dbName);
+ return promise;
+
+}
+
+function createDatabase(cloudant, dbName) {
+ return new Promise(function(resolve, reject) {
+ cloudant.db.create(dbName, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/account-actions/delete-database.js b/actions/account-actions/delete-database.js
new file mode 100755
index 0000000..f4e414f
--- /dev/null
+++ b/actions/account-actions/delete-database.js
@@ -0,0 +1,63 @@
+/**
+ * Delete database from Cloudant account:
+ * https://docs.cloudant.com/database.html#deleting-a-database
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ if (!dbName) {
+ return whisk.error('dbname is required.');
+ }
+
+ return destroyDatabase(cloudant, dbName);
+}
+
+function destroyDatabase(cloudant, dbName) {
+ return new Promise(function(resolve, reject) {
+ cloudant.db.destroy(dbName, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/account-actions/list-all-databases.js b/actions/account-actions/list-all-databases.js
new file mode 100755
index 0000000..da44b1d
--- /dev/null
+++ b/actions/account-actions/list-all-databases.js
@@ -0,0 +1,61 @@
+/**
+ * Get all databases in Cloudant account:
+ * https://docs.cloudant.com/database.html#get-databases
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+
+ return listAllDatabases(cloudant);
+}
+
+function listAllDatabases(cloudant) {
+ return new Promise(function(resolve, reject) {
+ cloudant.db.list(function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ //Response is an array and only JSON objects can be passed to whisk.done
+ var responseObj = {};
+ responseObj.all_databases = response;
+ resolve(responseObj);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/account-actions/read-database.js b/actions/account-actions/read-database.js
new file mode 100755
index 0000000..6744c97
--- /dev/null
+++ b/actions/account-actions/read-database.js
@@ -0,0 +1,62 @@
+/**
+ * Read database in Cloudant account:
+ * https://docs.cloudant.com/database.html#read
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ if (!dbName) {
+ return whisk.error('dbname is required.');
+ }
+
+ return readDatabase(cloudant, dbName);
+}
+
+function readDatabase(cloudant, dbName) {
+ return new Promise(function(resolve, reject) {
+ cloudant.db.get(dbName, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/account-actions/read-updates-feed.js b/actions/account-actions/read-updates-feed.js
new file mode 100755
index 0000000..24ad092
--- /dev/null
+++ b/actions/account-actions/read-updates-feed.js
@@ -0,0 +1,69 @@
+/**
+ * Read updates feed from Cloudant database:
+ * https://docs.cloudant.com/advanced.html#get-/_db_updates
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var params = {};
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return readUpdatesFeed(cloudant, params);
+}
+
+function readUpdatesFeed(cloudant, params) {
+ return new Promise(function(resolve, reject) {
+ cloudant.updates(params, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/changes.js b/actions/changes.js
new file mode 100644
index 0000000..9b0ef08
--- /dev/null
+++ b/actions/changes.js
@@ -0,0 +1,82 @@
+var request = require('request');
+
+function main(msg) {
+ console.log("cloudant trigger feed: ", msg);
+
+ // lifecycleEvent is one of [ create, delete ]
+ var lifecycleEvent = (msg.lifecycleEvent || 'CREATE').trim().toUpperCase();
+
+ // whisk trigger to fire
+ var trigger = msg.triggerName;
+ var replaceNameTrigger = trigger.replace(/\//g, ":");
+
+ // configuration parameters
+ var provider_endpoint = msg.package_endpoint;
+ var dbname = msg.dbname;
+ var user = msg.username;
+ var pass = msg.password;
+ var includeDoc = msg.includeDoc || false;
+ var host = msg.host;
+ var maxTriggers = msg.maxTriggers || 1000;
+
+ if (lifecycleEvent == 'CREATE') {
+ // auth key for trigger
+ var apiKey = msg.authKey;
+ var auth = apiKey.split(':');
+ var input = {};
+ input["accounturl"] = "https://" + host;
+ input["dbname"] = dbname;
+ input["user"] = user;
+ input["pass"] = pass;
+ input["includeDoc"] = includeDoc;
+ input["apikey"] = apiKey;
+ input["maxTriggers"] = maxTriggers;
+ input["callback"] = {};
+ input["callback"]["action"] = {};
+ input["callback"]["action"]["name"] = trigger;
+
+ return cloudantHelper(provider_endpoint, 'put', replaceNameTrigger, auth, input);
+ } else if (lifecycleEvent == 'DELETE') {
+ return cloudantHelper(provider_endpoint, 'delete', replaceNameTrigger);
+ } else {
+ return whisk.error('operation is neither CREATE or DELETE');
+ }
+}
+
+function cloudantHelper(endpoint, verb, name, auth, input) {
+ var uri = 'http://' + endpoint + '/cloudanttriggers/' + name;
+ var options = {
+ method : verb,
+ uri : uri
+ };
+
+ if(auth){
+ options.auth = {
+ user : auth[0],
+ pass : auth[1]
+ }
+ }
+
+ if (verb === 'put') {
+ options.json = input;
+ }
+
+ var promise = new Promise(function(resolve, reject) {
+ request(options, function(error, response, body) {
+ console.log('cloudant trigger feed: done http request', '[error:]', error);
+ if (!error && response.statusCode == 200) {
+ console.log(body);
+ resolve();
+ } else {
+ if (response) {
+ console.log('response code:', response.statusCode);
+ } else {
+ console.log('no response');
+ }
+ reject(error);
+ }
+ });
+ });
+
+ return promise;
+}
diff --git a/actions/database-actions/create-document.js b/actions/database-actions/create-document.js
new file mode 100755
index 0000000..9de6c85
--- /dev/null
+++ b/actions/database-actions/create-document.js
@@ -0,0 +1,94 @@
+/**
+ * Create a document in Cloudant database:
+ * https://docs.cloudant.com/document.html#documentCreate
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var doc = message.doc;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!doc) {
+ return whisk.error('doc is required.');
+ }
+
+ if (typeof message.doc === 'object') {
+ doc = message.doc;
+ } else if (typeof message.doc === 'string') {
+ try {
+ doc = JSON.parse(message.doc);
+ } catch (e) {
+ return whisk.error('doc field cannot be parsed. Ensure it is valid JSON.');
+ }
+ } else {
+ return whisk.error('doc field is ' + (typeof doc) + ' and should be an object or a JSON string.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return insert(cloudantDb, doc, params);
+}
+
+/**
+ * Create document in database.
+ */
+function insert(cloudantDb, doc, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.insert(doc, params, function(error, response) {
+ if (!error) {
+ console.log("success", response);
+ resolve(response);
+ } else {
+ console.log("error", error)
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/create-query-index.js b/actions/database-actions/create-query-index.js
new file mode 100755
index 0000000..2507e6b
--- /dev/null
+++ b/actions/database-actions/create-query-index.js
@@ -0,0 +1,78 @@
+/**
+ * Create a Cloudant index:
+ * https://docs.cloudant.com/cloudant_query.html#creating-an-index
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var index = message.index;
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!index) {
+ return whisk.error('index is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return createIndex(cloudantDb, index);
+}
+
+function createIndex(cloudantDb, index) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.index(index, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(response);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/create-update-attachment.js b/actions/database-actions/create-update-attachment.js
new file mode 100755
index 0000000..de9e110
--- /dev/null
+++ b/actions/database-actions/create-update-attachment.js
@@ -0,0 +1,98 @@
+/**
+ * Create and update attachment for document in Cloudant database:
+ * https://docs.cloudant.com/attachments.html#create-/-update
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var attName = message.attachmentname;
+ var att = message.attachment;
+ var contentType = message.contenttype;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ if(!attName) {
+ return whisk.error('attachmentname is required.');
+ }
+ if(!att) {
+ return whisk.error('attachment is required.');
+ }
+ if(!contentType) {
+ return whisk.error('contenttype is required.');
+ }
+ //Add document revision to query if it exists
+ if(typeof message.docrev !== 'undefined') {
+ params.rev = message.docrev;
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return insert(cloudantDb, docId, attName, att, contentType, params);
+}
+
+/**
+ * Insert attachment for document in database.
+ */
+function insert(cloudantDb, docId, attName, att, contentType, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.attachment.insert(docId, attName, att, contentType, params, function(error, response) {
+ if (!error) {
+ console.log("success", response);
+ resolve(response);
+ } else {
+ console.log("error", error)
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/delete-attachment.js b/actions/database-actions/delete-attachment.js
new file mode 100755
index 0000000..dacb951
--- /dev/null
+++ b/actions/database-actions/delete-attachment.js
@@ -0,0 +1,93 @@
+/**
+ * Delete attachment for document in Cloudant database:
+ * https://docs.cloudant.com/attachments.html#delete
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var attName = message.attachmentname;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ if(!attName) {
+ return whisk.error('attachmentname is required.');
+ }
+ //Add document revision to query if it exists
+ if(typeof message.docrev !== 'undefined') {
+ params.rev = message.docrev;
+ } else {
+ return whisk.error('docrev is required.');
+ }
+
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return deleteAttachment(cloudantDb, docId, attName, params);
+}
+
+/**
+ * Delete attachment for document in database.
+ */
+function deleteAttachment(cloudantDb, docId, attName, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.attachment.destroy(docId, attName, params, function(error, response) {
+ if (!error) {
+ console.log("success", response);
+ resolve(response);
+ } else {
+ console.log("error", error)
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/delete-document.js b/actions/database-actions/delete-document.js
new file mode 100755
index 0000000..7448e65
--- /dev/null
+++ b/actions/database-actions/delete-document.js
@@ -0,0 +1,76 @@
+/**
+ * Delete a document from Cloudant database:
+ * https://docs.cloudant.com/document.html#delete
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var docRev = message.docrev;
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ if(!docRev) {
+ return whisk.error('docrev is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ return destroy(cloudantDb, docId, docRev);
+
+}
+
+/**
+ * Delete document by id and rev.
+ */
+function destroy(cloudantDb, docId, docRev) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.destroy(docId, docRev, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.error('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/delete-query-index.js b/actions/database-actions/delete-query-index.js
new file mode 100755
index 0000000..522be2e
--- /dev/null
+++ b/actions/database-actions/delete-query-index.js
@@ -0,0 +1,86 @@
+/**
+ * Delete a Cloudant index:
+ * https://docs.cloudant.com/cloudant_query.html#deleting-an-index
+ **/
+
+var DESIGN_PREFIX = '_design/';
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var indexName = message.indexname;
+ var indexType = message.indextype;
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ if(!indexName) {
+ return whisk.error('indexname is required.');
+ }
+ if(!indexType) {
+ return whisk.error('indextype is required.');
+ }
+
+ return deleteIndexFromDesignDoc(cloudant, docId, indexName, indexType, dbName);
+}
+
+function deleteIndexFromDesignDoc(cloudant, docId, indexName, indexType, dbName) {
+
+ return new Promise(function(resolve, reject) {
+ var path = "_index/" + encodeURIComponent(docId)
+ + '/' + encodeURIComponent(indexType)
+ + '/' + encodeURIComponent(indexName);
+
+ cloudant.request({ db: encodeURIComponent(dbName),
+ method : 'delete',
+ path : path
+ }, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/delete-view.js b/actions/database-actions/delete-view.js
new file mode 100755
index 0000000..ae018be
--- /dev/null
+++ b/actions/database-actions/delete-view.js
@@ -0,0 +1,115 @@
+/**
+ * Delete a view from design document in Cloudant database:
+ * https://docs.cloudant.com/design_documents.html
+ **/
+
+var DESIGN_PREFIX = '_design/';
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var viewName = message.viewname;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if(!viewName) {
+ return whisk.error('viewname is required.');
+ }
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return deleteViewFromDesignDoc(cloudantDb, docId, viewName, params);
+}
+
+function deleteViewFromDesignDoc(cloudantDb, docId, viewName, params) {
+ //Check that doc id contains _design prefix
+ if (docId.indexOf(DESIGN_PREFIX) !== 0) {
+ docId = DESIGN_PREFIX + docId;
+ }
+
+ return getDocument(cloudantDb, docId)
+ .then(function(document) {
+ console.log("Got document: " + document);
+ delete document.views[viewName];
+
+ //Update the design document after removing the view
+ return insert(cloudantDb, document, params);
+ });
+}
+
+function getDocument(cloudantDb, docId) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.get(docId, function(error, response) {
+ if (!error) {
+ console.log("Got response: " + response);
+ resolve(response);
+ } else {
+ console.log("Got error: " + error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function insert(cloudantDb, doc, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.insert(doc, params, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error)
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/exec-query-find.js b/actions/database-actions/exec-query-find.js
new file mode 100755
index 0000000..2c85b1e
--- /dev/null
+++ b/actions/database-actions/exec-query-find.js
@@ -0,0 +1,81 @@
+/**
+ * Query using a Cloudant Query index:
+ * https://docs.cloudant.com/cloudant_query.html#finding-documents-using-an-index
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var query = message.query;
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!query) {
+ return whisk.error('query field is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.query === 'object') {
+ query = message.query;
+ } else if (typeof message.query === 'string') {
+ try {
+ query = JSON.parse(message.query);
+ } catch (e) {
+ return whisk.error('query field cannot be parsed. Ensure it is valid JSON.');
+ }
+ } else {
+ return whisk.error('query field is ' + (typeof query) + ' and should be an object or a JSON string.');
+ }
+
+ return queryIndex(cloudantDb, query);
+
+}
+
+function queryIndex(cloudantDb, query) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.find(query, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/exec-query-search.js b/actions/database-actions/exec-query-search.js
new file mode 100755
index 0000000..75d4f92
--- /dev/null
+++ b/actions/database-actions/exec-query-search.js
@@ -0,0 +1,89 @@
+/**
+ * Query with Cloudant search:
+ * https://docs.cloudant.com/search.html#queries
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var indexName = message.indexname;
+ var search = message.search;
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ if(!indexName) {
+ return whisk.error('indexname is required.');
+ }
+ if(!search) {
+ return whisk.error('search query is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ //Search should be in the form of {"q":"index:my query"}
+ if (typeof message.search === 'object') {
+ search = message.search;
+ } else if (typeof message.search === 'string') {
+ try {
+ search = JSON.parse(message.search);
+ } catch (e) {
+ return whisk.error('search field cannot be parsed. Ensure it is valid JSON.');
+ }
+ } else {
+ return whisk.error('search field is ' + (typeof search) + ' and should be an object or a JSON string.');
+ }
+
+ return querySearch(cloudantDb, docId, indexName, search);
+}
+
+function querySearch(cloudantDb, designDocId, designViewName, search) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.search(designDocId, designViewName, search, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/exec-query-view.js b/actions/database-actions/exec-query-view.js
new file mode 100755
index 0000000..dc1a611
--- /dev/null
+++ b/actions/database-actions/exec-query-view.js
@@ -0,0 +1,86 @@
+/**
+ * Execute view against Cloudant database:
+ * https://docs.cloudant.com/creating_views.html#using-views
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var viewName = message.viewname;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ if(!viewName) {
+ return whisk.error('viewname is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return queryView(cloudantDb, docId, viewName, params);
+}
+
+/**
+ * Get view by design doc id and view name.
+ */
+function queryView(cloudantDb, designDocId, designDocViewName, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.view(designDocId, designDocViewName, params, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.error('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/list-design-documents.js b/actions/database-actions/list-design-documents.js
new file mode 100755
index 0000000..8cd60eb
--- /dev/null
+++ b/actions/database-actions/list-design-documents.js
@@ -0,0 +1,79 @@
+/**
+ * List design documents in Cloudant database:
+ * https://docs.cloudant.com/design_documents.html
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var includeDocs = message.includedocs;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+ //Add start and end key to get _design docs
+ params.startkey = '_design'.toString();
+ params.endkey = '_design0'.toString();
+
+ //If includeDoc exists and is true, add field to additional params object
+ includeDocs = includeDocs.toString().trim().toLowerCase();
+ console.log('includeDocs: ' + includeDocs);
+ if(includeDocs === 'true') {
+ params.include_docs = 'true';
+ }
+
+ return listDesignDocuments(cloudantDb, params);
+}
+
+/**
+ * List design documents.
+ **/
+function listDesignDocuments(cloudantDb, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.list(params, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.error("error", error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/list-documents.js b/actions/database-actions/list-documents.js
new file mode 100755
index 0000000..1a576de
--- /dev/null
+++ b/actions/database-actions/list-documents.js
@@ -0,0 +1,78 @@
+/**
+ * Get all documents in Cloudant database:
+ * https://docs.cloudant.com/database.html#get-documents
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return listAllDocuments(cloudantDb, params);
+}
+
+/**
+ * List all documents.
+ */
+function listAllDocuments(cloudantDb, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.list(params, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.error("error", error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/list-query-indexes.js b/actions/database-actions/list-query-indexes.js
new file mode 100755
index 0000000..b91fc98
--- /dev/null
+++ b/actions/database-actions/list-query-indexes.js
@@ -0,0 +1,64 @@
+/**
+ * List Cloudant Query indexes in Cloudant database:
+ * https://docs.cloudant.com/cloudant_query.html#list-all-cloudant-query-indexes
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ return index(cloudantDb);
+}
+
+function index(cloudantDb) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.index(function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/manage-bulk-documents.js b/actions/database-actions/manage-bulk-documents.js
new file mode 100755
index 0000000..e99851c
--- /dev/null
+++ b/actions/database-actions/manage-bulk-documents.js
@@ -0,0 +1,93 @@
+/**
+ * Create, Update, and Delete documents in bulk:
+ * https://docs.cloudant.com/document.html#bulk-operations
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docs = message.docs;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docs) {
+ return whisk.error('docs is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ if (typeof message.docs === 'object') {
+ docs = message.docs;
+ } else if (typeof message.docs === 'string') {
+ try {
+ docs = JSON.parse(message.docs);
+ } catch (e) {
+ return whisk.error('docs field cannot be parsed. Ensure it is valid JSON.');
+ }
+ } else {
+ return whisk.error('docs field is ' + (typeof docs) + ' and should be an object or a JSON string.');
+ }
+
+ return bulk(cloudantDb, docs, params);
+}
+
+function bulk(cloudantDb, docs, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.bulk(docs, params, function(error, response) {
+ if (!error) {
+ var responseDocs = {};
+ responseDocs.docs = response;
+ console.log('success', response);
+ resolve(responseDocs);
+ } else {
+ console.log('Error: ', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/read-attachment.js b/actions/database-actions/read-attachment.js
new file mode 100755
index 0000000..a4827af
--- /dev/null
+++ b/actions/database-actions/read-attachment.js
@@ -0,0 +1,91 @@
+/**
+ * Read attachment for document in Cloudant database:
+ * https://docs.cloudant.com/attachments.html#read
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var attName = message.attachmentname;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ if(!attName) {
+ return whisk.error('attachmentname is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ //Add document revision to query if it exists
+ if(typeof message.docrev != 'undefined') {
+ params.rev = message.docrev;
+ }
+
+ return read(cloudantDb, docId, attName, params);
+}
+
+/**
+ * Read attachment for document in database.
+ */
+function read(cloudantDb, docId, attName, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.attachment.get(docId, attName, params, function(error, response) {
+ if (!error) {
+ console.log("success", response);
+ resolve(response);
+ } else {
+ console.log("error", error)
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/read-changes-feed.js b/actions/database-actions/read-changes-feed.js
new file mode 100755
index 0000000..256ff04
--- /dev/null
+++ b/actions/database-actions/read-changes-feed.js
@@ -0,0 +1,74 @@
+/**
+ * Read changes feed from Cloudant database:
+ * https://docs.cloudant.com/database.html#get-changes
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return changes(cloudant, dbName, params);
+}
+
+function changes(cloudant, dbName, params) {
+ return new Promise(function(resolve, reject) {
+ cloudant.db.changes(dbName, params, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.error('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/read-document.js b/actions/database-actions/read-document.js
new file mode 100755
index 0000000..bd1631f
--- /dev/null
+++ b/actions/database-actions/read-document.js
@@ -0,0 +1,79 @@
+/**
+ * Read a document in Cloudant database:
+ * https://docs.cloudant.com/document.html#read
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var docId = message.docid;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+ if(!docId) {
+ return whisk.error('docid is required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return readDocument(cloudantDb, docId, params);
+}
+
+function readDocument(cloudantDb, docId, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.get(docId, params, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.error('error', error);
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}
diff --git a/actions/database-actions/update-document.js b/actions/database-actions/update-document.js
new file mode 100755
index 0000000..6486502
--- /dev/null
+++ b/actions/database-actions/update-document.js
@@ -0,0 +1,94 @@
+/**
+ * Update a document in Cloudant database:
+ * https://docs.cloudant.com/document.html#update
+ **/
+
+function main(message) {
+ var cloudantOrError = getCloudantAccount(message);
+ if (typeof cloudantOrError !== 'object') {
+ return whisk.error('getCloudantAccount returned an unexpected object type.');
+ }
+ var cloudant = cloudantOrError;
+ var dbName = message.dbname;
+ var doc = message.doc;
+ var params = {};
+
+ if(!dbName) {
+ return whisk.error('dbname is required.');
+ }
+
+ if (typeof message.doc === 'object') {
+ doc = message.doc;
+ } else if (typeof message.doc === 'string') {
+ try {
+ doc = JSON.parse(message.doc);
+ } catch (e) {
+ return whisk.error('doc field cannot be parsed. Ensure it is valid JSON.');
+ }
+ } else {
+ return whisk.error('doc field is ' + (typeof doc) + ' and should be an object or a JSON string.');
+ }
+ if(!doc || !doc.hasOwnProperty("_rev")) {
+ return whisk.error('doc and doc._rev are required.');
+ }
+ var cloudantDb = cloudant.use(dbName);
+
+ if (typeof message.params === 'object') {
+ params = message.params;
+ } else if (typeof message.params === 'string') {
+ try {
+ params = JSON.parse(message.params);
+ } catch (e) {
+ return whisk.error('params field cannot be parsed. Ensure it is valid JSON.');
+ }
+ }
+
+ return insert(cloudantDb, doc, params);
+}
+
+/**
+ * Inserts updated document into database.
+ */
+function insert(cloudantDb, doc, params) {
+ return new Promise(function(resolve, reject) {
+ cloudantDb.insert(doc, params, function(error, response) {
+ if (!error) {
+ console.log('success', response);
+ resolve(response);
+ } else {
+ console.log('error', error)
+ reject(error);
+ }
+ });
+ });
+}
+
+function getCloudantAccount(message) {
+ // full cloudant URL - Cloudant NPM package has issues creating valid URLs
+ // when the username contains dashes (common in Bluemix scenarios)
+ var cloudantUrl;
+
+ if (message.url) {
+ // use bluemix binding
+ cloudantUrl = message.url;
+ } else {
+ if (!message.host) {
+ whisk.error('cloudant account host is required.');
+ return;
+ }
+ if (!message.username) {
+ whisk.error('cloudant account username is required.');
+ return;
+ }
+ if (!message.password) {
+ whisk.error('cloudant account password is required.');
+ return;
+ }
+
+ cloudantUrl = "https://" + message.username + ":" + message.password + "@" + message.host;
+ }
+
+ return require('cloudant')({
+ url: cloudantUrl
+ });
+}