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: "query",
sub_storage: {
"type": "dav" "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