/*jslint indent: 2, maxlen: 80, nomen: true, regexp: true, unparam: true */ /*global define, RSVP, jIO */ (function (dependencies, module) { "use strict"; if (typeof define === 'function' && define.amd) { return define(dependencies, module); } module(RSVP, jIO); }(['rsvp', 'jio'], function (RSVP, jIO) { "use strict"; /** * The jIO QueryStorage extension * * @class QueryStorage * @constructor */ function QueryStorage(spec) { this._sub_storage = spec.sub_storage; this._key_schema = spec.key_schema; } /** * Get a document * Parameters are passed through to the sub storage. * * @method get * @param {Object} command The JIO command */ QueryStorage.prototype.get = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.get.apply(substorage, args). then(command.success, command.error, command.notify); }; /** * Create a document in the sub storage. * Parameters are passed through to the sub storage. * * @method post * @param {Object} command The JIO command */ QueryStorage.prototype.post = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.post.apply(substorage, args). then(command.success, command.error, command.notify); }; /** * Create or update a document in the sub storage. * Parameters are passed through to the sub storage. * * @method put * @param {Object} command The JIO command */ QueryStorage.prototype.put = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.put.apply(substorage, args). then(command.success, command.error, command.notify); }; /** * Remove a document. * Parameters are passed through to the sub storage. * * @method remove * @param {Object} command The JIO command */ QueryStorage.prototype.remove = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.remove.apply(substorage, args). then(command.success, command.error, command.notify); }; /** * Get an attachment. * Parameters are passed through to the sub storage. * * @method getAttachment * @param {Object} command The JIO command */ QueryStorage.prototype.getAttachment = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.getAttachment.apply(substorage, args). then(command.success, command.error, command.notify); }; /** * Add an attachment to a document. * Parameters are passed through to the sub storage. * * @method putAttachment * @param {Object} command The JIO command */ QueryStorage.prototype.putAttachment = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.putAttachment.apply(substorage, args). then(command.success, command.error, command.notify); }; /** * Remove an attachment. * Parameters are passed through to the sub storage. * * @method removeAttachment * @param {Object} command The JIO command */ QueryStorage.prototype.removeAttachment = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.removeAttachment.apply(substorage, args). then(command.success, command.error, command.notify); }; function makeUnsupportedOptionsError(rejected_options) { throw { "status": 501, "error": "UnsupportedOptionError", "reason": "unsupported option", "arguments": rejected_options }; } /** * Retrieve documents. * This method performs an .allDocs() call on the substorage, * retrieving everything, then runs a query on the result. * * @method allDocs * @param {Object} command The given parameters * @param {Object} options The command options */ QueryStorage.prototype.allDocs = function (command, param, options) { var that = this, supported_options = { "limit": true, "query": true, "select_list": true, "sort_on": true // include_docs too, but it should be managed by sub storage }, cloned_options = JSON.parse(JSON.stringify(options)), substorage = command.storage(this._sub_storage); substorage.allDocs(cloned_options).then(null, function (reason) { if (reason.error !== "UnsupportedOptionError" || !Array.isArray(reason["arguments"]) || reason["arguments"].length === 0) { throw reason; } var offset = 0; reason["arguments"].slice().forEach(function (unsupported_option, i) { if (supported_options[unsupported_option]) { reason["arguments"].splice(i + offset, 1); offset -= 1; if ({"query": 1}[unsupported_option]) { cloned_options.partial_query = cloned_options.query; } if ({"query": 1, "sort_on": 1}[unsupported_option]) { cloned_options.include_docs = true; delete cloned_options.limit; } else if ({"select_list": 1}[unsupported_option]) { cloned_options.include_docs = true; } } delete cloned_options[unsupported_option]; }); if (reason["arguments"].length > 0) { throw makeUnsupportedOptionsError(reason["arguments"]); } return substorage.allDocs(cloned_options).then(null, function (reason) { if (reason.error !== "UnsupportedOptionError" || !Array.isArray(reason["arguments"]) || reason["arguments"].length === 0) { throw reason; } var partial_query_issue = true; reason["arguments"].slice().forEach(function (unsupported_option, i) { if (unsupported_option !== "partial_query") { partial_query_issue = false; } delete cloned_options[unsupported_option]; }); if (!partial_query_issue) { throw makeUnsupportedOptionsError(reason["arguments"]); } return substorage.allDocs(cloned_options); }); }).then(function (response) { var data_rows = response.data.rows, docs = {}, row, i, l; if (!cloned_options.include_docs || !(options.query || options.select_list || options.sort_on || options.limit)) { return response; } if (options.include_docs) { for (i = 0, l = data_rows.length; i < l; i += 1) { row = data_rows[i]; docs[row.id] = JSON.parse(JSON.stringify(row.doc)); row.doc._id = row.id; data_rows[i] = row.doc; } } else { for (i = 0, l = data_rows.length; i < l; i += 1) { row = data_rows[i]; row.doc._id = row.id; data_rows[i] = row.doc; } } if (options.select_list) { options.select_list.push("_id"); } return jIO.QueryFactory.create(options.query || "", that._key_schema). exec(data_rows, options). then(function (filtered_docs) { // reconstruct filtered rows, preserving the order from docs if (options.include_docs) { for (i = 0, l = filtered_docs.length; i < l; i += 1) { filtered_docs[i] = { "id": filtered_docs[i]._id, "doc": docs[filtered_docs[i]._id], "value": options.select_list ? filtered_docs[i] : {} }; delete filtered_docs[i].value._id; } } else { for (i = 0, l = filtered_docs.length; i < l; i += 1) { filtered_docs[i] = { "id": filtered_docs[i]._id, "value": options.select_list ? filtered_docs[i] : {} }; delete filtered_docs[i].value._id; } } response.data.rows = filtered_docs; response.data.total_rows = filtered_docs.length; return response; }); }).then(command.success, command.error, command.notify); }; /** * Check a document * Parameters are passed through to the sub storage. * * @method check * @param {Object} command The JIO command */ QueryStorage.prototype.check = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.check.apply(substorage, args). then(command.success, command.error, command.notify); }; /** * Repair a document * Parameters are passed through to the sub storage. * * @method repair * @param {Object} command The JIO command */ QueryStorage.prototype.repair = function (command) { var args = [].slice.call(arguments, 1), substorage; substorage = command.storage(this._sub_storage); substorage.repair.apply(substorage, args). then(command.success, command.error, command.notify); }; jIO.addStorage('query', QueryStorage); }));