Commit f563c978 authored by Tristan Cavelier's avatar Tristan Cavelier

replicaterevisionstorage amd compatible now

parent 286266f6
/*jslint indent: 2, maxlen: 80, nomen: true */ /*jslint indent: 2, maxlen: 80, nomen: true */
/*global jIO: true */ /*global jIO, define */
/** /**
* JIO Replicate Revision Storage. * JIO Replicate Revision Storage.
* It manages storages that manage revisions and conflicts. * It manages storages that manage revisions and conflicts.
...@@ -12,666 +13,680 @@ ...@@ -12,666 +13,680 @@
* ] * ]
* } * }
*/ */
jIO.addStorageType('replicaterevision', function (spec, my) { // define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO);
}(['jio'], function (jIO) {
"use strict"; "use strict";
var that, priv = {}; jIO.addStorageType('replicaterevision', function (spec, my) {
spec = spec || {}; var that, priv = {};
that = my.basicStorage(spec, my); spec = spec || {};
that = my.basicStorage(spec, my);
priv.storage_list_key = "storage_list"; priv.storage_list_key = "storage_list";
priv.storage_list = spec[priv.storage_list_key]; priv.storage_list = spec[priv.storage_list_key];
priv.emptyFunction = function () {}; priv.emptyFunction = function () {};
that.specToStore = function () { that.specToStore = function () {
var o = {}; var o = {};
o[priv.storage_list_key] = priv.storage_list; o[priv.storage_list_key] = priv.storage_list;
return o; return o;
}; };
/** /**
* Generate a new uuid * Generate a new uuid
* @method generateUuid * @method generateUuid
* @return {string} The new uuid * @return {string} The new uuid
*/ */
priv.generateUuid = function () { priv.generateUuid = function () {
var S4 = function () { var S4 = function () {
var i, string = Math.floor( var i, string = Math.floor(
Math.random() * 0x10000 /* 65536 */ Math.random() * 0x10000 /* 65536 */
).toString(16); ).toString(16);
for (i = string.length; i < 4; i += 1) { for (i = string.length; i < 4; i += 1) {
string = "0" + string; string = "0" + string;
} }
return string; return string;
};
return S4() + S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + S4() + S4();
}; };
return S4() + S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + S4() + S4();
};
/** /**
* Create an array containing dictionnary keys * Create an array containing dictionnary keys
* @method dictKeys2Array * @method dictKeys2Array
* @param {object} dict The object to convert * @param {object} dict The object to convert
* @return {array} The array of keys * @return {array} The array of keys
*/ */
priv.dictKeys2Array = function (dict) { priv.dictKeys2Array = function (dict) {
var k, newlist = []; var k, newlist = [];
for (k in dict) { for (k in dict) {
if (dict.hasOwnProperty(k)) { if (dict.hasOwnProperty(k)) {
newlist.push(k); newlist.push(k);
}
} }
} return newlist;
return newlist; };
};
/** /**
* Checks a revision format * Checks a revision format
* @method checkRevisionFormat * @method checkRevisionFormat
* @param {string} revision The revision string * @param {string} revision The revision string
* @return {boolean} True if ok, else false * @return {boolean} True if ok, else false
*/ */
priv.checkRevisionFormat = function (revision) { priv.checkRevisionFormat = function (revision) {
return (/^[0-9]+-[0-9a-zA-Z_]+$/.test(revision)); return (/^[0-9]+-[0-9a-zA-Z_]+$/.test(revision));
}; };
/** /**
* Clones an object in deep (without functions) * Clones an object in deep (without functions)
* @method clone * @method clone
* @param {any} object The object to clone * @param {any} object The object to clone
* @return {any} The cloned object * @return {any} The cloned object
*/ */
priv.clone = function (object) { priv.clone = function (object) {
var tmp = JSON.stringify(object); var tmp = JSON.stringify(object);
if (tmp === undefined) { if (tmp === undefined) {
return undefined; return undefined;
} }
return JSON.parse(tmp); return JSON.parse(tmp);
}; };
/** /**
* Like addJob but also return the method and the index of the storage * Like addJob but also return the method and the index of the storage
* @method send * @method send
* @param {string} method The request method * @param {string} method The request method
* @param {number} index The storage index * @param {number} index The storage index
* @param {object} doc The document object * @param {object} doc The document object
* @param {object} option The request object * @param {object} option The request object
* @param {function} callback The callback. Parameters: * @param {function} callback The callback. Parameters:
* - {string} The request method * - {string} The request method
* - {number} The storage index * - {number} The storage index
* - {object} The error object * - {object} The error object
* - {object} The response object * - {object} The response object
*/ */
priv.send = function (method, index, doc, option, callback) { priv.send = function (method, index, doc, option, callback) {
var wrapped_callback_success, wrapped_callback_error; var wrapped_callback_success, wrapped_callback_error;
callback = callback || priv.emptyFunction; callback = callback || priv.emptyFunction;
wrapped_callback_success = function (response) { wrapped_callback_success = function (response) {
callback(method, index, undefined, response); callback(method, index, undefined, response);
};
wrapped_callback_error = function (err) {
callback(method, index, err, undefined);
};
that.addJob(
method,
priv.storage_list[index],
doc,
option,
wrapped_callback_success,
wrapped_callback_error
);
}; };
wrapped_callback_error = function (err) {
callback(method, index, err, undefined); /**
* Use "send" method to all sub storages.
* Calling "callback" for each storage response.
* @method sendToAll
* @param {string} method The request method
* @param {object} doc The document object
* @param {object} option The request option
* @param {function} callback The callback. Parameters:
* - {string} The request method
* - {number} The storage index
* - {object} The error object
* - {object} The response object
*/
priv.sendToAll = function (method, doc, option, callback) {
var i;
for (i = 0; i < priv.storage_list.length; i += 1) {
priv.send(method, i, doc, option, callback);
}
}; };
that.addJob(
/**
* Use "send" method to all sub storages.
* Calling "callback" only with the first response
* @method sendToAllFastestResponseOnly
* @param {string} method The request method
* @param {object} doc The document object
* @param {object} option The request option
* @param {function} callback The callback. Parameters:
* - {string} The request method
* - {object} The error object
* - {object} The response object
*/
priv.sendToAllFastestResponseOnly = function (
method, method,
priv.storage_list[index],
doc, doc,
option, option,
wrapped_callback_success, callback
wrapped_callback_error ) {
); var i, callbackWrapper, error_count, last_error;
}; error_count = 0;
callbackWrapper = function (method, index, err, response) {
/** if (err) {
* Use "send" method to all sub storages. error_count += 1;
* Calling "callback" for each storage response. last_error = err;
* @method sendToAll if (error_count === priv.storage_list.length) {
* @param {string} method The request method return callback(method, err, response);
* @param {object} doc The document object }
* @param {object} option The request option
* @param {function} callback The callback. Parameters:
* - {string} The request method
* - {number} The storage index
* - {object} The error object
* - {object} The response object
*/
priv.sendToAll = function (method, doc, option, callback) {
var i;
for (i = 0; i < priv.storage_list.length; i += 1) {
priv.send(method, i, doc, option, callback);
}
};
/**
* Use "send" method to all sub storages.
* Calling "callback" only with the first response
* @method sendToAllFastestResponseOnly
* @param {string} method The request method
* @param {object} doc The document object
* @param {object} option The request option
* @param {function} callback The callback. Parameters:
* - {string} The request method
* - {object} The error object
* - {object} The response object
*/
priv.sendToAllFastestResponseOnly = function (method, doc, option, callback) {
var i, callbackWrapper, error_count, last_error;
error_count = 0;
callbackWrapper = function (method, index, err, response) {
if (err) {
error_count += 1;
last_error = err;
if (error_count === priv.storage_list.length) {
return callback(method, err, response);
} }
callback(method, err, response);
};
for (i = 0; i < priv.storage_list.length; i += 1) {
priv.send(method, i, doc, option, callbackWrapper);
} }
callback(method, err, response);
}; };
for (i = 0; i < priv.storage_list.length; i += 1) {
priv.send(method, i, doc, option, callbackWrapper);
}
};
/** /**
* Use "sendToAll" method, calling "callback" at the last response with * Use "sendToAll" method, calling "callback" at the last response with
* the response list * the response list
* @method sendToAllGetResponseList * @method sendToAllGetResponseList
* @param {string} method The request method * @param {string} method The request method
* @param {object} doc The document object * @param {object} doc The document object
* @param {object} option The request option * @param {object} option The request option
* @return {function} callback The callback. Parameters: * @return {function} callback The callback. Parameters:
* - {string} The request method * - {string} The request method
* - {object} The error object * - {object} The error object
* - {object} The response object * - {object} The response object
*/ */
priv.sendToAllGetResponseList = function (method, doc, option, callback) { priv.sendToAllGetResponseList = function (method, doc, option, callback) {
var wrapper, callback_count = 0, response_list = [], error_list = []; var wrapper, callback_count = 0, response_list = [], error_list = [];
response_list.length = priv.storage_list.length; response_list.length = priv.storage_list.length;
wrapper = function (method, index, err, response) { wrapper = function (method, index, err, response) {
error_list[index] = err; error_list[index] = err;
response_list[index] = response; response_list[index] = response;
callback_count += 1; callback_count += 1;
if (callback_count === priv.storage_list.length) { if (callback_count === priv.storage_list.length) {
callback(error_list, response_list); callback(error_list, response_list);
} }
};
priv.sendToAll(method, doc, option, wrapper);
}; };
priv.sendToAll(method, doc, option, wrapper);
};
/**
* Checks if the sub storage are identical
* @method check
* @param {object} command The JIO command
*/
that.check = function (command) {
function callback(err, response) {
if (err) {
return that.error(err);
}
that.success(response);
}
priv.check(
command.cloneDoc(),
command.cloneOption(),
callback
);
};
/** /**
* Repair the sub storages to make them identical * Checks if the sub storage are identical
* @method repair * @method check
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.repair = function (command) { that.check = function (command) {
function callback(err, response) { function callback(err, response) {
if (err) { if (err) {
return that.error(err); return that.error(err);
}
that.success(response);
} }
that.success(response); priv.check(
} command.cloneDoc(),
priv.repair( command.cloneOption(),
command.cloneDoc(), callback
command.cloneOption(), );
true, };
callback
);
};
priv.check = function (doc, option, success, error) {
priv.repair(doc, option, false, success, error);
};
priv.repair = function (doc, option, repair, callback) { /**
var functions = {}; * Repair the sub storages to make them identical
callback = callback || priv.emptyFunction; * @method repair
option = option || {}; * @param {object} command The JIO command
functions.begin = function () { */
// }; that.repair = function (command) {
// functions.repairAllSubStorages = function () { function callback(err, response) {
var i; if (err) {
for (i = 0; i < priv.storage_list.length; i += 1) { return that.error(err);
priv.send( }
repair ? "repair" : "check", that.success(response);
i,
doc,
option,
functions.repairAllSubStoragesCallback
);
} }
priv.repair(
command.cloneDoc(),
command.cloneOption(),
true,
callback
);
}; };
functions.repair_sub_storages_count = 0;
functions.repairAllSubStoragesCallback = function (method, priv.check = function (doc, option, success, error) {
index, err, response) { priv.repair(doc, option, false, success, error);
if (err) {
return that.error(err);
}
functions.repair_sub_storages_count += 1;
if (functions.repair_sub_storages_count === priv.storage_list.length) {
functions.getAllDocuments(functions.newParam(
doc,
option,
repair
));
}
}; };
functions.newParam = function (doc, option, repair) {
var param = { priv.repair = function (doc, option, repair, callback) {
"doc": doc, // the document to repair var functions = {};
"option": option, callback = callback || priv.emptyFunction;
"repair": repair, option = option || {};
"responses": { functions.begin = function () {
"count": 0, // };
"list": [ // functions.repairAllSubStorages = function () {
// 0: response0 var i;
// 1: response1 for (i = 0; i < priv.storage_list.length; i += 1) {
// 2: response2 priv.send(
], repair ? "repair" : "check",
"stats": { i,
// responseA: [0, 1] doc,
// responseB: [2] option,
functions.repairAllSubStoragesCallback
);
}
};
functions.repair_sub_storages_count = 0;
functions.repairAllSubStoragesCallback = function (method,
index, err, response) {
if (err) {
return that.error(err);
}
functions.repair_sub_storages_count += 1;
if (functions.repair_sub_storages_count === priv.storage_list.length) {
functions.getAllDocuments(functions.newParam(
doc,
option,
repair
));
}
};
functions.newParam = function (doc, option, repair) {
var param = {
"doc": doc, // the document to repair
"option": option,
"repair": repair,
"responses": {
"count": 0,
"list": [
// 0: response0
// 1: response1
// 2: response2
],
"stats": {
// responseA: [0, 1]
// responseB: [2]
},
"stats_items": [
// 0: [responseA, [0, 1]]
// 1: [responseB, [2]]
],
"attachments": {
// attachmentA : {_id: attachmentA, _revs_info, _mimetype: ..}
// attachmentB : {_id: attachmentB, _revs_info, _mimetype: ..}
}
}, },
"stats_items": [ "conflicts": {
// 0: [responseA, [0, 1]] // revC: true
// 1: [responseB, [2]] // revD: true
], },
"attachments": { "deal_result_state": "ok",
// attachmentA : {_id: attachmentA, _revs_info, _mimetype: ..} "my_rev": undefined
// attachmentB : {_id: attachmentB, _revs_info, _mimetype: ..} };
param.responses.list.length = priv.storage_list.length;
return param;
};
functions.getAllDocuments = function (param) {
var i, doc = priv.clone(param.doc), option = priv.clone(param.option);
option.conflicts = true;
option.revs = true;
option.revs_info = true;
for (i = 0; i < priv.storage_list.length; i += 1) {
// if the document is not loaded
priv.send("get", i, doc, option, functions.dealResults(param));
}
functions.finished_count += 1;
};
functions.dealResults = function (param) {
return function (method, index, err, response) {
var response_object = {};
if (param.deal_result_state !== "ok") {
// deal result is in a wrong state, exit
return;
}
if (err) {
if (err.status !== 404) {
// get document failed, exit
param.deal_result_state = "error";
callback({
"status": 40,
"statusText": "Check Failed",
"error": "check_failed",
"message": "An error occured on the sub storage",
"reason": err.reason
}, undefined);
return;
}
} }
}, // success to get the document
"conflicts": { // add the response in memory
// revC: true param.responses.count += 1;
// revD: true param.responses.list[index] = response;
},
"deal_result_state": "ok", // add the conflicting revision for other synchronizations
"my_rev": undefined functions.addConflicts(param, (response || {})._conflicts);
if (param.responses.count !== param.responses.list.length) {
// this is not the last response, wait for the next response
return;
}
// this is now the last response
functions.makeResponsesStats(param.responses);
if (param.responses.stats_items.length === 1) {
// the responses are equals!
response_object.ok = true;
response_object.id = param.doc._id;
if (doc._rev) {
response_object.rev = doc._rev;
// "rev": (typeof param.responses.list[0] === "object" ?
// param.responses.list[0]._rev : undefined)
}
callback(undefined, response_object);
return;
}
// the responses are different
if (param.repair === false) {
// do not repair
callback({
"status": 41,
"statusText": "Check Not Ok",
"error": "check_not_ok",
"message": "Some documents are different in the sub storages",
"reason": "Storage contents differ"
}, undefined);
return;
}
// repair
functions.getAttachments(param);
};
}; };
param.responses.list.length = priv.storage_list.length; functions.addConflicts = function (param, list) {
return param; var i;
}; list = list || [];
functions.getAllDocuments = function (param) { for (i = 0; i < list.length; i += 1) {
var i, doc = priv.clone(param.doc), option = priv.clone(param.option); param.conflicts[list[i]] = true;
option.conflicts = true;
option.revs = true;
option.revs_info = true;
for (i = 0; i < priv.storage_list.length; i += 1) {
// if the document is not loaded
priv.send("get", i, doc, option, functions.dealResults(param));
}
functions.finished_count += 1;
};
functions.dealResults = function (param) {
return function (method, index, err, response) {
var response_object = {};
if (param.deal_result_state !== "ok") {
// deal result is in a wrong state, exit
return;
} }
if (err) { };
if (err.status !== 404) { functions.makeResponsesStats = function (responses) {
// get document failed, exit var i, str_response;
param.deal_result_state = "error"; for (i = 0; i < responses.count; i += 1) {
str_response = JSON.stringify(responses.list[i]);
if (responses.stats[str_response] === undefined) {
responses.stats[str_response] = [];
responses.stats_items.push([
str_response,
responses.stats[str_response]
]);
}
responses.stats[str_response].push(i);
}
};
functions.getAttachments = function (param) {
var response, parsed_response, attachment;
for (response in param.responses.stats) {
if (param.responses.stats.hasOwnProperty(response)) {
parsed_response = JSON.parse(response);
for (attachment in parsed_response._attachments) {
if ((parsed_response._attachments).hasOwnProperty(attachment)) {
functions.get_attachment_count += 1;
priv.send(
"getAttachment",
param.responses.stats[response][0],
{
"_id": param.doc._id,
"_attachment": attachment,
"_rev": JSON.parse(response)._rev
},
param.option,
functions.getAttachmentsCallback(
param,
attachment,
param.responses.stats[response]
)
);
}
}
}
}
};
functions.get_attachment_count = 0;
functions.getAttachmentsCallback = function (
param,
attachment_id,
index_list
) {
return function (method, index, err, response) {
if (err) {
callback({ callback({
"status": 40, "status": 40,
"statusText": "Check Failed", "statusText": "Check Failed",
"error": "check_failed", "error": "check_failed",
"message": "An error occured on the sub storage", "message": "Unable to retreive attachments",
"reason": err.reason "reason": err.reason
}, undefined); }, undefined);
return; return;
} }
} functions.get_attachment_count -= 1;
// success to get the document param.responses.attachments[attachment_id] = response;
// add the response in memory if (functions.get_attachment_count === 0) {
param.responses.count += 1; functions.synchronizeAllSubStorage(param);
param.responses.list[index] = response; if (param.option.synchronize_conflicts !== false) {
functions.synchronizeConflicts(param);
// add the conflicting revision for other synchronizations }
functions.addConflicts(param, (response || {})._conflicts);
if (param.responses.count !== param.responses.list.length) {
// this is not the last response, wait for the next response
return;
}
// this is now the last response
functions.makeResponsesStats(param.responses);
if (param.responses.stats_items.length === 1) {
// the responses are equals!
response_object.ok = true;
response_object.id = param.doc._id;
if (doc._rev) {
response_object.rev = doc._rev;
// "rev": (typeof param.responses.list[0] === "object" ?
// param.responses.list[0]._rev : undefined)
} }
callback(undefined, response_object); };
return;
}
// the responses are different
if (param.repair === false) {
// do not repair
callback({
"status": 41,
"statusText": "Check Not Ok",
"error": "check_not_ok",
"message": "Some documents are different in the sub storages",
"reason": "Storage contents differ"
}, undefined);
return;
}
// repair
functions.getAttachments(param);
}; };
}; functions.synchronizeAllSubStorage = function (param) {
functions.addConflicts = function (param, list) { var i, j, len = param.responses.stats_items.length;
var i; for (i = 0; i < len; i += 1) {
list = list || []; // browsing responses
for (i = 0; i < list.length; i += 1) { for (j = 0; j < len; j += 1) {
param.conflicts[list[i]] = true; // browsing storage list
} if (i !== j) {
}; functions.synchronizeResponseToSubStorage(
functions.makeResponsesStats = function (responses) { param,
var i, str_response; param.responses.stats_items[i][0],
for (i = 0; i < responses.count; i += 1) { param.responses.stats_items[j][1]
str_response = JSON.stringify(responses.list[i]);
if (responses.stats[str_response] === undefined) {
responses.stats[str_response] = [];
responses.stats_items.push([
str_response,
responses.stats[str_response]
]);
}
responses.stats[str_response].push(i);
}
};
functions.getAttachments = function (param) {
var response, parsed_response, attachment;
for (response in param.responses.stats) {
if (param.responses.stats.hasOwnProperty(response)) {
parsed_response = JSON.parse(response);
for (attachment in parsed_response._attachments) {
if ((parsed_response._attachments).hasOwnProperty(attachment)) {
functions.get_attachment_count += 1;
priv.send(
"getAttachment",
param.responses.stats[response][0],
{
"_id": param.doc._id,
"_attachment": attachment,
"_rev": JSON.parse(response)._rev
},
param.option,
functions.getAttachmentsCallback(
param,
attachment,
param.responses.stats[response]
)
); );
} }
} }
} }
} functions.finished_count -= 1;
}; };
functions.get_attachment_count = 0; functions.synchronizeResponseToSubStorage = function (
functions.getAttachmentsCallback = function ( param,
param, response,
attachment_id, storage_list
index_list ) {
) { var i, new_doc, attachment_to_put = [];
return function (method, index, err, response) { if (response === undefined) {
if (err) { // no response to sync
callback({
"status": 40,
"statusText": "Check Failed",
"error": "check_failed",
"message": "Unable to retreive attachments",
"reason": err.reason
}, undefined);
return; return;
} }
functions.get_attachment_count -= 1; new_doc = JSON.parse(response);
param.responses.attachments[attachment_id] = response; new_doc._revs = new_doc._revisions;
if (functions.get_attachment_count === 0) { delete new_doc._rev;
functions.synchronizeAllSubStorage(param); delete new_doc._revisions;
if (param.option.synchronize_conflicts !== false) { delete new_doc._conflicts;
functions.synchronizeConflicts(param); for (i in new_doc._attachments) {
} if (new_doc._attachments.hasOwnProperty(i)) {
} attachment_to_put.push({
}; "_id": i,
}; "_mimetype": new_doc._attachments[i].content_type,
functions.synchronizeAllSubStorage = function (param) { "_revs_info": new_doc._revs_info
var i, j, len = param.responses.stats_items.length; });
for (i = 0; i < len; i += 1) {
// browsing responses
for (j = 0; j < len; j += 1) {
// browsing storage list
if (i !== j) {
functions.synchronizeResponseToSubStorage(
param,
param.responses.stats_items[i][0],
param.responses.stats_items[j][1]
);
} }
} }
} for (i = 0; i < storage_list.length; i += 1) {
functions.finished_count -= 1; functions.finished_count += attachment_to_put.length || 1;
};
functions.synchronizeResponseToSubStorage = function (
param,
response,
storage_list
) {
var i, new_doc, attachment_to_put = [];
if (response === undefined) {
// no response to sync
return;
}
new_doc = JSON.parse(response);
new_doc._revs = new_doc._revisions;
delete new_doc._rev;
delete new_doc._revisions;
delete new_doc._conflicts;
for (i in new_doc._attachments) {
if (new_doc._attachments.hasOwnProperty(i)) {
attachment_to_put.push({
"_id": i,
"_mimetype": new_doc._attachments[i].content_type,
"_revs_info": new_doc._revs_info
});
}
}
for (i = 0; i < storage_list.length; i += 1) {
functions.finished_count += attachment_to_put.length || 1;
priv.send(
"put",
storage_list[i],
new_doc,
param.option,
functions.putAttachments(param, attachment_to_put)
);
}
functions.finished_count += 1;
functions.finished();
};
functions.synchronizeConflicts = function (param) {
var rev, new_doc, new_option;
new_option = priv.clone(param.option);
new_option.synchronize_conflict = false;
for (rev in param.conflicts) {
if (param.conflicts.hasOwnProperty(rev)) {
new_doc = priv.clone(param.doc);
new_doc._rev = rev;
// no need to synchronize all the conflicts again, do it once
functions.getAllDocuments(functions.newParam(
new_doc,
new_option,
param.repair
));
}
}
};
functions.putAttachments = function (param, attachment_to_put) {
return function (method, index, err, response) {
var i, attachment;
if (err) {
return callback({
"status": 40,
"statusText": "Check Failed",
"error": "check_failed",
"message": "Unable to copy attachments",
"reason": err.reason
}, undefined);
}
for (i = 0; i < attachment_to_put.length; i += 1) {
attachment = {
"_id": param.doc._id,
"_attachment": attachment_to_put[i]._id,
"_mimetype": attachment_to_put[i]._mimetype,
"_revs_info": attachment_to_put[i]._revs_info,
// "_revs_info": param.responses.list[index]._revs_info,
"_data": param.responses.attachments[attachment_to_put[i]._id]
};
priv.send( priv.send(
"putAttachment", "put",
index, storage_list[i],
attachment, new_doc,
option, param.option,
functions.putAttachmentCallback(param) functions.putAttachments(param, attachment_to_put)
); );
} }
if (attachment_to_put.length === 0) { functions.finished_count += 1;
functions.finished(); functions.finished();
}
}; };
}; functions.synchronizeConflicts = function (param) {
functions.putAttachmentCallback = function (param) { var rev, new_doc, new_option;
return function (method, index, err, response) { new_option = priv.clone(param.option);
if (err) { new_option.synchronize_conflict = false;
return callback(err, undefined); for (rev in param.conflicts) {
if (param.conflicts.hasOwnProperty(rev)) {
new_doc = priv.clone(param.doc);
new_doc._rev = rev;
// no need to synchronize all the conflicts again, do it once
functions.getAllDocuments(functions.newParam(
new_doc,
new_option,
param.repair
));
}
} }
functions.finished();
}; };
}; functions.putAttachments = function (param, attachment_to_put) {
functions.finished_count = 0; return function (method, index, err, response) {
functions.finished = function () { var i, attachment;
var response_object = {}; if (err) {
functions.finished_count -= 1; return callback({
if (functions.finished_count === 0) { "status": 40,
response_object.ok = true; "statusText": "Check Failed",
response_object.id = doc._id; "error": "check_failed",
if (doc._rev) { "message": "Unable to copy attachments",
response_object.rev = doc._rev; "reason": err.reason
}, undefined);
}
for (i = 0; i < attachment_to_put.length; i += 1) {
attachment = {
"_id": param.doc._id,
"_attachment": attachment_to_put[i]._id,
"_mimetype": attachment_to_put[i]._mimetype,
"_revs_info": attachment_to_put[i]._revs_info,
// "_revs_info": param.responses.list[index]._revs_info,
"_data": param.responses.attachments[attachment_to_put[i]._id]
};
priv.send(
"putAttachment",
index,
attachment,
option,
functions.putAttachmentCallback(param)
);
}
if (attachment_to_put.length === 0) {
functions.finished();
}
};
};
functions.putAttachmentCallback = function (param) {
return function (method, index, err, response) {
if (err) {
return callback(err, undefined);
}
functions.finished();
};
};
functions.finished_count = 0;
functions.finished = function () {
var response_object = {};
functions.finished_count -= 1;
if (functions.finished_count === 0) {
response_object.ok = true;
response_object.id = doc._id;
if (doc._rev) {
response_object.rev = doc._rev;
}
callback(undefined, response_object);
} }
callback(undefined, response_object); };
} functions.begin();
}; };
functions.begin();
};
/** /**
* The generic method to use * The generic method to use
* @method genericRequest * @method genericRequest
* @param {object} command The JIO command * @param {object} command The JIO command
* @param {string} method The method to use * @param {string} method The method to use
*/ */
that.genericRequest = function (command, method) { that.genericRequest = function (command, method) {
var doc = command.cloneDoc(); var doc = command.cloneDoc();
doc._id = doc._id || priv.generateUuid(); doc._id = doc._id || priv.generateUuid();
priv.sendToAllFastestResponseOnly( priv.sendToAllFastestResponseOnly(
method, method,
doc, doc,
command.cloneOption(), command.cloneOption(),
function (method, err, response) { function (method, err, response) {
if (err) { if (err) {
return that.error(err); return that.error(err);
}
that.success(response);
} }
that.success(response); );
} };
);
};
/** /**
* Post the document metadata to all sub storages * Post the document metadata to all sub storages
* @method post * @method post
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.post = function (command) { that.post = function (command) {
that.genericRequest(command, "put"); that.genericRequest(command, "put");
}; };
/** /**
* Put the document metadata to all sub storages * Put the document metadata to all sub storages
* @method put * @method put
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.put = function (command) { that.put = function (command) {
that.genericRequest(command, "post"); that.genericRequest(command, "post");
}; };
/** /**
* Put an attachment to a document to all sub storages * Put an attachment to a document to all sub storages
* @method putAttachment * @method putAttachment
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.putAttachment = function (command) { that.putAttachment = function (command) {
that.genericRequest(command, "putAttachment"); that.genericRequest(command, "putAttachment");
}; };
/** /**
* Get the document from all sub storages, get the fastest. * Get the document from all sub storages, get the fastest.
* @method get * @method get
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.get = function (command) { that.get = function (command) {
that.genericRequest(command, "get"); that.genericRequest(command, "get");
}; };
/** /**
* Get the attachment from all sub storages, get the fastest. * Get the attachment from all sub storages, get the fastest.
* @method getAttachment * @method getAttachment
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.getAttachment = function (command) { that.getAttachment = function (command) {
that.genericRequest(command, "getAttachment"); that.genericRequest(command, "getAttachment");
}; };
/** /**
* Remove the document from all sub storages. * Remove the document from all sub storages.
* @method remove * @method remove
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.remove = function (command) { that.remove = function (command) {
that.genericRequest(command, "remove"); that.genericRequest(command, "remove");
}; };
/** /**
* Remove the attachment from all sub storages. * Remove the attachment from all sub storages.
* @method remove * @method remove
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.removeAttachment = function (command) { that.removeAttachment = function (command) {
that.genericRequest(command, "removeAttachment"); that.genericRequest(command, "removeAttachment");
}; };
return that; 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