/** * This mixin provides the ability to convert the parse tree of an `Ext.data.Query` * (that is, its `ast` or Abstract Syntax Tree) into an array of serialized * {@link Ext.util.Filter filters}. This singleton can also produce an `ast` from such an * array. * @private * @since 6.7.0 */Ext.define('Ext.data.query.Converter', { /** * Returns the array of serialized {@link Ext.util.Filter filter} objects equivalent * to this query if possible. If this query is empty, this method returns `null`. If * the query cannot be converted without loss into a filters array, this method will * return `undefined`. * @return {Object[]} */ getFilters: function() { var me = this, ast = me.ast, exprToFilter = me.exprToFilter, operatorTypeMap = me.operatorTypeMap, fn = me.fn, on = ast && ast.on, expr, filter, filters, i, ident, n, op, ret, value, xlat; if (ast) { // We cache the filters on the fn since they are valid for as long as the // fn is valid. if (fn.hasOwnProperty('$filters')) { ret = fn.$filters; } else { if (ast.type === 'and' && on) { filters = []; for (i = 0, n = on.length; i < n; ++i) { expr = on[i]; ident = expr.on; if (!ident || ident.length !== 2) { break; } value = ident[1]; ident = ident[0]; if (ident.type !== 'id') { break; } if (!(xlat = exprToFilter[expr.type])) { op = operatorTypeMap[expr.type]; if (!op || !(xlat = exprToFilter[op[0]])) { break; } } if (!(filter = xlat(expr, ident.value, value, op))) { break; } filters.push(filter); } if (i === n) { ret = filters; } } fn.$filters = ret; } } else { ret = null; } return ret; }, setFilters: function(filters) { var me = this, ast = null, n = filters && filters.length, expr, filter, i, op, xlat; if (n) { ast = { type: 'and', on: [] }; for (i = 0; i < n; ++i) { filter = filters[i]; if (!(xlat = me.filterToExpr[op = filter.operator])) { expr = { type: me.getOperatorType(op), on: [ { type: 'id', value: filter.property }, filter.value ] }; } else { expr = xlat(filter); } ast.on.push(expr); } } me.ast = ast; me.refresh(); }, privates: { exprToFilter: { binary: function(expr, ident, value, info) { return Ext.isPrimitive(value) && { property: ident, operator: info[1], value: value }; }, 'in': function(expr, ident, value) { var i = 0, list = value.value; if (value.type === 'list' && Ext.isArray(list)) { for (i = list.length; i-- > 0; /* empty */) { if (!Ext.isPrimitive(list[i])) { break; } } } return (i < 0) && { property: ident, operator: 'in', value: list }; }, like: function(expr, ident, value) { if (value.type === 'regexp') { return { property: ident, operator: '/=', value: value.value }; } return (value.type === 'string') && { property: ident, operator: 'like', value: value.value }; } }, filterToExpr: { '/=': function(filter) { return { type: 'like', on: [{ type: 'id', value: filter.property }, { type: 'regexp', value: filter.value }] }; }, 'in': function(filter) { return { type: 'in', on: [{ type: 'id', value: filter.property }, { type: 'list', value: filter.value }] }; }, like: function(filter) { return { type: 'like', on: [{ type: 'id', value: filter.property }, { type: 'string', value: filter.value, // Escape regex characters which may be present in filter string re: Ext.String.escapeRegex(filter.value), flags: 'i' }] }; } } }});