Commit e6c460b4 authored by Romain Courteaud's avatar Romain Courteaud

Release version 3.6.0

Include new google drive storage and performance improvement for QueryStorage's allDocs.
parent d005d845
......@@ -3889,229 +3889,6 @@ if (typeof define === 'function' && define.amd) {
makeGlobal();
}
}).call(this);
;/*jslint indent: 2, maxlen: 80, sloppy: true */
var query_class_dict = {};
;/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global parseStringToObject: true, emptyFunction: true, sortOn: true, limit:
true, select: true, window, stringEscapeRegexpCharacters: true,
deepClone, RSVP*/
/**
* The query to use to filter a list of objects.
* This is an abstract class.
*
* @class Query
* @constructor
*/
function Query() {
/**
* Called before parsing the query. Must be overridden!
*
* @method onParseStart
* @param {Object} object The object shared in the parse process
* @param {Object} option Some option gave in parse()
*/
this.onParseStart = emptyFunction;
/**
* Called when parsing a simple query. Must be overridden!
*
* @method onParseSimpleQuery
* @param {Object} object The object shared in the parse process
* @param {Object} option Some option gave in parse()
*/
this.onParseSimpleQuery = emptyFunction;
/**
* Called when parsing a complex query. Must be overridden!
*
* @method onParseComplexQuery
* @param {Object} object The object shared in the parse process
* @param {Object} option Some option gave in parse()
*/
this.onParseComplexQuery = emptyFunction;
/**
* Called after parsing the query. Must be overridden!
*
* @method onParseEnd
* @param {Object} object The object shared in the parse process
* @param {Object} option Some option gave in parse()
*/
this.onParseEnd = emptyFunction;
}
/**
* Filter the item list with matching item only
*
* @method exec
* @param {Array} item_list The list of object
* @param {Object} [option] Some operation option
* @param {Array} [option.select_list] A object keys to retrieve
* @param {Array} [option.sort_on] Couples of object keys and "ascending"
* or "descending"
* @param {Array} [option.limit] Couple of integer, first is an index and
* second is the length.
*/
Query.prototype.exec = function (item_list, option) {
var i, promises = [];
if (!Array.isArray(item_list)) {
throw new TypeError("Query().exec(): Argument 1 is not of type 'array'");
}
if (option === undefined) {
option = {};
}
if (typeof option !== 'object') {
throw new TypeError("Query().exec(): " +
"Optional argument 2 is not of type 'object'");
}
for (i = 0; i < item_list.length; i += 1) {
if (!item_list[i]) {
promises.push(RSVP.resolve(false));
} else {
promises.push(this.match(item_list[i]));
}
}
return new RSVP.Queue()
.push(function () {
return RSVP.all(promises);
})
.push(function (answers) {
var j;
for (j = answers.length - 1; j >= 0; j -= 1) {
if (!answers[j]) {
item_list.splice(j, 1);
}
}
if (option.sort_on) {
return sortOn(option.sort_on, item_list);
}
})
.push(function () {
if (option.limit) {
return limit(option.limit, item_list);
}
})
.push(function () {
return select(option.select_list || [], item_list);
})
.push(function () {
return item_list;
});
};
/**
* Test if an item matches this query
*
* @method match
* @param {Object} item The object to test
* @return {Boolean} true if match, false otherwise
*/
Query.prototype.match = function () {
return RSVP.resolve(true);
};
/**
* Browse the Query in deep calling parser method in each step.
*
* `onParseStart` is called first, on end `onParseEnd` is called.
* It starts from the simple queries at the bottom of the tree calling the
* parser method `onParseSimpleQuery`, and go up calling the
* `onParseComplexQuery` method.
*
* @method parse
* @param {Object} option Any options you want (except 'parsed')
* @return {Any} The parse result
*/
Query.prototype.parse = function (option) {
var that = this,
object;
/**
* The recursive parser.
*
* @param {Object} object The object shared in the parse process
* @param {Object} options Some options usable in the parseMethods
* @return {Any} The parser result
*/
function recParse(object, option) {
var query = object.parsed,
queue = new RSVP.Queue(),
i;
function enqueue(j) {
queue
.push(function () {
object.parsed = query.query_list[j];
return recParse(object, option);
})
.push(function () {
query.query_list[j] = object.parsed;
});
}
if (query.type === "complex") {
for (i = 0; i < query.query_list.length; i += 1) {
enqueue(i);
}
return queue
.push(function () {
object.parsed = query;
return that.onParseComplexQuery(object, option);
});
}
if (query.type === "simple") {
return that.onParseSimpleQuery(object, option);
}
}
object = {
parsed: JSON.parse(JSON.stringify(that.serialized()))
};
return new RSVP.Queue()
.push(function () {
return that.onParseStart(object, option);
})
.push(function () {
return recParse(object, option);
})
.push(function () {
return that.onParseEnd(object, option);
})
.push(function () {
return object.parsed;
});
};
/**
* Convert this query to a parsable string.
*
* @method toString
* @return {String} The string version of this query
*/
Query.prototype.toString = function () {
return "";
};
/**
* Convert this query to an jsonable object in order to be remake thanks to
* QueryFactory class.
*
* @method serialized
* @return {Object} The jsonable object
*/
Query.prototype.serialized = function () {
return undefined;
};
window.Query = Query;
;/**
* Parse a text request to a json query object tree
*
......@@ -4815,72 +4592,486 @@ if ((error_count = __NODEJS_parse(string, error_offsets, error_lookaheads)) > 0)
; return result;
} // parseStringToObject
Query.parseStringToObject = parseStringToObject;
;/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query: true, query_class_dict: true, inherits: true,
window, QueryFactory, RSVP */
;/*global RSVP, window, parseStringToObject*/
/*jslint nomen: true, maxlen: 90*/
(function (RSVP, window, parseStringToObject) {
"use strict";
/**
* The ComplexQuery inherits from Query, and compares one or several metadata
* values.
*
* @class ComplexQuery
* @extends Query
* @param {Object} [spec={}] The specifications
* @param {String} [spec.operator="AND"] The compare method to use
* @param {String} spec.key The metadata key
* @param {String} spec.value The value of the metadata to compare
*/
function ComplexQuery(spec, key_schema) {
Query.call(this);
var query_class_dict = {},
regexp_escape = /[\-\[\]{}()*+?.,\\\^$|#\s]/g,
regexp_percent = /%/g,
regexp_underscore = /_/g,
regexp_operator = /^(?:AND|OR|NOT)$/i,
regexp_comparaison = /^(?:!?=|<=?|>=?)$/i;
/**
* Logical operator to use to compare object values
* Convert metadata values to array of strings. ex:
*
* @attribute operator
* @type String
* @default "AND"
* @optional
* "a" -> ["a"],
* {"content": "a"} -> ["a"]
*
* @param {Any} value The metadata value
* @return {Array} The value in string array format
*/
this.operator = spec.operator;
function metadataValueToStringArray(value) {
var i, new_value = [];
if (value === undefined) {
return undefined;
}
if (!Array.isArray(value)) {
value = [value];
}
for (i = 0; i < value.length; i += 1) {
if (typeof value[i] === 'object') {
new_value[i] = value[i].content;
} else {
new_value[i] = value[i];
}
}
return new_value;
}
/**
* The sub Query list which are used to query an item.
* A sort function to sort items by key
*
* @attribute query_list
* @type Array
* @default []
* @optional
*/
this.query_list = spec.query_list || [];
/*jslint unparam: true*/
this.query_list = this.query_list.map(
// decorate the map to avoid sending the index as key_schema argument
function (o, i) { return QueryFactory.create(o, key_schema); }
);
/*jslint unparam: false*/
}
inherits(ComplexQuery, Query);
ComplexQuery.prototype.operator = "AND";
ComplexQuery.prototype.type = "complex";
/**
* #crossLink "Query/match:method"
* @param {String} key The key to sort on
* @param {String} [way="ascending"] 'ascending' or 'descending'
* @return {Function} The sort function
*/
ComplexQuery.prototype.match = function (item) {
var operator = this.operator;
if (!(/^(?:AND|OR|NOT)$/i.test(operator))) {
operator = "AND";
}
return this[operator.toUpperCase()](item);
};
function sortFunction(key, way) {
var result;
if (way === 'descending') {
result = 1;
} else if (way === 'ascending') {
result = -1;
} else {
throw new TypeError("Query.sortFunction(): " +
"Argument 2 must be 'ascending' or 'descending'");
}
return function (a, b) {
// this comparison is 5 times faster than json comparison
var i, l;
a = metadataValueToStringArray(a[key]) || [];
b = metadataValueToStringArray(b[key]) || [];
l = a.length > b.length ? a.length : b.length;
for (i = 0; i < l; i += 1) {
if (a[i] === undefined) {
return result;
}
if (b[i] === undefined) {
return -result;
}
if (a[i] > b[i]) {
return -result;
}
if (a[i] < b[i]) {
return result;
}
}
return 0;
};
}
/**
/**
* Sort a list of items, according to keys and directions.
*
* @param {Array} sort_on_option List of couples [key, direction]
* @param {Array} list The item list to sort
* @return {Array} The filtered list
*/
function sortOn(sort_on_option, list) {
var sort_index;
if (!Array.isArray(sort_on_option)) {
throw new TypeError("jioquery.sortOn(): " +
"Argument 1 is not of type 'array'");
}
for (sort_index = sort_on_option.length - 1; sort_index >= 0;
sort_index -= 1) {
list.sort(sortFunction(
sort_on_option[sort_index][0],
sort_on_option[sort_index][1]
));
}
return list;
}
/**
* Limit a list of items, according to index and length.
*
* @param {Array} limit_option A couple [from, length]
* @param {Array} list The item list to limit
* @return {Array} The filtered list
*/
function limit(limit_option, list) {
if (!Array.isArray(limit_option)) {
throw new TypeError("jioquery.limit(): " +
"Argument 1 is not of type 'array'");
}
if (!Array.isArray(list)) {
throw new TypeError("jioquery.limit(): " +
"Argument 2 is not of type 'array'");
}
list.splice(0, limit_option[0]);
if (limit_option[1]) {
list.splice(limit_option[1]);
}
return list;
}
/**
* Filter a list of items, modifying them to select only wanted keys.
*
* @param {Array} select_option Key list to keep
* @param {Array} list The item list to filter
* @return {Array} The filtered list
*/
function select(select_option, list) {
var i, j, new_item;
if (!Array.isArray(select_option)) {
throw new TypeError("jioquery.select(): " +
"Argument 1 is not of type Array");
}
if (!Array.isArray(list)) {
throw new TypeError("jioquery.select(): " +
"Argument 2 is not of type Array");
}
for (i = 0; i < list.length; i += 1) {
new_item = {};
for (j = 0; j < select_option.length; j += 1) {
if (list[i].hasOwnProperty([select_option[j]])) {
new_item[select_option[j]] = list[i][select_option[j]];
}
}
for (j in new_item) {
if (new_item.hasOwnProperty(j)) {
list[i] = new_item;
break;
}
}
}
return list;
}
/**
* The query to use to filter a list of objects.
* This is an abstract class.
*
* @class Query
* @constructor
*/
function Query() {
/**
* Called before parsing the query. Must be overridden!
*
* @method onParseStart
* @param {Object} object The object shared in the parse process
* @param {Object} option Some option gave in parse()
*/
// this.onParseStart = emptyFunction;
/**
* Called when parsing a simple query. Must be overridden!
*
* @method onParseSimpleQuery
* @param {Object} object The object shared in the parse process
* @param {Object} option Some option gave in parse()
*/
// this.onParseSimpleQuery = emptyFunction;
/**
* Called when parsing a complex query. Must be overridden!
*
* @method onParseComplexQuery
* @param {Object} object The object shared in the parse process
* @param {Object} option Some option gave in parse()
*/
// this.onParseComplexQuery = emptyFunction;
/**
* Called after parsing the query. Must be overridden!
*
* @method onParseEnd
* @param {Object} object The object shared in the parse process
* @param {Object} option Some option gave in parse()
*/
// this.onParseEnd = emptyFunction;
return;
}
/**
* Filter the item list with matching item only
*
* @method exec
* @param {Array} item_list The list of object
* @param {Object} [option] Some operation option
* @param {Array} [option.select_list] A object keys to retrieve
* @param {Array} [option.sort_on] Couples of object keys and "ascending"
* or "descending"
* @param {Array} [option.limit] Couple of integer, first is an index and
* second is the length.
*/
Query.prototype.exec = function (item_list, option) {
if (!Array.isArray(item_list)) {
throw new TypeError("Query().exec(): Argument 1 is not of type 'array'");
}
if (option === undefined) {
option = {};
}
if (typeof option !== 'object') {
throw new TypeError("Query().exec(): " +
"Optional argument 2 is not of type 'object'");
}
var context = this,
i;
for (i = item_list.length - 1; i >= 0; i -= 1) {
if (!context.match(item_list[i])) {
item_list.splice(i, 1);
}
}
if (option.sort_on) {
sortOn(option.sort_on, item_list);
}
if (option.limit) {
limit(option.limit, item_list);
}
select(option.select_list || [], item_list);
return new RSVP.Queue()
.push(function () {
return item_list;
});
};
/**
* Test if an item matches this query
*
* @method match
* @param {Object} item The object to test
* @return {Boolean} true if match, false otherwise
*/
Query.prototype.match = function () {
return true;
};
/**
* Browse the Query in deep calling parser method in each step.
*
* `onParseStart` is called first, on end `onParseEnd` is called.
* It starts from the simple queries at the bottom of the tree calling the
* parser method `onParseSimpleQuery`, and go up calling the
* `onParseComplexQuery` method.
*
* @method parse
* @param {Object} option Any options you want (except 'parsed')
* @return {Any} The parse result
*/
Query.prototype.parse = function (option) {
var that = this,
object;
/**
* The recursive parser.
*
* @param {Object} object The object shared in the parse process
* @param {Object} options Some options usable in the parseMethods
* @return {Any} The parser result
*/
function recParse(object, option) {
var query = object.parsed,
queue = new RSVP.Queue(),
i;
function enqueue(j) {
queue
.push(function () {
object.parsed = query.query_list[j];
return recParse(object, option);
})
.push(function () {
query.query_list[j] = object.parsed;
});
}
if (query.type === "complex") {
for (i = 0; i < query.query_list.length; i += 1) {
enqueue(i);
}
return queue
.push(function () {
object.parsed = query;
return that.onParseComplexQuery(object, option);
});
}
if (query.type === "simple") {
return that.onParseSimpleQuery(object, option);
}
}
object = {
parsed: JSON.parse(JSON.stringify(that.serialized()))
};
return new RSVP.Queue()
.push(function () {
return that.onParseStart(object, option);
})
.push(function () {
return recParse(object, option);
})
.push(function () {
return that.onParseEnd(object, option);
})
.push(function () {
return object.parsed;
});
};
/**
* Convert this query to a parsable string.
*
* @method toString
* @return {String} The string version of this query
*/
Query.prototype.toString = function () {
return "";
};
/**
* Convert this query to an jsonable object in order to be remake thanks to
* QueryFactory class.
*
* @method serialized
* @return {Object} The jsonable object
*/
Query.prototype.serialized = function () {
return undefined;
};
/**
* Provides static methods to create Query object
*
* @class QueryFactory
*/
function QueryFactory() {
return;
}
/**
* Escapes regexp special chars from a string.
*
* @param {String} string The string to escape
* @return {String} The escaped string
*/
function stringEscapeRegexpCharacters(string) {
return string.replace(regexp_escape, "\\$&");
}
/**
* Inherits the prototype methods from one constructor into another. The
* prototype of `constructor` will be set to a new object created from
* `superConstructor`.
*
* @param {Function} constructor The constructor which inherits the super one
* @param {Function} superConstructor The super constructor
*/
function inherits(constructor, superConstructor) {
constructor.super_ = superConstructor;
constructor.prototype = Object.create(superConstructor.prototype, {
"constructor": {
"configurable": true,
"enumerable": false,
"writable": true,
"value": constructor
}
});
}
/**
* Convert a search text to a regexp.
*
* @param {String} string The string to convert
* @param {Boolean} [use_wildcard_character=true] Use wildcard "%" and "_"
* @return {RegExp} The search text regexp
*/
function searchTextToRegExp(string, use_wildcard_characters) {
if (typeof string !== 'string') {
throw new TypeError("jioquery.searchTextToRegExp(): " +
"Argument 1 is not of type 'string'");
}
if (use_wildcard_characters === false) {
return new RegExp("^" + stringEscapeRegexpCharacters(string) + "$");
}
return new RegExp("^" + stringEscapeRegexpCharacters(string)
.replace(regexp_percent, '.*')
.replace(regexp_underscore, '.') + "$");
}
/**
* The ComplexQuery inherits from Query, and compares one or several metadata
* values.
*
* @class ComplexQuery
* @extends Query
* @param {Object} [spec={}] The specifications
* @param {String} [spec.operator="AND"] The compare method to use
* @param {String} spec.key The metadata key
* @param {String} spec.value The value of the metadata to compare
*/
function ComplexQuery(spec, key_schema) {
Query.call(this);
/**
* Logical operator to use to compare object values
*
* @attribute operator
* @type String
* @default "AND"
* @optional
*/
this.operator = spec.operator;
/**
* The sub Query list which are used to query an item.
*
* @attribute query_list
* @type Array
* @default []
* @optional
*/
this.query_list = spec.query_list || [];
this.query_list = this.query_list.map(
// decorate the map to avoid sending the index as key_schema argument
function (o) { return QueryFactory.create(o, key_schema); }
);
}
inherits(ComplexQuery, Query);
ComplexQuery.prototype.operator = "AND";
ComplexQuery.prototype.type = "complex";
/**
* #crossLink "Query/match:method"
*/
ComplexQuery.prototype.match = function (item) {
var operator = this.operator;
if (!(regexp_operator.test(operator))) {
operator = "AND";
}
return this[operator.toUpperCase()](item);
};
/**
* #crossLink "Query/toString:method"
*/
ComplexQuery.prototype.toString = function () {
ComplexQuery.prototype.toString = function () {
var str_list = [], this_operator = this.operator;
if (this.operator === "NOT") {
str_list.push("NOT (");
......@@ -4896,12 +5087,12 @@ ComplexQuery.prototype.toString = function () {
});
str_list.length -= 1;
return str_list.join(" ");
};
};
/**
/**
* #crossLink "Query/serialized:method"
*/
ComplexQuery.prototype.serialized = function () {
ComplexQuery.prototype.serialized = function () {
var s = {
"type": "complex",
"operator": this.operator,
......@@ -4913,10 +5104,10 @@ ComplexQuery.prototype.serialized = function () {
);
});
return s;
};
ComplexQuery.prototype.toJSON = ComplexQuery.prototype.serialized;
};
ComplexQuery.prototype.toJSON = ComplexQuery.prototype.serialized;
/**
/**
* Comparison operator, test if all sub queries match the
* item value
*
......@@ -4924,34 +5115,19 @@ ComplexQuery.prototype.toJSON = ComplexQuery.prototype.serialized;
* @param {Object} item The item to match
* @return {Boolean} true if all match, false otherwise
*/
ComplexQuery.prototype.AND = function (item) {
var queue = new RSVP.Queue(),
context = this,
ComplexQuery.prototype.AND = function (item) {
var result = true,
i = 0;
function executeNextIfNotFalse(result) {
if (result === false) {
// No need to evaluate the other elements, as one is false
return result;
}
if (context.query_list.length === i) {
// No new element to loop on
return true;
}
queue
.push(function () {
var sub_result = context.query_list[i].match(item);
while (result && (i !== this.query_list.length)) {
result = this.query_list[i].match(item);
i += 1;
return sub_result;
})
.push(executeNextIfNotFalse);
}
return result;
executeNextIfNotFalse(true);
return queue;
};
};
/**
/**
* Comparison operator, test if one of the sub queries matches the
* item value
*
......@@ -4959,68 +5135,31 @@ ComplexQuery.prototype.AND = function (item) {
* @param {Object} item The item to match
* @return {Boolean} true if one match, false otherwise
*/
ComplexQuery.prototype.OR = function (item) {
var queue = new RSVP.Queue(),
context = this,
ComplexQuery.prototype.OR = function (item) {
var result = false,
i = 0;
function executeNextIfNotTrue(result) {
if (result === true) {
// No need to evaluate the other elements, as one is true
return result;
}
if (context.query_list.length === i) {
// No new element to loop on
return false;
}
queue
.push(function () {
var sub_result = context.query_list[i].match(item);
while ((!result) && (i !== this.query_list.length)) {
result = this.query_list[i].match(item);
i += 1;
return sub_result;
})
.push(executeNextIfNotTrue);
}
executeNextIfNotTrue(false);
return queue;
};
/**
* Comparison operator, test if the sub query does not match the
* item value
*
* @method NOT
* @param {Object} item The item to match
* @return {Boolean} true if one match, false otherwise
*/
ComplexQuery.prototype.NOT = function (item) {
return new RSVP.Queue()
.push(function () {
return this.query_list[0].match(item);
})
.push(function (answer) {
return !answer;
});
};
query_class_dict.complex = ComplexQuery;
window.ComplexQuery = ComplexQuery;
;/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global window, ComplexQuery, SimpleQuery, Query, parseStringToObject,
query_class_dict */
return result;
};
/**
* Provides static methods to create Query object
/**
* Comparison operator, test if the sub query does not match the
* item value
*
* @class QueryFactory
* @method NOT
* @param {Object} item The item to match
* @return {Boolean} true if one match, false otherwise
*/
function QueryFactory() {
return;
}
ComplexQuery.prototype.NOT = function (item) {
return !this.query_list[0].match(item);
};
/**
/**
* Creates Query object from a search text string or a serialized version
* of a Query.
*
......@@ -5030,7 +5169,7 @@ function QueryFactory() {
* of a Query
* @return {Query} A Query object
*/
QueryFactory.create = function (object, key_schema) {
QueryFactory.create = function (object, key_schema) {
if (object === "") {
return new Query();
}
......@@ -5043,13 +5182,9 @@ QueryFactory.create = function (object, key_schema) {
}
throw new TypeError("QueryFactory.create(): " +
"Argument 1 is not a search text or a parsable object");
};
window.QueryFactory = QueryFactory;
;/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query, exports */
};
function objectToSearchText(query) {
function objectToSearchText(query) {
var str_list = [];
if (query.type === "complex") {
str_list.push("(");
......@@ -5066,13 +5201,9 @@ function objectToSearchText(query) {
(query.operator || "") + ' "' + query.value + '"';
}
throw new TypeError("This object is not a query");
}
Query.objectToSearchText = objectToSearchText;
;/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query, inherits, query_class_dict, window,
searchTextToRegExp, RSVP */
}
var checkKeySchema = function (key_schema) {
function checkKeySchema(key_schema) {
var prop;
if (key_schema !== undefined) {
......@@ -5099,10 +5230,9 @@ var checkKeySchema = function (key_schema) {
}
}
}
};
}
/**
/**
* The SimpleQuery inherits from Query, and compares one metadata value
*
* @class SimpleQuery
......@@ -5112,7 +5242,7 @@ var checkKeySchema = function (key_schema) {
* @param {String} spec.key The metadata key
* @param {String} spec.value The value of the metadata to compare
*/
function SimpleQuery(spec, key_schema) {
function SimpleQuery(spec, key_schema) {
Query.call(this);
checkKeySchema(key_schema);
......@@ -5144,12 +5274,12 @@ function SimpleQuery(spec, key_schema) {
*/
this.value = spec.value;
}
inherits(SimpleQuery, Query);
}
inherits(SimpleQuery, Query);
SimpleQuery.prototype.type = "simple";
SimpleQuery.prototype.type = "simple";
var checkKey = function (key) {
function checkKey(key) {
var prop;
if (key.read_from === undefined) {
......@@ -5169,13 +5299,12 @@ var checkKey = function (key) {
}
}
}
};
}
/**
/**
* #crossLink "Query/match:method"
*/
SimpleQuery.prototype.match = function (item) {
SimpleQuery.prototype.match = function (item) {
var object_value = null,
equal_match = null,
cast_to = null,
......@@ -5184,10 +5313,9 @@ SimpleQuery.prototype.match = function (item) {
value = null,
key = this.key;
/*jslint regexp: true */
if (!(/^(?:!?=|<=?|>=?)$/i.test(operator))) {
if (!(regexp_comparaison.test(operator))) {
// `operator` is not correct, we have to change it to "like" or "="
if (/%/.test(this.value)) {
if (regexp_percent.test(this.value)) {
// `value` contains a non escaped `%`
operator = "like";
} else {
......@@ -5246,23 +5374,23 @@ SimpleQuery.prototype.match = function (item) {
value = this.value;
}
if (object_value === undefined || value === undefined) {
return RSVP.resolve(false);
return false;
}
return matchMethod(object_value, value);
};
};
/**
/**
* #crossLink "Query/toString:method"
*/
SimpleQuery.prototype.toString = function () {
SimpleQuery.prototype.toString = function () {
return (this.key ? this.key + ":" : "") +
(this.operator ? " " + this.operator : "") + ' "' + this.value + '"';
};
};
/**
/**
* #crossLink "Query/serialized:method"
*/
SimpleQuery.prototype.serialized = function () {
SimpleQuery.prototype.serialized = function () {
var object = {
"type": "simple",
"key": this.key,
......@@ -5272,10 +5400,10 @@ SimpleQuery.prototype.serialized = function () {
object.operator = this.operator;
}
return object;
};
SimpleQuery.prototype.toJSON = SimpleQuery.prototype.serialized;
};
SimpleQuery.prototype.toJSON = SimpleQuery.prototype.serialized;
/**
/**
* Comparison operator, test if this query value matches the item value
*
* @method =
......@@ -5283,7 +5411,7 @@ SimpleQuery.prototype.toJSON = SimpleQuery.prototype.serialized;
* @param {String} comparison_value The comparison value
* @return {Boolean} true if match, false otherwise
*/
SimpleQuery.prototype["="] = function (object_value, comparison_value) {
SimpleQuery.prototype["="] = function (object_value, comparison_value) {
var value, i;
if (!Array.isArray(object_value)) {
object_value = [object_value];
......@@ -5294,19 +5422,16 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value) {
value = value.content;
}
if (typeof value.cmp === "function") {
return RSVP.resolve(value.cmp(comparison_value) === 0);
return (value.cmp(comparison_value) === 0);
}
if (
searchTextToRegExp(comparison_value.toString(), false).
test(value.toString())
) {
return RSVP.resolve(true);
if (comparison_value.toString() === value.toString()) {
return true;
}
}
return RSVP.resolve(false);
};
return false;
};
/**
/**
* Comparison operator, test if this query value matches the item value
*
* @method like
......@@ -5314,7 +5439,7 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value) {
* @param {String} comparison_value The comparison value
* @return {Boolean} true if match, false otherwise
*/
SimpleQuery.prototype.like = function (object_value, comparison_value) {
SimpleQuery.prototype.like = function (object_value, comparison_value) {
var value, i;
if (!Array.isArray(object_value)) {
object_value = [object_value];
......@@ -5325,18 +5450,18 @@ SimpleQuery.prototype.like = function (object_value, comparison_value) {
value = value.content;
}
if (typeof value.cmp === "function") {
return RSVP.resolve(value.cmp(comparison_value) === 0);
return (value.cmp(comparison_value) === 0);
}
if (
searchTextToRegExp(comparison_value.toString()).test(value.toString())
) {
return RSVP.resolve(true);
return true;
}
}
return RSVP.resolve(false);
};
return false;
};
/**
/**
* Comparison operator, test if this query value does not match the item value
*
* @method !=
......@@ -5344,7 +5469,7 @@ SimpleQuery.prototype.like = function (object_value, comparison_value) {
* @param {String} comparison_value The comparison value
* @return {Boolean} true if not match, false otherwise
*/
SimpleQuery.prototype["!="] = function (object_value, comparison_value) {
SimpleQuery.prototype["!="] = function (object_value, comparison_value) {
var value, i;
if (!Array.isArray(object_value)) {
object_value = [object_value];
......@@ -5355,19 +5480,16 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value) {
value = value.content;
}
if (typeof value.cmp === "function") {
return RSVP.resolve(value.cmp(comparison_value) !== 0);
return (value.cmp(comparison_value) !== 0);
}
if (
searchTextToRegExp(comparison_value.toString(), false).
test(value.toString())
) {
return RSVP.resolve(false);
if (comparison_value.toString() === value.toString()) {
return false;
}
}
return RSVP.resolve(true);
};
return true;
};
/**
/**
* Comparison operator, test if this query value is lower than the item value
*
* @method <
......@@ -5375,7 +5497,7 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value) {
* @param {Number, String} comparison_value The comparison value
* @return {Boolean} true if lower, false otherwise
*/
SimpleQuery.prototype["<"] = function (object_value, comparison_value) {
SimpleQuery.prototype["<"] = function (object_value, comparison_value) {
var value;
if (!Array.isArray(object_value)) {
object_value = [object_value];
......@@ -5385,326 +5507,95 @@ SimpleQuery.prototype["<"] = function (object_value, comparison_value) {
value = value.content;
}
if (typeof value.cmp === "function") {
return RSVP.resolve(value.cmp(comparison_value) < 0);
return (value.cmp(comparison_value) < 0);
}
return RSVP.resolve(value < comparison_value);
};
return (value < comparison_value);
};
/**
/**
* Comparison operator, test if this query value is equal or lower than the
* item value
*
* @method <=
* @param {Number, String} object_value The value to compare
* @param {Number, String} comparison_value The comparison value
* @return {Boolean} true if equal or lower, false otherwise
*/
SimpleQuery.prototype["<="] = function (object_value, comparison_value) {
var value;
if (!Array.isArray(object_value)) {
object_value = [object_value];
}
value = object_value[0];
if (typeof value === 'object' && value.hasOwnProperty('content')) {
value = value.content;
}
if (typeof value.cmp === "function") {
return RSVP.resolve(value.cmp(comparison_value) <= 0);
}
return RSVP.resolve(value <= comparison_value);
};
/**
* Comparison operator, test if this query value is greater than the item
* value
*
* @method >
* @param {Number, String} object_value The value to compare
* @param {Number, String} comparison_value The comparison value
* @return {Boolean} true if greater, false otherwise
*/
SimpleQuery.prototype[">"] = function (object_value, comparison_value) {
var value;
if (!Array.isArray(object_value)) {
object_value = [object_value];
}
value = object_value[0];
if (typeof value === 'object' && value.hasOwnProperty('content')) {
value = value.content;
}
if (typeof value.cmp === "function") {
return RSVP.resolve(value.cmp(comparison_value) > 0);
}
return RSVP.resolve(value > comparison_value);
};
/**
* Comparison operator, test if this query value is equal or greater than the
* item value
*
* @method >=
* @param {Number, String} object_value The value to compare
* @param {Number, String} comparison_value The comparison value
* @return {Boolean} true if equal or greater, false otherwise
*/
SimpleQuery.prototype[">="] = function (object_value, comparison_value) {
var value;
if (!Array.isArray(object_value)) {
object_value = [object_value];
}
value = object_value[0];
if (typeof value === 'object' && value.hasOwnProperty('content')) {
value = value.content;
}
if (typeof value.cmp === "function") {
return RSVP.resolve(value.cmp(comparison_value) >= 0);
}
return RSVP.resolve(value >= comparison_value);
};
query_class_dict.simple = SimpleQuery;
window.SimpleQuery = SimpleQuery;
;/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query, RSVP, deepClone */
/**
* Escapes regexp special chars from a string.
*
* @param {String} string The string to escape
* @return {String} The escaped string
*/
function stringEscapeRegexpCharacters(string) {
if (typeof string === "string") {
return string.replace(/([\\\.\$\[\]\(\)\{\}\^\?\*\+\-])/g, "\\$1");
}
throw new TypeError("Query.stringEscapeRegexpCharacters(): " +
"Argument no 1 is not of type 'string'");
}
Query.stringEscapeRegexpCharacters = stringEscapeRegexpCharacters;
/**
* Convert metadata values to array of strings. ex:
*
* "a" -> ["a"],
* {"content": "a"} -> ["a"]
*
* @param {Any} value The metadata value
* @return {Array} The value in string array format
*/
function metadataValueToStringArray(value) {
var i, new_value = [];
if (value === undefined) {
return undefined;
}
if (!Array.isArray(value)) {
value = [value];
}
for (i = 0; i < value.length; i += 1) {
if (typeof value[i] === 'object') {
new_value[i] = value[i].content;
} else {
new_value[i] = value[i];
}
}
return new_value;
}
/**
* A sort function to sort items by key
*
* @param {String} key The key to sort on
* @param {String} [way="ascending"] 'ascending' or 'descending'
* @return {Function} The sort function
*/
function sortFunction(key, way) {
var result;
if (way === 'descending') {
result = 1;
} else if (way === 'ascending') {
result = -1;
} else {
throw new TypeError("Query.sortFunction(): " +
"Argument 2 must be 'ascending' or 'descending'");
}
return function (a, b) {
// this comparison is 5 times faster than json comparison
var i, l;
a = metadataValueToStringArray(a[key]) || [];
b = metadataValueToStringArray(b[key]) || [];
l = a.length > b.length ? a.length : b.length;
for (i = 0; i < l; i += 1) {
if (a[i] === undefined) {
return result;
}
if (b[i] === undefined) {
return -result;
}
if (a[i] > b[i]) {
return -result;
}
if (a[i] < b[i]) {
return result;
}
}
return 0;
};
}
/**
* Inherits the prototype methods from one constructor into another. The
* prototype of `constructor` will be set to a new object created from
* `superConstructor`.
*
* @param {Function} constructor The constructor which inherits the super one
* @param {Function} superConstructor The super constructor
*/
function inherits(constructor, superConstructor) {
constructor.super_ = superConstructor;
constructor.prototype = Object.create(superConstructor.prototype, {
"constructor": {
"configurable": true,
"enumerable": false,
"writable": true,
"value": constructor
}
});
}
/**
* Does nothing
*/
function emptyFunction() {
return;
}
/**
* Filter a list of items, modifying them to select only wanted keys. If
* `clone` is true, then the method will act on a cloned list.
*
* @param {Array} select_option Key list to keep
* @param {Array} list The item list to filter
* @param {Boolean} [clone=false] If true, modifies a clone of the list
* @return {Array} The filtered list
*/
function select(select_option, list, clone) {
var i, j, new_item;
if (!Array.isArray(select_option)) {
throw new TypeError("jioquery.select(): " +
"Argument 1 is not of type Array");
}
if (!Array.isArray(list)) {
throw new TypeError("jioquery.select(): " +
"Argument 2 is not of type Array");
}
if (clone === true) {
list = deepClone(list);
}
for (i = 0; i < list.length; i += 1) {
new_item = {};
for (j = 0; j < select_option.length; j += 1) {
if (list[i].hasOwnProperty([select_option[j]])) {
new_item[select_option[j]] = list[i][select_option[j]];
}
}
for (j in new_item) {
if (new_item.hasOwnProperty(j)) {
list[i] = new_item;
break;
* @return {Boolean} true if equal or lower, false otherwise
*/
SimpleQuery.prototype["<="] = function (object_value, comparison_value) {
var value;
if (!Array.isArray(object_value)) {
object_value = [object_value];
}
value = object_value[0];
if (typeof value === 'object' && value.hasOwnProperty('content')) {
value = value.content;
}
if (typeof value.cmp === "function") {
return (value.cmp(comparison_value) <= 0);
}
return list;
}
Query.select = select;
return (value <= comparison_value);
};
/**
* Sort a list of items, according to keys and directions. If `clone` is true,
* then the method will act on a cloned list.
/**
* Comparison operator, test if this query value is greater than the item
* value
*
* @param {Array} sort_on_option List of couples [key, direction]
* @param {Array} list The item list to sort
* @param {Boolean} [clone=false] If true, modifies a clone of the list
* @return {Array} The filtered list
* @method >
* @param {Number, String} object_value The value to compare
* @param {Number, String} comparison_value The comparison value
* @return {Boolean} true if greater, false otherwise
*/
function sortOn(sort_on_option, list, clone) {
var sort_index;
if (!Array.isArray(sort_on_option)) {
throw new TypeError("jioquery.sortOn(): " +
"Argument 1 is not of type 'array'");
SimpleQuery.prototype[">"] = function (object_value, comparison_value) {
var value;
if (!Array.isArray(object_value)) {
object_value = [object_value];
}
if (clone) {
list = deepClone(list);
value = object_value[0];
if (typeof value === 'object' && value.hasOwnProperty('content')) {
value = value.content;
}
for (sort_index = sort_on_option.length - 1; sort_index >= 0;
sort_index -= 1) {
list.sort(sortFunction(
sort_on_option[sort_index][0],
sort_on_option[sort_index][1]
));
if (typeof value.cmp === "function") {
return (value.cmp(comparison_value) > 0);
}
return list;
}
Query.sortOn = sortOn;
return (value > comparison_value);
};
/**
* Limit a list of items, according to index and length. If `clone` is true,
* then the method will act on a cloned list.
/**
* Comparison operator, test if this query value is equal or greater than the
* item value
*
* @param {Array} limit_option A couple [from, length]
* @param {Array} list The item list to limit
* @param {Boolean} [clone=false] If true, modifies a clone of the list
* @return {Array} The filtered list
* @method >=
* @param {Number, String} object_value The value to compare
* @param {Number, String} comparison_value The comparison value
* @return {Boolean} true if equal or greater, false otherwise
*/
function limit(limit_option, list, clone) {
if (!Array.isArray(limit_option)) {
throw new TypeError("jioquery.limit(): " +
"Argument 1 is not of type 'array'");
}
if (!Array.isArray(list)) {
throw new TypeError("jioquery.limit(): " +
"Argument 2 is not of type 'array'");
SimpleQuery.prototype[">="] = function (object_value, comparison_value) {
var value;
if (!Array.isArray(object_value)) {
object_value = [object_value];
}
if (clone) {
list = deepClone(list);
value = object_value[0];
if (typeof value === 'object' && value.hasOwnProperty('content')) {
value = value.content;
}
list.splice(0, limit_option[0]);
if (limit_option[1]) {
list.splice(limit_option[1]);
if (typeof value.cmp === "function") {
return (value.cmp(comparison_value) >= 0);
}
return list;
}
return (value >= comparison_value);
};
Query.limit = limit;
query_class_dict.simple = SimpleQuery;
query_class_dict.complex = ComplexQuery;
/**
* Convert a search text to a regexp.
*
* @param {String} string The string to convert
* @param {Boolean} [use_wildcard_character=true] Use wildcard "%" and "_"
* @return {RegExp} The search text regexp
*/
function searchTextToRegExp(string, use_wildcard_characters) {
if (typeof string !== 'string') {
throw new TypeError("jioquery.searchTextToRegExp(): " +
"Argument 1 is not of type 'string'");
}
if (use_wildcard_characters === false) {
return new RegExp("^" + stringEscapeRegexpCharacters(string) + "$");
}
return new RegExp("^" + stringEscapeRegexpCharacters(string).replace(
/%/g,
".*"
).replace(
/_/g,
"."
) + "$");
}
Query.parseStringToObject = parseStringToObject;
Query.objectToSearchText = objectToSearchText;
window.Query = Query;
window.SimpleQuery = SimpleQuery;
window.ComplexQuery = ComplexQuery;
window.QueryFactory = QueryFactory;
Query.searchTextToRegExp = searchTextToRegExp;
}(RSVP, window, parseStringToObject));
;/*global window, moment */
/*jslint nomen: true, maxlen: 200*/
(function (window, moment) {
......@@ -5950,70 +5841,6 @@ Query.searchTextToRegExp = searchTextToRegExp;
}
util.ajax = ajax;
/**
* Clones all native object in deep. Managed types: Object, Array, String,
* Number, Boolean, Function, null.
*
* It can also clone object which are serializable, like Date.
*
* To make a class serializable, you need to implement the `toJSON` function
* which returns a JSON representation of the object. The returned value is
* used as first parameter of the object constructor.
*
* @param {A} object The object to clone
* @return {A} The cloned object
*/
function deepClone(object) {
var i, cloned;
if (Array.isArray(object)) {
cloned = [];
for (i = 0; i < object.length; i += 1) {
cloned[i] = deepClone(object[i]);
}
return cloned;
}
if (object === null) {
return null;
}
if (typeof object === 'object') {
if (Object.getPrototypeOf(object) === Object.prototype) {
cloned = {};
for (i in object) {
if (object.hasOwnProperty(i)) {
cloned[i] = deepClone(object[i]);
}
}
return cloned;
}
if (object instanceof Date) {
// XXX this block is to enable phantomjs and browsers compatibility with
// Date.prototype.toJSON when it is an invalid date. In phantomjs, it
// returns `"Invalid Date"` but in browsers it returns `null`. In
// browsers, giving `null` as parameter to `new Date()` doesn't return
// an invalid date.
// Cloning a date with `return new Date(object)` has problems on
// Firefox.
// I don't know why... (Tested on Firefox 23)
if (isFinite(object.getTime())) {
return new Date(object.toJSON());
}
return new Date("Invalid Date");
}
// clone serializable objects
if (typeof object.toJSON === 'function') {
return new (Object.getPrototypeOf(object).constructor)(object.toJSON());
}
// cannot clone
return object;
}
return object;
}
util.deepClone = deepClone;
function readBlobAsText(blob, encoding) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject, notify) {
......@@ -7525,13 +7352,13 @@ Query.searchTextToRegExp = searchTextToRegExp;
attachments: {}
};
}
this._database[id].doc = JSON.stringify(metadata);
this._database[id].doc = metadata;
return id;
};
MemoryStorage.prototype.get = function (id) {
try {
return JSON.parse(this._database[id].doc);
return this._database[id].doc;
} catch (error) {
if (error instanceof TypeError) {
throw new jIO.util.jIOError(
......@@ -7619,18 +7446,26 @@ Query.searchTextToRegExp = searchTextToRegExp;
MemoryStorage.prototype.hasCapacity = function (name) {
return (name === "list");
return ((name === "list") || (name === "include"));
};
MemoryStorage.prototype.buildQuery = function () {
MemoryStorage.prototype.buildQuery = function (options) {
var rows = [],
i;
for (i in this._database) {
if (this._database.hasOwnProperty(i)) {
if (options.include_docs === true) {
rows.push({
id: i,
value: {},
doc: this._database[i]
});
} else {
rows.push({
id: i,
value: {}
});
}
}
}
......@@ -8622,6 +8457,250 @@ Query.searchTextToRegExp = searchTextToRegExp;
jIO.addStorage('dav', DavStorage);
}(jIO, RSVP, DOMParser, Blob));
;/*
* Copyright 2015, Nexedi SA
* Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html
*/
/**
* JIO Google Drive Storage. Type = "gdrive".
* Google Drive "database" storage.
*/
/*global jIO, Blob, RSVP, UriTemplate, JSON*/
/*jslint nomen: true*/
(function (jIO, Blob, RSVP, UriTemplate, JSON) {
"use strict";
var UPLOAD_URL = "https://www.googleapis.com{/upload}/drive/v2/files{/id}" +
"{?uploadType,access_token}",
upload_template = UriTemplate.parse(UPLOAD_URL),
REMOVE_URL = "https://www.googleapis.com/drive/v2/" +
"files{/id,trash}{?access_token}",
remove_template = UriTemplate.parse(REMOVE_URL),
LIST_URL = "https://www.googleapis.com/drive/v2/files" +
"?prettyPrint=false{&pageToken}&q=trashed=false" +
"&fields=nextPageToken,items(id){&access_token}",
list_template = UriTemplate.parse(LIST_URL),
GET_URL = "https://www.googleapis.com/drive/v2/files{/id}{?alt}",
get_template = UriTemplate.parse(GET_URL);
function handleError(error, id) {
if (error.target.status === 404) {
throw new jIO.util.jIOError(
"Cannot find document: " + id,
404
);
}
throw error;
}
function listPage(result, token) {
var i,
obj;
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
"type": "GET",
"url": list_template.expand({
pageToken : (result.nextPageToken || ""),
access_token: token
})
});
})
.push(function (data) {
obj = JSON.parse(data.target.response || data.target.responseText);
for (i = 0; i < obj.items.length; i += 1) {
obj.items[i].value = {};
result.push(obj.items[i]);
}
result.nextPageToken = obj.nextPageToken;
return result;
}, handleError);
}
function checkName(name) {
if (name !== "enclosure") {
throw new jIO.util.jIOError("Only support 'enclosure' attachment", 400);
}
}
/**
* The JIO Google Drive Storage extension
*
* @class GdriveStorage
* @constructor
*/
function GdriveStorage(spec) {
if (spec === undefined || spec.access_token === undefined ||
typeof spec.access_token !== 'string') {
throw new TypeError("Access Token must be a string " +
"which contains more than one character.");
}
if (spec.trashing !== undefined &&
(spec.trashing !== true && spec.trashing !== false)) {
throw new TypeError("trashing parameter" +
" must be a boolean (true or false)");
}
this._trashing = spec.trashing || true;
this._access_token = spec.access_token;
return;
}
function recursiveAllDocs(result, accessToken) {
return new RSVP.Queue()
.push(function () {
return listPage(result, accessToken);
})
.push(function () {
if (result.nextPageToken) {
return recursiveAllDocs(result, accessToken);
}
return result;
});
}
GdriveStorage.prototype.hasCapacity = function (name) {
return (name === "list");
};
GdriveStorage.prototype.buildQuery = function () {
return recursiveAllDocs([], this._access_token);
};
function sendMetaData(id, param, token) {
var boundary = "-------314159265358979323846";
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
"type": id ? "PUT" : "POST",
"url": upload_template.expand({
access_token: token,
id: id || [],
upload: id ? [] : "upload",
uploadType: "multipart"
}),
headers: {
"Content-Type" : 'multipart/related; boundary="' + boundary + '"'
},
data: '--' + boundary + '\n' +
'Content-Type: application/json; charset=UTF-8\n\n' +
JSON.stringify(param) + '\n\n--' + boundary + "--"
});
})
.push(function (result) {
var obj = JSON.parse(result.target.responseText);
return obj.id;
},
function (error) {handleError(error, id); });
}
GdriveStorage.prototype.put = function (id, param) {
return sendMetaData(id, param, this._access_token);
};
GdriveStorage.prototype.post = function (param) {
return sendMetaData(undefined, param, this._access_token);
};
function sendData(id, blob, token) {
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
"type": "PUT",
"url": upload_template.expand({
access_token: token,
upload: "upload",
id: id,
uploadType: "media"
}),
data: blob
});
})
.push(function (data) {
data = JSON.parse(data.target.responseText);
if (data.mimeType === "application/vnd.google-apps.folder") {
throw new jIO.util.jIOError("cannot put attachments to folder", 400);
}
return data;
}, function (error) {handleError(error, id); });
}
GdriveStorage.prototype.putAttachment = function (id, name, blob) {
checkName(name);
return sendData(id, blob, this._access_token);
};
GdriveStorage.prototype.remove = function (id) {
var that = this;
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
type: that._trashing ? "POST" : "DELETE",
url: remove_template.expand({
id : id,
access_token : that._access_token,
trash : that._trashing ? "trash" : []
})
});
})
.push(undefined, function (error) {handleError(error, id); });
};
function getData(id, attach, token) {
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
type: "GET",
dataType: attach ? "blob" : "json",
url: get_template.expand({
id: id,
alt: attach ? "media" : [],
access_token: token
}),
headers: {
"Authorization" : "Bearer " + token
}
});
})
.push(function (evt) {
return evt.target.response ||
(attach ? new Blob([evt.target.responseText],
{"type" :
evt.target.responseHeaders["Content-Type"]}) :
JSON.parse(evt.target.responseText));
}, function (error) {handleError(error, id); });
}
GdriveStorage.prototype.get = function (id) {
return getData(id, false, this._access_token);
};
GdriveStorage.prototype.getAttachment = function (id, name) {
checkName(name);
return getData(id, true, this._access_token);
};
GdriveStorage.prototype.allAttachments = function (id) {
var token = this._access_token;
return new RSVP.Queue()
.push(function () {
return getData(id, false, token);
})
.push(function (data) {
if (data.mimeType === "application/vnd.google-apps.folder") {
return {};
}
return {"enclosure": {}};
});
};
jIO.addStorage('gdrive', GdriveStorage);
}(jIO, Blob, RSVP, UriTemplate, JSON));
;/*jslint nomen: true */
/*global RSVP*/
......@@ -8880,10 +8959,10 @@ Query.searchTextToRegExp = searchTextToRegExp;
// }
/*jslint nomen: true, unparam: true */
/*global jIO, UriTemplate, FormData, RSVP, URI, Blob, objectToSearchText,
/*global jIO, UriTemplate, FormData, RSVP, URI, Blob,
SimpleQuery, ComplexQuery*/
(function (jIO, UriTemplate, FormData, RSVP, URI, Blob, objectToSearchText,
(function (jIO, UriTemplate, FormData, RSVP, URI, Blob,
SimpleQuery, ComplexQuery) {
"use strict";
......@@ -9340,14 +9419,14 @@ Query.searchTextToRegExp = searchTextToRegExp;
if (result_list) {
local_roles = result_list;
parsed_query.query_list.splice(i, 1);
query = objectToSearchText(parsed_query);
query = jIO.Query.objectToSearchText(parsed_query);
i = parsed_query.query_list.length;
} else {
result_list = isMultipleLocalRoles(sub_query);
if (result_list) {
local_roles = result_list;
parsed_query.query_list.splice(i, 1);
query = objectToSearchText(parsed_query);
query = jIO.Query.objectToSearchText(parsed_query);
i = parsed_query.query_list.length;
}
}
......@@ -9398,7 +9477,7 @@ Query.searchTextToRegExp = searchTextToRegExp;
jIO.addStorage("erp5", ERP5Storage);
}(jIO, UriTemplate, FormData, RSVP, URI, Blob, objectToSearchText,
}(jIO, UriTemplate, FormData, RSVP, URI, Blob,
SimpleQuery, ComplexQuery));
;/*jslint nomen: true*/
/*global RSVP*/
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "jio",
"version": "v3.5.0",
"version": "v3.6.0",
"license": "LGPLv3",
"author": "Nexedi SA",
"contributors": [
......
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