mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 21:15:56 +08:00
feat: lowercase operators support in the where clause is updated (#3657)
* feat: lowercase operators suuport in the where clause is updated * feat: options is now updated * chore: log message is updated * chore: auto completed is updated * chore: tagRegex is updated * feat: update regex to math operators and text operators * chore: operator is updated * chore: options is updated --------- Co-authored-by: Yunus A M <myounis.ar@live.com>
This commit is contained in:
parent
587034f573
commit
0e04b779a9
@ -278,23 +278,35 @@ export const QUERY_BUILDER_SEARCH_VALUES = {
|
||||
|
||||
export const OPERATORS = {
|
||||
IN: 'IN',
|
||||
in: 'in',
|
||||
NIN: 'NOT_IN',
|
||||
not_in: 'not_in',
|
||||
LIKE: 'LIKE',
|
||||
like: 'like',
|
||||
NLIKE: 'NOT_LIKE',
|
||||
not_like: 'not_like',
|
||||
REGEX: 'REGEX',
|
||||
regex: 'regex',
|
||||
NREGEX: 'NOT_REGEX',
|
||||
nregex: 'not_regex',
|
||||
'=': '=',
|
||||
'!=': '!=',
|
||||
EXISTS: 'EXISTS',
|
||||
exists: 'exists',
|
||||
NOT_EXISTS: 'NOT_EXISTS',
|
||||
not_exists: 'not_exists',
|
||||
CONTAINS: 'CONTAINS',
|
||||
contains: 'contains',
|
||||
NOT_CONTAINS: 'NOT_CONTAINS',
|
||||
not_contains: 'not_contains',
|
||||
'>=': '>=',
|
||||
'>': '>',
|
||||
'<=': '<=',
|
||||
'<': '<',
|
||||
HAS: 'HAS',
|
||||
has: 'has',
|
||||
NHAS: 'NHAS',
|
||||
nhas: 'nhas',
|
||||
};
|
||||
|
||||
export const QUERY_BUILDER_OPERATORS_BY_TYPES = {
|
||||
|
@ -3,25 +3,42 @@ import { parse } from 'papaparse';
|
||||
|
||||
import { orderByValueDelimiter } from '../OrderByFilter/utils';
|
||||
|
||||
const operators = /=|!=|>=|>|<=|<$/;
|
||||
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
export const tagRegexp = /^\s*(.*?)\s*(IN|NOT_IN|LIKE|NOT_LIKE|REGEX|NOT_REGEX|=|!=|EXISTS|NOT_EXISTS|CONTAINS|NOT_CONTAINS|>=|>|<=|<|HAS|NHAS)\s*(.*)$/g;
|
||||
export const tagRegexpV1 = /^\s*(.*?)\s*(IN|in|NOT_IN|nin|LIKE|like|NOT_LIKE|nlike|REGEX|regex|NOT_REGEX|nregex|=|!=|EXISTS|exists|NOT_EXISTS|nexists|CONTAINS|contains|NOT_CONTAINS|ncontains|>=|>|<=|<|HAS|has|NHAS|nhas)\s*(.*)$/g;
|
||||
|
||||
export const tagRegexpV2 = /^\s*(.+?)\s+(IN|in|NOT_IN|nin|LIKE|like|NOT_LIKE|nlike|REGEX|regex|NOT_REGEX|nregex|EXISTS|exists|NOT_EXISTS|nexists|CONTAINS|contains|NOT_CONTAINS|ncontains|HAS|has|NHAS|nhas|=|!=|>=|>|<=|<)\s*(.*)$/g;
|
||||
|
||||
export function isInNInOperator(value: string): boolean {
|
||||
return value === OPERATORS.IN || value === OPERATORS.NIN;
|
||||
}
|
||||
|
||||
function endsWithOperator(inputString: string): boolean {
|
||||
return operators.test(inputString);
|
||||
}
|
||||
|
||||
interface ITagToken {
|
||||
tagKey: string;
|
||||
tagOperator: string;
|
||||
tagValue: string[];
|
||||
}
|
||||
|
||||
export function getMatchRegex(str: string): RegExp {
|
||||
if (endsWithOperator(str)) {
|
||||
return tagRegexpV1;
|
||||
}
|
||||
|
||||
return tagRegexpV2;
|
||||
}
|
||||
|
||||
export function getTagToken(tag: string): ITagToken {
|
||||
const matches = tag?.matchAll(tagRegexp);
|
||||
const matches = tag?.matchAll(getMatchRegex(tag));
|
||||
const [match] = matches ? Array.from(matches) : [];
|
||||
|
||||
if (match) {
|
||||
const [, matchTagKey, matchTagOperator, matchTagValue] = match;
|
||||
|
||||
return {
|
||||
tagKey: matchTagKey,
|
||||
tagOperator: matchTagOperator,
|
||||
@ -51,65 +68,11 @@ export function getRemovePrefixFromKey(tag: string): string {
|
||||
}
|
||||
|
||||
export function getOperatorValue(op: string): string {
|
||||
switch (op) {
|
||||
case 'IN':
|
||||
return 'in';
|
||||
case 'NOT_IN':
|
||||
return 'nin';
|
||||
case OPERATORS.REGEX:
|
||||
return 'regex';
|
||||
case OPERATORS.HAS:
|
||||
return 'has';
|
||||
case OPERATORS.NHAS:
|
||||
return 'nhas';
|
||||
case OPERATORS.NREGEX:
|
||||
return 'nregex';
|
||||
case 'LIKE':
|
||||
return 'like';
|
||||
case 'NOT_LIKE':
|
||||
return 'nlike';
|
||||
case 'EXISTS':
|
||||
return 'exists';
|
||||
case 'NOT_EXISTS':
|
||||
return 'nexists';
|
||||
case 'CONTAINS':
|
||||
return 'contains';
|
||||
case 'NOT_CONTAINS':
|
||||
return 'ncontains';
|
||||
default:
|
||||
return op;
|
||||
}
|
||||
return op.toLocaleLowerCase();
|
||||
}
|
||||
|
||||
export function getOperatorFromValue(op: string): string {
|
||||
switch (op) {
|
||||
case 'in':
|
||||
return 'IN';
|
||||
case 'nin':
|
||||
return 'NOT_IN';
|
||||
case 'like':
|
||||
return 'LIKE';
|
||||
case 'regex':
|
||||
return OPERATORS.REGEX;
|
||||
case 'nregex':
|
||||
return OPERATORS.NREGEX;
|
||||
case 'nlike':
|
||||
return 'NOT_LIKE';
|
||||
case 'exists':
|
||||
return 'EXISTS';
|
||||
case 'nexists':
|
||||
return 'NOT_EXISTS';
|
||||
case 'contains':
|
||||
return 'CONTAINS';
|
||||
case 'ncontains':
|
||||
return 'NOT_CONTAINS';
|
||||
case 'has':
|
||||
return OPERATORS.HAS;
|
||||
case 'nhas':
|
||||
return OPERATORS.NHAS;
|
||||
default:
|
||||
return op;
|
||||
}
|
||||
return op.toLocaleLowerCase();
|
||||
}
|
||||
|
||||
export function replaceStringWithMaxLength(
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {
|
||||
getMatchRegex,
|
||||
getRemovePrefixFromKey,
|
||||
getTagToken,
|
||||
replaceStringWithMaxLength,
|
||||
tagRegexp,
|
||||
} from 'container/QueryBuilder/filters/QueryBuilderSearch/utils';
|
||||
import { Option } from 'container/QueryBuilder/type';
|
||||
import { parse } from 'papaparse';
|
||||
@ -33,7 +33,7 @@ export const useAutoComplete = (
|
||||
searchKey,
|
||||
);
|
||||
|
||||
const [key, operator, result] = useSetCurrentKeyAndOperator(searchValue, keys);
|
||||
const [key, operator, result] = useSetCurrentKeyAndOperator(searchValue);
|
||||
|
||||
const handleSearch = (value: string): void => {
|
||||
const prefixFreeValue = getRemovePrefixFromKey(getTagToken(value).tagKey);
|
||||
@ -58,7 +58,7 @@ export const useAutoComplete = (
|
||||
(value: string): void => {
|
||||
if (isMulti) {
|
||||
setSearchValue((prev: string) => {
|
||||
const matches = prev?.matchAll(tagRegexp);
|
||||
const matches = prev?.matchAll(getMatchRegex(prev));
|
||||
const [match] = matches ? Array.from(matches) : [];
|
||||
const [, , , matchTagValue] = match;
|
||||
const data = parse(matchTagValue).data.flat();
|
||||
|
@ -8,23 +8,35 @@ export type OperatorType =
|
||||
|
||||
const operatorTypeMapper: Record<string, OperatorType> = {
|
||||
[OPERATORS.IN]: 'MULTIPLY_VALUE',
|
||||
[OPERATORS.in]: 'MULTIPLY_VALUE',
|
||||
[OPERATORS.NIN]: 'MULTIPLY_VALUE',
|
||||
[OPERATORS.not_in]: 'MULTIPLY_VALUE',
|
||||
[OPERATORS.EXISTS]: 'NON_VALUE',
|
||||
[OPERATORS.exists]: 'NON_VALUE',
|
||||
[OPERATORS.NOT_EXISTS]: 'NON_VALUE',
|
||||
[OPERATORS.not_exists]: 'NON_VALUE',
|
||||
[OPERATORS['<=']]: 'SINGLE_VALUE',
|
||||
[OPERATORS['<']]: 'SINGLE_VALUE',
|
||||
[OPERATORS['>=']]: 'SINGLE_VALUE',
|
||||
[OPERATORS['>']]: 'SINGLE_VALUE',
|
||||
[OPERATORS.LIKE]: 'SINGLE_VALUE',
|
||||
[OPERATORS.like]: 'SINGLE_VALUE',
|
||||
[OPERATORS.NLIKE]: 'SINGLE_VALUE',
|
||||
[OPERATORS.not_like]: 'SINGLE_VALUE',
|
||||
[OPERATORS.REGEX]: 'SINGLE_VALUE',
|
||||
[OPERATORS.regex]: 'SINGLE_VALUE',
|
||||
[OPERATORS.NREGEX]: 'SINGLE_VALUE',
|
||||
[OPERATORS.nregex]: 'SINGLE_VALUE',
|
||||
[OPERATORS.CONTAINS]: 'SINGLE_VALUE',
|
||||
[OPERATORS.contains]: 'SINGLE_VALUE',
|
||||
[OPERATORS.NOT_CONTAINS]: 'SINGLE_VALUE',
|
||||
[OPERATORS.not_contains]: 'SINGLE_VALUE',
|
||||
[OPERATORS['=']]: 'SINGLE_VALUE',
|
||||
[OPERATORS['!=']]: 'SINGLE_VALUE',
|
||||
[OPERATORS.HAS]: 'SINGLE_VALUE',
|
||||
[OPERATORS.has]: 'SINGLE_VALUE',
|
||||
[OPERATORS.NHAS]: 'SINGLE_VALUE',
|
||||
[OPERATORS.nhas]: 'SINGLE_VALUE',
|
||||
};
|
||||
|
||||
export const useOperatorType = (operator: string): OperatorType =>
|
||||
|
@ -81,8 +81,8 @@ export const useOptions = (
|
||||
const getKeyOperatorOptions = useCallback(
|
||||
(key: string) => {
|
||||
const operatorsOptions = operators?.map((operator) => ({
|
||||
value: `${key} ${operator} `,
|
||||
label: `${key} ${operator} `,
|
||||
value: `${key} ${operator.toLowerCase()} `,
|
||||
label: `${key} ${operator.toLowerCase()} `,
|
||||
}));
|
||||
if (whereClauseConfig) {
|
||||
return [
|
||||
@ -148,22 +148,24 @@ export const useOptions = (
|
||||
|
||||
return useMemo(
|
||||
() =>
|
||||
(
|
||||
options.filter(
|
||||
options
|
||||
.filter(
|
||||
(option, index, self) =>
|
||||
index ===
|
||||
self.findIndex(
|
||||
(o) => o.label === option.label && o.value === option.value, // to remove duplicate & empty options from list
|
||||
) && option.value !== '',
|
||||
) || []
|
||||
).map((option) => {
|
||||
)
|
||||
.map((option) => {
|
||||
const { tagValue } = getTagToken(searchValue);
|
||||
if (isMulti) {
|
||||
return {
|
||||
...option,
|
||||
selected: tagValue
|
||||
.filter((i) => i.trim().replace(/^\s+/, '') === option.value)
|
||||
.includes(option.value),
|
||||
selected: Array.isArray(tagValue)
|
||||
? tagValue
|
||||
?.filter((i) => i.trim().replace(/^\s+/, '') === option.value)
|
||||
?.includes(option.value)
|
||||
: String(tagValue).includes(option.value),
|
||||
};
|
||||
}
|
||||
return option;
|
||||
|
@ -1,32 +1,24 @@
|
||||
import {
|
||||
getRemovePrefixFromKey,
|
||||
getTagToken,
|
||||
} from 'container/QueryBuilder/filters/QueryBuilderSearch/utils';
|
||||
import { useMemo } from 'react';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { getTagToken } from 'container/QueryBuilder/filters/QueryBuilderSearch/utils';
|
||||
import { useMemo, useRef } from 'react';
|
||||
|
||||
type ICurrentKeyAndOperator = [string, string, string[]];
|
||||
|
||||
export const useSetCurrentKeyAndOperator = (
|
||||
value: string,
|
||||
keys: BaseAutocompleteData[],
|
||||
): ICurrentKeyAndOperator => {
|
||||
const [key, operator, result] = useMemo(() => {
|
||||
let key = '';
|
||||
let operator = '';
|
||||
const keyRef = useRef<string>('');
|
||||
const operatorRef = useRef<string>('');
|
||||
|
||||
const result = useMemo(() => {
|
||||
let result: string[] = [];
|
||||
const { tagKey, tagOperator, tagValue } = getTagToken(value);
|
||||
const isSuggestKey = keys?.some(
|
||||
(el) => el?.key === getRemovePrefixFromKey(tagKey),
|
||||
);
|
||||
if (isSuggestKey || keys.length === 0) {
|
||||
key = tagKey || '';
|
||||
operator = tagOperator || '';
|
||||
|
||||
keyRef.current = tagKey || '';
|
||||
operatorRef.current = tagOperator || '';
|
||||
result = tagValue || [];
|
||||
}
|
||||
|
||||
return [key, operator, result];
|
||||
}, [value, keys]);
|
||||
return result;
|
||||
}, [value]);
|
||||
|
||||
return [key, operator, result];
|
||||
return [keyRef.current, operatorRef.current, result];
|
||||
};
|
||||
|
@ -74,6 +74,7 @@ export const useTag = (
|
||||
const handleAddTag = useCallback(
|
||||
(value: string): void => {
|
||||
const { tagKey } = getTagToken(value);
|
||||
|
||||
const [key, id] = tagKey.split('-');
|
||||
|
||||
if (id === 'custom') {
|
||||
|
Loading…
x
Reference in New Issue
Block a user