diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index dc8ce60263..5e7daef53e 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -238,14 +238,21 @@ const Query = (props: Props) => { setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) + const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) if (prevCursorChar === FIELD_START_SYMBOL) { helpWidgetRef.current.isOpen = false - return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) + return asSuggestionsRef( + getFieldsSuggestions( + attributesRef.current, + range, + false, + foundArg?.stopArg?.name === DefinedArgumentName.query + ), + false + ) } const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset } - const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) - switch (foundArg?.stopArg?.name) { case DefinedArgumentName.index: { return handleIndexSuggestions(command, foundArg, prevArgs.length, currentOffsetArg, range) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts index 43b8d04254..9e08a40283 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts @@ -1,4 +1,9 @@ -import { getGeneralSuggestions, isIndexComplete } from 'uiSrc/pages/search/components/query/utils' +import { + addFieldAttribute, + getFieldsSuggestions, + getGeneralSuggestions, + isIndexComplete +} from 'uiSrc/pages/search/components/query/utils' import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' import { addOwnTokenToArgs, buildSuggestion, findCurrentArgument } from 'uiSrc/pages/search/utils' import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' @@ -122,3 +127,47 @@ describe('isIndexComplete', () => { expect(testResult).toEqual(result) }) }) + +const mockedFields = [ + { identifier: 'name', attribute: 'name', type: 'TEXT', WEIGHT: '1', SORTABLE: true, NOSTEM: true }, + { identifier: 'description', attribute: 'description', type: 'TEXT', WEIGHT: '1' }, + { identifier: 'class', attribute: 'class', type: 'TAG', SEPARATOR: ',' }, + { identifier: 'type', attribute: 'type', type: 'TAG', SEPARATOR: ';' }, + { identifier: 'address_city', attribute: 'city', type: 'TAG', SEPARATOR: ',' }, + { identifier: 'address_street', attribute: 'address', type: 'TEXT', WEIGHT: '1', NOSTEM: true }, + { identifier: 'students', attribute: 'students', type: 'NUMERIC', SORTABLE: true }, + { identifier: 'location', attribute: 'location', type: 'GEO' } +] + +const getFieldsSuggestionsTests = [ + [ + [mockedFields, {}], + mockedFields.map((field) => ({ + detail: field.attribute, + insertText: field.attribute, + insertTextRules: 4, + kind: undefined, + label: field.attribute, + range: expect.any(Object), + })) + ], + [ + [mockedFields, {}, false, true], + mockedFields.map((field) => ({ + detail: field.attribute, + insertText: addFieldAttribute(field.attribute, field.type), + insertTextRules: 4, + kind: undefined, + label: field.attribute, + range: expect.any(Object), + })) + ], +] + +describe('getFieldsSuggestions', () => { + it.each(getFieldsSuggestionsTests)('should properly return value for %s', (input, result) => { + const testResult = getFieldsSuggestions(...input) + + expect(testResult).toEqual(result) + }) +}) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 3c3def04ed..6519932cbc 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -35,9 +35,28 @@ export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: mon } }) -export const getFieldsSuggestions = (fields: any[], range: monaco.IRange, spaceAfter = false) => - fields.map(({ attribute }) => { - const insertText = attribute.trim() ? attribute : `"${attribute}"` +export const addFieldAttribute = (attribute: string, type: string) => { + switch (type) { + case 'TAG': return `${attribute}:{\${1:tag}}` + case 'TEXT': return `${attribute}:(\${1:term})` + case 'NUMERIC': return `${attribute}:[\${1:range}]` + case 'GEO': return `${attribute}:[\${1:lon} \${2:lat} \${3:radius} \${4:unit}]` + case 'VECTOR': return `${attribute} \${1:vector}` + default: return attribute + } +} + +export const getFieldsSuggestions = ( + fields: any[], + range: monaco.IRange, + spaceAfter = false, + withType = false +) => + fields.map((field) => { + const { attribute, type } = field + const attibuteText = attribute.trim() ? attribute : `\\"${attribute}\\"` + const insertText = withType ? addFieldAttribute(attibuteText, type) : attibuteText + return { label: attribute || ' ', kind: monacoEditor.languages.CompletionItemKind.Reference,