Commit 863c7420 authored by Tristan Cavelier's avatar Tristan Cavelier

replicate storage redesigned, WIP

parent 054e9fc8
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, nomen: true, regexp: true */
/*global jIO: true */ /*global define, jIO */
jIO.addStorageType('replicate', function (spec, my) {
var that, cloned_option, priv = {}, // {
super_serialized = that.serialized; // "type": "replicate",
// "storage_list": [<storage spec>, ...]
// "conditions": {
// "modified": "greatest date",
// "type": {"action": "afs", "coefficient": 2},
// }
// }
spec = spec || {}; // conditions:
that = my.basicStorage(spec, my); // - lastest date (ld)/ earliest date (ed)
// - greatest number (gn) / lowest number (ln) // 2 > 1
// - alphabeticaly farthest string (afs) / alph.. closest string (acs)
// - greatest version (gv) / lowest version (lv) // '1.10c' > '1.9c'
// - longest list (ll) / shortest list (sl) // [0].length > [].length
// - longest string (ls) / shortest string (ss) // 'a'.length > ''.length
// - contains content type (contentType) // ["aa", "text/plain"] > ["zz", "zz"]
// - contains DCMIType vocabulary (DCMIType)
// // ["aa", "Text"] > ["zz", "Web Page"]
priv.return_value_array = []; // define([module_name], [dependencies], module);
priv.storagelist = spec.storagelist || []; (function (dependencies, module) {
priv.nb_storage = priv.storagelist.length; "use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO);
}(['jio'], function (jIO) {
"use strict";
that.serialized = function () { var actions = {}, content_type_re = new RegExp(
var o = super_serialized(); "^\\s*([a-z]+/[a-zA-Z0-9\\+\\-\\.]+)\\s*" +
o.storagelist = priv.storagelist; "(?:;\\s*charset\\s*=\\s*([a-zA-Z0-9\\-]+)\\s*)?$"
return o; ), dcmi_types = {
'Collection': 'Collection',
'Dataset': 'Dataset',
'Event': 'Event',
'Image': 'Image',
'InteractiveResource': 'InteractiveResource',
'MovingImage': 'MovingImage',
'PhysicalObject': 'PhysicalObject',
'Service': 'Service',
'Software': 'Software',
'Sound': 'Sound',
'StillImage': 'StillImage',
'Text': 'Text'
}; };
that.validateState = function () {
if (priv.storagelist.length === 0) { /**
return 'Need at least one parameter: "storagelist" ' + * Returns the number with the lowest value
'containing at least one storage.'; *
* @param {Number} *values The values to compare
* @return {Number} The minimum
*/
function min() {
var i, val;
for (i = 1; i < arguments.length; i += 1) {
if (val === undefined || val > arguments[i]) {
val = arguments[i];
}
}
return val;
}
/**
* Creates a new array of numbers, strings, or booleans from a metadata array.
*
* @param {Array} array The metadata array
* @return {Array} The new array
*/
function metadataArrayToContentArray(array) {
var i;
array = array.slice();
for (i = 0; i < array.length; i += 1) {
if (typeof array[i] === 'object') {
array[i] = array[i].content;
}
} }
return ''; return array;
}
// initialize actions
actions.ld = function compareAsDate(a, b) {
a = new Date(a);
b = new Date(b);
return a < b ? -1 : a > b ? 1 : 0;
}; };
actions['lastest date'] = actions.ld;
priv.isTheLast = function (error_array) { actions.ed = function (a, b) {
return (error_array.length === priv.nb_storage); return -actions.ld(a, b);
}; };
actions['earliest date'] = actions.ed;
priv.doJob = function (command, errormessage, nodocid) { actions.gn = function compareAsNumber(a, b) {
var done = false, a = parseFloat(a);
error_array = [], b = parseFloat(b);
i, if (a < b) {
error = function (err) { return -1;
if (!done) { }
error_array.push(err); if (b < a) {
if (priv.isTheLast(error_array)) { return 1;
that.error({ }
status: 207, if (isNaN(a)) {
statusText: 'Multi-Status', if (isNaN(b)) {
error: 'multi_status', return 0;
message: 'All ' + errormessage + (!nodocid ? ' "' + }
command.getDocId() + '"' : ' ') + ' requests have failed.', return -1;
reason: 'requests fail',
array: error_array
});
}
}
},
success = function (val) {
if (!done) {
done = true;
that.success(val);
}
};
for (i = 0; i < priv.nb_storage; i += 1) {
cloned_option = command.cloneOption();
that.addJob(command.getLabel(), priv.storagelist[i],
command.cloneDoc(), cloned_option, success, error);
} }
if (isNaN(b)) {
return 1;
}
return 0;
}; };
actions['greatest number'] = actions.gn;
that.post = function (command) { actions.ln = function (a, b) {
priv.doJob(command, 'post'); return -actions.gn(a, b);
that.end();
}; };
actions['lowest number'] = actions.ln;
/** actions.afs = function compareAsString(a, b) {
* Save a document in several storages. if (Array.isArray(a)) {
* @method put a = metadataArrayToContentArray(a).join(', ');
*/ } else if (typeof a === 'object') {
that.put = function (command) { a = a.content.toString();
priv.doJob(command, 'put'); } else {
that.end(); a = a.toString();
}
if (Array.isArray(b)) {
b = metadataArrayToContentArray(b).join(', ');
} else if (typeof b === 'object') {
b = b.content.toString();
} else {
a = a.toString();
}
return a < b ? -1 : a > b ? 1 : 0;
}; };
actions['alphabeticaly farthest string'] = actions.afs;
/** actions.acs = function (a, b) {
* Load a document from several storages, and send the first retreived return -actions.afs(a, b);
* document. };
* @method get
*/ actions.ll = function compareLengthAsList(a, b) {
that.get = function (command) { if (!Array.isArray(a)) {
priv.doJob(command, 'get'); a = 1;
that.end(); } else {
a = a.length;
}
if (!Array.isArray(b)) {
b = 1;
} else {
b = b.length;
}
return a < b ? -1 : a > b ? 1 : 0;
};
actions['longest list'] = actions.ll;
actions.sl = function (a, b) {
return -actions.ll(a, b);
}; };
actions['shortest list'] = actions.sl;
actions.ls = function compareLengthAsString(a, b) {
if (a === undefined || a === null) {
a = 0;
} else {
a = a.toString().length;
}
if (b === undefined || b === null) {
b = 0;
} else {
b = b.toString().length;
}
return a < b ? -1 : a > b ? 1 : 0;
};
actions['longest string'] = actions.ls;
actions.ss = function (a, b) {
return -actions.ls(a, b);
};
actions['shortest string'] = actions.ss;
/** /**
* Get a document list from several storages, and returns the first * Splits the version into an array of numbers and separators
* retreived document list. *
* @method allDocs * @param {String} str The string to split
* @return {Array} The splited version
*/ */
that.allDocs = function (command) { function versionSplit(str) {
priv.doJob(command, 'allDocs', true); var part, res = [];
that.end(); if (str === undefined || str === null) {
}; return [];
}
str = str.toString().trim();
while (part !== null && str !== '') {
part = /([0-9]+)?([^0-9]+)?/.exec(str);
if (part[1] !== undefined) {
res[res.length] = parseInt(part[1], 10);
}
res[res.length] = part[2];
str = str.slice(part[0].length);
}
return res;
}
/** /**
* Remove a document from several storages. * Comparison function to compare version string. This function can be used
* @method remove * in the Array.prototype.sort method.
*
* @param {String} a The first value to compare
* @param {String} b The second value to compare
* @return {Number} if a < b: -1, if a > b: 1, else 0
*/ */
that.remove = function (command) { actions.gv = function compareVersion(a, b) {
priv.doJob(command, 'remove'); var i, l;
that.end(); a = versionSplit(a);
b = versionSplit(b);
l = min(a.length, b.length);
for (i = 0; i < l; i += 1) {
if (a[i] < b[i]) {
return -1;
}
if (a[i] > b[i]) {
return 1;
}
}
if (i < a.length) {
return 1;
}
if (i < b.length) {
return -1;
}
return 0;
};
actions['greatest version'] = actions.gv;
actions.lv = function (a, b) {
return -actions.gv(a, b);
};
actions['lowest version'] = actions.lv;
function getMetadataContentType(meta) {
var i, res;
if (!Array.isArray(meta)) {
meta = [meta];
}
for (i = 0; i < meta.length; i += 1) {
if (typeof meta[i] === 'object') {
res = meta[i].content;
} else {
res = meta[i];
}
res = content_type_re.exec(res.toString());
if (res !== null) {
return res[1] + (res[2] !== undefined ? ";charset=" + res[2] : "");
}
}
}
actions.contentType = function (a, b) {
a = getMetadataContentType(a);
b = getMetadataContentType(b);
if (a === undefined) {
if (b === undefined) {
return 0;
}
return -1;
}
if (b === undefined) {
return 1;
}
return 0;
}; };
actions['contains content type'] = actions.contentType;
function getMetadataDCMIType(meta) {
var i, res;
if (!Array.isArray(meta)) {
meta = [meta];
}
for (i = 0; i < meta.length; i += 1) {
if (typeof meta[i] === 'object') {
res = meta[i].content;
} else {
res = meta[i];
}
if (dcmi_types[res]) {
return res;
}
}
}
actions.DCMIType = function (a, b) {
a = getMetadataDCMIType(a);
b = getMetadataDCMIType(b);
if (a === undefined) {
if (b === undefined) {
return 0;
}
return -1;
}
if (b === undefined) {
return 1;
}
return 0;
};
actions['contains DCMIType vocabulary'] = actions.DCMIType;
function runDocumentMetadataRound(documents, metadata, action, coef) {
var i, res, winners = [0];
for (i = 1; i < documents.length; i += 1) {
res = actions[action](documents[winners[0]][0], documents[i][0]);
if (res === 0) {
winners[winners.length] = i;
} else if (res < 0) {
winners = [i];
}
}
for (i = 0; i < winners.length; i += 1) {
documents[winners[i]][1] += coef;
}
return documents;
}
function runDocumentMetadataBattle(documents, conditions) {
var i, coef, action;
for (i = 0; i < documents.length; i += 1) {
documents[i] = [documents[i], 0];
}
for (i in conditions) {
if (conditions.hasOwnProperty(i)) {
if (typeof conditions[i] === 'string') {
action = conditions[i];
coef = 1;
} else if (typeof conditions[i] === 'object') {
action = conditions[i].action;
coef = conditions[i].coef;
if (typeof coef !== 'number' && coef === 0) {
action = '';
}
}
if (actions[action]) {
runDocumentMetadataRound(documents, i, action, coef);
}
}
}
return documents;
}
function replicateStorage(spec, my) {
var error, priv = {}, that = my.basicStorage(spec, my);
if (typeof spec.conditions !== 'object' ||
Object.getPrototypeOf(spec.conditions) !== Object.prototype) {
error = new TypeError("ReplicateStorage(): " +
"'conditions' is not of type 'object'");
}
if (Array.isArray(spec.storage_list)) {
error = new TypeError("ReplicateStorage(): " +
"'storage_list' is not of type 'array'");
}
//////////////////////////////
// Overrides
that.validateState = function () {
return error && error.message;
};
that.specToStore = function () {
return {
"storage_list": spec.storage_list,
"conditions": spec.conditions,
};
};
//////////////////////////////
// JIO Commands
that.post = function (command) {
var metadata, options;
metadata = command.cloneDoc();
options = command.cloneOptions();
};
return that;
}
jIO.addStorageType('replicate', replicateStorage);
return that; }));
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment