Skip to content

Commit

Permalink
UIPQB-76 Build queries that search for null / empty values
Browse files Browse the repository at this point in the history
  • Loading branch information
vashjs committed Feb 20, 2024
1 parent 4330ef4 commit abc9a57
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { SelectionContainer } from '../SelectionContainer/SelectionContainer';
import { ISO_FORMAT } from '../../helpers/timeUtils';

import css from '../../../QueryBuilder.css';
import { staticBooleanOptions } from '../../helpers/selectOptions';

export const DataTypeInput = ({
availableValues,
Expand All @@ -28,6 +29,7 @@ export const DataTypeInput = ({
}) => {
const isInRelatedOperator = [OPERATORS.IN, OPERATORS.NOT_IN].includes(operator);
const isEqualRelatedOperator = [OPERATORS.EQUAL, OPERATORS.NOT_EQUAL].includes(operator);
const isEmptyRelatedOperator = [OPERATORS.EMPTY].includes(operator);
const hasSourceOrValues = source || availableValues;

const textControl = ({ testId, type = 'text', textClass }) => {
Expand Down Expand Up @@ -147,6 +149,18 @@ export const DataTypeInput = ({
: selectControl({ testId: 'data-input-select-arrayType' });
};

if (isEmptyRelatedOperator) {
return (
<SelectionContainer
component={Select}
testId="data-input-select-booleanType"
availableValues={staticBooleanOptions}
onChange={(e) => onChange(e.target.value, index, COLUMN_KEYS.VALUE)}
{...rest}
/>
);
}

switch (dataType) {
case DATA_TYPES.StringType:
return stringTypeControls();
Expand Down
4 changes: 4 additions & 0 deletions src/QueryBuilder/QueryBuilder/helpers/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ const getQueryOperand = (item) => {
case OPERATORS.NOT_CONTAINS:
queryOperand = { [field]: { $not_contains: value } };
break;
case OPERATORS.EMPTY:
queryOperand = { [field]: { $empty: value } };
break;
default:
break;
}
Expand Down Expand Up @@ -137,6 +140,7 @@ const getSourceFields = (field) => ({
$nin: (value) => ({ operator: OPERATORS.NOT_IN, value }),
$contains: (value) => ({ operator: OPERATORS.CONTAINS, value }),
$not_contains: (value) => ({ operator: OPERATORS.NOT_CONTAINS, value }),
$empty: (value) => ({ operator: OPERATORS.EMPTY, value }),
$regex: (value) => {
return value?.includes('^')
? { operator: OPERATORS.STARTS_WITH, value: value?.replace(cleanerRegex, '') }
Expand Down
8 changes: 8 additions & 0 deletions src/QueryBuilder/QueryBuilder/helpers/query.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ describe('mongoQueryToSource()', () => {
operator: { options: expect.any(Array), current: OPERATORS.NOT_CONTAINS },
value: { current: 'value' },
},
{
boolean: { options: booleanOptions, current: '$and' },
field: { options: fieldOptions, current: 'department_ids', dataType: DATA_TYPES.ArrayType },
operator: { options: expect.any(Array), current: OPERATORS.EMPTY },
value: { current: 'value' },
},
];

const initialValues = {
Expand All @@ -114,6 +120,7 @@ describe('mongoQueryToSource()', () => {
{ user_id: { $in: ['value', 'value2'] } },
{ department_names: { $contains: 'value' } },
{ department_names: { $not_contains: 'value' } },
{ department_ids: { $empty: 'value' } },
],
};

Expand Down Expand Up @@ -180,6 +187,7 @@ describe('mongoQueryToSource()', () => {
{ user_id: { $in: ['value', 'value2'] } },
{ department_names: { $contains: 'value' } },
{ department_names: { $not_contains: 'value' } },
{ department_ids: { $empty: 'value' } },
],
};

Expand Down
12 changes: 12 additions & 0 deletions src/QueryBuilder/QueryBuilder/helpers/selectOptions.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FormattedMessage } from 'react-intl';
import { DATA_TYPES } from '../../../constants/dataTypes';
import { BOOLEAN_OPERATORS, OPERATORS } from '../../../constants/operators';
import { COLUMN_KEYS } from '../../../constants/columnKeys';
Expand All @@ -18,19 +19,22 @@ const baseLogicalOperators = () => [
{ label: OPERATORS.NOT_EQUAL, value: OPERATORS.NOT_EQUAL },
{ label: OPERATORS.GREATER_THAN, value: OPERATORS.GREATER_THAN },
{ label: OPERATORS.LESS_THAN, value: OPERATORS.LESS_THAN },
{ label: OPERATORS.EMPTY, value: OPERATORS.EMPTY },
];

const extendedLogicalOperators = () => [
...baseLogicalOperators(),
{ label: OPERATORS.GREATER_THAN_OR_EQUAL, value: OPERATORS.GREATER_THAN_OR_EQUAL },
{ label: OPERATORS.LESS_THAN_OR_EQUAL, value: OPERATORS.LESS_THAN_OR_EQUAL },
{ label: OPERATORS.EMPTY, value: OPERATORS.EMPTY },
];

const UUIDOperators = () => [
{ label: OPERATORS.EQUAL, value: OPERATORS.EQUAL },
{ label: OPERATORS.NOT_EQUAL, value: OPERATORS.NOT_EQUAL },
{ label: OPERATORS.IN, value: OPERATORS.IN },
{ label: OPERATORS.NOT_IN, value: OPERATORS.NOT_IN },
{ label: OPERATORS.EMPTY, value: OPERATORS.EMPTY },
];

const ArrayOperators = () => [
Expand All @@ -40,6 +44,7 @@ const ArrayOperators = () => [
{ label: OPERATORS.NOT_IN, value: OPERATORS.NOT_IN },
{ label: OPERATORS.CONTAINS, value: OPERATORS.CONTAINS },
{ label: OPERATORS.NOT_CONTAINS, value: OPERATORS.NOT_CONTAINS },
{ label: OPERATORS.EMPTY, value: OPERATORS.EMPTY },
];

export const getFilledValues = (options) => {
Expand All @@ -57,12 +62,14 @@ const stringOperators = (hasSourceOrValues) => {
{ label: OPERATORS.CONTAINS, value: OPERATORS.CONTAINS },
{ label: OPERATORS.STARTS_WITH, value: OPERATORS.STARTS_WITH },
]),
{ label: OPERATORS.EMPTY, value: OPERATORS.EMPTY },
];
};

const booleanOperators = () => [
{ label: OPERATORS.EQUAL, value: OPERATORS.EQUAL },
{ label: OPERATORS.NOT_EQUAL, value: OPERATORS.NOT_EQUAL },
{ label: OPERATORS.EMPTY, value: OPERATORS.EMPTY },
];

export const getOperatorOptions = ({
Expand Down Expand Up @@ -122,6 +129,11 @@ export const booleanOptions = [
{ label: 'AND', value: BOOLEAN_OPERATORS.AND },
];

export const staticBooleanOptions = [
{ label: <FormattedMessage id="ui-plugin-query-builder.columns.true" />, value: true },
{ label: <FormattedMessage id="ui-plugin-query-builder.options.false" />, value: false },
];

export const sourceTemplate = (fieldOptions = []) => ({
[COLUMN_KEYS.BOOLEAN]: { options: booleanOptions, current: '' },
[COLUMN_KEYS.FIELD]: { options: fieldOptions, current: '' },
Expand Down
1 change: 1 addition & 0 deletions src/constants/operators.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const OPERATORS = {
CONTAINS: 'contains',
NOT_CONTAINS: 'not contains',
STARTS_WITH: 'starts with',
EMPTY: ' is null/empty',
};

export const BOOLEAN_OPERATORS = {
Expand Down
8 changes: 8 additions & 0 deletions test/jest/data/entityType.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,14 @@ export const entityType = {
'labelAlias': 'Department names',
'visibleByDefault': true,
},
{
'name': 'department_ids',
'dataType': {
'dataType': 'arrayType',
},
'labelAlias': 'Department Ids',
'visibleByDefault': true,
},
],
'defaultSort': [
{
Expand Down
3 changes: 3 additions & 0 deletions translations/ui-plugin-query-builder/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"columns.value": "Value",
"columns.action": "Actions",

"options.true": "True",
"options.false": "False",

"control.info.separateValues": "Separate multiple values with a comma.",
"control.selection.placeholder": "Select field",
"control.value.placeholder": "Select value",
Expand Down

0 comments on commit abc9a57

Please sign in to comment.