/**
* This singleton provides the ability to convert the parse tree of an `Ext.data.Query`
* (that is, its `ast` or Abstract Syntax Tree) into a `String`.
* @private
* @since 6.7.0
*/
Ext.define('Ext.data.query.Stringifier', {
stringify: function(node) {
var me = this,
t = typeof node,
type = node.type,
operatorTypeMap = me.operatorTypeMap,
priority = me.getPriority(node),
stringifiers = me.stringifiers,
op, stringifier;
if (t === 'boolean' || t === 'number') {
return String(node);
}
if (t === 'string') {
return Ext.JSON.encode(node);
}
stringifier = stringifiers[type];
if (!stringifier && type in operatorTypeMap) {
op = operatorTypeMap[type];
stringifier = stringifiers[op[0]];
op = op[2] || op[1];
}
if (typeof stringifier === 'string') {
stringifier = stringifiers[stringifier];
}
return stringifier(me, node, priority, op);
},
privates: {
getPriority: function(node) {
var symbols = this.symbols,
operatorTypeMap = this.operatorTypeMap,
type = node.type,
ret = 1e9,
op;
if (type === 'between') {
ret = 0;
ret = symbols[type].priority;
}
else if (type === 'and' || type === 'or' || type === 'in' || type === 'like') {
ret = symbols[type].priority;
}
else if (type in operatorTypeMap) {
op = operatorTypeMap[type];
ret = symbols[op[1]].priority;
}
return ret;
},
stringifiers: {
and: 'or',
or: function(me, node, priority) {
var op = (node.type === 'or') ? ' or ' : ' and ',
s = '',
on = node.on,
i, lhs, parenL;
for (i = 0; i < on.length; ++i) {
if (s) {
s += op;
}
lhs = on[i];
parenL = me.getPriority(lhs) < priority;
lhs = me.stringify(lhs);
if (parenL) {
lhs = '(' + lhs + ')';
}
s += lhs;
}
return s;
},
between: function(me, node, priority) {
var on = node.on,
lhs = on[0],
parenL = me.getPriority(lhs) < priority,
i, parenR, rhs, s;
lhs = me.stringify(lhs);
if (parenL) {
lhs = '(' + lhs + ')';
}
s = lhs + ' between ';
priority = me.symbols.and.priority;
for (i = 0; i < 2; ++i) {
if (i) {
s += ' and ';
}
rhs = on[i + 1];
parenR = i
? (rhs.type !== 'id' && !Ext.isPrimitive(rhs))
: (me.getPriority(rhs) < priority);
rhs = me.stringify(rhs);
if (parenR) {
rhs = '(' + rhs + ')';
}
s += rhs;
}
return s;
},
binary: function(me, node, priority, op) {
var on = node.on,
lhs = on[0],
rhs = on[1],
parenL = me.getPriority(lhs) < priority,
parenR = me.getPriority(rhs) < priority;
lhs = me.stringify(lhs);
rhs = me.stringify(rhs);
if (parenL) {
lhs = '(' + lhs + ')';
}
if (parenR) {
rhs = '(' + rhs + ')';
}
return lhs + ' ' + op + ' ' + rhs;
},
fn: function(me, node) {
return node.fn + '(' + me.stringifyArray(node.args) + ')';
},
id: function(me, node) {
return node.value;
},
list: function(me, node) {
return '(' + me.stringifyArray(node.value) + ')';
},
regexp: function(me, node) {
return '/' + node.value + '/' + (node.flags || '');
},
string: function(me, node) {
return Ext.JSON.encode(node.value);
},
unary: function(me, node, priority, op) {
var on = node.on,
rhs = me.stringify(on),
t = on.type;
if (t !== 'fn' && t !== 'id' && t !== 'unary') {
rhs = '(' + rhs + ')';
}
return op + rhs;
}
},
stringifyArray: function(array) {
var s = '',
i, expr;
for (i = 0; i < array.length; ++i) {
if (s) {
s += ', ';
}
expr = array[i];
expr = this.stringify(expr);
s += expr;
}
return s;
}
}
});