...
 
Commits (33)
......@@ -26,7 +26,7 @@ TESTDIR = test
EXAMPLEDIR = examples
EXTERNALDIR = external
VERSION = 3.36.0
VERSION = 3.37.0
JIOVERSION = ${DISTDIR}/jio-v${VERSION}.js
JIOLATEST = ${DISTDIR}/jio-latest.js
JIONODEVERSION = ${DISTDIR}/jio-v${VERSION}-node.js
......@@ -59,6 +59,11 @@ ${LINTDIR}/queries/query.js: ${SRCDIR}/queries/query.js
${JSLINT} ${LINTOPTS} $<
@cat $< > $@
${LINTDIR}/indexeddb/indexeddb.js: ${SRCDIR}/indexeddb/indexeddb.js
@mkdir -p $(@D)
${JSLINT} ${LINTOPTS} $<
@cat $< > $@
${LINTDIR}/${TESTDIR}/jio.storage/%.js: ${TESTDIR}/jio.storage/%.js
@mkdir -p $(@D)
${JSLINT} ${LINTOPTS} --predef QUnit --predef RSVP --predef jIO $<
......@@ -104,10 +109,12 @@ lint: $(patsubst ${TESTDIR}/jio.storage/%.js, ${LINTDIR}/${TESTDIR}/jio.storage/
$(patsubst ${EXAMPLEDIR}/%.js, ${LINTDIR}/${EXAMPLEDIR}/%.js, $(wildcard ${EXAMPLEDIR}/*.js)) \
${LINTDIR}/queries/query.js \
${LINTDIR}/jio.date/jiodate.js \
${LINTDIR}/indexeddb/indexeddb.js \
${LINTDIR}/jio.js \
${LINTDIR}/node/jio.js \
${LINTDIR}/${TESTDIR}/node.js \
${LINTDIR}/${TESTDIR}/node/node-require.js \
${LINTDIR}/${TESTDIR}/node/ajax.tests.js \
$(patsubst ${SRCDIR}/jio.storage/%.js, ${LINTDIR}/jio.storage/%.js, $(wildcard ${SRCDIR}/jio.storage/*.js))
#############################################
......@@ -128,6 +135,7 @@ ${JIOVERSION}: ${EXTERNALDIR}/URI.js \
${SRCDIR}/queries/parser-end.js \
${SRCDIR}/queries/query.js \
${SRCDIR}/jio.date/jiodate.js \
${SRCDIR}/indexeddb/indexeddb.js \
${SRCDIR}/jio.js \
${EXTERNALDIR}/rusha.js \
${SRCDIR}/jio.storage/replicatestorage.js \
......@@ -149,9 +157,11 @@ ${JIOVERSION}: ${EXTERNALDIR}/URI.js \
${SRCDIR}/jio.storage/localstorage.js \
${SRCDIR}/jio.storage/indexeddbstorage.js \
${SRCDIR}/jio.storage/cryptstorage.js \
${SRCDIR}/jio.storage/websqlstorage.js \
${SRCDIR}/jio.storage/fbstorage.js \
${SRCDIR}/jio.storage/cloudooostorage.js
${SRCDIR}/jio.storage/cloudooostorage.js \
${SRCDIR}/jio.storage/nocapacitystorage.js \
${SRCDIR}/jio.storage/liststorage.js \
${SRCDIR}/jio.storage/indexstorage2.js
@mkdir -p $(@D)
cat $^ > $@
......@@ -254,6 +264,7 @@ ${EXTERNALDIR}/renderjs-latest.js:
clean:
rm -rf ${LINTDIR}
rm ${SRCDIR}/queries/build/parser.js
forceclean: clean
rm -rf ${EXTERNALDIR} ${SRCDIR}/queries/build/parser.js
......@@ -7870,11 +7870,11 @@ var arrayExtend = function () {
}
return {type:"complex",operator:operator,query_list:query_list2};
}, simpleQuerySetKey = function (query, key) {
}, querySetKey = function (query, key) {
var i;
if (query.type === "complex") {
for (i = 0; i < query.query_list.length; ++i) {
simpleQuerySetKey (query.query_list[i],key);
querySetKey(query.query_list[i], key);
}
return true;
}
......@@ -7995,7 +7995,7 @@ case 12:
this.$ = $$[$0-1];
break;
case 13:
simpleQuerySetKey($$[$0], $$[$0-2]); this.$ = $$[$0];
querySetKey($$[$0], $$[$0-2]); this.$ = $$[$0];
break;
case 15:
$$[$0].operator = $$[$0-1] ; this.$ = $$[$0];
......@@ -9124,21 +9124,8 @@ return new Parser;
* #crossLink "Query/toString:method"
*/
ComplexQuery.prototype.toString = function () {
var str_list = [], this_operator = this.operator;
if (this.operator === "NOT") {
str_list.push("NOT (");
str_list.push(this.query_list[0].toString());
str_list.push(")");
return str_list.join(" ");
}
this.query_list.forEach(function (query) {
str_list.push("(");
str_list.push(query.toString());
str_list.push(")");
str_list.push(this_operator);
});
str_list.length -= 1;
return str_list.join(" ");
/*global objectToSearchText */
return objectToSearchText(this.toJSON());
};
/**
......@@ -9237,21 +9224,60 @@ return new Parser;
};
function objectToSearchText(query) {
var str_list = [];
if (query.type === "complex") {
str_list.push("(");
(query.query_list || []).forEach(function (sub_query) {
str_list.push(objectToSearchText(sub_query));
str_list.push(query.operator);
});
str_list.length -= 1;
str_list.push(")");
return str_list.join(" ");
}
var i = 0,
query_list = null,
string_list = null,
operator = "",
common_key = "";
if (query.type === "simple") {
return (query.key ? query.key + ": " : "") +
(query.operator || "") + ' "' + query.value + '"';
}
if (query.type === "complex") {
query_list = query.query_list;
if (!query_list || query_list.length === 0) {
return "";
}
operator = query.operator || "";
if (operator === "NOT") {
// fallback to AND operator if several queries are given
// i.e. `NOT ( a AND b )`
return "NOT ( " + objectToSearchText(
{type: "complex", operator: "AND", query_list: query_list}
) + " )";
}
if (query_list.length === 1) {
return objectToSearchText(query_list[0]);
}
common_key = query_list[i].key;
for (i = 1; i < query_list.length; i += 1) {
if (query_list[i].type !== "simple" ||
query_list[i].key !== common_key) {
break;
}
}
string_list = [];
if (i === query_list.length) {
for (i = 0; i < query_list.length; i += 1) {
string_list.push(
(query_list[i].operator || "") +
' "' + query_list[i].value + '"'
);
}
} else {
common_key = "";
for (i = 0; i < query_list.length; i += 1) {
string_list.push(objectToSearchText(query_list[i]));
}
}
if (string_list.length > 1) {
return (common_key ? common_key + ": " : "") +
"( " + string_list.join(" " + operator + " ") + " )";
}
return (common_key ? common_key + ": " : "") +
string_list[0];
}
throw new TypeError("This object is not a query");
}
......@@ -9419,8 +9445,7 @@ return new Parser;
* #crossLink "Query/toString:method"
*/
SimpleQuery.prototype.toString = function () {
return (this.key ? this.key + ":" : "") +
(this.operator ? " " + this.operator : "") + ' "' + this.value + '"';
return objectToSearchText(this.toJSON());
};
/**
......@@ -10090,17 +10115,11 @@ var XMLHttpRequest = global.XMLHttpRequest || module.exports,
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global window, RSVP, Blob, XMLHttpRequest, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator */
FileReader, ArrayBuffer, Uint8Array */
(function (window, RSVP, Blob, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator) {
FileReader, ArrayBuffer, Uint8Array) {
"use strict";
if (window.openDatabase === undefined) {
window.openDatabase = function () {
throw new Error('WebSQL is not supported by ' + navigator.userAgent);
};
}
/* Safari does not define DOMError */
if (window.DOMError === undefined) {
window.DOMError = {};
......@@ -10546,6 +10565,7 @@ var XMLHttpRequest = global.XMLHttpRequest || module.exports,
if (context.hasCapacity("list") &&
((options.query === undefined) || context.hasCapacity("query")) &&
((options.sort_on === undefined) || context.hasCapacity("sort")) &&
((options.group_by === undefined) || context.hasCapacity("group")) &&
((options.select_list === undefined) ||
context.hasCapacity("select")) &&
((options.include_docs === undefined) ||
......@@ -10632,7 +10652,7 @@ var XMLHttpRequest = global.XMLHttpRequest || module.exports,
window.jIO = jIO;
}(window, RSVP, Blob, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator));
FileReader, ArrayBuffer, Uint8Array));
/*
* Copyright 2018, Nexedi SA
*
......@@ -14178,7 +14198,7 @@ var jIO = window.jIO,
ERP5Storage.prototype.hasCapacity = function (name) {
return ((name === "list") || (name === "query") ||
(name === "select") || (name === "limit") ||
(name === "sort"));
(name === "sort") || (name === "group"));
};
function isSingleLocalRoles(parsed_query) {
......@@ -14246,7 +14266,8 @@ var jIO = window.jIO,
local_roles,
local_role_found = false,
selection_domain,
sort_list = [];
sort_list = [],
group_list = [];
if (options.query) {
parsed_query = jIO.QueryFactory.create(options.query);
result_list = isSingleLocalRoles(parsed_query);
......@@ -14318,6 +14339,10 @@ var jIO = window.jIO,
}
}
if (options.group_by) {
group_list = options.group_by;
}
if (selection_domain) {
selection_domain = JSON.stringify(selection_domain);
}
......@@ -14331,6 +14356,7 @@ var jIO = window.jIO,
select_list: options.select_list || ["title", "reference"],
limit: options.limit,
sort_on: sort_list,
group_by: group_list,
local_roles: local_roles,
selection_domain: selection_domain
})
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -18,7 +18,7 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global console, btoa, Blob*/
/*global console, btoa, Blob, indexedDB*/
/*jslint nomen: true, maxlen: 200*/
(function (window, QUnit, jIO, rJS) {
"use strict";
......@@ -28,7 +28,9 @@
ok = QUnit.ok,
stop = QUnit.stop,
start = QUnit.start,
deepEqual = QUnit.deepEqual;
deepEqual = QUnit.deepEqual,
test_signature_database = 'test_signature_storage_scenario';
rJS(window)
......@@ -60,12 +62,22 @@
return g.run({
type: "query",
sub_storage: {
type: "uuid",
type: "list",
signature_storage: {
type: "indexeddb",
database: test_signature_database
},
sub_storage: {
type: "union",
storage_list: [{
type: "memory"
}]
type: "nocapacity",
sub_storage: {
type: "uuid",
sub_storage: {
type: "union",
storage_list: [{
type: "memory"
}]
}
}
}
}
});
......@@ -362,6 +374,9 @@
.then(function () {
return jio.repair();
})
.then(function () {
return indexedDB.deleteDatabase('jio:' + test_signature_database);
})
.fail(function (error) {
console.error("---");
......
{
"name": "jio",
"version": "v3.36.0",
"version": "v3.37.0",
"license": "GPLv3+",
"author": "Nexedi SA",
"contributors": [
......
/*
* Copyright 2019, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true */
/*global indexedDB, RSVP, IDBOpenDBRequest, DOMError, Event, Set, DOMException,
window*/
(function (indexedDB, RSVP, IDBOpenDBRequest, DOMError, DOMException) {
"use strict";
function waitForIDBRequest(request) {
return new RSVP.Promise(function (resolve, reject) {
request.onerror = reject;
request.onsuccess = resolve;
});
}
function waitForAllSynchronousCursor(request, callback) {
var force_cancellation = false;
function canceller() {
force_cancellation = true;
}
function resolver(resolve, reject) {
request.onerror = reject;
request.onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor && !force_cancellation) {
try {
callback(cursor);
} catch (error) {
reject(error);
}
// continue to next iteration
cursor["continue"]();
} else {
resolve();
}
};
}
return new RSVP.Promise(resolver, canceller);
}
function waitForOpenIndexedDB(db_name, version, upgrade_handler, callback) {
var request;
function canceller() {
if ((request !== undefined) && (request.result !== undefined)) {
request.result.close();
}
}
function resolver(resolve, reject) {
// Open DB //
request = indexedDB.open(db_name, version);
request.onerror = function (error) {
canceller();
if ((error !== undefined) &&
(error.target instanceof IDBOpenDBRequest) &&
((error.target.error instanceof DOMError) ||
(error.target.error instanceof DOMException))) {
reject("Connection to: " + db_name + " failed: " +
error.target.error.message);
} else {
reject(error);
}
};
request.onabort = function () {
canceller();
reject("Aborting connection to: " + db_name);
};
request.ontimeout = function () {
reject("Connection to: " + db_name + " timeout");
};
request.onblocked = function () {
canceller();
reject("Connection to: " + db_name + " was blocked");
};
// Create DB if necessary //
request.onupgradeneeded = upgrade_handler;
request.onversionchange = function () {
canceller();
reject(db_name + " was upgraded");
};
request.onsuccess = function () {
var result;
try {
result = callback(request.result);
} catch (error) {
reject(error);
}
return new RSVP.Queue()
.push(function () {
return result;
})
.push(function (final_result) {
canceller();
resolve(final_result);
}, function (error) {
canceller();
reject(error);
});
};
}
return new RSVP.Promise(resolver, canceller);
}
function waitForRepairableOpenIndexedDB(db_name, version, index_keys,
sub_storage_description, signature_storage_name, upgrade_handler,
callback) {
var handleUpgradeNeeded = function (evt) {
return upgrade_handler(evt, index_keys, sub_storage_description,
signature_storage_name);
};
return waitForOpenIndexedDB(db_name, version, handleUpgradeNeeded,
callback);
}
function waitForTransaction(db, stores, flag, callback) {
var tx = db.transaction(stores, flag);
function canceller() {
try {
tx.abort();
} catch (unused) {
// Transaction already finished
return;
}
}
function resolver(resolve, reject) {
var result;
try {
result = callback(tx);
} catch (error) {
reject(error);
}
tx.oncomplete = function () {
return new RSVP.Queue()
.push(function () {
return result;
})
.push(resolve, function (error) {
canceller();
reject(error);
});
};
tx.onerror = function (error) {
canceller();
reject(error);
};
tx.onabort = function (evt) {
reject(evt.target);
};
return tx;
}
return new RSVP.Promise(resolver, canceller);
}
window.waitForTransaction = waitForTransaction;
window.waitForOpenIndexedDB = waitForOpenIndexedDB;
window.waitForIDBRequest = waitForIDBRequest;
window.waitForAllSynchronousCursor = waitForAllSynchronousCursor;
window.waitForRepairableOpenIndexedDB = waitForRepairableOpenIndexedDB;
}(indexedDB, RSVP, IDBOpenDBRequest, DOMError, DOMException));
\ No newline at end of file
......@@ -18,17 +18,11 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global window, RSVP, Blob, XMLHttpRequest, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator */
FileReader, ArrayBuffer, Uint8Array */
(function (window, RSVP, Blob, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator) {
FileReader, ArrayBuffer, Uint8Array) {
"use strict";
if (window.openDatabase === undefined) {
window.openDatabase = function () {
throw new Error('WebSQL is not supported by ' + navigator.userAgent);
};
}
/* Safari does not define DOMError */
if (window.DOMError === undefined) {
window.DOMError = {};
......@@ -474,6 +468,7 @@
if (context.hasCapacity("list") &&
((options.query === undefined) || context.hasCapacity("query")) &&
((options.sort_on === undefined) || context.hasCapacity("sort")) &&
((options.group_by === undefined) || context.hasCapacity("group")) &&
((options.select_list === undefined) ||
context.hasCapacity("select")) &&
((options.include_docs === undefined) ||
......@@ -560,4 +555,4 @@
window.jIO = jIO;
}(window, RSVP, Blob, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator));
FileReader, ArrayBuffer, Uint8Array));
......@@ -419,7 +419,7 @@
ERP5Storage.prototype.hasCapacity = function (name) {
return ((name === "list") || (name === "query") ||
(name === "select") || (name === "limit") ||
(name === "sort"));
(name === "sort") || (name === "group"));
};
function isSingleLocalRoles(parsed_query) {
......@@ -487,7 +487,8 @@
local_roles,
local_role_found = false,
selection_domain,
sort_list = [];
sort_list = [],
group_list = [];
if (options.query) {
parsed_query = jIO.QueryFactory.create(options.query);
result_list = isSingleLocalRoles(parsed_query);
......@@ -559,6 +560,10 @@
}
}
if (options.group_by) {
group_list = options.group_by;
}
if (selection_domain) {
selection_domain = JSON.stringify(selection_domain);
}
......@@ -572,6 +577,7 @@
select_list: options.select_list || ["title", "reference"],
limit: options.limit,
sort_on: sort_list,
group_by: group_list,
local_roles: local_roles,
selection_domain: selection_domain
})
......
This diff is collapsed.
This diff is collapsed.
......@@ -150,7 +150,12 @@
_linshare_uuid: entry_list[i].uuid
};
if (options.include_docs === true) {
entry.doc = JSON.parse(entry_list[i].metaData) || {};
try {
entry.doc = JSON.parse(entry_list[i].metaData) || {};
} catch (error) {
// Metadata are not always JSON
entry.doc = {};
}
}
result_list.push(entry);
......
/*
* Copyright 2019, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global Set*/
(function (jIO) {
"use strict";
function ListStorage(spec) {
this._sub_storage = jIO.createJIO(spec.sub_storage);
this._signature_storage = jIO.createJIO(spec.signature_storage);
}
ListStorage.prototype.get = function () {
return this._sub_storage.get.apply(this._sub_storage, arguments);
};
ListStorage.prototype.allAttachments = function () {
return this._sub_storage.allAttachments.apply(this._sub_storage, arguments);
};
ListStorage.prototype.post = function (value) {
var gadget = this;
return gadget._sub_storage.post(value)
.push(function (id) {
return gadget._signature_storage.put(id, {})
.push(function () {
return id;
});
});
};
ListStorage.prototype.put = function (id, value) {
var gadget = this;
return gadget._sub_storage.put(id, value)
.push(function (result) {
return gadget._signature_storage.put(id, {})
.push(function () {
return result;
});
});
};
ListStorage.prototype.remove = function (id) {
var gadget = this;
return gadget._sub_storage.remove(id)
.push(function (result) {
return gadget._signature_storage.remove(id)
.push(function () {
return result;
});
});
};
ListStorage.prototype.getAttachment = function () {
return this._sub_storage.getAttachment.apply(this._sub_storage, arguments);
};
ListStorage.prototype.putAttachment = function () {
return this._sub_storage.putAttachment.apply(this._sub_storage, arguments);
};
ListStorage.prototype.removeAttachment = function () {
return this._sub_storage.removeAttachment.apply(this._sub_storage,
arguments);
};
ListStorage.prototype.repair = function () {
return this._sub_storage.repair.apply(this._sub_storage, arguments);
};
ListStorage.prototype.hasCapacity = function (name) {
if (name === "list") {
return this._signature_storage.hasCapacity('list');
}
return false;
};
ListStorage.prototype.buildQuery = function () {
return this._signature_storage.buildQuery();
};
jIO.addStorage('list', ListStorage);
}(jIO));
\ No newline at end of file
/*
* Copyright 2019, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
(function (jIO) {
"use strict";
function NoCapacityStorage(spec) {
this._sub_storage = jIO.createJIO(spec.sub_storage);
}
NoCapacityStorage.prototype.get = function () {
return this._sub_storage.get.apply(this._sub_storage, arguments);
};
NoCapacityStorage.prototype.allAttachments = function () {
return this._sub_storage.allAttachments.apply(this._sub_storage, arguments);
};
NoCapacityStorage.prototype.post = function () {
return this._sub_storage.post.apply(this._sub_storage, arguments);
};
NoCapacityStorage.prototype.put = function () {
return this._sub_storage.put.apply(this._sub_storage, arguments);
};
NoCapacityStorage.prototype.remove = function () {
return this._sub_storage.remove.apply(this._sub_storage, arguments);
};
NoCapacityStorage.prototype.getAttachment = function () {
return this._sub_storage.getAttachment.apply(this._sub_storage, arguments);
};
NoCapacityStorage.prototype.putAttachment = function () {
return this._sub_storage.putAttachment.apply(this._sub_storage, arguments);
};
NoCapacityStorage.prototype.removeAttachment = function () {
return this._sub_storage.removeAttachment.apply(this._sub_storage,
arguments);
};
NoCapacityStorage.prototype.repair = function () {
return this._sub_storage.repair.apply(this._sub_storage, arguments);
};
jIO.addStorage('nocapacity', NoCapacityStorage);
}(jIO));
\ No newline at end of file
......@@ -190,11 +190,10 @@
try {
return window.atob(str);
} catch (err) {
var buffer;
if (str instanceof Buffer) {
buffer = str;
} else {
buffer = Buffer.from(str.toString(), 'base64');
var buffer = Buffer.from(str.toString(), 'base64');
// Provide the same behaviour than the browser atob
if (buffer.toString('base64') !== str) {
throw new Error('The string to be decoded is not correctly encoded.');
}
return buffer.toString('binary');
}
......@@ -206,13 +205,7 @@
try {
return window.btoa(str);
} catch (err) {
var buffer;
if (str instanceof Buffer) {
buffer = str;
} else {
buffer = Buffer.from(str.toString(), 'binary');
}
return buffer.toString('base64');
return Buffer.from(str.toString(), 'binary').toString('base64');
}
}
......@@ -220,8 +213,8 @@
}(window, WeakMap, ArrayBuffer, Uint8Array));
var XMLHttpRequest = global.XMLHttpRequest || module.exports,
Blob = window.Blob,
global.XMLHttpRequest = module.exports;
var Blob = window.Blob,
atob = window.atob,
btoa = window.btoa,
FileReader = window.FileReader,
......
......@@ -19,7 +19,7 @@
*/
/*global window */
(function (window, jIO, Blob) {
(function (window, jIO, Blob, RSVP) {
"use strict";
var FormData,
......@@ -41,32 +41,71 @@
};
window.FormData = FormData;
function convertToBlob(promise, convert) {
if (!convert) {
return promise;
}
var result;
if (promise instanceof RSVP.Queue) {
result = promise;
} else {
result = new RSVP.Queue()
.push(function () {
return promise;
});
}
return result
.push(function (evt) {
evt.target.response = new Blob(
[evt.target.response || evt.target.responseText],
{type: evt.target.getResponseHeader('Content-Type')}
);
return evt;
});
}
originalAjax = jIO.util.ajax;
jIO.util.ajax = function ajax(param) {
var result,
need_convertion = (param.dataType === 'blob');
// Copy the param dict document (no need for deep copy) to
// allow tests to check them
param = Object.assign({}, param);
if (need_convertion) {
param.dataType = 'arraybuffer';
}
if (param.data instanceof Blob) {
// Blob is not supported by xhr2, so convert to ArrayBuffer instead
return jIO.util.readBlobAsArrayBuffer(param.data).then(function (data) {
param.data = data.target.result;
return originalAjax(param);
});
}
if (param.data instanceof FormData) {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsArrayBuffer(param.data);
})
.push(function (evt) {
param.data = evt.target.result;
return originalAjax(param);
});
} else if (param.data instanceof FormData) {
// Implement minimal FormData for erp5storage
if (!param.hasOwnProperty('headers')) {
param.headers = {};
} else {
// Copy the param dict document (no need for deep copy) to
// allow tests to check them
param.headers = Object.assign({}, param.headers);
}
param.headers["Content-Type"] = "multipart\/form-data; boundary=" +
param.data.boundary;
param.data.body += '--' + param.data.boundary + '--\r\n';
param.data = param.data.body;
return originalAjax(param);
result = originalAjax(param);
} else {
result = originalAjax(param);
}
return originalAjax(param);
return convertToBlob(result, need_convertion);
};
}(window, window.jIO, window.Blob));
}(window, window.jIO, window.Blob, window.RSVP));
// Define a global variable to allow storages to access jIO
var jIO = window.jIO,
......
......@@ -105,7 +105,7 @@ case 12:
this.$ = $$[$0-1];
break;
case 13:
simpleQuerySetKey($$[$0], $$[$0-2]); this.$ = $$[$0];
querySetKey($$[$0], $$[$0-2]); this.$ = $$[$0];
break;
case 15:
$$[$0].operator = $$[$0-1] ; this.$ = $$[$0];
......
......@@ -61,7 +61,7 @@ boolean_expression
expression
: LEFT_PARENTHESE search_text RIGHT_PARENTHESE { $$ = $2; }
| WORD DEFINITION expression { simpleQuerySetKey($3, $1); $$ = $3; }
| WORD DEFINITION expression { querySetKey($3, $1); $$ = $3; }
| value { $$ = $1; }
;
......
......@@ -58,11 +58,11 @@ var arrayExtend = function () {
}
return {type:"complex",operator:operator,query_list:query_list2};
}, simpleQuerySetKey = function (query, key) {
}, querySetKey = function (query, key) {
var i;
if (query.type === "complex") {
for (i = 0; i < query.query_list.length; ++i) {
simpleQuerySetKey (query.query_list[i],key);
querySetKey(query.query_list[i], key);
}
return true;
}
......
......@@ -573,21 +573,8 @@
* #crossLink "Query/toString:method"
*/
ComplexQuery.prototype.toString = function () {
var str_list = [], this_operator = this.operator;
if (this.operator === "NOT") {
str_list.push("NOT (");
str_list.push(this.query_list[0].toString());
str_list.push(")");
return str_list.join(" ");
}
this.query_list.forEach(function (query) {
str_list.push("(");
str_list.push(query.toString());
str_list.push(")");
str_list.push(this_operator);
});
str_list.length -= 1;
return str_list.join(" ");
/*global objectToSearchText */
return objectToSearchText(this.toJSON());
};
/**
......@@ -686,21 +673,60 @@
};
function objectToSearchText(query) {
var str_list = [];
if (query.type === "complex") {
str_list.push("(");
(query.query_list || []).forEach(function (sub_query) {
str_list.push(objectToSearchText(sub_query));
str_list.push(query.operator);
});
str_list.length -= 1;
str_list.push(")");
return str_list.join(" ");
}
var i = 0,
query_list = null,
string_list = null,
operator = "",
common_key = "";
if (query.type === "simple") {
return (query.key ? query.key + ": " : "") +
(query.operator || "") + ' "' + query.value + '"';
}
if (query.type === "complex") {
query_list = query.query_list;
if (!query_list || query_list.length === 0) {
return "";
}
operator = query.operator || "";
if (operator === "NOT") {
// fallback to AND operator if several queries are given
// i.e. `NOT ( a AND b )`
return "NOT ( " + objectToSearchText(
{type: "complex", operator: "AND", query_list: query_list}
) + " )";
}
if (query_list.length === 1) {
return objectToSearchText(query_list[0]);
}
common_key = query_list[i].key;
for (i = 1; i < query_list.length; i += 1) {
if (query_list[i].type !== "simple" ||
query_list[i].key !== common_key) {
break;
}
}
string_list = [];
if (i === query_list.length) {
for (i = 0; i < query_list.length; i += 1) {
string_list.push(
(query_list[i].operator || "") +
' "' + query_list[i].value + '"'
);
}
} else {
common_key = "";
for (i = 0; i < query_list.length; i += 1) {
string_list.push(objectToSearchText(query_list[i]));
}
}
if (string_list.length > 1) {
return (common_key ? common_key + ": " : "") +
"( " + string_list.join(" " + operator + " ") + " )";
}
return (common_key ? common_key + ": " : "") +
string_list[0];
}
throw new TypeError("This object is not a query");
}
......@@ -868,8 +894,7 @@
* #crossLink "Query/toString:method"
*/
SimpleQuery.prototype.toString = function () {
return (this.key ? this.key + ":" : "") +
(this.operator ? " " + this.operator : "") + ' "' + this.value + '"';
return objectToSearchText(this.toJSON());
};
/**
......
......@@ -709,6 +709,8 @@
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.spy_ajax = sinon.spy(jIO.util, "ajax");
this.jio = jIO.createJIO({
type: "dropbox",
access_token: token
......@@ -717,6 +719,8 @@
teardown: function () {
this.server.restore();
delete this.server;
this.spy_ajax.restore();
delete this.spy_ajax;
}
});
......@@ -789,14 +793,15 @@
test("putAttachment document", function () {
var blob = new Blob(["foo"], {"type": "xapplication/foo"}),
url_put_att = "https://content.dropboxapi.com/2/files/upload",
server = this.server;
server = this.server,
context = this;
this.server.respondWith("POST", url_put_att, [204, {
"Content-Type": "text/xml"
}, ""]);
stop();
expect(7);
expect(11);
this.jio.putAttachment(
"/putAttachment1/",
......@@ -804,20 +809,26 @@
blob
)
.then(function () {
ok(context.spy_ajax.calledOnce, "ajax count " +
context.spy_ajax.callCount);
equal(context.spy_ajax.firstCall.args[0].type, "POST");
equal(context.spy_ajax.firstCall.args[0].url, url_put_att);
deepEqual(context.spy_ajax.firstCall.args[0].xhrFields, undefined);
deepEqual(context.spy_ajax.firstCall.args[0].headers, {
"Authorization": "Bearer sample_token",
"Content-Type": "application/octet-stream",
"Dropbox-API-Arg": '{"path":"/putAttachment1/attachment1",' +
'"mode":"overwrite",' +
'"autorename":false,"mute":false}'
});
equal(context.spy_ajax.firstCall.args[0].data, blob);
equal(server.requests.length, 1);
equal(server.requests[0].method, "POST");
equal(server.requests[0].url, url_put_att);
equal(server.requests[0].status, 204);
equal(server.requests[0].responseText, "");
deepEqual(server.requests[0].requestHeaders, {
"Authorization": "Bearer sample_token",
"Content-Type": "application/octet-stream;charset=utf-8",
"Dropbox-API-Arg": '{"path":"/putAttachment1/attachment1",' +
'"mode":"overwrite",' +
'"autorename":false,"mute":false}'
});
equal(server.requests[0].requestBody, blob);
})
.fail(function (error) {
ok(false, error);
......@@ -992,8 +1003,12 @@
type: "dropbox",
access_token: token
});
this.spy_ajax = sinon.spy(jIO.util, "ajax");
},
teardown: function () {
this.spy_ajax.restore();
delete this.spy_ajax;
this.server.restore();
delete this.server;
}
......@@ -1064,7 +1079,7 @@
test("getAttachment document", function () {
var url = "https://content.dropboxapi.com/2/files/download",
server = this.server;
context = this;
this.server.respondWith("POST", url, [200, {
"Content-Type": "text/xplain"
}, "foo\nbaré"]);
......@@ -1077,20 +1092,20 @@
"attachment1"
)
.then(function (result) {
equal(server.requests.length, 1);
equal(server.requests[0].method, "POST");
equal(server.requests[0].url, url);
equal(server.requests[0].status, 200);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].responseText, "foo\nbaré");
deepEqual(server.requests[0].requestHeaders, {
equal(context.spy_ajax.callCount, 1);
equal(context.spy_ajax.firstCall.args[0].type, "POST");
equal(context.spy_ajax.firstCall.args[0].url, url);
equal(context.spy_ajax.firstCall.args[0].data, undefined);
equal(context.spy_ajax.firstCall.args[0].dataType, 'blob');
deepEqual(context.spy_ajax.firstCall.args[0].xhrFields, undefined);
deepEqual(context.spy_ajax.firstCall.args[0].headers, {
"Authorization": "Bearer sample_token",
"Content-Type": "text/plain;charset=utf-8",
"Dropbox-API-Arg": '{"path":"/getAttachment1/attachment1"}'
});
ok(result instanceof Blob, "Data is Blob");
deepEqual(result.type, "text/xplain", "Check mimetype");
return jIO.util.readBlobAsText(result);
})
.then(function (result) {
......
This diff is collapsed.
......@@ -427,6 +427,8 @@
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.spy_ajax = sinon.spy(jIO.util, "ajax");
this.jio = jIO.createJIO({
type: "gdrive",
access_token: token
......@@ -435,6 +437,8 @@
teardown: function () {
this.server.restore();
delete this.server;
this.spy_ajax.restore();
delete this.spy_ajax;
}
});
......@@ -464,13 +468,14 @@
var blob = new Blob(["foo"]),
url_put_att = domain + "/upload/drive/v2/files/sampleId?" +
"uploadType=media&access_token=" + token,
server = this.server;
server = this.server,
context = this;
this.server.respondWith("PUT", url_put_att, [204, {
"Content-Type": "text/xml"
}, '{"mimeType": "text/xml"}']);
stop();
expect(7);
expect(11);
this.jio.putAttachment(
"sampleId",
......@@ -478,16 +483,20 @@
blob
)
.then(function () {
ok(context.spy_ajax.calledOnce, "ajax count " +
context.spy_ajax.callCount);
equal(context.spy_ajax.firstCall.args[0].type, "PUT");
equal(context.spy_ajax.firstCall.args[0].url, url_put_att);
deepEqual(context.spy_ajax.firstCall.args[0].xhrFields, undefined);
deepEqual(context.spy_ajax.firstCall.args[0].headers, undefined);
equal(context.spy_ajax.firstCall.args[0].data, blob);
equal(server.requests.length, 1);
equal(server.requests[0].method, "PUT");
equal(server.requests[0].url, url_put_att);
equal(server.requests[0].status, 204);
equal(server.requests[0].responseText, "{\"mimeType\": \"text/xml\"}");
deepEqual(server.requests[0].requestHeaders, {
"Content-Type": "text/plain;charset=utf-8"
});
equal(server.requests[0].requestBody, blob);
})
.fail(function (error) {
ok(false, error);
......
This diff is collapsed.
......@@ -294,6 +294,55 @@
});
});
test("get all documents, include docs and unexpected metadata", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2',
metaData: 'unexpectedfoo'
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(7);
this.jio.allDocs({include_docs: true})
.then(function (result) {
deepEqual(result, {
data: {
rows: [{
_linshare_uuid: "uuid1",
id: "foo1",
value: {},
doc: {}
}],
total_rows: 1
}
}, "Check document");
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("get all documents and keep only one doc per name", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
......
This diff is collapsed.
This diff is collapsed.
......@@ -964,6 +964,44 @@
start();
});
});
test("group_by is not handled", function () {
stop();
expect(3);
function StorageGroupCapacity() {
return this;
}
StorageGroupCapacity.prototype.hasCapacity = function (capacity) {
return ((capacity === "list") || (capacity === "group"));
};
jIO.addStorage('querystoragegroupcapacity', StorageGroupCapacity);
var jio = jIO.createJIO({
type: "query",
sub_storage: {
type: "querystoragegroupcapacity"
}
});
jio.allDocs({
group_by: ["title"]
})
.then(function () {
ok(false, 'Must fail as group is not handled');
})
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.status_code, 501);
equal(error.message,
"Capacity 'group' is not implemented on 'query'");
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// queryStorage.repair
/////////////////////////////////////////////////////////////////
......
</
......@@ -3298,7 +3298,7 @@
test("signature document is not synced", function () {
stop();
expect(6);
expect(7);
var context = this;
......@@ -3307,26 +3307,34 @@
this.jio = jIO.createJIO({
type: "replicate",
local_sub_storage: {
type: "uuid",
sub_storage: {
type: "document",
document_id: "/",
sub_storage: {
type: "local",
sessiononly: true
}
}
type: "memory"
},
remote_sub_storage: {
type: "memory"
}
});
// Hack to ensure that the signature is stored in the
// same local storage, even if memory is used
context.jio.__storage._signature_sub_storage
.__storage._sub_storage
.__storage._sub_storage
.__storage._database =
context.jio.__storage._local_sub_storage
.__storage._database;
context.jio.post({"title": "foo"})
context.jio.put('barfoo', {"title": "foo"})
.then(function () {