Commit efa69bc5 authored by Romain Courteaud's avatar Romain Courteaud 🐸

Implement first simple version of query capacity.

Enough for now to force usage of querystorage and simplify allDocs everywhere else.
parent 94fc1a5f
...@@ -19,12 +19,18 @@ ...@@ -19,12 +19,18 @@
}) })
.ready(function (g) { .ready(function (g) {
return g.run({ return g.run({
"type": "local" type: "query",
sub_storage: {
type: "local"
}
}); });
}) })
.ready(function (g) { .ready(function (g) {
return g.run({ return g.run({
"type": "dav" type: "query",
sub_storage: {
"type": "dav"
}
}); });
}) })
.declareMethod('run', function (jio_options) { .declareMethod('run', function (jio_options) {
...@@ -32,7 +38,7 @@ ...@@ -32,7 +38,7 @@
test('Test "' + jio_options.type + '"scenario', function () { test('Test "' + jio_options.type + '"scenario', function () {
var jio; var jio;
stop(); stop();
expect(3); expect(9);
try { try {
jio = jIO.createJIO(jio_options); jio = jIO.createJIO(jio_options);
...@@ -65,6 +71,57 @@ ...@@ -65,6 +71,57 @@
}) })
.then(function (doc_id) { .then(function (doc_id) {
ok(doc_id, "Document removed"); ok(doc_id, "Document removed");
// Create some documents to check allDocs
return RSVP.all([
jio.put({"_id": "id1", "title": "1 ID", "int_index": 1}),
jio.put({"_id": "id2", "title": "2 ID", "int_index": 2}),
jio.put({"_id": "id3", "title": "3 ID", "int_index": 3})
]);
})
.then(function (all_doc_id) {
equal(all_doc_id[0], "id1", "Document 1 correctly created");
equal(all_doc_id[1], "id2", "Document 2 correctly created");
equal(all_doc_id[2], "id3", "Document 3 correctly created");
// Default allDocs call
return jio.allDocs();
})
.then(function (result) {
deepEqual(result, {
data: {
rows: [{
id: "id1",
value: {}
}, {
id: "id2",
value: {}
}, {
id: "id3",
value: {}
}],
total_rows: 3
}
}, "default allDocs OK");
// Filter the result
return jio.allDocs({
query: 'title: "2 ID"',
select_list: ["int_index"]
});
})
.then(function (result) {
deepEqual(result, {
data: {
rows: [{
doc: {},
id: "id2",
value: {int_index: 2}
}],
total_rows: 1
}
}, "filter allDocs OK");
// XXX Check include docs, sort, limit, select
}) })
.fail(function (error) { .fail(function (error) {
console.error(error.stack); console.error(error.stack);
......
/*global window, RSVP, Blob, XMLHttpRequest, QueryFactory, Query */ /*global window, RSVP, Blob, XMLHttpRequest, QueryFactory, Query, console */
/*jslint maxlen: 200*/ /*jslint maxlen: 200*/
(function (window, RSVP, Blob, QueryFactory, Query) { (function (window, RSVP, Blob, QueryFactory, Query) {
"use strict"; "use strict";
...@@ -237,7 +237,7 @@ ...@@ -237,7 +237,7 @@
if (storage_method === undefined) { if (storage_method === undefined) {
throw new jIO.util.jIOError( throw new jIO.util.jIOError(
"Capacity '" + name + "' is not implemented", "Capacity '" + name + "' is not implemented",
500 501
); );
} }
return storage_method.apply( return storage_method.apply(
...@@ -322,7 +322,61 @@ ...@@ -322,7 +322,61 @@
checkAttachmentId(param); checkAttachmentId(param);
}); });
declareMethod(JioProxyStorage, "allDocs"); JioProxyStorage.prototype.buildQuery = function () {
var storage_method = this.__storage.buildQuery,
context = this,
argument_list = arguments;
if (storage_method === undefined) {
throw new jIO.util.jIOError(
"Capacity 'buildQuery' is not implemented",
501
);
}
return new RSVP.Queue()
.push(function () {
return storage_method.apply(
context.__storage,
argument_list
);
});
};
JioProxyStorage.prototype.hasCapacity = function (name) {
var storage_method = this.__storage.hasCapacity;
if ((storage_method === undefined) || !storage_method.apply(this.__storage, arguments)) {
throw new jIO.util.jIOError(
"Capacity '" + name + "' is not implemented",
501
);
}
return true;
};
JioProxyStorage.prototype.allDocs = function (options) {
var context = this;
if (options === undefined) {
options = {};
}
return new RSVP.Queue()
.push(function () {
if (context.hasCapacity("list") &&
((options.query === undefined) || context.hasCapacity("query")) &&
((options.sort_on === undefined) || context.hasCapacity("sort")) &&
((options.select_list === undefined) || context.hasCapacity("select")) &&
((options.include_docs === undefined) || context.hasCapacity("include")) &&
((options.limit === undefined) || context.hasCapacity("limit"))) {
return context.buildQuery(options);
}
})
.push(function (result) {
return {
data: {
rows: result,
total_rows: result.length
}
};
});
};
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Storage builder // Storage builder
......
...@@ -305,8 +305,6 @@ ...@@ -305,8 +305,6 @@
null, null,
this._url + '/' + idsToFileName(param._id), this._url + '/' + idsToFileName(param._id),
null, null,
undefined,
undefined,
this._login this._login
); );
}; };
...@@ -323,54 +321,6 @@ ...@@ -323,54 +321,6 @@
); );
}; };
DavStorage.prototype._allDocs = function (param) {
return ajax[this._auth_type](
"PROPFIND",
"text",
this._url + '/',
null,
undefined,
undefined,
this._login
).then(function (e) {
var i, rows = [], row, responses = new DOMParser().parseFromString(
e.target.responseText,
"text/xml"
).querySelectorAll(
"D\\:response, response"
);
if (responses.length === 1) {
return {"target": {"response": {
"total_rows": 0,
"rows": []
}, "status": 200}};
}
// exclude parent folder and browse
for (i = 1; i < responses.length; i += 1) {
row = {
"id": "",
"value": {}
};
row.id = responses[i].querySelector("D\\:href, href").
textContent.split('/').slice(-1)[0];
row.id = fileNameToIds(row.id);
if (row.id.length !== 1) {
row = undefined;
} else {
row.id = row.id[0];
}
if (row !== undefined) {
if (row.id !== "") {
rows[rows.length] = row;
}
}
}
return {"target": {"response": {
"total_rows": rows.length,
"rows": rows
}, "status": 200}};
});
};
// JIO COMMANDS // // JIO COMMANDS //
...@@ -603,6 +553,10 @@ ...@@ -603,6 +553,10 @@
* @param {Object} param The command parameters * @param {Object} param The command parameters
* @param {Object} options The command options * @param {Object} options The command options
*/ */
DavStorage.prototype.remove = function (param) {
return this._remove(param);
};
// DavStorage.prototype.remove = function (param) { // DavStorage.prototype.remove = function (param) {
// var that = this, o = { // var that = this, o = {
// error_message: "DavStorage, unable to get metadata.", // error_message: "DavStorage, unable to get metadata.",
...@@ -766,76 +720,49 @@ ...@@ -766,76 +720,49 @@
* @param {Boolean} [options.include_docs=false] * @param {Boolean} [options.include_docs=false]
* Also retrieve the actual document content. * Also retrieve the actual document content.
*/ */
// DavStorage.prototype.allDocs = function (param, options) { DavStorage.prototype.hasCapacity = function (name) {
// var that = this, o = { return (name === "list");
// error_message: "DavStorage, an error occured while " + };
// "retrieving document list", DavStorage.prototype.buildQuery = function (param) {
// max_percentage: options.include_docs === true ? 20 : 100, return ajax[this._auth_type](
// notifyAllDocsProgress: function (e) { "PROPFIND",
// command.notify({ "text",
// "method": "remove", this._url + '/',
// "message": "Retrieving document list", null,
// "loaded": e.loaded, this._login
// "total": e.total, ).then(function (e) {
// "percentage": (e.loaded / e.total) * o.max_percentage var i, rows = [], row, responses = new DOMParser().parseFromString(
// }); e.target.responseText,
// }, "text/xml"
// getAllMetadataIfNecessary: function (e) { ).querySelectorAll(
// var requests = []; "D\\:response, response"
// o.alldocs_result = e; );
// if (options.include_docs !== true || if (responses.length === 1) {
// e.target.response.rows.length === 0) { return [];
// return; }
// } // exclude parent folder and browse
// for (i = 1; i < responses.length; i += 1) {
// e.target.response.rows.forEach(function (row) { row = {
// if (row.id !== "") { "id": "",
// requests[requests.length] = that._get({"_id": row.id}). "value": {}
// then(function (e) { };
// row.doc = e.target.response; row.id = responses[i].querySelector("D\\:href, href").
// }); textContent.split('/').slice(-1)[0];
// } row.id = fileNameToIds(row.id);
// }); if (row.id.length !== 1) {
// row = undefined;
// o.count = 0; } else {
// o.nb_requests = requests.length; row.id = row.id[0];
// o.error_message = "DavStorage, an error occured while " + }
// "getting document metadata"; if (row !== undefined) {
// return RSVP.all(requests).then(null, null, function (e) { if (row.id !== "") {
// if (e.value.loaded === e.value.total) { rows[rows.length] = row;
// o.count += 1; }
// command.notify({ }
// "method": "allDocs", }
// "message": "Getting all documents metadata", return rows;
// "loaded": o.count, });
// "total": o.nb_requests, };
// "percentage": Math.min(
// o.count / o.nb_requests * 80 + 20,
// 100
// )
// });
// }
// throw null;
// });
// },
// success: function () {
// command.success(o.alldocs_result.target.status, {
// "data": o.alldocs_result.target.response
// });
// },
// reject: function (e) {
// return command.reject(
// e.target.status,
// e.target.statusText,
// o.error_message
// );
// }
// };
//
// this._allDocs(param, options).
// then(o.getAllMetadataIfNecessary).
// then(o.success, o.reject, o.notifyProgress);
// };
/** /**
* Check the storage or a specific document * Check the storage or a specific document
......
...@@ -269,33 +269,34 @@ ...@@ -269,33 +269,34 @@
* @param {Object} param The given parameters * @param {Object} param The given parameters
* @param {Object} options The command options * @param {Object} options The command options
*/ */
LocalStorage.prototype.remove = function (command, param) { LocalStorage.prototype.remove = function (param) {
var doc, i, attachment_list; // var doc, i, attachment_list;
doc = this._storage.getItem(param._id); // doc = this._storage.getItem(param._id);
attachment_list = []; // attachment_list = [];
if (doc !== null && typeof doc === "object") { // if (doc !== null && typeof doc === "object") {
if (typeof doc._attachments === "object") { // if (typeof doc._attachments === "object") {
// prepare list of attachments // // prepare list of attachments
for (i in doc._attachments) { // for (i in doc._attachments) {
if (doc._attachments.hasOwnProperty(i)) { // if (doc._attachments.hasOwnProperty(i)) {
attachment_list.push(i); // attachment_list.push(i);
} // }
} // }
} // }
} else { // } else {
return command.error( // return command.error(
"not_found", // "not_found",
"missing", // "missing",
"Document not found" // "Document not found"
); // );
} // }
this._storage.removeItem(this._localpath + "/" + param._id); this._storage.removeItem(param._id);
// delete all attachments // // delete all attachments
for (i = 0; i < attachment_list.length; i += 1) { // for (i = 0; i < attachment_list.length; i += 1) {
this._storage.removeItem(this._localpath + "/" + param._id + // this._storage.removeItem(this._localpath + "/" + param._id +
"/" + attachment_list[i]); // "/" + attachment_list[i]);
} // }
command.success(); // command.success();
return param._id;
}; };
/** /**
...@@ -334,6 +335,25 @@ ...@@ -334,6 +335,25 @@
command.success(); command.success();
}; };
LocalStorage.prototype.hasCapacity = function (name) {
return (name === "list");
};
LocalStorage.prototype.buildQuery = function () {
var rows = [],
i;
for (i in this._database) {
if (this._database.hasOwnProperty(i)) {
rows.push({
id: i,
value: {}
});
}
}
return rows;
};
// /** // /**
// * Get all filenames belonging to a user from the document index // * Get all filenames belonging to a user from the document index
// * // *
......
/*jslint nomen: true*/ /*jslint nomen: true, maxlen: 200*/
/*global console*/ /*global console, RSVP*/
(function (jIO) { (function (jIO) {
"use strict"; "use strict";
...@@ -36,15 +36,209 @@ ...@@ -36,15 +36,209 @@
* @param {Object} command The given parameters * @param {Object} command The given parameters
* @param {Object} options The command options * @param {Object} options The command options
*/ */
QueryStorage.prototype.allDocs = function (options) { QueryStorage.prototype.hasCapacity = function (name) {
console.log(options); if (name === "list") {
// var context = this, return this._sub_storage.hasCapacity(name);
var substorage = this._sub_storage; }
// // we need the full documents in order to perform the query, will return true;
// // remove them later if they were not required. };
// include_docs = (options.include_docs || options.query) ? true : false; QueryStorage.prototype.buildQuery = function (options) {
var substorage = this._sub_storage,
return substorage.allDocs.apply(substorage, arguments); context = this,
// sub_query_result,
sub_options = {},
is_manual_query_needed = false,
is_manual_include_needed = false;
if (substorage.hasCapacity("list")) {
// Can substorage handle the queries if needed?
try {
if (((options.query !== undefined) && (!substorage.hasCapacity("query"))) ||
((options.sort_on !== undefined) && (!substorage.hasCapacity("sort"))) ||
((options.select_list !== undefined) && (!substorage.hasCapacity("select"))) ||
((options.limit !== undefined) && (!substorage.hasCapacity("limit")))) {
sub_options.query = options.query;
sub_options.sort_on = options.sort_on;
sub_options.select_list = options.select_list;
sub_options.limit = options.limit;
}
} catch (error) {
if ((error instanceof jIO.util.jIOError) && (error.status_code === 501)) {
is_manual_query_needed = true;
} else {
throw error;
}
}
// Can substorage include the docs if needed?
try {
if ((is_manual_query_needed || (options.include_docs === true)) && (!substorage.hasCapacity("include"))) {
sub_options.include_docs = options.include_docs;
}
} catch (error) {
if ((error instanceof jIO.util.jIOError) && (error.status_code === 501)) {
is_manual_include_needed = true;
} else {
throw error;
}
}
return substorage.buildQuery(sub_options)
// Include docs if needed
.push(function (result) {
var include_query_list = [result],
len,
i;
if (is_manual_include_needed) {
len = result.length;
for (i = 0; i < len; i += 1) {
include_query_list.push(
substorage.get({"_id": result[i].id})
);
}
result = RSVP.all(include_query_list);
}
return result;
})
.push(function (result) {
var original_result,
len,
i;
if (is_manual_include_needed) {
original_result = result[0];
len = original_result.length;
for (i = 0; i < len; i += 1) {
original_result[i].doc = result[i + 1];
}
result = original_result;
}
return result;
})
// Manual query if needed
.push(function (result) {
var data_rows = [],
len,
i;
if (is_manual_query_needed) {
// sub_query_result = result;
len = result.length;
for (i = 0; i < len; i += 1) {
data_rows.push(result[i].doc);
}
if (options.select_list) {
options.select_list.push("_id");
}
result = jIO.QueryFactory.create(options.query || "", context._key_schema).
exec(data_rows, options);
}
return result;
})
// reconstruct filtered rows, preserving the order from docs
.push(function (result) {
var new_result = [],
element,
len,
i;
if (is_manual_query_needed) {
len = result.length;
for (i = 0; i < len; i += 1) {
element = {
id: result[i]._id,
value: options.select_list ? result[i] : {},
doc: {}
};
if (options.select_list) {
// Does not work if user manually request _id
delete element.value._id;
}
if (options.include_docs) {
// XXX To implement
throw new Error("QueryStorage does not support include docs");
}
new_result.push(element);
}
result = new_result;
}
return result;
});
// 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;
// });
// 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(function (response) {
//
// ((options.include_docs === undefined) || context.hasCapacity("include")) &&
// }
//
// return context.buildQuery.apply(context, arguments);
// }
//
// // // we need the full documents in order to perform the query, will
// // // remove them later if they were not required.
// // include_docs = (options.include_docs || options.query) ? true : false;
//
// console.log("QueryStorage: calling substorage buildQuery");
// return substorage.buildQuery.apply(substorage, arguments);
// return substorage.buildQuery.apply(substorage, arguments)
// .push(function (result) {
// });
// substorage.allDocs({ // substorage.allDocs({
// "include_docs": include_docs // "include_docs": include_docs
// }).then(function (response) { // }).then(function (response) {
......
...@@ -33,9 +33,12 @@ ...@@ -33,9 +33,12 @@
deepEqual(param, {"_id": "bar", "title": "foo"}, "post 200 called"); deepEqual(param, {"_id": "bar", "title": "foo"}, "post 200 called");
return param._id; return param._id;
}; };
Storage200.prototype.allDocs = function (options) { Storage200.prototype.buildQuery = function (options) {
deepEqual(options, {"_id": "bar", "title": "foo"}, "post 200 called"); console.log("Storage200: buildQuery");
return options._id; deepEqual(options, {include_docs: true, query: 'title: "two"'},
"buildQuery 200 called");
console.log("Storage200: return");
return "taboulet";
}; };
jIO.addStorage('querystorage200', Storage200); jIO.addStorage('querystorage200', Storage200);
......
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