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 @@
})
.ready(function (g) {
return g.run({
"type": "local"
type: "query",
sub_storage: {
type: "local"
}
});
})
.ready(function (g) {
return g.run({
"type": "dav"
type: "query",
sub_storage: {
"type": "dav"
}
});
})
.declareMethod('run', function (jio_options) {
......@@ -32,7 +38,7 @@
test('Test "' + jio_options.type + '"scenario', function () {
var jio;
stop();
expect(3);
expect(9);
try {
jio = jIO.createJIO(jio_options);
......@@ -65,6 +71,57 @@
})
.then(function (doc_id) {
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) {
console.error(error.stack);
......
/*global window, RSVP, Blob, XMLHttpRequest, QueryFactory, Query */
/*global window, RSVP, Blob, XMLHttpRequest, QueryFactory, Query, console */
/*jslint maxlen: 200*/
(function (window, RSVP, Blob, QueryFactory, Query) {
"use strict";
......@@ -237,7 +237,7 @@
if (storage_method === undefined) {
throw new jIO.util.jIOError(
"Capacity '" + name + "' is not implemented",
500
501
);
}
return storage_method.apply(
......@@ -322,7 +322,61 @@
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
......
......@@ -305,8 +305,6 @@
null,
this._url + '/' + idsToFileName(param._id),
null,
undefined,
undefined,
this._login
);
};
......@@ -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 //
......@@ -603,6 +553,10 @@
* @param {Object} param The command parameters
* @param {Object} options The command options
*/
DavStorage.prototype.remove = function (param) {
return this._remove(param);
};
// DavStorage.prototype.remove = function (param) {
// var that = this, o = {
// error_message: "DavStorage, unable to get metadata.",
......@@ -766,76 +720,49 @@
* @param {Boolean} [options.include_docs=false]
* Also retrieve the actual document content.
*/
// DavStorage.prototype.allDocs = function (param, options) {
// var that = this, o = {
// error_message: "DavStorage, an error occured while " +
// "retrieving document list",
// max_percentage: options.include_docs === true ? 20 : 100,
// notifyAllDocsProgress: function (e) {
// command.notify({
// "method": "remove",
// "message": "Retrieving document list",
// "loaded": e.loaded,
// "total": e.total,
// "percentage": (e.loaded / e.total) * o.max_percentage
// });
// },
// getAllMetadataIfNecessary: function (e) {
// var requests = [];
// o.alldocs_result = e;
// if (options.include_docs !== true ||
// e.target.response.rows.length === 0) {
// return;
// }
//
// e.target.response.rows.forEach(function (row) {
// if (row.id !== "") {
// requests[requests.length] = that._get({"_id": row.id}).
// then(function (e) {
// row.doc = e.target.response;
// });
// }
// });
//
// o.count = 0;
// o.nb_requests = requests.length;
// o.error_message = "DavStorage, an error occured while " +
// "getting document metadata";
// return RSVP.all(requests).then(null, null, function (e) {
// if (e.value.loaded === e.value.total) {
// o.count += 1;
// command.notify({
// "method": "allDocs",
// "message": "Getting all documents metadata",
// "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);
// };
DavStorage.prototype.hasCapacity = function (name) {
return (name === "list");
};
DavStorage.prototype.buildQuery = function (param) {
return ajax[this._auth_type](
"PROPFIND",
"text",
this._url + '/',
null,
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 [];
}
// 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 rows;
});
};
/**
* Check the storage or a specific document
......
......@@ -269,33 +269,34 @@
* @param {Object} param The given parameters
* @param {Object} options The command options
*/
LocalStorage.prototype.remove = function (command, param) {
var doc, i, attachment_list;
doc = this._storage.getItem(param._id);
attachment_list = [];
if (doc !== null && typeof doc === "object") {
if (typeof doc._attachments === "object") {
// prepare list of attachments
for (i in doc._attachments) {
if (doc._attachments.hasOwnProperty(i)) {
attachment_list.push(i);
}
}
}
} else {
return command.error(
"not_found",
"missing",
"Document not found"
);
}
this._storage.removeItem(this._localpath + "/" + param._id);
// delete all attachments
for (i = 0; i < attachment_list.length; i += 1) {
this._storage.removeItem(this._localpath + "/" + param._id +
"/" + attachment_list[i]);
}
command.success();
LocalStorage.prototype.remove = function (param) {
// var doc, i, attachment_list;
// doc = this._storage.getItem(param._id);
// attachment_list = [];
// if (doc !== null && typeof doc === "object") {
// if (typeof doc._attachments === "object") {
// // prepare list of attachments
// for (i in doc._attachments) {
// if (doc._attachments.hasOwnProperty(i)) {
// attachment_list.push(i);
// }
// }
// }
// } else {
// return command.error(
// "not_found",
// "missing",
// "Document not found"
// );
// }
this._storage.removeItem(param._id);
// // delete all attachments
// for (i = 0; i < attachment_list.length; i += 1) {
// this._storage.removeItem(this._localpath + "/" + param._id +
// "/" + attachment_list[i]);
// }
// command.success();
return param._id;
};
/**
......@@ -334,6 +335,25 @@
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
// *
......
/*jslint nomen: true*/
/*global console*/
/*jslint nomen: true, maxlen: 200*/
/*global console, RSVP*/
(function (jIO) {
"use strict";
......@@ -36,15 +36,209 @@
* @param {Object} command The given parameters
* @param {Object} options The command options
*/
QueryStorage.prototype.allDocs = function (options) {
console.log(options);
// var context = this,
var substorage = this._sub_storage;
// // 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;
return substorage.allDocs.apply(substorage, arguments);
QueryStorage.prototype.hasCapacity = function (name) {
if (name === "list") {
return this._sub_storage.hasCapacity(name);
}
return true;
};
QueryStorage.prototype.buildQuery = function (options) {
var substorage = this._sub_storage,
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({
// "include_docs": include_docs
// }).then(function (response) {
......
......@@ -33,9 +33,12 @@
deepEqual(param, {"_id": "bar", "title": "foo"}, "post 200 called");
return param._id;
};
Storage200.prototype.allDocs = function (options) {
deepEqual(options, {"_id": "bar", "title": "foo"}, "post 200 called");
return options._id;
Storage200.prototype.buildQuery = function (options) {
console.log("Storage200: buildQuery");
deepEqual(options, {include_docs: true, query: 'title: "two"'},
"buildQuery 200 called");
console.log("Storage200: return");
return "taboulet";
};
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