Skip to content

Commit

Permalink
UIPQB-64 Query builder can’t edit single condition queries without AN…
Browse files Browse the repository at this point in the history
…D wrapper
  • Loading branch information
vashjs committed Nov 7, 2023
1 parent 36af5da commit 9879fa4
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 66 deletions.
111 changes: 57 additions & 54 deletions src/QueryBuilder/QueryBuilder/helpers/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,63 +48,66 @@ export const getTransformedValue = (val) => {
return val;
};

const escapeRegex = (value) => {
const escapedValue = value.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');

return `${escapedValue}`;
};

const getQueryOperand = (item) => {
let queryOperand = {};

const field = item.field.current;
const operator = item.operator.current;
const value = item.value.current;

switch (operator) {
case OPERATORS.EQUAL:
queryOperand = { [field]: { $eq: value } };
break;
case OPERATORS.NOT_EQUAL:
queryOperand = { [field]: { $ne: value } };
break;
case OPERATORS.GREATER_THAN:
queryOperand = { [field]: { $gt: value } };
break;
case OPERATORS.GREATER_THAN_OR_EQUAL:
queryOperand = { [field]: { $gte: value } };
break;
case OPERATORS.LESS_THAN:
queryOperand = { [field]: { $lt: value } };
break;
case OPERATORS.LESS_THAN_OR_EQUAL:
queryOperand = { [field]: { $lte: value } };
break;
case OPERATORS.IN:
queryOperand = { [field]: { $in: getTransformedValue(value) } };
break;
case OPERATORS.NOT_IN:
queryOperand = { [field]: { $nin: getTransformedValue(value) } };
break;
case OPERATORS.STARTS_WITH:
queryOperand = { [field]: { $regex: new RegExp(`^${escapeRegex(value)}`).source } };
break;
case OPERATORS.CONTAINS:
queryOperand = { [field]: { $regex: new RegExp(escapeRegex(value)).source } };
break;
default:
break;
}

return queryOperand;
};

export const sourceToMongoQuery = (source) => {
const query = {};
const andQuery = [];
let queryItem = {};

const escapeRegex = (value) => {
const escapedValue = value.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');

return `${escapedValue}`;
};

source.forEach((item) => {
const field = item.field.current;
const operator = item.operator.current;
const value = item.value.current;

switch (operator) {
case OPERATORS.EQUAL:
queryItem = { [field]: { $eq: value } };
break;
case OPERATORS.NOT_EQUAL:
queryItem = { [field]: { $ne: value } };
break;
case OPERATORS.GREATER_THAN:
queryItem = { [field]: { $gt: value } };
break;
case OPERATORS.GREATER_THAN_OR_EQUAL:
queryItem = { [field]: { $gte: value } };
break;
case OPERATORS.LESS_THAN:
queryItem = { [field]: { $lt: value } };
break;
case OPERATORS.LESS_THAN_OR_EQUAL:
queryItem = { [field]: { $lte: value } };
break;
case OPERATORS.IN:
queryItem = { [field]: { $in: getTransformedValue(value) } };
break;
case OPERATORS.NOT_IN:
queryItem = { [field]: { $nin: getTransformedValue(value) } };
break;
case OPERATORS.STARTS_WITH:
queryItem = { [field]: { $regex: new RegExp(`^${escapeRegex(value)}`).source } };
break;
case OPERATORS.CONTAINS:
queryItem = { [field]: { $regex: new RegExp(escapeRegex(value)).source } };
break;
default:
break;
}

andQuery.push(queryItem);
});
const boolOperator = source.find(item => Boolean(item.boolean.current))?.boolean.current;
const queryOperands = source.map(getQueryOperand);

// temporary solution, because we should support only $and operator
if (andQuery.length) {
query.$and = andQuery;
if (boolOperator) {
query[boolOperator] = queryOperands;
} else {
return queryOperands[0];
}

return query;
Expand Down
20 changes: 10 additions & 10 deletions src/QueryBuilder/QueryBuilder/helpers/query.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,62 +17,62 @@ describe('mongoQueryToSource()', () => {

const source = [
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'user_first_name' },
operator: { options: expect.any(Array), current: OPERATORS.EQUAL },
value: { current: 'value' },
},
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'user_first_name' },
operator: { options: expect.any(Array), current: OPERATORS.NOT_EQUAL },
value: { current: 'value' },
},
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'user_last_name' },
operator: { options: expect.any(Array), current: OPERATORS.GREATER_THAN },
value: { current: 'value' },
},
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'user_last_name' },
operator: { options: expect.any(Array), current: OPERATORS.LESS_THAN },
value: { current: 10 },
},
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'user_last_name' },
operator: { options: expect.any(Array), current: OPERATORS.GREATER_THAN_OR_EQUAL },
value: { current: 'value' },
},

{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'languages' },
operator: { options: expect.any(Array), current: OPERATORS.IN },
value: { current: [{ label: 'value', value: 'value' }, { label: 'value2', value: 'value2' }] },
},
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'user_full_name' },
operator: { options: expect.any(Array), current: OPERATORS.CONTAINS },
value: { current: 'abc' },
},
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'languages' },
operator: { options: expect.any(Array), current: OPERATORS.NOT_IN },
value: { current: [{ label: 'value', value: 'value' }, { label: 'value2', value: 'value2' }] },
},
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'user_id' },
operator: { options: expect.any(Array), current: OPERATORS.NOT_IN },
value: { current: 'value, value2' },
},
{
boolean: { options: booleanOptions, current: 'AND' },
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'user_id' },
operator: { options: expect.any(Array), current: OPERATORS.IN },
value: { current: 'value, value2' },
Expand Down
2 changes: 1 addition & 1 deletion src/QueryBuilder/QueryBuilder/helpers/selectOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export const getFieldOptions = (options) => {
};

export const booleanOptions = [
{ label: 'AND', value: 'AND' },
{ label: 'AND', value: OPERATORS.AND },
];

export const sourceTemplate = (fieldOptions = []) => ({
Expand Down
2 changes: 1 addition & 1 deletion src/constants/operators.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ export const OPERATORS = {
NOT_IN: 'not in',
CONTAINS: 'contains',
STARTS_WITH: 'starts with',
AND: 'AND',
AND: '$and',
};

0 comments on commit 9879fa4

Please sign in to comment.