Source: index.js

'use strict';

/** @class
* @param {znHttp} znHttp A ZnHttp reference
*/
function BackendFactory(znHttp) {

	if (!znHttp) {
		znHttp = require('../../../lib/zn-http')();
	}

	let self = {};

	/**
	 * @function formatResponse
	 * @memberof BackendFactory
	 * @description Helper to format API response data.
	 *
	 * @param {Response} response A Node Response object.
	 *
	 * @return {Array<Object>} An array of  plain objects containing the results.
	 */
	self.formatResponse = response => {
		return response.getBody().data;
	};

	/**
	 * @function errHandler
	 * @memberof BackendFactory
	 * @description Helper to handle API errors.
	 *
	 * @param {Response} err A Node Response object.
	 */
	self.errHandler = err => {
		// @TODO whether to throw an actual error is tentative.
		throw new Error(err.getBody());
	};

	/**
	 * @function getActivity
	 * @memberof BackendFactory
	 * @description Load an Activity by id.
	 *
	 * @param {number} id The activity id.
	 *
	 * @return {Promise<Array<Object>>}
	 */
	self.getActivity = id => {
		return znHttp.get('/activities/' + id).then(self.formatResponse);
	};

	/**
	 * @function getRecord
	 * @memberof BackendFactory
	 * @description Load a record by id.
	 *
	 * @param {number} formId
	 * @param {number} recordId
	 *
	 * @return {Promise<Object>}
	 */
	self.getRecord = (formId, recordId) => {
		return znHttp.get('/forms/' + formId + '/records/' + recordId).then(self.formatResponse);
	};

	/**
	 * @function createRecord
	 * @memberof BackendFactory
	 * @description Creates a new record.
	 *
	 * @param {number} formId
	 * @param {Object} data Record data.
	 *
	 * @return {Promise<Object>}
	 */
	self.createRecord = (formId, data) => {
		return znHttp.post('/forms/' + formId + '/records', data).then(self.formatResponse);
	};

	/**
	 * @function updateRecord
	 * @memberof BackendFactory
	 * @description Updates an existing record.
	 *
	 * @param {number} formId
	 * @param {number} recordId
	 * @param {Object} data Record data.
	 *
	 * @return {Promise<Object>}
	 */
	self.updateRecord = (formId, recordId, data) => {
		return znHttp.put('/forms/' + formId + '/records/' + recordId, data).then(self.formatResponse);
	};

	/**
	 * @function deleteRecord
	 * @memberof BackendFactory
	 * @description Deletes a record.
	 *
	 * @param {number} formId
	 * @param {number} recordId
	 *
	 * @return {Promise<Object>}
	 */
	self.deleteRecord = (formId, recordId) => {
		return znHttp.del('/forms/' + formId + '/records/' + recordId).then(self.formatResponse);
	};

	/**
	 * @function getForm
	 * @memberof BackendFactory
	 * @description Gets a form.
	 *
	 * @param {number} formId
	 *
	 * @return {Promise<Object>}
	 */
	self.getForm = formId => {
		return znHttp.get('/forms/' + formId).then(self.formatResponse);
	};

	/**
	 * @function moveRecord
	 * @memberof BackendFactory
	 * @description Convenience method to move a record to a given folder.
	 *
	 * @param {number} formId
	 * @param {number} recordId
	 * @param {number} folderId
	 *
	 * @return {Promise<Object>}
	 */
	self.moveRecord = (formId, recordId, folderId) => {
		var data = {
			id: recordId,
			folder: {
				id: folderId
			}
		};
		return self.updateRecord(formId, recordId, data);
	};

	/**
	 * @function fetchBatched
	 * @memberof BackendFactory
	 * @description fetch all for given resource
	 *
	 * @param {string} path valid Zengine API url params (ex: '/forms/123/records')
	 * @param {object} params key/value pairs of query params (ex: { limit: 50, folder: 1234 })
	 *
	 * @returns {any[]} An array of Zengine objects
	 */
	self.fetchBatched = (path, params = {}) => {
		/**
		 * @param {number} page
		 * @param {object[]} results
		 * @param {number} limit this parameter is necessary to accurately maintain the limit across calls, in the event the API returns a different limit than the user defines in `params`
		 *
		 * @returns {Promise<object[]>} recursively calls API and returns all relevant data
		 */
		function getPage (page = 1, results = [], limit = params.limit || 20) {
			return znHttp.get(path, { params: { ...params, limit, page } })
				.then(res => {
					const body = res.getBody();
					const limit = body.limit;
					const total = body.totalCount;

					body.data && results.push(...body.data); // jshint ignore:line

					return total > page * limit ? getPage(page + 1, results, limit) : results;
				});
			}

		return getPage();
	};

	/**
	 * @function fetchBatchedPaginated
	 * @memberof BackendFactory
	 * @description fetch all for a given resource, chunked by page
	 *
	 * @param {number} path
	 * @param {object} params
	 *
	 * @returns {object[][]} An array of arrays storing the Zengine resources
	 */
	self.fetchBatchedPaginated = (path, params = {}) => {
		/**
		 * @param {number} page
		 * @param {object[][]} pages
		 * @param {number} limit this parameter is necessary to accurately maintain the limit across calls, in the event the API returns a different limit than the user defines in `params`
		 *
		 * @returns {Promise<object[][]>} recursively calls API and returns paginated data
		 */
		function getPage (page = 1, pages = [], limit = params.limit || 20) {
			return znHttp.get(path, { params: { ...params, limit, page } })
				.then(res => {
					const body = res.getBody();
					const limit = body.limit;
					const total = body.totalCount;

					body.data && pages.push(body.data);// jshint ignore:line

					return total > page * limit ? getPage(page + 1, pages, limit) : pages;
				});
			}

		return getPage();
	};

	return self;

}

module.exports = BackendFactory;