UNPKG

cheetah-framework

Version:

Cheetah Framework JS used in all our applications

272 lines (238 loc) 7.33 kB
import { Model } from '@cheetah/models/Model' import { BUILDER_OPERATORS, RELATION_TYPE_OPERATORS, OPERATORS } from '@cheetah/components/QueryBuilder/utils/QueryBuilderHelper' class Criterion extends Model { constructor (data) { super(data) this.initBuilderFields() } /** * Default values should consist of every possible key:value * a criterion can have to ensure the reactivity is * properly bound the every props. * * @return {object} */ get defaultValue () { return { /** * Aggregation field key */ relation: null, /** * Criterion field key */ field: null, /** * Operator for simple criterion OR operator for criteria * if the current criterion is an aggregator. */ operator: null, /** * Comparison value for simple criterion */ value: null, /** * Comparison column for criterion comparing * two fields */ value_of: null, /** * List of aggregation conditions.Support only * a single condition. */ aggregators: [{ /** * Aggregation type */ aggregation: null, /** * Aggregated column */ field: null, /** * Aggregation operator for comparison */ operator: null, /** * Aggregation value to compare */ value: null }], /** * Array of criteria for an aggregation. Expect to receive an array * of criteria that will be converted to: * * { * operator: {string}, * criteria: {Criteria[]|Criterion[]} * } */ criteria: [], /** * Props used by the query builder */ builder_operator: null, builder_compare_field: false, is_editing: false } } /** * Set the criterion builder operator which will, in the end, * define the criterion structure. * * @param value */ setBuilderOperatorAttribute (value) { this._attributes.builder_operator = value } /** * Guesses builder fields based on received data. This function should be * called only on new criterion instances. * * Should basically be reverting what this.toJSON() does. */ initBuilderFields () { if (this.value_of) { this.builder_compare_field = true } if (_.includes([BUILDER_OPERATORS.LIKE, BUILDER_OPERATORS.NOT_LIKE], this.operator)) { /** * Fail safely check if the value ends or starts * with "%" before doing an operation. */ if (_.startsWith(this.value, '%') && _.endsWith(this.value, '%')) { this.value = this.value.slice(1, -1) } } if (this.aggregators[0].aggregation) { this.builder_operator = this.aggregators[0].aggregation this.field = this.relation this.criteria = _.pick(this, ['operator', 'criteria']) } else if (_.includes(_.values(RELATION_TYPE_OPERATORS), this.type)) { this.field = this.relation this.builder_operator = BUILDER_OPERATORS[this.type === RELATION_TYPE_OPERATORS.WITH ? 'EXIST' : 'NOT_EXIST'] this.criteria = _.pick(this, ['operator', 'criteria']) } else { this.criteria = { operator: OPERATORS.AND, criteria: [] } this.builder_operator = this.operator } } get isAggregation () { return _.includes(_.pick(BUILDER_OPERATORS, ['COUNT', 'MAX', 'MIN']), this.builder_operator) } get hasSubQuery () { return this.isAggregation || _.includes(_.pick(BUILDER_OPERATORS, ['EXIST', 'NOT_EXIST']), this.builder_operator) } /** * is_editing getter used by the query builder. * Use native getter to prevent sending it in the payload * * @return {boolean} */ get is_editing () { return this._attributes.is_editing } /** * is_editing setter used by the query builder. * * @param {boolean} value */ set is_editing (value) { this._attributes.is_editing = value } /** * Parse builder_* fields to get the true * criterion structure. * * @return {object} */ toJSON () { const baseObject = _.cloneDeep(super.toJSON()) if (this.isAggregation) { if (baseObject.builder_operator === BUILDER_OPERATORS.COUNT) { _.unset(baseObject, 'aggregators.0.field') } _.set(baseObject, 'aggregators.0.aggregation', baseObject.builder_operator) return { relation: baseObject.field, ..._.pick(baseObject, ['aggregators']), ...baseObject.criteria } } if (_.includes(_.pick(BUILDER_OPERATORS, ['EXIST', 'NOT_EXIST']), baseObject.builder_operator)) { switch (baseObject.builder_operator) { case BUILDER_OPERATORS.EXIST: _.set(baseObject, 'type', RELATION_TYPE_OPERATORS.WITH) _.set(baseObject, 'value', BUILDER_OPERATORS.EXIST) break case BUILDER_OPERATORS.NOT_EXIST: _.set(baseObject, 'type', RELATION_TYPE_OPERATORS.WITHOUT) _.set(baseObject, 'value', BUILDER_OPERATORS.EXIST) break } return { relation: baseObject.field, ..._.pick(baseObject, ['type', 'value']), ...baseObject.criteria } } if (baseObject.builder_compare_field) { return { operator: baseObject.builder_operator, ..._.pick(baseObject, ['field', 'value_of', 'builder_compare_field']) } } if (_.includes([BUILDER_OPERATORS.LIKE, BUILDER_OPERATORS.NOT_LIKE], baseObject.builder_operator)) { return { operator: baseObject.builder_operator, field: baseObject.field, value: `%${baseObject.value}%` } } return { operator: baseObject.builder_operator, ..._.pick(baseObject, ['field', 'value']) } } static getOperatorsFor (fieldType) { let operators = [] switch (fieldType) { case 'string' : operators = ['EQUAL', 'NOT_EQUAL', 'LIKE', 'NOT_LIKE', 'IN', 'NOT_IN', 'NULL', 'NOT_NULL'] break case 'boolean' : operators = ['EQUAL', 'NOT_EQUAL', 'NULL', 'NOT_NULL'] break case 'enum' : operators = ['EQUAL', 'NOT_EQUAL', 'IN', 'NOT_IN', 'NULL', 'NOT_NULL'] break case 'relation' : operators = ['EXIST', 'NOT_EXIST', 'COUNT'] break case 'integer' : case 'float' : case 'decimal' : operators = ['EQUAL', 'NOT_EQUAL', 'LT', 'LTE', 'GT', 'GTE', 'IN', 'NOT_IN', 'NULL', 'NOT_NULL'] break case 'date': case 'datetime': operators = ['EQUAL', 'NOT_EQUAL', 'LT', 'LTE', 'GT', 'GTE', 'NULL', 'NOT_NULL'] break case 'model' : operators = ['EQUAL', 'NOT_EQUAL', 'IN', 'NOT_IN', 'NULL', 'NOT_NULL'] break case 'aggregation': operators = ['EQUAL', 'NOT_EQUAL', 'LT', 'LTE', 'GT', 'GTE'] break } return _.values(_.pick(Criterion.BUILDER_OPERATORS, operators)) } } Criterion.BUILDER_OPERATORS = BUILDER_OPERATORS Criterion.RELATION_TYPE_OPERATORS = RELATION_TYPE_OPERATORS Criterion.allBuilderOperators = _.values(BUILDER_OPERATORS) Criterion.arrayableBuilderOperators = _.values(_.pick(BUILDER_OPERATORS, ['IN', 'NOT_IN'])) export default Criterion