...
 
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 could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
......@@ -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
})
......
......@@ -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) {
......
......@@ -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);
......
......@@ -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([
......
/*
* 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 Blob*/
(function (jIO, QUnit) {
"use strict";
var test = QUnit.test,
stop = QUnit.stop,
expect = QUnit.expect,
deepEqual = QUnit.deepEqual,
ok = QUnit.ok,
start = QUnit.start,
equal = QUnit.equal,
module = QUnit.module,
throws = QUnit.throws;
/////////////////////////////////////////////////////////////////
// Custom test substorage definition
/////////////////////////////////////////////////////////////////
function DummyStorage() {
return this;
}
jIO.addStorage('dummystorage', DummyStorage);
/////////////////////////////////////////////////////////////////
// NoCapacityStorage constructor
/////////////////////////////////////////////////////////////////
module("NoCapacityStorage.constructor");
test("create storage", function () {
var jio = jIO.createJIO({
type: "nocapacity",
sub_storage: {
type: "dummystorage"
}
});
equal(jio.__type, "nocapacity");
equal(jio.__storage._sub_storage.__type, "dummystorage");
});
/////////////////////////////////////////////////////////////////
// NoCapacityStorage.get
/////////////////////////////////////////////////////////////////
module("NoCapacityStorage.get");
test("get called substorage get", function () {
stop();
expect(2);
var jio = jIO.createJIO({
type: "nocapacity",
sub_storage: {
type: "dummystorage"
}
});
DummyStorage.prototype.get = function (id) {
equal(id, "1");
return {"name": "test_name"};
};
jio.get("1")
.then(function (result) {
deepEqual(result, {
"name": "test_name"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// NoCapacityStorage.allAttachments
/////////////////////////////////////////////////////////////////
module("NoCapacityStorage.allAttachments");
test("allAttachments called substorage allAttachments", function () {
stop();
expect(2);
var jio = jIO.createJIO({
type: "nocapacity",
sub_storage: {
type: "dummystorage"
}
});
DummyStorage.prototype.allAttachments = function (id) {
equal(id, "1");
return {attachmentname: {}};
};
jio.allAttachments("1")
.then(function (result) {
deepEqual(result, {
attachmentname: {}
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// NoCapacityStorage.post
/////////////////////////////////////////////////////////////////
module("NoCapacityStorage.post");
test("post called substorage post", function () {
stop();
expect(2);
var jio = jIO.createJIO({
type: "nocapacity",
sub_storage: {
type: "dummystorage"
}
});
DummyStorage.prototype.post = function (param) {
deepEqual(param, {"name": "test_name"});
return "posted";
};
jio.post({"name": "test_name"})
.then(function (result) {
equal(result, "posted");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// NoCapacityStorage.put
/////////////////////////////////////////////////////////////////
module("NoCapacityStorage.put");
test("put called substorage put", function () {
stop();
expect(3);
var jio = jIO.createJIO({
type: "nocapacity",
sub_storage: {
type: "dummystorage"
}
});
DummyStorage.prototype.put = function (id, param) {
equal(id, "1");
deepEqual(param, {"name": "test_name"});
return id;
};
jio.put("1", {"name": "test_name"})
.then(function (result) {
equal(result, "1");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// NoCapacityStorage.remove
/////////////////////////////////////////////////////////////////
module("NoCapacityStorage.remove");
test("remove called substorage remove", function () {
stop();
expect(2);
var jio = jIO.createJIO({
type: "nocapacity",
sub_storage: {
type: "dummystorage"
}
});
DummyStorage.prototype.remove = function (id) {
deepEqual(id, "1");
return id;
};
jio.remove("1")
.then(function (result) {
equal(result, "1");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// NoCapacityStorage.getAttachment
/////////////////////////////////////////////////////////////////
module("NoCapacityStorage.getAttachment");
test("getAttachment called substorage getAttachment", function () {
stop();
expect(3);
var jio = jIO.createJIO({
type: "nocapacity",
sub_storage: {
type: "dummystorage"
}
}),
blob = new Blob([""]);
DummyStorage.prototype.getAttachment = function (id, name) {
equal(id, "1");
equal(name, "test_name");
return blob;
};