Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
E
ecommerce-ui
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
ecommerce-ui
Commits
a1e93301
Commit
a1e93301
authored
Apr 08, 2014
by
Sven Franck
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
libs: update JIO and localStorage to latest to fix bugs
parent
ac0a7350
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
2166 additions
and
93 deletions
+2166
-93
ext/libs/jio/jio.js
ext/libs/jio/jio.js
+2103
-41
ext/libs/jio/localstorage.js
ext/libs/jio/localstorage.js
+63
-52
No files found.
ext/libs/jio/jio.js
View file @
a1e93301
...
@@ -549,7 +549,7 @@ function inherits(constructor, superConstructor) {
...
@@ -549,7 +549,7 @@ function inherits(constructor, superConstructor) {
}
}
/**
/**
* Clones jsonable object in de
ep
* Clones jsonable object in de
pth
*
*
* @param {A} object The jsonable object to clone
* @param {A} object The jsonable object to clone
* @return {A} The cloned object
* @return {A} The cloned object
...
@@ -570,7 +570,7 @@ exports.util.jsonDeepClone = jsonDeepClone;
...
@@ -570,7 +570,7 @@ exports.util.jsonDeepClone = jsonDeepClone;
* It can also clone object which are serializable, like Date.
* It can also clone object which are serializable, like Date.
*
*
* To make a class serializable, you need to implement the `toJSON` function
* To make a class serializable, you need to implement the `toJSON` function
* which returns a JSON representation of the object. The return value is used
* which returns a JSON representation of the object. The return
ed
value is used
* as first parameter of the object constructor.
* as first parameter of the object constructor.
*
*
* @param {A} object The object to clone
* @param {A} object The object to clone
...
@@ -600,12 +600,12 @@ function deepClone(object) {
...
@@ -600,12 +600,12 @@ function deepClone(object) {
}
}
if
(
object
instanceof
Date
)
{
if
(
object
instanceof
Date
)
{
// XXX this block is to enable phantomjs and browsers compatibility with
// XXX this block is to enable phantomjs and browsers compatibility with
// Date.prototype.toJSON when it is a invalid date. In phantomjs, it
// Date.prototype.toJSON when it is a
n
invalid date. In phantomjs, it
// returns `"Invalid Date"` but in browsers it returns `null`. In
// returns `"Invalid Date"` but in browsers it returns `null`. In
// browsers, giv
e
`null` as parameter to `new Date()` doesn't return an
// browsers, giv
ing
`null` as parameter to `new Date()` doesn't return an
// invalid date.
// invalid date.
// Clon
ning date with `return new Date(object)` make
problems on Firefox.
// Clon
ing a date with `return new Date(object)` has
problems on Firefox.
// I don't know why... (Tested on Firefox 23)
// I don't know why... (Tested on Firefox 23)
if
(
isFinite
(
object
.
getTime
()))
{
if
(
isFinite
(
object
.
getTime
()))
{
...
@@ -625,7 +625,7 @@ function deepClone(object) {
...
@@ -625,7 +625,7 @@ function deepClone(object) {
exports
.
util
.
deepClone
=
deepClone
;
exports
.
util
.
deepClone
=
deepClone
;
/**
/**
* Update a diction
n
ary by adding/replacing key values from another dict.
* Update a dictionary by adding/replacing key values from another dict.
* Enumerable values equal to undefined are also used.
* Enumerable values equal to undefined are also used.
*
*
* @param {Object} original The dict to update
* @param {Object} original The dict to update
...
@@ -687,16 +687,14 @@ exports.util.dictFilter = dictFilter;
...
@@ -687,16 +687,14 @@ exports.util.dictFilter = dictFilter;
* @return {Object} The type dict
* @return {Object} The type dict
*/
*/
function
arrayValuesToTypeDict
(
array
)
{
function
arrayValuesToTypeDict
(
array
)
{
var
i
,
type
,
types
=
{};
var
i
,
l
,
type_object
=
{},
type
,
v
;
for
(
i
=
0
;
i
<
array
.
length
;
i
+=
1
)
{
for
(
i
=
0
,
l
=
array
.
length
;
i
<
l
;
i
+=
1
)
{
type
=
Array
.
isArray
(
array
[
i
])
?
'
array
'
:
typeof
array
[
i
];
v
=
array
[
i
];
if
(
!
types
[
type
])
{
type
=
Array
.
isArray
(
v
)
?
"
array
"
:
typeof
v
;
types
[
type
]
=
[
array
[
i
]];
/*jslint ass: true */
}
else
{
(
type_object
[
type
]
=
type_object
[
type
]
||
[]).
push
(
v
);
types
[
type
][
types
[
type
].
length
]
=
array
[
i
];
}
}
return
type_object
;
}
return
types
;
}
}
/**
/**
...
@@ -817,7 +815,7 @@ exports.util.readBlobAsText = readBlobAsText;
...
@@ -817,7 +815,7 @@ exports.util.readBlobAsText = readBlobAsText;
/**
/**
* Send request with XHR and return a promise. xhr.onload: The promise is
* Send request with XHR and return a promise. xhr.onload: The promise is
* resolve when the status code is lower than 400 with the xhr object as first
* resolve
d
when the status code is lower than 400 with the xhr object as first
* parameter. xhr.onerror: reject with xhr object as first
* parameter. xhr.onerror: reject with xhr object as first
* parameter. xhr.onprogress: notifies the xhr object.
* parameter. xhr.onprogress: notifies the xhr object.
*
*
...
@@ -826,7 +824,7 @@ exports.util.readBlobAsText = readBlobAsText;
...
@@ -826,7 +824,7 @@ exports.util.readBlobAsText = readBlobAsText;
* @param {String} [param.dataType=""] The data type to retrieve
* @param {String} [param.dataType=""] The data type to retrieve
* @param {String} param.url The url
* @param {String} param.url The url
* @param {Any} [param.data] The data to send
* @param {Any} [param.data] The data to send
* @param {Function} [param.beforeSend] A function called just before send
* @param {Function} [param.beforeSend] A function called just before
the
send
* request. The first parameter of this function is the XHR object.
* request. The first parameter of this function is the XHR object.
* @return {Promise} The promise
* @return {Promise} The promise
*/
*/
...
@@ -851,9 +849,6 @@ function ajax(param) {
...
@@ -851,9 +849,6 @@ function ajax(param) {
});
});
xhr
.
addEventListener
(
"
error
"
,
reject
);
xhr
.
addEventListener
(
"
error
"
,
reject
);
xhr
.
addEventListener
(
"
progress
"
,
notify
);
xhr
.
addEventListener
(
"
progress
"
,
notify
);
if
(
typeof
param
.
beforeSend
===
'
function
'
)
{
param
.
beforeSend
(
xhr
);
}
if
(
typeof
param
.
xhrFields
===
'
object
'
&&
param
.
xhrFields
!==
null
)
{
if
(
typeof
param
.
xhrFields
===
'
object
'
&&
param
.
xhrFields
!==
null
)
{
for
(
k
in
param
.
xhrFields
)
{
for
(
k
in
param
.
xhrFields
)
{
if
(
param
.
xhrFields
.
hasOwnProperty
(
k
))
{
if
(
param
.
xhrFields
.
hasOwnProperty
(
k
))
{
...
@@ -861,6 +856,9 @@ function ajax(param) {
...
@@ -861,6 +856,9 @@ function ajax(param) {
}
}
}
}
}
}
if
(
typeof
param
.
beforeSend
===
'
function
'
)
{
param
.
beforeSend
(
xhr
);
}
xhr
.
send
(
param
.
data
);
xhr
.
send
(
param
.
data
);
},
function
()
{
},
function
()
{
xhr
.
abort
();
xhr
.
abort
();
...
@@ -933,6 +931,169 @@ function methodType(method) {
...
@@ -933,6 +931,169 @@ function methodType(method) {
}
}
}
}
/**
* forEach(array, callback[, thisArg]): Promise
*
* It executes the provided `callback` once for each element of the array with
* an assigned value asynchronously. If the `callback` returns a promise, then
* the function will wait for its fulfillment before executing the next
* iteration.
*
* `callback` is invoked with three arguments:
*
* - the element value
* - the element index
* - the array being traversed
*
* If a `thisArg` parameter is provided to `forEach`, it will be passed to
* `callback` when invoked, for use as its `this` value. Otherwise, the value
* `undefined` will be passed for use as its `this` value.
*
* Unlike `Array.prototype.forEach`, you can stop the iteration by throwing
* something, or by doing a `cancel` to the returned promise if it is
* cancellable promise.
*
* Inspired by `Array.prototype.forEach` from Mozilla Developer Network.
*
* @param {Array} array The array to parse
* @param {Function} callback Function to execute for each element.
* @param {Any} [thisArg] Value to use as `this` when executing `callback`.
* @param {Promise} A new promise.
*/
function
forEach
(
array
,
fn
,
thisArg
)
{
if
(
arguments
.
length
===
0
)
{
throw
new
TypeError
(
"
missing argument 0 when calling function forEach
"
);
}
if
(
!
Array
.
isArray
(
array
))
{
throw
new
TypeError
(
array
+
"
is not an array
"
);
}
if
(
arguments
.
length
===
1
)
{
throw
new
TypeError
(
"
missing argument 1 when calling function forEach
"
);
}
if
(
typeof
fn
!==
"
function
"
)
{
throw
new
TypeError
(
fn
+
"
is not a function
"
);
}
var
cancelled
,
current_promise
=
RSVP
.
resolve
();
return
new
RSVP
.
Promise
(
function
(
done
,
fail
,
notify
)
{
var
i
=
0
;
function
next
()
{
if
(
cancelled
)
{
fail
(
new
Error
(
"
Cancelled
"
));
return
;
}
if
(
i
<
array
.
length
)
{
current_promise
=
current_promise
.
then
(
fn
.
bind
(
thisArg
,
array
[
i
],
i
,
array
));
current_promise
.
then
(
next
,
fail
,
notify
);
i
+=
1
;
return
;
}
done
();
}
next
();
},
function
()
{
cancelled
=
true
;
if
(
typeof
current_promise
.
cancel
===
"
function
"
)
{
current_promise
.
cancel
();
}
});
}
exports
.
util
.
forEach
=
forEach
;
/**
* range(stop, callback): Promise
* range(start, stop[, step], callback): Promise
*
* It executes the provided `callback` once for each step between `start` and
* `stop`. If the `callback` returns a promise, then the function will wait
* for its fulfillment before executing the next iteration.
*
* `callback` is invoked with one argument:
*
* - the index of the step
*
* `start`, `stop` and `step` must be finite numbers. If `step` is not
* provided, then the default step will be `1`. If `start` and `step` are not
* provided, `start` will be `0` and `step` will be `1`.
*
* Inspired by `range()` from Python 3 built-in functions.
*
* range(10, function (index) {
* return notifyIndex(index);
* }).then(onDone, onError, onNotify);
*
* @param {Number} [start=0] The start index
* @param {Number} stop The stop index
* @param {Number} [step=1] One step
* @param {Function} callback Function to execute on each iteration.
* @param {Promise} A new promise with no fulfillment value.
*/
function
range
(
start
,
stop
,
step
,
callback
)
{
var
type_object
,
cancelled
,
current_promise
;
type_object
=
arrayValuesToTypeDict
([
start
,
stop
,
step
,
callback
]);
if
(
type_object
[
"
function
"
].
length
!==
1
)
{
throw
new
TypeError
(
"
range(): only one callback is needed
"
);
}
start
=
type_object
.
number
.
length
;
if
(
start
<
1
)
{
throw
new
TypeError
(
"
range(): 1, 2 or 3 numbers are needed
"
);
}
if
(
start
>
3
)
{
throw
new
TypeError
(
"
range(): only 1, 2 or 3 numbers are needed
"
);
}
callback
=
type_object
[
"
function
"
][
0
];
if
(
start
===
1
)
{
start
=
0
;
stop
=
type_object
.
number
[
0
];
step
=
1
;
}
if
(
start
===
2
)
{
start
=
type_object
.
number
[
0
];
stop
=
type_object
.
number
[
1
];
step
=
1
;
}
if
(
start
===
3
)
{
start
=
type_object
.
number
[
0
];
stop
=
type_object
.
number
[
1
];
step
=
type_object
.
number
[
2
];
if
(
step
===
0
)
{
throw
new
TypeError
(
"
range(): step must not be zero
"
);
}
}
type_object
=
undefined
;
current_promise
=
RSVP
.
resolve
();
return
new
RSVP
.
Promise
(
function
(
done
,
fail
,
notify
)
{
var
i
=
start
,
test
;
function
next
()
{
if
(
cancelled
)
{
fail
(
new
Error
(
"
Cancelled
"
));
return
;
}
test
=
step
>
0
?
i
<
stop
:
i
>
stop
;
if
(
test
)
{
current_promise
=
current_promise
.
then
(
callback
.
bind
(
null
,
i
));
current_promise
.
then
(
next
,
fail
,
notify
);
i
+=
step
;
return
;
}
done
();
}
next
();
},
function
()
{
cancelled
=
true
;
if
(
typeof
current_promise
.
cancel
===
"
function
"
)
{
current_promise
.
cancel
();
}
});
}
exports
.
util
.
range
=
range
;
/*jslint indent: 2, maxlen: 80, nomen: true, sloppy: true */
/*jslint indent: 2, maxlen: 80, nomen: true, sloppy: true */
/*global secureMethods, exports, console */
/*global secureMethods, exports, console */
...
@@ -2119,7 +2280,7 @@ function addJobRuleCondition(name, method) {
...
@@ -2119,7 +2280,7 @@ function addJobRuleCondition(name, method) {
exports
.
addJobRuleCondition
=
addJobRuleCondition
;
exports
.
addJobRuleCondition
=
addJobRuleCondition
;
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */
/*global constants, dictUpdate, deepClone */
/*global constants, dictUpdate, deepClone
, DOMException
*/
function
restCommandRejecter
(
param
,
args
)
{
function
restCommandRejecter
(
param
,
args
)
{
// reject(status, reason, message, {"custom": "value"});
// reject(status, reason, message, {"custom": "value"});
...
@@ -2192,8 +2353,22 @@ function restCommandRejecter(param, args) {
...
@@ -2192,8 +2353,22 @@ function restCommandRejecter(param, args) {
if
((
arg
.
statusText
||
arg
.
status
>=
0
))
{
if
((
arg
.
statusText
||
arg
.
status
>=
0
))
{
current_priority
.
status
=
arg
.
statusText
||
arg
.
status
;
current_priority
.
status
=
arg
.
statusText
||
arg
.
status
;
}
}
if
(
arg
instanceof
Error
)
{
if
(
arg
instanceof
Error
||
arg
instanceof
DOMException
)
{
current_priority
.
reason
=
arg
.
message
||
""
;
if
(
arg
.
code
!==
undefined
&&
arg
.
code
!==
null
)
{
current_priority
.
code
=
arg
.
code
;
}
if
(
arg
.
lineNumber
!==
undefined
&&
arg
.
lineNumber
!==
null
)
{
current_priority
.
lineNumber
=
arg
.
lineNumber
;
}
if
(
arg
.
columnNumber
!==
undefined
&&
arg
.
columnNumber
!==
null
)
{
current_priority
.
columnNumber
=
arg
.
columnNumber
;
}
if
(
arg
.
filename
!==
undefined
&&
arg
.
filename
!==
null
)
{
current_priority
.
filename
=
arg
.
filename
;
}
if
(
arg
.
message
!==
undefined
&&
arg
.
message
!==
null
)
{
current_priority
.
reason
=
arg
.
message
;
}
current_priority
.
error
=
arg
.
name
;
current_priority
.
error
=
arg
.
name
;
}
}
}
}
...
@@ -2224,6 +2399,7 @@ function restCommandRejecter(param, args) {
...
@@ -2224,6 +2399,7 @@ function restCommandRejecter(param, args) {
priority
.
error
=
priority
.
statusText
.
toLowerCase
().
replace
(
/ /g
,
'
_
'
).
priority
.
error
=
priority
.
statusText
.
toLowerCase
().
replace
(
/ /g
,
'
_
'
).
replace
(
/
[^
_a-z
]
/g
,
''
);
replace
(
/
[^
_a-z
]
/g
,
''
);
}
}
param
.
storage_response
=
priority
;
return
param
.
solver
.
reject
(
deepClone
(
priority
));
return
param
.
solver
.
reject
(
deepClone
(
priority
));
}
}
...
@@ -2250,8 +2426,8 @@ function restCommandResolver(param, args) {
...
@@ -2250,8 +2426,8 @@ function restCommandResolver(param, args) {
args
=
Array
.
prototype
.
slice
.
call
(
args
);
args
=
Array
.
prototype
.
slice
.
call
(
args
);
arg
=
args
.
shift
();
arg
=
args
.
shift
();
// priority
3
- never change
// priority
4
- never change
current_priority
=
priority
[
3
];
current_priority
=
priority
[
4
];
if
(
param
.
kwargs
.
_id
)
{
if
(
param
.
kwargs
.
_id
)
{
current_priority
.
id
=
param
.
kwargs
.
_id
;
current_priority
.
id
=
param
.
kwargs
.
_id
;
}
}
...
@@ -2350,6 +2526,8 @@ function restCommandResolver(param, args) {
...
@@ -2350,6 +2526,8 @@ function restCommandResolver(param, args) {
param
.
method
+
'
method needs a dict as returned "data".
'
param
.
method
+
'
method needs a dict as returned "data".
'
]);
]);
}
}
param
.
storage_response
=
priority
;
return
param
.
solver
.
resolve
(
deepClone
(
priority
));
return
param
.
solver
.
resolve
(
deepClone
(
priority
));
}
}
...
@@ -2372,8 +2550,6 @@ function enableJobChecker(jio, shared, options) {
...
@@ -2372,8 +2550,6 @@ function enableJobChecker(jio, shared, options) {
// emits 'job:modified', 'job:start', 'job:resolved',
// emits 'job:modified', 'job:start', 'job:resolved',
// 'job:end', 'job:reject' events
// 'job:end', 'job:reject' events
var
i
;
shared
.
job_rule_action_names
=
[
undefined
,
"
ok
"
,
"
wait
"
,
"
update
"
,
"
deny
"
];
shared
.
job_rule_action_names
=
[
undefined
,
"
ok
"
,
"
wait
"
,
"
update
"
,
"
deny
"
];
shared
.
job_rule_actions
=
{
shared
.
job_rule_actions
=
{
...
@@ -2398,11 +2574,11 @@ function enableJobChecker(jio, shared, options) {
...
@@ -2398,11 +2574,11 @@ function enableJobChecker(jio, shared, options) {
if
(
!
original_job
.
solver
)
{
if
(
!
original_job
.
solver
)
{
original_job
.
solver
=
new_job
.
solver
;
original_job
.
solver
=
new_job
.
solver
;
}
else
{
}
else
{
original_job
.
promise
.
then
(
original_job
.
promise
.
then
(
function
()
{
new_job
.
command
.
resolve
,
new_job
.
command
.
resolve
(
deepClone
(
original_job
.
storage_response
));
new_job
.
command
.
reject
,
},
function
()
{
new_job
.
command
.
notify
new_job
.
command
.
reject
(
deepClone
(
original_job
.
storage_response
));
);
},
new_job
.
command
.
notify
);
}
}
}
}
new_job
.
state
=
'
running
'
;
new_job
.
state
=
'
running
'
;
...
@@ -2555,6 +2731,8 @@ function enableJobChecker(jio, shared, options) {
...
@@ -2555,6 +2731,8 @@ function enableJobChecker(jio, shared, options) {
}
}
}
}
var
index
;
if
(
options
.
job_management
!==
false
)
{
if
(
options
.
job_management
!==
false
)
{
shared
.
job_rules
=
[{
shared
.
job_rules
=
[{
...
@@ -2594,8 +2772,8 @@ function enableJobChecker(jio, shared, options) {
...
@@ -2594,8 +2772,8 @@ function enableJobChecker(jio, shared, options) {
}
}
if
(
Array
.
isArray
(
options
.
job_rules
))
{
if
(
Array
.
isArray
(
options
.
job_rules
))
{
for
(
i
=
0
;
i
<
options
.
job_rules
.
length
;
i
+=
1
)
{
for
(
i
ndex
=
0
;
index
<
options
.
job_rules
.
length
;
index
+=
1
)
{
addJobRule
(
deepClone
(
options
.
job_rules
[
i
]));
addJobRule
(
deepClone
(
options
.
job_rules
[
i
ndex
]));
}
}
}
}
...
@@ -2949,9 +3127,10 @@ function enableJobRecovery(jio, shared, options) {
...
@@ -2949,9 +3127,10 @@ function enableJobRecovery(jio, shared, options) {
var
i
,
job_array
,
delay
,
deadline
,
recovery_delay
;
var
i
,
job_array
,
delay
,
deadline
,
recovery_delay
;
recovery_delay
=
numberOrDefault
(
options
.
recovery_delay
,
10000
);
// 1 m 30 s === default firefox request timeout
recovery_delay
=
numberOrDefault
(
options
.
recovery_delay
,
90000
);
if
(
recovery_delay
<
0
)
{
if
(
recovery_delay
<
0
)
{
recovery_delay
=
1
0000
;
recovery_delay
=
9
0000
;
}
}
if
(
options
.
job_management
!==
false
&&
options
.
job_recovery
!==
false
)
{
if
(
options
.
job_management
!==
false
&&
options
.
job_recovery
!==
false
)
{
...
@@ -3152,8 +3331,8 @@ function enableJobTimeout(jio, shared, options) {
...
@@ -3152,8 +3331,8 @@ function enableJobTimeout(jio, shared, options) {
number
:
default_value
);
number
:
default_value
);
}
}
//
10 seconds
by default
//
Infinity
by default
var
default_timeout
=
positiveNumberOrDefault
(
options
.
default_timeout
,
1000
0
);
var
default_timeout
=
positiveNumberOrDefault
(
options
.
default_timeout
,
0
);
function
timeoutReject
(
param
)
{
function
timeoutReject
(
param
)
{
return
function
()
{
return
function
()
{
...
@@ -3168,7 +3347,8 @@ function enableJobTimeout(jio, shared, options) {
...
@@ -3168,7 +3347,8 @@ function enableJobTimeout(jio, shared, options) {
}
}
function
initJob
(
job
)
{
function
initJob
(
job
)
{
if
(
typeof
job
.
timeout
!==
'
number
'
||
job
.
timeout
<
0
)
{
if
(
typeof
job
.
timeout
!==
'
number
'
||
!
isFinite
(
job
.
timeout
)
||
job
.
timeout
<
0
)
{
job
.
timeout
=
positiveNumberOrDefault
(
job
.
timeout
=
positiveNumberOrDefault
(
job
.
options
.
timeout
,
job
.
options
.
timeout
,
default_timeout
default_timeout
...
@@ -3258,7 +3438,7 @@ function enableRestAPI(jio, shared) { // (jio, shared, options)
...
@@ -3258,7 +3438,7 @@ function enableRestAPI(jio, shared) { // (jio, shared, options)
}
}
param
.
kwargs
=
deepClone
(
param
.
kwargs
);
param
.
kwargs
=
deepClone
(
param
.
kwargs
);
}
else
{
}
else
{
param
.
kwargs
=
deepClone
(
type_dict
.
object
.
shift
())
;
param
.
kwargs
=
{}
;
}
}
param
.
solver
=
{};
param
.
solver
=
{};
param
.
options
=
deepClone
(
type_dict
.
object
.
shift
())
||
{};
param
.
options
=
deepClone
(
type_dict
.
object
.
shift
())
||
{};
...
@@ -3427,4 +3607,1886 @@ function enableRestParamChecker(jio, shared) {
...
@@ -3427,4 +3607,1886 @@ function enableRestParamChecker(jio, shared) {
}
}
/*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, exports, stringEscapeRegexpCharacters: true,
deepClone, RSVP, sequence */
/**
* 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
sequence
([
function
()
{
return
RSVP
.
all
(
promises
);
},
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
);
}
},
function
()
{
if
(
option
.
limit
)
{
return
limit
(
option
.
limit
,
item_list
);
}
},
function
()
{
return
select
(
option
.
select_list
||
[],
item_list
);
},
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
;
if
(
query
.
type
===
"
complex
"
)
{
return
sequence
([
function
()
{
return
sequence
(
query
.
query_list
.
map
(
function
(
v
,
i
)
{
/*jslint unparam: true */
return
function
()
{
return
sequence
([
function
()
{
object
.
parsed
=
query
.
query_list
[
i
];
return
recParse
(
object
,
option
);
},
function
()
{
query
.
query_list
[
i
]
=
object
.
parsed
;
}]);
};
}));
},
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
sequence
([
function
()
{
return
that
.
onParseStart
(
object
,
option
);
},
function
()
{
return
recParse
(
object
,
option
);
},
function
()
{
return
that
.
onParseEnd
(
object
,
option
);
},
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
;
};
exports
.
Query
=
Query
;
/**
* Parse a text request to a json query object tree
*
* @param {String} string The string to parse
* @return {Object} The json query tree
*/
function
parseStringToObject
(
string
)
{
/*
Default template driver for JS/CC generated parsers running as
browser-based JavaScript/ECMAScript applications.
WARNING: This parser template will not run as console and has lesser
features for debugging than the console derivates for the
various JavaScript platforms.
Features:
- Parser trace messages
- Integrated panic-mode error recovery
Written 2007, 2008 by Jan Max Meyer, J.M.K S.F. Software Technologies
This is in the public domain.
*/
var
NODEJS__dbg_withtrace
=
false
;
var
NODEJS__dbg_string
=
new
String
();
function
__NODEJS_dbg_print
(
text
)
{
NODEJS__dbg_string
+=
text
+
"
\n
"
;
}
function
__NODEJS_lex
(
info
)
{
var
state
=
0
;
var
match
=
-
1
;
var
match_pos
=
0
;
var
start
=
0
;
var
pos
=
info
.
offset
+
1
;
do
{
pos
--
;
state
=
0
;
match
=
-
2
;
start
=
pos
;
if
(
info
.
src
.
length
<=
start
)
return
19
;
do
{
switch
(
state
)
{
case
0
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
8
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
10
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
info
.
src
.
charCodeAt
(
pos
)
==
59
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
63
&&
info
.
src
.
charCodeAt
(
pos
)
<=
64
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
66
&&
info
.
src
.
charCodeAt
(
pos
)
<=
77
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
80
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
9
)
state
=
2
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
40
)
state
=
3
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
41
)
state
=
4
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
60
||
info
.
src
.
charCodeAt
(
pos
)
==
62
)
state
=
5
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
33
)
state
=
11
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
79
)
state
=
12
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
32
)
state
=
13
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
61
)
state
=
14
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
34
)
state
=
15
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
65
)
state
=
19
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
78
)
state
=
20
;
else
state
=
-
1
;
break
;
case
1
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
state
=
-
1
;
match
=
10
;
match_pos
=
pos
;
break
;
case
2
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
state
=
-
1
;
match
=
1
;
match_pos
=
pos
;
break
;
case
3
:
state
=
-
1
;
match
=
3
;
match_pos
=
pos
;
break
;
case
4
:
state
=
-
1
;
match
=
4
;
match_pos
=
pos
;
break
;
case
5
:
if
(
info
.
src
.
charCodeAt
(
pos
)
==
61
)
state
=
14
;
else
state
=
-
1
;
match
=
11
;
match_pos
=
pos
;
break
;
case
6
:
state
=
-
1
;
match
=
8
;
match_pos
=
pos
;
break
;
case
7
:
state
=
-
1
;
match
=
9
;
match_pos
=
pos
;
break
;
case
8
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
state
=
-
1
;
match
=
6
;
match_pos
=
pos
;
break
;
case
9
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
state
=
-
1
;
match
=
5
;
match_pos
=
pos
;
break
;
case
10
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
state
=
-
1
;
match
=
7
;
match_pos
=
pos
;
break
;
case
11
:
if
(
info
.
src
.
charCodeAt
(
pos
)
==
61
)
state
=
14
;
else
state
=
-
1
;
break
;
case
12
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
81
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
83
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
82
)
state
=
8
;
else
state
=
-
1
;
match
=
10
;
match_pos
=
pos
;
break
;
case
13
:
state
=
-
1
;
match
=
1
;
match_pos
=
pos
;
break
;
case
14
:
state
=
-
1
;
match
=
11
;
match_pos
=
pos
;
break
;
case
15
:
if
(
info
.
src
.
charCodeAt
(
pos
)
==
34
)
state
=
7
;
else
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
33
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
91
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
93
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
15
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
92
)
state
=
17
;
else
state
=
-
1
;
break
;
case
16
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
67
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
69
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
68
)
state
=
9
;
else
state
=
-
1
;
match
=
10
;
match_pos
=
pos
;
break
;
case
17
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
15
;
else
state
=
-
1
;
break
;
case
18
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
83
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
85
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
84
)
state
=
10
;
else
state
=
-
1
;
match
=
10
;
match_pos
=
pos
;
break
;
case
19
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
77
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
79
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
78
)
state
=
16
;
else
state
=
-
1
;
match
=
10
;
match_pos
=
pos
;
break
;
case
20
:
if
(
(
info
.
src
.
charCodeAt
(
pos
)
>=
0
&&
info
.
src
.
charCodeAt
(
pos
)
<=
31
)
||
info
.
src
.
charCodeAt
(
pos
)
==
33
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
35
&&
info
.
src
.
charCodeAt
(
pos
)
<=
39
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
42
&&
info
.
src
.
charCodeAt
(
pos
)
<=
57
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
59
&&
info
.
src
.
charCodeAt
(
pos
)
<=
78
)
||
(
info
.
src
.
charCodeAt
(
pos
)
>=
80
&&
info
.
src
.
charCodeAt
(
pos
)
<=
254
)
)
state
=
1
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
58
)
state
=
6
;
else
if
(
info
.
src
.
charCodeAt
(
pos
)
==
79
)
state
=
18
;
else
state
=
-
1
;
match
=
10
;
match_pos
=
pos
;
break
;
}
pos
++
;
}
while
(
state
>
-
1
);
}
while
(
1
>
-
1
&&
match
==
1
);
if
(
match
>
-
1
)
{
info
.
att
=
info
.
src
.
substr
(
start
,
match_pos
-
start
);
info
.
offset
=
match_pos
;
}
else
{
info
.
att
=
new
String
();
match
=
-
1
;
}
return
match
;
}
function
__NODEJS_parse
(
src
,
err_off
,
err_la
)
{
var
sstack
=
new
Array
();
var
vstack
=
new
Array
();
var
err_cnt
=
0
;
var
act
;
var
go
;
var
la
;
var
rval
;
var
parseinfo
=
new
Function
(
""
,
"
var offset; var src; var att;
"
);
var
info
=
new
parseinfo
();
/* Pop-Table */
var
pop_tab
=
new
Array
(
new
Array
(
0
/* begin' */
,
1
),
new
Array
(
13
/* begin */
,
1
),
new
Array
(
12
/* search_text */
,
1
),
new
Array
(
12
/* search_text */
,
2
),
new
Array
(
12
/* search_text */
,
3
),
new
Array
(
14
/* and_expression */
,
1
),
new
Array
(
14
/* and_expression */
,
3
),
new
Array
(
15
/* boolean_expression */
,
2
),
new
Array
(
15
/* boolean_expression */
,
1
),
new
Array
(
16
/* expression */
,
3
),
new
Array
(
16
/* expression */
,
2
),
new
Array
(
16
/* expression */
,
1
),
new
Array
(
17
/* value */
,
2
),
new
Array
(
17
/* value */
,
1
),
new
Array
(
18
/* string */
,
1
),
new
Array
(
18
/* string */
,
1
)
);
/* Action-Table */
var
act_tab
=
new
Array
(
/* State 0 */
new
Array
(
7
/* "NOT" */
,
5
,
3
/* "LEFT_PARENTHESE" */
,
7
,
8
/* "COLUMN" */
,
8
,
11
/* "OPERATOR" */
,
10
,
10
/* "WORD" */
,
12
,
9
/* "STRING" */
,
13
),
/* State 1 */
new
Array
(
19
/* "$" */
,
0
),
/* State 2 */
new
Array
(
19
/* "$" */
,
-
1
),
/* State 3 */
new
Array
(
6
/* "OR" */
,
14
,
7
/* "NOT" */
,
5
,
3
/* "LEFT_PARENTHESE" */
,
7
,
8
/* "COLUMN" */
,
8
,
11
/* "OPERATOR" */
,
10
,
10
/* "WORD" */
,
12
,
9
/* "STRING" */
,
13
,
19
/* "$" */
,
-
2
,
4
/* "RIGHT_PARENTHESE" */
,
-
2
),
/* State 4 */
new
Array
(
5
/* "AND" */
,
16
,
19
/* "$" */
,
-
5
,
7
/* "NOT" */
,
-
5
,
3
/* "LEFT_PARENTHESE" */
,
-
5
,
8
/* "COLUMN" */
,
-
5
,
11
/* "OPERATOR" */
,
-
5
,
10
/* "WORD" */
,
-
5
,
9
/* "STRING" */
,
-
5
,
6
/* "OR" */
,
-
5
,
4
/* "RIGHT_PARENTHESE" */
,
-
5
),
/* State 5 */
new
Array
(
3
/* "LEFT_PARENTHESE" */
,
7
,
8
/* "COLUMN" */
,
8
,
11
/* "OPERATOR" */
,
10
,
10
/* "WORD" */
,
12
,
9
/* "STRING" */
,
13
),
/* State 6 */
new
Array
(
19
/* "$" */
,
-
8
,
7
/* "NOT" */
,
-
8
,
3
/* "LEFT_PARENTHESE" */
,
-
8
,
8
/* "COLUMN" */
,
-
8
,
11
/* "OPERATOR" */
,
-
8
,
10
/* "WORD" */
,
-
8
,
9
/* "STRING" */
,
-
8
,
6
/* "OR" */
,
-
8
,
5
/* "AND" */
,
-
8
,
4
/* "RIGHT_PARENTHESE" */
,
-
8
),
/* State 7 */
new
Array
(
7
/* "NOT" */
,
5
,
3
/* "LEFT_PARENTHESE" */
,
7
,
8
/* "COLUMN" */
,
8
,
11
/* "OPERATOR" */
,
10
,
10
/* "WORD" */
,
12
,
9
/* "STRING" */
,
13
),
/* State 8 */
new
Array
(
3
/* "LEFT_PARENTHESE" */
,
7
,
8
/* "COLUMN" */
,
8
,
11
/* "OPERATOR" */
,
10
,
10
/* "WORD" */
,
12
,
9
/* "STRING" */
,
13
),
/* State 9 */
new
Array
(
19
/* "$" */
,
-
11
,
7
/* "NOT" */
,
-
11
,
3
/* "LEFT_PARENTHESE" */
,
-
11
,
8
/* "COLUMN" */
,
-
11
,
11
/* "OPERATOR" */
,
-
11
,
10
/* "WORD" */
,
-
11
,
9
/* "STRING" */
,
-
11
,
6
/* "OR" */
,
-
11
,
5
/* "AND" */
,
-
11
,
4
/* "RIGHT_PARENTHESE" */
,
-
11
),
/* State 10 */
new
Array
(
10
/* "WORD" */
,
12
,
9
/* "STRING" */
,
13
),
/* State 11 */
new
Array
(
19
/* "$" */
,
-
13
,
7
/* "NOT" */
,
-
13
,
3
/* "LEFT_PARENTHESE" */
,
-
13
,
8
/* "COLUMN" */
,
-
13
,
11
/* "OPERATOR" */
,
-
13
,
10
/* "WORD" */
,
-
13
,
9
/* "STRING" */
,
-
13
,
6
/* "OR" */
,
-
13
,
5
/* "AND" */
,
-
13
,
4
/* "RIGHT_PARENTHESE" */
,
-
13
),
/* State 12 */
new
Array
(
19
/* "$" */
,
-
14
,
7
/* "NOT" */
,
-
14
,
3
/* "LEFT_PARENTHESE" */
,
-
14
,
8
/* "COLUMN" */
,
-
14
,
11
/* "OPERATOR" */
,
-
14
,
10
/* "WORD" */
,
-
14
,
9
/* "STRING" */
,
-
14
,
6
/* "OR" */
,
-
14
,
5
/* "AND" */
,
-
14
,
4
/* "RIGHT_PARENTHESE" */
,
-
14
),
/* State 13 */
new
Array
(
19
/* "$" */
,
-
15
,
7
/* "NOT" */
,
-
15
,
3
/* "LEFT_PARENTHESE" */
,
-
15
,
8
/* "COLUMN" */
,
-
15
,
11
/* "OPERATOR" */
,
-
15
,
10
/* "WORD" */
,
-
15
,
9
/* "STRING" */
,
-
15
,
6
/* "OR" */
,
-
15
,
5
/* "AND" */
,
-
15
,
4
/* "RIGHT_PARENTHESE" */
,
-
15
),
/* State 14 */
new
Array
(
7
/* "NOT" */
,
5
,
3
/* "LEFT_PARENTHESE" */
,
7
,
8
/* "COLUMN" */
,
8
,
11
/* "OPERATOR" */
,
10
,
10
/* "WORD" */
,
12
,
9
/* "STRING" */
,
13
),
/* State 15 */
new
Array
(
19
/* "$" */
,
-
3
,
4
/* "RIGHT_PARENTHESE" */
,
-
3
),
/* State 16 */
new
Array
(
7
/* "NOT" */
,
5
,
3
/* "LEFT_PARENTHESE" */
,
7
,
8
/* "COLUMN" */
,
8
,
11
/* "OPERATOR" */
,
10
,
10
/* "WORD" */
,
12
,
9
/* "STRING" */
,
13
),
/* State 17 */
new
Array
(
19
/* "$" */
,
-
7
,
7
/* "NOT" */
,
-
7
,
3
/* "LEFT_PARENTHESE" */
,
-
7
,
8
/* "COLUMN" */
,
-
7
,
11
/* "OPERATOR" */
,
-
7
,
10
/* "WORD" */
,
-
7
,
9
/* "STRING" */
,
-
7
,
6
/* "OR" */
,
-
7
,
5
/* "AND" */
,
-
7
,
4
/* "RIGHT_PARENTHESE" */
,
-
7
),
/* State 18 */
new
Array
(
4
/* "RIGHT_PARENTHESE" */
,
23
),
/* State 19 */
new
Array
(
19
/* "$" */
,
-
10
,
7
/* "NOT" */
,
-
10
,
3
/* "LEFT_PARENTHESE" */
,
-
10
,
8
/* "COLUMN" */
,
-
10
,
11
/* "OPERATOR" */
,
-
10
,
10
/* "WORD" */
,
-
10
,
9
/* "STRING" */
,
-
10
,
6
/* "OR" */
,
-
10
,
5
/* "AND" */
,
-
10
,
4
/* "RIGHT_PARENTHESE" */
,
-
10
),
/* State 20 */
new
Array
(
19
/* "$" */
,
-
12
,
7
/* "NOT" */
,
-
12
,
3
/* "LEFT_PARENTHESE" */
,
-
12
,
8
/* "COLUMN" */
,
-
12
,
11
/* "OPERATOR" */
,
-
12
,
10
/* "WORD" */
,
-
12
,
9
/* "STRING" */
,
-
12
,
6
/* "OR" */
,
-
12
,
5
/* "AND" */
,
-
12
,
4
/* "RIGHT_PARENTHESE" */
,
-
12
),
/* State 21 */
new
Array
(
19
/* "$" */
,
-
4
,
4
/* "RIGHT_PARENTHESE" */
,
-
4
),
/* State 22 */
new
Array
(
19
/* "$" */
,
-
6
,
7
/* "NOT" */
,
-
6
,
3
/* "LEFT_PARENTHESE" */
,
-
6
,
8
/* "COLUMN" */
,
-
6
,
11
/* "OPERATOR" */
,
-
6
,
10
/* "WORD" */
,
-
6
,
9
/* "STRING" */
,
-
6
,
6
/* "OR" */
,
-
6
,
4
/* "RIGHT_PARENTHESE" */
,
-
6
),
/* State 23 */
new
Array
(
19
/* "$" */
,
-
9
,
7
/* "NOT" */
,
-
9
,
3
/* "LEFT_PARENTHESE" */
,
-
9
,
8
/* "COLUMN" */
,
-
9
,
11
/* "OPERATOR" */
,
-
9
,
10
/* "WORD" */
,
-
9
,
9
/* "STRING" */
,
-
9
,
6
/* "OR" */
,
-
9
,
5
/* "AND" */
,
-
9
,
4
/* "RIGHT_PARENTHESE" */
,
-
9
)
);
/* Goto-Table */
var
goto_tab
=
new
Array
(
/* State 0 */
new
Array
(
13
/* begin */
,
1
,
12
/* search_text */
,
2
,
14
/* and_expression */
,
3
,
15
/* boolean_expression */
,
4
,
16
/* expression */
,
6
,
17
/* value */
,
9
,
18
/* string */
,
11
),
/* State 1 */
new
Array
(
),
/* State 2 */
new
Array
(
),
/* State 3 */
new
Array
(
12
/* search_text */
,
15
,
14
/* and_expression */
,
3
,
15
/* boolean_expression */
,
4
,
16
/* expression */
,
6
,
17
/* value */
,
9
,
18
/* string */
,
11
),
/* State 4 */
new
Array
(
),
/* State 5 */
new
Array
(
16
/* expression */
,
17
,
17
/* value */
,
9
,
18
/* string */
,
11
),
/* State 6 */
new
Array
(
),
/* State 7 */
new
Array
(
12
/* search_text */
,
18
,
14
/* and_expression */
,
3
,
15
/* boolean_expression */
,
4
,
16
/* expression */
,
6
,
17
/* value */
,
9
,
18
/* string */
,
11
),
/* State 8 */
new
Array
(
16
/* expression */
,
19
,
17
/* value */
,
9
,
18
/* string */
,
11
),
/* State 9 */
new
Array
(
),
/* State 10 */
new
Array
(
18
/* string */
,
20
),
/* State 11 */
new
Array
(
),
/* State 12 */
new
Array
(
),
/* State 13 */
new
Array
(
),
/* State 14 */
new
Array
(
12
/* search_text */
,
21
,
14
/* and_expression */
,
3
,
15
/* boolean_expression */
,
4
,
16
/* expression */
,
6
,
17
/* value */
,
9
,
18
/* string */
,
11
),
/* State 15 */
new
Array
(
),
/* State 16 */
new
Array
(
14
/* and_expression */
,
22
,
15
/* boolean_expression */
,
4
,
16
/* expression */
,
6
,
17
/* value */
,
9
,
18
/* string */
,
11
),
/* State 17 */
new
Array
(
),
/* State 18 */
new
Array
(
),
/* State 19 */
new
Array
(
),
/* State 20 */
new
Array
(
),
/* State 21 */
new
Array
(
),
/* State 22 */
new
Array
(
),
/* State 23 */
new
Array
(
)
);
/* Symbol labels */
var
labels
=
new
Array
(
"
begin'
"
/* Non-terminal symbol */
,
"
WHITESPACE
"
/* Terminal symbol */
,
"
WHITESPACE
"
/* Terminal symbol */
,
"
LEFT_PARENTHESE
"
/* Terminal symbol */
,
"
RIGHT_PARENTHESE
"
/* Terminal symbol */
,
"
AND
"
/* Terminal symbol */
,
"
OR
"
/* Terminal symbol */
,
"
NOT
"
/* Terminal symbol */
,
"
COLUMN
"
/* Terminal symbol */
,
"
STRING
"
/* Terminal symbol */
,
"
WORD
"
/* Terminal symbol */
,
"
OPERATOR
"
/* Terminal symbol */
,
"
search_text
"
/* Non-terminal symbol */
,
"
begin
"
/* Non-terminal symbol */
,
"
and_expression
"
/* Non-terminal symbol */
,
"
boolean_expression
"
/* Non-terminal symbol */
,
"
expression
"
/* Non-terminal symbol */
,
"
value
"
/* Non-terminal symbol */
,
"
string
"
/* Non-terminal symbol */
,
"
$
"
/* Terminal symbol */
);
info
.
offset
=
0
;
info
.
src
=
src
;
info
.
att
=
new
String
();
if
(
!
err_off
)
err_off
=
new
Array
();
if
(
!
err_la
)
err_la
=
new
Array
();
sstack
.
push
(
0
);
vstack
.
push
(
0
);
la
=
__NODEJS_lex
(
info
);
while
(
true
)
{
act
=
25
;
for
(
var
i
=
0
;
i
<
act_tab
[
sstack
[
sstack
.
length
-
1
]].
length
;
i
+=
2
)
{
if
(
act_tab
[
sstack
[
sstack
.
length
-
1
]][
i
]
==
la
)
{
act
=
act_tab
[
sstack
[
sstack
.
length
-
1
]][
i
+
1
];
break
;
}
}
if
(
NODEJS__dbg_withtrace
&&
sstack
.
length
>
0
)
{
__NODEJS_dbg_print
(
"
\n
State
"
+
sstack
[
sstack
.
length
-
1
]
+
"
\n
"
+
"
\t
Lookahead:
"
+
labels
[
la
]
+
"
(
\"
"
+
info
.
att
+
"
\"
)
\n
"
+
"
\t
Action:
"
+
act
+
"
\n
"
+
"
\t
Source:
\"
"
+
info
.
src
.
substr
(
info
.
offset
,
30
)
+
(
(
info
.
offset
+
30
<
info
.
src
.
length
)
?
"
...
"
:
""
)
+
"
\"\n
"
+
"
\t
Stack:
"
+
sstack
.
join
()
+
"
\n
"
+
"
\t
Value stack:
"
+
vstack
.
join
()
+
"
\n
"
);
}
//Panic-mode: Try recovery when parse-error occurs!
if
(
act
==
25
)
{
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
Error detected: There is no reduce or shift on the symbol
"
+
labels
[
la
]
);
err_cnt
++
;
err_off
.
push
(
info
.
offset
-
info
.
att
.
length
);
err_la
.
push
(
new
Array
()
);
for
(
var
i
=
0
;
i
<
act_tab
[
sstack
[
sstack
.
length
-
1
]].
length
;
i
+=
2
)
err_la
[
err_la
.
length
-
1
].
push
(
labels
[
act_tab
[
sstack
[
sstack
.
length
-
1
]][
i
]]
);
//Remember the original stack!
var
rsstack
=
new
Array
();
var
rvstack
=
new
Array
();
for
(
var
i
=
0
;
i
<
sstack
.
length
;
i
++
)
{
rsstack
[
i
]
=
sstack
[
i
];
rvstack
[
i
]
=
vstack
[
i
];
}
while
(
act
==
25
&&
la
!=
19
)
{
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
\t
Error recovery
\n
"
+
"
Current lookahead:
"
+
labels
[
la
]
+
"
(
"
+
info
.
att
+
"
)
\n
"
+
"
Action:
"
+
act
+
"
\n\n
"
);
if
(
la
==
-
1
)
info
.
offset
++
;
while
(
act
==
25
&&
sstack
.
length
>
0
)
{
sstack
.
pop
();
vstack
.
pop
();
if
(
sstack
.
length
==
0
)
break
;
act
=
25
;
for
(
var
i
=
0
;
i
<
act_tab
[
sstack
[
sstack
.
length
-
1
]].
length
;
i
+=
2
)
{
if
(
act_tab
[
sstack
[
sstack
.
length
-
1
]][
i
]
==
la
)
{
act
=
act_tab
[
sstack
[
sstack
.
length
-
1
]][
i
+
1
];
break
;
}
}
}
if
(
act
!=
25
)
break
;
for
(
var
i
=
0
;
i
<
rsstack
.
length
;
i
++
)
{
sstack
.
push
(
rsstack
[
i
]
);
vstack
.
push
(
rvstack
[
i
]
);
}
la
=
__NODEJS_lex
(
info
);
}
if
(
act
==
25
)
{
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
\t
Error recovery failed, terminating parse process...
"
);
break
;
}
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
\t
Error recovery succeeded, continuing
"
);
}
/*
if( act == 25 )
break;
*/
//Shift
if
(
act
>
0
)
{
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
Shifting symbol:
"
+
labels
[
la
]
+
"
(
"
+
info
.
att
+
"
)
"
);
sstack
.
push
(
act
);
vstack
.
push
(
info
.
att
);
la
=
__NODEJS_lex
(
info
);
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
\t
New lookahead symbol:
"
+
labels
[
la
]
+
"
(
"
+
info
.
att
+
"
)
"
);
}
//Reduce
else
{
act
*=
-
1
;
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
Reducing by producution:
"
+
act
);
rval
=
void
(
0
);
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
\t
Performing semantic action...
"
);
switch
(
act
)
{
case
0
:
{
rval
=
vstack
[
vstack
.
length
-
1
];
}
break
;
case
1
:
{
result
=
vstack
[
vstack
.
length
-
1
];
}
break
;
case
2
:
{
rval
=
vstack
[
vstack
.
length
-
1
];
}
break
;
case
3
:
{
rval
=
mkComplexQuery
(
'
OR
'
,[
vstack
[
vstack
.
length
-
2
],
vstack
[
vstack
.
length
-
1
]]);
}
break
;
case
4
:
{
rval
=
mkComplexQuery
(
'
OR
'
,[
vstack
[
vstack
.
length
-
3
],
vstack
[
vstack
.
length
-
1
]]);
}
break
;
case
5
:
{
rval
=
vstack
[
vstack
.
length
-
1
]
;
}
break
;
case
6
:
{
rval
=
mkComplexQuery
(
'
AND
'
,[
vstack
[
vstack
.
length
-
3
],
vstack
[
vstack
.
length
-
1
]]);
}
break
;
case
7
:
{
rval
=
mkNotQuery
(
vstack
[
vstack
.
length
-
1
]);
}
break
;
case
8
:
{
rval
=
vstack
[
vstack
.
length
-
1
];
}
break
;
case
9
:
{
rval
=
vstack
[
vstack
.
length
-
2
];
}
break
;
case
10
:
{
simpleQuerySetKey
(
vstack
[
vstack
.
length
-
1
],
vstack
[
vstack
.
length
-
2
].
split
(
'
:
'
).
slice
(
0
,
-
1
).
join
(
'
:
'
));
rval
=
vstack
[
vstack
.
length
-
1
];
}
break
;
case
11
:
{
rval
=
vstack
[
vstack
.
length
-
1
];
}
break
;
case
12
:
{
vstack
[
vstack
.
length
-
1
].
operator
=
vstack
[
vstack
.
length
-
2
]
;
rval
=
vstack
[
vstack
.
length
-
1
];
}
break
;
case
13
:
{
rval
=
vstack
[
vstack
.
length
-
1
];
}
break
;
case
14
:
{
rval
=
mkSimpleQuery
(
''
,
vstack
[
vstack
.
length
-
1
]);
}
break
;
case
15
:
{
rval
=
mkSimpleQuery
(
''
,
vstack
[
vstack
.
length
-
1
].
split
(
'
"
'
).
slice
(
1
,
-
1
).
join
(
'
"
'
));
}
break
;
}
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
\t
Popping
"
+
pop_tab
[
act
][
1
]
+
"
off the stack...
"
);
for
(
var
i
=
0
;
i
<
pop_tab
[
act
][
1
];
i
++
)
{
sstack
.
pop
();
vstack
.
pop
();
}
go
=
-
1
;
for
(
var
i
=
0
;
i
<
goto_tab
[
sstack
[
sstack
.
length
-
1
]].
length
;
i
+=
2
)
{
if
(
goto_tab
[
sstack
[
sstack
.
length
-
1
]][
i
]
==
pop_tab
[
act
][
0
]
)
{
go
=
goto_tab
[
sstack
[
sstack
.
length
-
1
]][
i
+
1
];
break
;
}
}
if
(
act
==
0
)
break
;
if
(
NODEJS__dbg_withtrace
)
__NODEJS_dbg_print
(
"
\t
Pushing non-terminal
"
+
labels
[
pop_tab
[
act
][
0
]
]
);
sstack
.
push
(
go
);
vstack
.
push
(
rval
);
}
if
(
NODEJS__dbg_withtrace
)
{
alert
(
NODEJS__dbg_string
);
NODEJS__dbg_string
=
new
String
();
}
}
if
(
NODEJS__dbg_withtrace
)
{
__NODEJS_dbg_print
(
"
\n
Parse complete.
"
);
alert
(
NODEJS__dbg_string
);
}
return
err_cnt
;
}
var
arrayExtend
=
function
()
{
var
j
,
i
,
newlist
=
[],
list_list
=
arguments
;
for
(
j
=
0
;
j
<
list_list
.
length
;
j
+=
1
)
{
for
(
i
=
0
;
i
<
list_list
[
j
].
length
;
i
+=
1
)
{
newlist
.
push
(
list_list
[
j
][
i
]);
}
}
return
newlist
;
},
mkSimpleQuery
=
function
(
key
,
value
,
operator
)
{
var
object
=
{
"
type
"
:
"
simple
"
,
"
key
"
:
key
,
"
value
"
:
value
};
if
(
operator
!==
undefined
)
{
object
.
operator
=
operator
;
}
return
object
;
},
mkNotQuery
=
function
(
query
)
{
if
(
query
.
operator
===
"
NOT
"
)
{
return
query
.
query_list
[
0
];
}
return
{
"
type
"
:
"
complex
"
,
"
operator
"
:
"
NOT
"
,
"
query_list
"
:
[
query
]};
},
mkComplexQuery
=
function
(
operator
,
query_list
)
{
var
i
,
query_list2
=
[];
for
(
i
=
0
;
i
<
query_list
.
length
;
i
+=
1
)
{
if
(
query_list
[
i
].
operator
===
operator
)
{
query_list2
=
arrayExtend
(
query_list2
,
query_list
[
i
].
query_list
);
}
else
{
query_list2
.
push
(
query_list
[
i
]);
}
}
return
{
type
:
"
complex
"
,
operator
:
operator
,
query_list
:
query_list2
};
},
simpleQuerySetKey
=
function
(
query
,
key
)
{
var
i
;
if
(
query
.
type
===
"
complex
"
)
{
for
(
i
=
0
;
i
<
query
.
query_list
.
length
;
++
i
)
{
simpleQuerySetKey
(
query
.
query_list
[
i
],
key
);
}
return
true
;
}
if
(
query
.
type
===
"
simple
"
&&
!
query
.
key
)
{
query
.
key
=
key
;
return
true
;
}
return
false
;
},
error_offsets
=
[],
error_lookaheads
=
[],
error_count
=
0
,
result
;
if
((
error_count
=
__NODEJS_parse
(
string
,
error_offsets
,
error_lookaheads
))
>
0
)
{
var
i
;
for
(
i
=
0
;
i
<
error_count
;
i
+=
1
)
{
throw
new
Error
(
"
Parse error near
\"
"
+
string
.
substr
(
error_offsets
[
i
])
+
"
\"
, expecting
\"
"
+
error_lookaheads
[
i
].
join
()
+
"
\"
"
);
}
}
return
result
;
}
// parseStringToObject
Query
.
parseStringToObject
=
parseStringToObject
;
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query: true, query_class_dict: true, inherits: true,
exports, QueryFactory, RSVP, sequence */
/**
* 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
||
[];
/*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"
*/
ComplexQuery
.
prototype
.
match
=
function
(
item
)
{
var
operator
=
this
.
operator
;
if
(
!
(
/^
(?:
AND|OR|NOT
)
$/i
.
test
(
operator
)))
{
operator
=
"
AND
"
;
}
return
this
[
operator
.
toUpperCase
()](
item
);
};
/**
* #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
(
"
"
);
};
/**
* #crossLink "Query/serialized:method"
*/
ComplexQuery
.
prototype
.
serialized
=
function
()
{
var
s
=
{
"
type
"
:
"
complex
"
,
"
operator
"
:
this
.
operator
,
"
query_list
"
:
[]
};
this
.
query_list
.
forEach
(
function
(
query
)
{
s
.
query_list
.
push
(
typeof
query
.
toJSON
===
"
function
"
?
query
.
toJSON
()
:
query
);
});
return
s
;
};
ComplexQuery
.
prototype
.
toJSON
=
ComplexQuery
.
prototype
.
serialized
;
/**
* Comparison operator, test if all sub queries match the
* item value
*
* @method AND
* @param {Object} item The item to match
* @return {Boolean} true if all match, false otherwise
*/
ComplexQuery
.
prototype
.
AND
=
function
(
item
)
{
var
j
,
promises
=
[];
for
(
j
=
0
;
j
<
this
.
query_list
.
length
;
j
+=
1
)
{
promises
.
push
(
this
.
query_list
[
j
].
match
(
item
));
}
function
cancel
()
{
var
i
;
for
(
i
=
0
;
i
<
promises
.
length
;
i
+=
1
)
{
if
(
typeof
promises
.
cancel
===
'
function
'
)
{
promises
.
cancel
();
}
}
}
return
new
RSVP
.
Promise
(
function
(
resolve
,
reject
)
{
var
i
,
count
=
0
;
function
resolver
(
value
)
{
if
(
!
value
)
{
resolve
(
false
);
}
count
+=
1
;
if
(
count
===
promises
.
length
)
{
resolve
(
true
);
}
}
function
rejecter
(
err
)
{
reject
(
err
);
cancel
();
}
for
(
i
=
0
;
i
<
promises
.
length
;
i
+=
1
)
{
promises
[
i
].
then
(
resolver
,
rejecter
);
}
},
cancel
);
};
/**
* Comparison operator, test if one of the sub queries matches the
* item value
*
* @method OR
* @param {Object} item The item to match
* @return {Boolean} true if one match, false otherwise
*/
ComplexQuery
.
prototype
.
OR
=
function
(
item
)
{
var
j
,
promises
=
[];
for
(
j
=
0
;
j
<
this
.
query_list
.
length
;
j
+=
1
)
{
promises
.
push
(
this
.
query_list
[
j
].
match
(
item
));
}
function
cancel
()
{
var
i
;
for
(
i
=
0
;
i
<
promises
.
length
;
i
+=
1
)
{
if
(
typeof
promises
.
cancel
===
'
function
'
)
{
promises
.
cancel
();
}
}
}
return
new
RSVP
.
Promise
(
function
(
resolve
,
reject
)
{
var
i
,
count
=
0
;
function
resolver
(
value
)
{
if
(
value
)
{
resolve
(
true
);
}
count
+=
1
;
if
(
count
===
promises
.
length
)
{
resolve
(
false
);
}
}
function
rejecter
(
err
)
{
reject
(
err
);
cancel
();
}
for
(
i
=
0
;
i
<
promises
.
length
;
i
+=
1
)
{
promises
[
i
].
then
(
resolver
,
rejecter
);
}
},
cancel
);
};
/**
* 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
sequence
([
function
()
{
return
this
.
query_list
[
0
].
match
(
item
);
},
function
(
answer
)
{
return
!
answer
;
}]);
};
query_class_dict
.
complex
=
ComplexQuery
;
exports
.
ComplexQuery
=
ComplexQuery
;
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global exports, ComplexQuery, SimpleQuery, Query, parseStringToObject,
query_class_dict */
/**
* Provides static methods to create Query object
*
* @class QueryFactory
*/
function
QueryFactory
()
{
return
;
}
/**
* Creates Query object from a search text string or a serialized version
* of a Query.
*
* @method create
* @static
* @param {Object,String} object The search text or the serialized version
* of a Query
* @return {Query} A Query object
*/
QueryFactory
.
create
=
function
(
object
,
key_schema
)
{
if
(
object
===
""
)
{
return
new
Query
();
}
if
(
typeof
object
===
"
string
"
)
{
object
=
parseStringToObject
(
object
);
}
if
(
typeof
(
object
||
{}).
type
===
"
string
"
&&
query_class_dict
[
object
.
type
])
{
return
new
query_class_dict
[
object
.
type
](
object
,
key_schema
);
}
throw
new
TypeError
(
"
QueryFactory.create():
"
+
"
Argument 1 is not a search text or a parsable object
"
);
};
exports
.
QueryFactory
=
QueryFactory
;
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query, exports */
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
(
"
"
);
}
if
(
query
.
type
===
"
simple
"
)
{
return
(
query
.
key
?
query
.
key
+
"
:
"
:
""
)
+
(
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, exports,
searchTextToRegExp, RSVP */
var
checkKeySchema
=
function
(
key_schema
)
{
var
prop
;
if
(
key_schema
!==
undefined
)
{
if
(
typeof
key_schema
!==
'
object
'
)
{
throw
new
TypeError
(
"
SimpleQuery().create():
"
+
"
key_schema is not of type 'object'
"
);
}
// key_set is mandatory
if
(
key_schema
.
key_set
===
undefined
)
{
throw
new
TypeError
(
"
SimpleQuery().create():
"
+
"
key_schema has no 'key_set' property
"
);
}
for
(
prop
in
key_schema
)
{
if
(
key_schema
.
hasOwnProperty
(
prop
))
{
switch
(
prop
)
{
case
'
key_set
'
:
case
'
cast_lookup
'
:
case
'
match_lookup
'
:
break
;
default
:
throw
new
TypeError
(
"
SimpleQuery().create():
"
+
"
key_schema has unknown property '
"
+
prop
+
"
'
"
);
}
}
}
}
};
/**
* The SimpleQuery inherits from Query, and compares one metadata value
*
* @class SimpleQuery
* @extends Query
* @param {Object} [spec={}] The specifications
* @param {String} [spec.operator="="] The compare method to use
* @param {String} spec.key The metadata key
* @param {String} spec.value The value of the metadata to compare
*/
function
SimpleQuery
(
spec
,
key_schema
)
{
Query
.
call
(
this
);
checkKeySchema
(
key_schema
);
this
.
_key_schema
=
key_schema
||
{};
/**
* Operator to use to compare object values
*
* @attribute operator
* @type String
* @optional
*/
this
.
operator
=
spec
.
operator
;
/**
* Key of the object which refers to the value to compare
*
* @attribute key
* @type String
*/
this
.
key
=
spec
.
key
;
/**
* Value is used to do the comparison with the object value
*
* @attribute value
* @type String
*/
this
.
value
=
spec
.
value
;
}
inherits
(
SimpleQuery
,
Query
);
SimpleQuery
.
prototype
.
type
=
"
simple
"
;
var
checkKey
=
function
(
key
)
{
var
prop
;
if
(
key
.
read_from
===
undefined
)
{
throw
new
TypeError
(
"
Custom key is missing the read_from property
"
);
}
for
(
prop
in
key
)
{
if
(
key
.
hasOwnProperty
(
prop
))
{
switch
(
prop
)
{
case
'
read_from
'
:
case
'
cast_to
'
:
case
'
equal_match
'
:
break
;
default
:
throw
new
TypeError
(
"
Custom key has unknown property '
"
+
prop
+
"
'
"
);
}
}
}
};
/**
* #crossLink "Query/match:method"
*/
SimpleQuery
.
prototype
.
match
=
function
(
item
)
{
var
object_value
=
null
,
equal_match
=
null
,
cast_to
=
null
,
matchMethod
=
null
,
operator
=
this
.
operator
,
value
=
null
,
key
=
this
.
key
;
/*jslint regexp: true */
if
(
!
(
/^
(?:
!
?
=|<=
?
|>=
?)
$/i
.
test
(
operator
)))
{
// `operator` is not correct, we have to change it to "like" or "="
if
(
/%/
.
test
(
this
.
value
))
{
// `value` contains a non escaped `%`
operator
=
"
like
"
;
}
else
{
// `value` does not contain non escaped `%`
operator
=
"
=
"
;
}
}
matchMethod
=
this
[
operator
];
if
(
this
.
_key_schema
.
key_set
&&
this
.
_key_schema
.
key_set
[
key
]
!==
undefined
)
{
key
=
this
.
_key_schema
.
key_set
[
key
];
}
if
(
typeof
key
===
'
object
'
)
{
checkKey
(
key
);
object_value
=
item
[
key
.
read_from
];
equal_match
=
key
.
equal_match
;
// equal_match can be a string
if
(
typeof
equal_match
===
'
string
'
)
{
// XXX raise error if equal_match not in match_lookup
equal_match
=
this
.
_key_schema
.
match_lookup
[
equal_match
];
}
// equal_match overrides the default '=' operator
if
(
equal_match
!==
undefined
)
{
matchMethod
=
(
operator
===
"
=
"
||
operator
===
"
like
"
?
equal_match
:
matchMethod
);
}
value
=
this
.
value
;
cast_to
=
key
.
cast_to
;
if
(
cast_to
)
{
// cast_to can be a string
if
(
typeof
cast_to
===
'
string
'
)
{
// XXX raise error if cast_to not in cast_lookup
cast_to
=
this
.
_key_schema
.
cast_lookup
[
cast_to
];
}
try
{
value
=
cast_to
(
value
);
}
catch
(
e
)
{
value
=
undefined
;
}
try
{
object_value
=
cast_to
(
object_value
);
}
catch
(
e
)
{
object_value
=
undefined
;
}
}
}
else
{
object_value
=
item
[
key
];
value
=
this
.
value
;
}
if
(
object_value
===
undefined
||
value
===
undefined
)
{
return
RSVP
.
resolve
(
false
);
}
return
matchMethod
(
object_value
,
value
);
};
/**
* #crossLink "Query/toString:method"
*/
SimpleQuery
.
prototype
.
toString
=
function
()
{
return
(
this
.
key
?
this
.
key
+
"
:
"
:
""
)
+
(
this
.
operator
?
"
"
+
this
.
operator
:
""
)
+
'
"
'
+
this
.
value
+
'
"
'
;
};
/**
* #crossLink "Query/serialized:method"
*/
SimpleQuery
.
prototype
.
serialized
=
function
()
{
var
object
=
{
"
type
"
:
"
simple
"
,
"
key
"
:
this
.
key
,
"
value
"
:
this
.
value
};
if
(
this
.
operator
!==
undefined
)
{
object
.
operator
=
this
.
operator
;
}
return
object
;
};
SimpleQuery
.
prototype
.
toJSON
=
SimpleQuery
.
prototype
.
serialized
;
/**
* Comparison operator, test if this query value matches the item value
*
* @method =
* @param {String} object_value The value to compare
* @param {String} comparison_value The comparison value
* @return {Boolean} true if match, false otherwise
*/
SimpleQuery
.
prototype
[
"
=
"
]
=
function
(
object_value
,
comparison_value
)
{
var
value
,
i
;
if
(
!
Array
.
isArray
(
object_value
))
{
object_value
=
[
object_value
];
}
for
(
i
=
0
;
i
<
object_value
.
length
;
i
+=
1
)
{
value
=
object_value
[
i
];
if
(
typeof
value
===
'
object
'
&&
value
.
hasOwnProperty
(
'
content
'
))
{
value
=
value
.
content
;
}
if
(
typeof
value
.
cmp
===
"
function
"
)
{
return
RSVP
.
resolve
(
value
.
cmp
(
comparison_value
)
===
0
);
}
if
(
searchTextToRegExp
(
comparison_value
.
toString
(),
false
).
test
(
value
.
toString
())
)
{
return
RSVP
.
resolve
(
true
);
}
}
return
RSVP
.
resolve
(
false
);
};
/**
* Comparison operator, test if this query value matches the item value
*
* @method like
* @param {String} object_value The value to compare
* @param {String} comparison_value The comparison value
* @return {Boolean} true if match, false otherwise
*/
SimpleQuery
.
prototype
.
like
=
function
(
object_value
,
comparison_value
)
{
var
value
,
i
;
if
(
!
Array
.
isArray
(
object_value
))
{
object_value
=
[
object_value
];
}
for
(
i
=
0
;
i
<
object_value
.
length
;
i
+=
1
)
{
value
=
object_value
[
i
];
if
(
typeof
value
===
'
object
'
&&
value
.
hasOwnProperty
(
'
content
'
))
{
value
=
value
.
content
;
}
if
(
typeof
value
.
cmp
===
"
function
"
)
{
return
RSVP
.
resolve
(
value
.
cmp
(
comparison_value
)
===
0
);
}
if
(
searchTextToRegExp
(
comparison_value
.
toString
()).
test
(
value
.
toString
())
)
{
return
RSVP
.
resolve
(
true
);
}
}
return
RSVP
.
resolve
(
false
);
};
/**
* Comparison operator, test if this query value does not match the item value
*
* @method !=
* @param {String} object_value The value to compare
* @param {String} comparison_value The comparison value
* @return {Boolean} true if not match, false otherwise
*/
SimpleQuery
.
prototype
[
"
!=
"
]
=
function
(
object_value
,
comparison_value
)
{
var
value
,
i
;
if
(
!
Array
.
isArray
(
object_value
))
{
object_value
=
[
object_value
];
}
for
(
i
=
0
;
i
<
object_value
.
length
;
i
+=
1
)
{
value
=
object_value
[
i
];
if
(
typeof
value
===
'
object
'
&&
value
.
hasOwnProperty
(
'
content
'
))
{
value
=
value
.
content
;
}
if
(
typeof
value
.
cmp
===
"
function
"
)
{
return
RSVP
.
resolve
(
value
.
cmp
(
comparison_value
)
!==
0
);
}
if
(
searchTextToRegExp
(
comparison_value
.
toString
(),
false
).
test
(
value
.
toString
())
)
{
return
RSVP
.
resolve
(
false
);
}
}
return
RSVP
.
resolve
(
true
);
};
/**
* Comparison operator, test if this query value is 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 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 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
;
exports
.
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
)
{
if
(
way
===
'
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
1
;
}
if
(
b
[
i
]
===
undefined
)
{
return
-
1
;
}
if
(
a
[
i
]
>
b
[
i
])
{
return
-
1
;
}
if
(
a
[
i
]
<
b
[
i
])
{
return
1
;
}
}
return
0
;
};
}
if
(
way
===
'
ascending
'
)
{
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
-
1
;
}
if
(
b
[
i
]
===
undefined
)
{
return
1
;
}
if
(
a
[
i
]
>
b
[
i
])
{
return
1
;
}
if
(
a
[
i
]
<
b
[
i
])
{
return
-
1
;
}
}
return
0
;
};
}
throw
new
TypeError
(
"
Query.sortFunction():
"
+
"
Argument 2 must be 'ascending' or 'descending'
"
);
}
/**
* 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
list
;
}
Query
.
select
=
select
;
/**
* Sort a list of items, according to keys and directions. If `clone` is true,
* then the method will act on a cloned list.
*
* @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
*/
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'
"
);
}
if
(
clone
)
{
list
=
deepClone
(
list
);
}
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
;
}
Query
.
sortOn
=
sortOn
;
/**
* Limit a list of items, according to index and length. If `clone` is true,
* then the method will act on a cloned list.
*
* @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
*/
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'
"
);
}
if
(
clone
)
{
list
=
deepClone
(
list
);
}
list
.
splice
(
0
,
limit_option
[
0
]);
if
(
limit_option
[
1
])
{
list
.
splice
(
limit_option
[
1
]);
}
return
list
;
}
Query
.
limit
=
limit
;
/**
* 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
.
searchTextToRegExp
=
searchTextToRegExp
;
/**
* sequence(thens): Promise
*
* Executes a sequence of *then* callbacks. It acts like
* `smth().then(callback).then(callback)...`. The first callback is called with
* no parameter.
*
* Elements of `thens` array can be a function or an array contaning at most
* three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
*
* When `cancel()` is executed, each then promises are cancelled at the same
* time.
*
* @param {Array} thens An array of *then* callbacks
* @return {Promise} A new promise
*/
function
sequence
(
thens
)
{
var
promises
=
[];
return
new
RSVP
.
Promise
(
function
(
resolve
,
reject
,
notify
)
{
var
i
;
promises
[
0
]
=
new
RSVP
.
Promise
(
function
(
resolve
)
{
resolve
();
});
for
(
i
=
0
;
i
<
thens
.
length
;
i
+=
1
)
{
if
(
Array
.
isArray
(
thens
[
i
]))
{
promises
[
i
+
1
]
=
promises
[
i
].
then
(
thens
[
i
][
0
],
thens
[
i
][
1
],
thens
[
i
][
2
]);
}
else
{
promises
[
i
+
1
]
=
promises
[
i
].
then
(
thens
[
i
]);
}
}
promises
[
i
].
then
(
resolve
,
reject
,
notify
);
},
function
()
{
var
i
;
for
(
i
=
0
;
i
<
promises
.
length
;
i
+=
1
)
{
promises
[
i
].
cancel
();
}
});
}
}));
}));
ext/libs/jio/localstorage.js
View file @
a1e93301
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
*/
*/
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */
/*global jIO, localStorage, setTimeout,
complex_queries, window, define
,
/*global jIO, localStorage, setTimeout,
window, define, Blob, Uint8Array
,
exports, require */
exports, require */
/**
/**
...
@@ -54,15 +54,14 @@
...
@@ -54,15 +54,14 @@
return
define
(
dependencies
,
module
);
return
define
(
dependencies
,
module
);
}
}
if
(
typeof
exports
===
'
object
'
)
{
if
(
typeof
exports
===
'
object
'
)
{
return
module
(
exports
,
require
(
'
jio
'
)
,
require
(
'
complex_queries
'
)
);
return
module
(
exports
,
require
(
'
jio
'
));
}
}
window
.
local_storage
=
{};
window
.
local_storage
=
{};
module
(
window
.
local_storage
,
jIO
,
complex_queries
);
module
(
window
.
local_storage
,
jIO
);
}([
}([
'
exports
'
,
'
exports
'
,
'
jio
'
,
'
jio
'
'
complex_queries
'
],
function
(
exports
,
jIO
)
{
],
function
(
exports
,
jIO
,
complex_queries
)
{
"
use strict
"
;
"
use strict
"
;
/**
/**
...
@@ -124,9 +123,8 @@
...
@@ -124,9 +123,8 @@
* @constructor
* @constructor
*/
*/
function
LocalStorage
(
spec
)
{
function
LocalStorage
(
spec
)
{
if
(
typeof
spec
.
username
!==
'
string
'
&&
!
spec
.
username
)
{
if
(
typeof
spec
.
username
!==
'
string
'
||
spec
.
username
===
''
)
{
throw
new
TypeError
(
"
LocalStorage 'username' must be a string
"
+
throw
new
TypeError
(
"
LocalStorage 'username' must be a non-empty string
"
);
"
which contains more than one character.
"
);
}
}
this
.
_localpath
=
'
jio/localstorage/
'
+
spec
.
username
+
'
/
'
+
(
this
.
_localpath
=
'
jio/localstorage/
'
+
spec
.
username
+
'
/
'
+
(
spec
.
application_name
===
null
||
spec
.
application_name
===
spec
.
application_name
===
null
||
spec
.
application_name
===
...
@@ -142,6 +140,7 @@
...
@@ -142,6 +140,7 @@
this
.
_database
=
localStorage
;
this
.
_database
=
localStorage
;
this
.
_storage
=
localstorage
;
this
.
_storage
=
localstorage
;
this
.
_mode
=
"
localStorage
"
;
this
.
_mode
=
"
localStorage
"
;
this
.
_key_schema
=
spec
.
key_schema
;
break
;
break
;
}
}
}
}
...
@@ -215,7 +214,7 @@
...
@@ -215,7 +214,7 @@
* @param {Object} options The command options
* @param {Object} options The command options
*/
*/
LocalStorage
.
prototype
.
putAttachment
=
function
(
command
,
param
)
{
LocalStorage
.
prototype
.
putAttachment
=
function
(
command
,
param
)
{
var
that
=
this
,
doc
,
status
=
"
ok
"
;
var
that
=
this
,
doc
,
status
=
"
created
"
;
doc
=
this
.
_storage
.
getItem
(
this
.
_localpath
+
"
/
"
+
param
.
_id
);
doc
=
this
.
_storage
.
getItem
(
this
.
_localpath
+
"
/
"
+
param
.
_id
);
if
(
doc
===
null
)
{
if
(
doc
===
null
)
{
// the document does not exist
// the document does not exist
...
@@ -231,7 +230,7 @@
...
@@ -231,7 +230,7 @@
jIO
.
util
.
readBlobAsBinaryString
(
param
.
_blob
).
then
(
function
(
e
)
{
jIO
.
util
.
readBlobAsBinaryString
(
param
.
_blob
).
then
(
function
(
e
)
{
doc
.
_attachments
=
doc
.
_attachments
||
{};
doc
.
_attachments
=
doc
.
_attachments
||
{};
if
(
doc
.
_attachments
[
param
.
_attachment
])
{
if
(
doc
.
_attachments
[
param
.
_attachment
])
{
status
=
"
created
"
;
status
=
"
no_content
"
;
}
}
doc
.
_attachments
[
param
.
_attachment
]
=
{
doc
.
_attachments
[
param
.
_attachment
]
=
{
"
content_type
"
:
param
.
_blob
.
type
,
"
content_type
"
:
param
.
_blob
.
type
,
...
@@ -287,7 +286,7 @@
...
@@ -287,7 +286,7 @@
* @param {Object} options The command options
* @param {Object} options The command options
*/
*/
LocalStorage
.
prototype
.
getAttachment
=
function
(
command
,
param
)
{
LocalStorage
.
prototype
.
getAttachment
=
function
(
command
,
param
)
{
var
doc
;
var
doc
,
i
,
uint8array
,
binarystring
;
doc
=
this
.
_storage
.
getItem
(
this
.
_localpath
+
"
/
"
+
param
.
_id
);
doc
=
this
.
_storage
.
getItem
(
this
.
_localpath
+
"
/
"
+
param
.
_id
);
if
(
doc
===
null
)
{
if
(
doc
===
null
)
{
return
command
.
error
(
return
command
.
error
(
...
@@ -306,12 +305,22 @@
...
@@ -306,12 +305,22 @@
);
);
}
}
// Storing data twice in binarystring and in uint8array (in memory)
// is not a problem here because localStorage <= 5MB
binarystring
=
this
.
_storage
.
getItem
(
this
.
_localpath
+
"
/
"
+
param
.
_id
+
"
/
"
+
param
.
_attachment
)
||
""
;
uint8array
=
new
Uint8Array
(
binarystring
.
length
);
for
(
i
=
0
;
i
<
binarystring
.
length
;
i
+=
1
)
{
uint8array
[
i
]
=
binarystring
.
charCodeAt
(
i
);
// mask `& 0xFF` not necessary
}
uint8array
=
new
Blob
([
uint8array
],
{
"
type
"
:
doc
.
_attachments
[
param
.
_attachment
].
content_type
||
""
});
command
.
success
({
command
.
success
({
"
data
"
:
this
.
_storage
.
getItem
(
"
data
"
:
uint8array
,
this
.
_localpath
+
"
/
"
+
param
.
_id
+
"
digest
"
:
doc
.
_attachments
[
param
.
_attachment
].
digest
"
/
"
+
param
.
_attachment
)
||
""
,
"
content_type
"
:
doc
.
_attachments
[
param
.
_attachment
].
content_type
||
""
});
});
};
};
...
@@ -362,7 +371,7 @@
...
@@ -362,7 +371,7 @@
*/
*/
LocalStorage
.
prototype
.
removeAttachment
=
function
(
command
,
param
)
{
LocalStorage
.
prototype
.
removeAttachment
=
function
(
command
,
param
)
{
var
doc
=
this
.
_storage
.
getItem
(
this
.
_localpath
+
"
/
"
+
param
.
_id
);
var
doc
=
this
.
_storage
.
getItem
(
this
.
_localpath
+
"
/
"
+
param
.
_id
);
if
(
typeof
doc
!==
'
object
'
)
{
if
(
typeof
doc
!==
'
object
'
||
doc
===
null
)
{
return
command
.
error
(
return
command
.
error
(
"
not_found
"
,
"
not_found
"
,
"
missing document
"
,
"
missing document
"
,
...
@@ -402,7 +411,7 @@
...
@@ -402,7 +411,7 @@
rows
=
[];
rows
=
[];
document_list
=
[];
document_list
=
[];
path_re
=
new
RegExp
(
path_re
=
new
RegExp
(
"
^
"
+
complex_queries
.
stringEscapeRegexpCharacters
(
this
.
_localpath
)
+
"
^
"
+
jIO
.
Query
.
stringEscapeRegexpCharacters
(
this
.
_localpath
)
+
"
/[^/]+$
"
"
/[^/]+$
"
);
);
if
(
options
.
query
===
undefined
&&
options
.
sort_on
===
undefined
&&
if
(
options
.
query
===
undefined
&&
options
.
sort_on
===
undefined
&&
...
@@ -425,7 +434,7 @@
...
@@ -425,7 +434,7 @@
}
}
command
.
success
({
"
data
"
:
{
"
rows
"
:
rows
,
"
total_rows
"
:
rows
.
length
}});
command
.
success
({
"
data
"
:
{
"
rows
"
:
rows
,
"
total_rows
"
:
rows
.
length
}});
}
else
{
}
else
{
// create
complex
query object from returned results
// create
jio
query object from returned results
for
(
i
in
this
.
_database
)
{
for
(
i
in
this
.
_database
)
{
if
(
this
.
_database
.
hasOwnProperty
(
i
))
{
if
(
this
.
_database
.
hasOwnProperty
(
i
))
{
if
(
path_re
.
test
(
i
))
{
if
(
path_re
.
test
(
i
))
{
...
@@ -444,27 +453,29 @@
...
@@ -444,27 +453,29 @@
document_object
[
meta
.
_id
]
=
meta
;
document_object
[
meta
.
_id
]
=
meta
;
});
});
}
}
complex_queries
.
QueryFactory
.
create
(
options
.
query
||
""
).
jIO
.
QueryFactory
.
create
(
options
.
query
||
""
,
exec
(
document_list
,
options
);
this
.
_key_schema
).
document_list
=
document_list
.
map
(
function
(
value
)
{
exec
(
document_list
,
options
).
then
(
function
()
{
var
o
=
{
document_list
=
document_list
.
map
(
function
(
value
)
{
"
id
"
:
value
.
_id
,
var
o
=
{
"
key
"
:
value
.
_id
"
id
"
:
value
.
_id
,
};
"
key
"
:
value
.
_id
if
(
options
.
include_docs
===
true
)
{
};
o
.
doc
=
document_object
[
value
.
_id
];
if
(
options
.
include_docs
===
true
)
{
delete
document_object
[
value
.
_id
];
o
.
doc
=
document_object
[
value
.
_id
];
}
delete
document_object
[
value
.
_id
];
if
(
delete_id
)
{
}
delete
value
.
_id
;
if
(
delete_id
)
{
}
delete
value
.
_id
;
o
.
value
=
value
;
}
return
o
;
o
.
value
=
value
;
});
return
o
;
command
.
success
({
"
data
"
:
{
});
"
total_rows
"
:
document_list
.
length
,
command
.
success
({
"
data
"
:
{
"
rows
"
:
document_list
"
total_rows
"
:
document_list
.
length
,
}});
"
rows
"
:
document_list
}});
});
}
}
};
};
...
@@ -502,13 +513,13 @@
...
@@ -502,13 +513,13 @@
*/
*/
LocalStorage
.
prototype
.
genericRepair
=
function
(
command
,
param
,
repair
)
{
LocalStorage
.
prototype
.
genericRepair
=
function
(
command
,
param
,
repair
)
{
var
that
=
this
,
result
;
var
that
=
this
,
final_
result
;
function
referenceAttachment
(
param
,
attachment
)
{
function
referenceAttachment
(
param
,
attachment
)
{
if
(
jIO
.
util
.
indexOf
(
param
.
referenced_attachments
,
attachment
)
!==
-
1
)
{
if
(
param
.
referenced_attachments
.
indexOf
(
attachment
)
!==
-
1
)
{
return
;
return
;
}
}
var
i
=
jIO
.
util
.
indexOf
(
param
.
unreferenced_attachments
,
attachment
);
var
i
=
param
.
unreferenced_attachments
.
indexOf
(
attachment
);
if
(
i
!==
-
1
)
{
if
(
i
!==
-
1
)
{
param
.
unreferenced_attachments
.
splice
(
i
,
1
);
param
.
unreferenced_attachments
.
splice
(
i
,
1
);
}
}
...
@@ -517,10 +528,10 @@
...
@@ -517,10 +528,10 @@
}
}
function
attachmentFound
(
param
,
attachment
)
{
function
attachmentFound
(
param
,
attachment
)
{
if
(
jIO
.
util
.
indexOf
(
param
.
referenced_attachments
,
attachment
)
!==
-
1
)
{
if
(
param
.
referenced_attachments
.
indexOf
(
attachment
)
!==
-
1
)
{
return
;
return
;
}
}
if
(
jIO
.
util
.
indexOf
(
param
.
unreferenced_attachments
,
attachment
)
!==
-
1
)
{
if
(
param
.
unreferenced_attachments
.
indexOf
(
attachment
)
!==
-
1
)
{
return
;
return
;
}
}
param
.
unreferenced_attachments
[
param
.
unreferenced_attachments
.
length
]
=
param
.
unreferenced_attachments
[
param
.
unreferenced_attachments
.
length
]
=
...
@@ -535,7 +546,7 @@
...
@@ -535,7 +546,7 @@
}
}
// check document type
// check document type
if
(
typeof
doc
!==
'
object
'
)
{
if
(
typeof
doc
!==
'
object
'
||
doc
===
null
)
{
// wrong document
// wrong document
if
(
!
repair
)
{
if
(
!
repair
)
{
return
{
"
error
"
:
true
,
"
answers
"
:
[
return
{
"
error
"
:
true
,
"
answers
"
:
[
...
@@ -656,14 +667,14 @@
...
@@ -656,14 +667,14 @@
param
.
referenced_attachments
=
[];
param
.
referenced_attachments
=
[];
param
.
unreferenced_attachments
=
[];
param
.
unreferenced_attachments
=
[];
if
(
typeof
param
.
_id
===
'
string
'
)
{
if
(
typeof
param
.
_id
===
'
string
'
)
{
result
=
repairOne
(
param
,
repair
)
||
{};
final_
result
=
repairOne
(
param
,
repair
)
||
{};
}
else
{
}
else
{
result
=
repairAll
(
param
,
repair
)
||
{};
final_
result
=
repairAll
(
param
,
repair
)
||
{};
}
}
if
(
result
.
error
)
{
if
(
final_
result
.
error
)
{
return
command
.
error
.
apply
(
command
,
result
.
answers
||
[]);
return
command
.
error
.
apply
(
command
,
final_
result
.
answers
||
[]);
}
}
command
.
success
.
apply
(
command
,
result
.
answers
||
[]);
command
.
success
.
apply
(
command
,
final_
result
.
answers
||
[]);
};
};
jIO
.
addStorage
(
'
local
'
,
LocalStorage
);
jIO
.
addStorage
(
'
local
'
,
LocalStorage
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment