API Docs for: 0.9.0
Show:

File: lib/storageAdapter/keyValueStorageAdapter.js

// Copyright 2014, Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

var Promise = require('promise');
var uuid = require('uuid');
var PNGImage = require('pngjs-image');

var StorageAdapter = require('./storageAdapter');

/**
 * Key-Value storage adapter
 *
 * @class KeyValueStorageAdapter
 * @extends StorageAdapter
 * @constructor
 * @param {object} options
 * @param {ConnectionAdapter} options.connection
 * @param {string} options.company
 * @param {string} options.department
 * @param {string} options.project
 * @param {string} options.job
 *
 * @property {ConnectionAdapter} _connection
 * @property {string} _company
 * @property {object} _companyInfo
 * @property {string} _department
 * @property {object} _departmentInfo
 * @property {string} _project
 * @property {object} _projectInfo
 * @property {string} _job
 * @property {object} _jobInfo
 * @property {object} _buildInfo
 */
var KeyValueStorageAdapter = StorageAdapter.extend(

	/** @lends KeyValueStorageAdapter.prototype */
	{
		/**
		 * Initializes the source-adapter
		 *
		 * @method initialize
		 */
		initialize: function () {
			this.__super();

			this._connection = this._options.connection;
			this._company = this._options.company;
			this._department = this._options.department;
			this._project = this._options.project;
			this._job = this._options.job;

			this.setPromise(this._prepareCompanyBucket());
			this.setPromise(this._prepareDepartmentBucket());
			this.setPromise(this._prepareProjectBucket());
			this.setPromise(this._prepareJobBucket());
			this.setPromise(this._prepareBuildBucket());
		},


		/**
		 * Prepare a bucket
		 *
		 * @method _prepareBucket
		 * @return {Promise}
		 * @private
		 */
		_prepareBucket: function (bucketName, key, initialValue, failWhenExist) {

			return this.getPromise().then(function () {

				return this._connection.hasBucket(bucketName).then(function (hasBucket) {

					if (!hasBucket) {
						throw new Error('The ' + bucketName + ' bucket is not available in the key-value instance.');
					}
				});

			}.bind(this)).then(function () {

				return this._connection.hasBucketKey(bucketName, key, this._bucketKeyFilter).then(function (hasBucketKey) {

					if (hasBucketKey) {
						if (failWhenExist) {
							throw new Error('The ' + bucketName + ' bucket with key ' + key + ' is already available in the key-value instance.');
						}
					} else {
						return this._connection.setObjectFromJSON(bucketName, key, initialValue);
					}
				}.bind(this));

			}.bind(this));
		},


		/**
		 * Prepare the companies bucket
		 *
		 * @method _prepareCompanyBucket
		 * @return {Promise}
		 * @private
		 */
		_prepareCompanyBucket: function () {
			var id = 'company_' + uuid.v4();
			return this._prepareBucket('companies', this._company, {
				id: id
			}).then(function () {
				return this._connection.getObjectAsJSON('companies', this._company).then(function (info) {
					this._companyInfo = info;
				}.bind(this));
			}.bind(this));
		},

		/**
		 * Prepare the departments bucket
		 *
		 * @method _prepareDepartmentBucket
		 * @return {Promise}
		 * @private
		 */
		_prepareDepartmentBucket: function () {
			var id = 'department_' + uuid.v4();
			return this._prepareBucket('departments', this._department, {
				id: id
			}).then(function () {
				return this._connection.getObjectAsJSON('departments', this._department).then(function (info) {
					this._departmentInfo = info;
				}.bind(this));
			}.bind(this));
		},

		/**
		 * Prepare the projects bucket
		 *
		 * @method _prepareProjectBucket
		 * @return {Promise}
		 * @private
		 */
		_prepareProjectBucket: function () {
			var id = 'project_' + uuid.v4();
			return this._prepareBucket('projects', this._project, {
				id: id
			}).then(function () {
				return this._connection.getObjectAsJSON('projects', this._project).then(function (info) {
					this._projectInfo = info;
				}.bind(this));
			}.bind(this));
		},

		/**
		 * Prepare the jobs bucket
		 *
		 * @method _prepareJobBucket
		 * @return {Promise}
		 * @private
		 */
		_prepareJobBucket: function () {
			var id = 'job_' + uuid.v4();
			return this._prepareBucket('jobs', this._job, {
				id: id,
				approvedScreensBucket: this._getCurrentApprovedScreenBucket(id)
			}).then(function () {
				return this._connection.getObjectAsJSON('jobs', this._job).then(function (info) {
					this._jobInfo = info;
				}.bind(this));
			}.bind(this));
		},

		/**
		 * Prepare the build bucket
		 *
		 * @method _prepareBuildBucket
		 * @return {Promise}
		 * @private
		 */
		_prepareBuildBucket: function () {
			var id = 'build_' + uuid.v4();
			this._buildInfo = {
				id: id,
				creationTime: +(new Date()),
				approvedScreensBucket: this._getApprovedScreenBucket(id),
				highlightScreensBucket: this._getHighlightScreenBucket(id),
				buildScreensBucket: this._getBuildScreenBucket(id)
			};
			return this._prepareBucket('builds', this._build, this._buildInfo, true);
		},


		/**
		 * Loads an image blob and returns a promise for it
		 *
		 * @method _loadImage
		 * @param {Buffer} blob
		 * @returns {Promise} With {PNGImage} Image
		 * @private
		 */
		_loadImage: function (blob) {
			return new Promise(function (resolve, reject) {
				PNGImage.loadImage(blob, function (err, image) {
					if (err) {
						reject(err);
					} else {
						resolve(image);
					}
				});
			})
		},

		/**
		 * Saves an image to a blob and returns a promise for it
		 *
		 * @method _blobImage
		 * @param {PNGImage} image
		 * @returns {Promise} With {Buffer} Blob
		 * @private
		 */
		_blobImage: function (image) {
			return new Promise(function (resolve, reject) {
				image.toBlob(function (err, blob) {
					if (err) {
						reject(err);
					} else {
						resolve(blob);
					}
				});
			})
		},


		/**
		 * Gets the current approved-screen bucket
		 *
		 * @method _getCurrentApprovedScreenBucket
		 * @param {string} [id]
		 * @return {string}
		 * @private
		 */
		_getCurrentApprovedScreenBucket: function (id) {
			return (id || this._jobInfo.id) + '_approved';
		},

		/**
		 * Gets the approved-screen bucket
		 *
		 * @method _getApprovedScreenBucket
		 * @param {string} [id]
		 * @return {string}
		 * @private
		 */
		_getApprovedScreenBucket: function (id) {
			return (id || this._buildInfo.id) + '_approved';
		},

		/**
		 * Gets the highlight-screen bucket
		 *
		 * @method _getHighlightScreenBucket
		 * @param {string} [id]
		 * @return {string}
		 * @private
		 */
		_getHighlightScreenBucket: function (id) {
			return (id || this._buildInfo.id) + '_highlight';
		},

		/**
		 * Gets the build-screen bucket
		 *
		 * @method _getBuildScreenBucket
		 * @param {string} [id]
		 * @return {string}
		 * @private
		 */
		_getBuildScreenBucket: function (id) {
			return (id || this._buildInfo.id) + '_build';
		},


		/**
		 * Key filter for bucket keys
		 *
		 * @method _bucketKeyFilter
		 * @param {string} key
		 * @return {boolean}
		 * @private
		 */
		_bucketKeyFilter: function (key) {
			return (key.substr(0, 1) !== '_');
		},


		/**
		 * Gets a list of currently approve screen names
		 *
		 * @method getCurrentApprovedScreenNames
		 * @return {Promise} With {string[]} List of approved screen names
		 */
		getCurrentApprovedScreenNames: function () {
			return this.getPromise().then(function () {
				return this._connection.getBucketKeys(this._getCurrentApprovedScreenBucket());
			}.bind(this));
		},

		/**
		 * Gets a specific currently approved screen
		 *
		 * @method getCurrentApprovedScreen
		 * @param {string} name Name of approved screen
		 * @return {Promise} With {PNGImage} Approved screen
		 */
		getCurrentApprovedScreen: function (name) {
			return this.getPromise().then(function () {
				return this._connection.getObject(this._getCurrentApprovedScreenBucket(), name);
			}.bind(this)).then(function (blob) {
				return this._loadImage(blob);
			});
		},

		/**
		 * Archives a specific currently approved screen
		 *
		 * @method archiveCurrentApprovedScreen
		 * @param {string} name Name of approved screen
		 * @param {PNGImage} image Screen to archive
		 * @return {Promise}
		 */
		archiveCurrentApprovedScreen: function (name, image) {
			return this.getPromise().then(function () {
				return this._blobImage(image);
			}.bind(this)).then(function (blob) {
				return this._connection.setObject(this._getCurrentApprovedScreenBucket(), name, blob, 'image/png');
			}.bind(this));
		},


		/**
		 * Gets a list of approve screen names
		 *
		 * @method getApprovedScreenNames
		 * @return {Promise} With {string[]} List of approved screen names
		 */
		getApprovedScreenNames: function () {
			return this.getPromise().then(function () {
				return this._connection.getBucketKeys(this._getApprovedScreenBucket());
			}.bind(this));
		},

		/**
		 * Gets a specific approved screen
		 *
		 * @method getApprovedScreen
		 * @param {string} name Name of approved screen
		 * @return {Promise} With {PNGImage} Approved screen
		 */
		getApprovedScreen: function (name) {
			return this.getPromise().then(function () {
				return this._connection.getObject(this._getApprovedScreenBucket(), name);
			}.bind(this)).then(function (blob) {
				return this._loadImage(blob);
			});
		},

		/**
		 * Archives a specific approved screen
		 *
		 * @method archiveApprovedScreen
		 * @param {string} name Name of approved screen
		 * @param {PNGImage} image Screen to archive
		 * @return {Promise}
		 */
		archiveApprovedScreen: function (name, image) {
			return this.getPromise().then(function () {
				return this._blobImage(image);
			}.bind(this)).then(function (blob) {
				return this._connection.setObject(this._getApprovedScreenBucket(), name, blob, 'image/png');
			}.bind(this));
		},


		/**
		 * Gets a list of build screen names
		 *
		 * @method getBuildScreenNames
		 * @return {Promise} With {string[]} List of build screen names
		 */
		getBuildScreenNames: function () {
			return this.getPromise().then(function () {
				return this._connection.getBucketKeys(this._getBuildScreenBucket());
			}.bind(this));
		},

		/**
		 * Gets a specific build screen
		 *
		 * @method getBuildScreen
		 * @param {string} name Name of build screen
		 * @return {Promise} With {PNGImage}
		 */
		getBuildScreen: function (name) {
			return this.getPromise().then(function () {
				return this._connection.getObject(this._getBuildScreenBucket(), name);
			}.bind(this)).then(function (blob) {
				return this._loadImage(blob);
			});
		},

		/**
		 * Archives a specific build screen
		 *
		 * @method archiveBuildScreen
		 * @param {string} name Name of build screen
		 * @param {PNGImage} image Screen to archive
		 * @return {Promise}
		 */
		archiveBuildScreen: function (name, image) {
			return this.getPromise().then(function () {
				return this._blobImage(image);
			}.bind(this)).then(function (blob) {
				return this._connection.setObject(this._getBuildScreenBucket(), name, blob, 'image/png');
			}.bind(this));
		},


		/**
		 * Gets a list of build highlight names
		 *
		 * @method getHighlightScreenNames
		 * @return {Promise} With {string[]} List of build screen names
		 */
		getHighlightScreenNames: function () {
			return this.getPromise().then(function () {
				return this._connection.getBucketKeys(this._getHighlightScreenBucket());
			}.bind(this));
		},

		/**
		 * Gets a specific highlight screen
		 *
		 * @method getHighlightScreen
		 * @param {string} name Name of build screen
		 * @return {Promise} With {PNGImage} Build screen
		 */
		getHighlightScreen: function (name) {
			return this.getPromise().then(function () {
				return this._connection.getObject(this._getHighlightScreenBucket(), name);
			}.bind(this)).then(function (blob) {
				return this._loadImage(blob);
			});
		},

		/**
		 * Archives a specific highlight screen
		 *
		 * @method archiveHighlightScreen
		 * @param {string} name Name of highlight screen
		 * @param {PNGImage} image Screen to archive
		 * @return {Promise}
		 */
		archiveHighlightScreen: function (name, image) {
			return this.getPromise().then(function () {
				return this._blobImage(image);
			}.bind(this)).then(function (blob) {
				return this._connection.setObject(this._getHighlightScreenBucket(), name, blob, 'image/png');
			}.bind(this));
		}
	},

	{
		/**
		 * Type of class
		 *
		 * @property TYPE
		 * @type string
		 */
		TYPE: 'KeyValueStorageAdapter'
	});

module.exports = KeyValueStorageAdapter;