2015-03-19 23:48:04 +00:00
|
|
|
/*global define*/
|
|
|
|
|
|
|
|
define(
|
2015-03-20 00:04:16 +00:00
|
|
|
[],
|
|
|
|
function () {
|
2015-03-19 23:48:04 +00:00
|
|
|
'use strict';
|
|
|
|
|
2015-03-20 00:04:16 +00:00
|
|
|
// JSLint doesn't like underscore-prefixed properties,
|
|
|
|
// so hide them here.
|
|
|
|
var SRC = "_source",
|
|
|
|
REV = "_version",
|
2015-03-20 20:40:53 +00:00
|
|
|
ID = "_id",
|
|
|
|
CONFLICT = 409;
|
2015-03-19 23:48:04 +00:00
|
|
|
|
|
|
|
/**
|
2015-03-20 00:04:16 +00:00
|
|
|
* The ElasticPersistenceProvider reads and writes JSON documents
|
|
|
|
* (more specifically, domain object models) to/from an ElasticSearch
|
2015-03-19 23:48:04 +00:00
|
|
|
* instance.
|
|
|
|
* @constructor
|
|
|
|
*/
|
2015-03-20 00:04:16 +00:00
|
|
|
function ElasticPersistenceProvider($http, $q, SPACE, ROOT, PATH) {
|
2015-03-19 23:48:04 +00:00
|
|
|
var spaces = [ SPACE ],
|
|
|
|
revs = {};
|
|
|
|
|
|
|
|
// Convert a subpath to a full path, suitable to pass
|
|
|
|
// to $http.
|
|
|
|
function url(subpath) {
|
2015-03-20 00:04:16 +00:00
|
|
|
return ROOT + '/' + PATH + '/' + subpath;
|
2015-03-19 23:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Issue a request using $http; get back the plain JS object
|
|
|
|
// from the expected JSON response
|
2015-03-20 00:04:16 +00:00
|
|
|
function request(subpath, method, value, params) {
|
2015-03-19 23:48:04 +00:00
|
|
|
return $http({
|
|
|
|
method: method,
|
|
|
|
url: url(subpath),
|
2015-03-20 00:04:16 +00:00
|
|
|
params: params,
|
2015-03-19 23:48:04 +00:00
|
|
|
data: value
|
|
|
|
}).then(function (response) {
|
|
|
|
return response.data;
|
2015-03-20 21:06:11 +00:00
|
|
|
}, function (response) {
|
|
|
|
return (response || {}).data;
|
2015-03-19 23:48:04 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shorthand methods for GET/PUT methods
|
|
|
|
function get(subpath) {
|
|
|
|
return request(subpath, "GET");
|
|
|
|
}
|
2015-03-20 00:04:16 +00:00
|
|
|
function put(subpath, value, params) {
|
|
|
|
return request(subpath, "PUT", value, params);
|
|
|
|
}
|
|
|
|
function del(subpath) {
|
|
|
|
return request(subpath, "DELETE");
|
2015-03-19 23:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pull out a list of document IDs from CouchDB's
|
|
|
|
// _all_docs response
|
|
|
|
function getIdsFromAllDocs(allDocs) {
|
|
|
|
return allDocs.rows.map(function (r) { return r.id; });
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a domain object model out of CouchDB's response
|
|
|
|
function getModel(response) {
|
2015-03-20 00:04:16 +00:00
|
|
|
if (response && response[SRC]) {
|
2015-03-19 23:48:04 +00:00
|
|
|
revs[response[ID]] = response[REV];
|
2015-03-20 00:04:16 +00:00
|
|
|
return response[SRC];
|
2015-03-19 23:48:04 +00:00
|
|
|
} else {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-20 20:40:53 +00:00
|
|
|
// Handle an update error
|
|
|
|
function handleError(response, key) {
|
|
|
|
var error = new Error("Persistence error.");
|
|
|
|
if ((response || {}).status === CONFLICT) {
|
|
|
|
error.key = "revision";
|
|
|
|
// Load the updated model, then reject the promise
|
|
|
|
return get(key).then(function (model) {
|
|
|
|
error.model = model;
|
|
|
|
throw error;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// Reject the promise
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
|
2015-03-19 23:48:04 +00:00
|
|
|
// Check the response to a create/update/delete request;
|
|
|
|
// track the rev if it's valid, otherwise return false to
|
|
|
|
// indicate that the request failed.
|
2015-03-20 20:40:53 +00:00
|
|
|
function checkResponse(response, key) {
|
|
|
|
var error;
|
|
|
|
if (response && !response.error) {
|
2015-03-20 21:06:11 +00:00
|
|
|
revs[key] = response[REV];
|
2015-03-20 20:40:53 +00:00
|
|
|
return response;
|
2015-03-19 23:48:04 +00:00
|
|
|
} else {
|
2015-03-20 20:40:53 +00:00
|
|
|
return handleError(response, key);
|
2015-03-19 23:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
/**
|
|
|
|
* List all persistence spaces which this provider
|
|
|
|
* recognizes.
|
|
|
|
*
|
|
|
|
* @returns {Promise.<string[]>} a promise for a list of
|
|
|
|
* spaces supported by this provider
|
|
|
|
*/
|
|
|
|
listSpaces: function () {
|
|
|
|
return $q.when(spaces);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* List all objects (by their identifiers) that are stored
|
|
|
|
* in the given persistence space, per this provider.
|
|
|
|
* @param {string} space the space to check
|
|
|
|
* @returns {Promise.<string[]>} a promise for the list of
|
|
|
|
* identifiers
|
|
|
|
*/
|
|
|
|
listObjects: function (space) {
|
|
|
|
return get("_all_docs").then(getIdsFromAllDocs);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Create a new object in the specified persistence space.
|
|
|
|
* @param {string} space the space in which to store the object
|
|
|
|
* @param {string} key the identifier for the persisted object
|
|
|
|
* @param {object} value a JSONifiable object that should be
|
|
|
|
* stored and associated with the provided identifier
|
|
|
|
* @returns {Promise.<boolean>} a promise for an indication
|
|
|
|
* of the success (true) or failure (false) of this
|
|
|
|
* operation
|
|
|
|
*/
|
|
|
|
createObject: function (space, key, value) {
|
2015-03-20 00:04:16 +00:00
|
|
|
return put(key, value).then(checkResponse);
|
2015-03-19 23:48:04 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read an existing object back from persistence.
|
|
|
|
* @param {string} space the space in which to look for
|
|
|
|
* the object
|
|
|
|
* @param {string} key the identifier for the persisted object
|
|
|
|
* @returns {Promise.<object>} a promise for the stored
|
|
|
|
* object; this will resolve to undefined if no such
|
|
|
|
* object is found.
|
|
|
|
*/
|
|
|
|
readObject: function (space, key) {
|
|
|
|
return get(key).then(getModel);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Update an existing object in the specified persistence space.
|
|
|
|
* @param {string} space the space in which to store the object
|
|
|
|
* @param {string} key the identifier for the persisted object
|
|
|
|
* @param {object} value a JSONifiable object that should be
|
|
|
|
* stored and associated with the provided identifier
|
|
|
|
* @returns {Promise.<boolean>} a promise for an indication
|
|
|
|
* of the success (true) or failure (false) of this
|
|
|
|
* operation
|
|
|
|
*/
|
2015-03-20 21:39:47 +00:00
|
|
|
updateObject: function (space, key, value, options) {
|
|
|
|
var check = (options || {}).check;
|
2015-03-20 20:40:53 +00:00
|
|
|
function checkUpdate(response) {
|
|
|
|
return checkResponse(response, key);
|
|
|
|
}
|
2015-03-20 21:39:47 +00:00
|
|
|
return put(key, value, check && { version: revs[key] })
|
2015-03-20 20:40:53 +00:00
|
|
|
.then(checkUpdate);
|
2015-03-19 23:48:04 +00:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Delete an object in the specified persistence space.
|
|
|
|
* @param {string} space the space from which to delete this
|
|
|
|
* object
|
|
|
|
* @param {string} key the identifier of the persisted object
|
|
|
|
* @param {object} value a JSONifiable object that should be
|
|
|
|
* deleted
|
|
|
|
* @returns {Promise.<boolean>} a promise for an indication
|
|
|
|
* of the success (true) or failure (false) of this
|
|
|
|
* operation
|
|
|
|
*/
|
|
|
|
deleteObject: function (space, key, value) {
|
2015-03-20 00:04:16 +00:00
|
|
|
return del(key).then(checkResponse);
|
2015-03-19 23:48:04 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return ElasticPersistenceProvider;
|
|
|
|
}
|
|
|
|
);
|