diff --git a/examples/esql_validation_example/public/app.tsx b/examples/esql_validation_example/public/app.tsx index f785b31de3ba2..62b6405678d15 100644 --- a/examples/esql_validation_example/public/app.tsx +++ b/examples/esql_validation_example/public/app.tsx @@ -23,7 +23,7 @@ import { import type { CoreStart } from '@kbn/core/public'; -import { ESQLCallbacks, validateQuery } from '@kbn/esql-validation-autocomplete'; +import { ESQLCallbacks, ESQLRealField, validateQuery } from '@kbn/esql-validation-autocomplete'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; import type { StartDependencies } from './plugin'; import { CodeSnippet } from './code_snippet'; @@ -52,10 +52,11 @@ export const App = (props: { core: CoreStart; plugins: StartDependencies }) => { ['index1', 'anotherIndex', 'dataStream'].map((name) => ({ name, hidden: false })) : undefined, getFieldsFor: callbacksEnabled.fields - ? async () => [ - { name: 'numberField', type: 'number' }, - { name: 'stringField', type: 'string' }, - ] + ? async () => + [ + { name: 'doubleField', type: 'double' }, + { name: 'keywordField', type: 'keyword' }, + ] as ESQLRealField[] : undefined, getPolicies: callbacksEnabled.policies ? async () => [ diff --git a/packages/kbn-esql-validation-autocomplete/scripts/generate_function_validation_tests.ts b/packages/kbn-esql-validation-autocomplete/scripts/generate_function_validation_tests.ts index d3497115aecf9..f431d3cddb2c5 100644 --- a/packages/kbn-esql-validation-autocomplete/scripts/generate_function_validation_tests.ts +++ b/packages/kbn-esql-validation-autocomplete/scripts/generate_function_validation_tests.ts @@ -18,16 +18,17 @@ import { getFunctionSignatures } from '../src/definitions/helpers'; import { timeUnits } from '../src/definitions/literals'; import { nonNullable } from '../src/shared/helpers'; import { - SupportedFieldType, + SupportedDataType, FunctionDefinition, - supportedFieldTypes, - isSupportedFieldType, + dataTypes, + isSupportedDataType, + fieldTypes, } from '../src/definitions/types'; import { FUNCTION_DESCRIBE_BLOCK_NAME } from '../src/validation/function_describe_block_name'; import { getMaxMinNumberOfParams } from '../src/validation/helpers'; import { ESQL_NUMBER_TYPES, isNumericType, isStringType } from '../src/shared/esql_types'; -export const fieldNameFromType = (type: SupportedFieldType) => `${camelCase(type)}Field`; +export const fieldNameFromType = (type: SupportedDataType) => `${camelCase(type)}Field`; function main() { const testCasesByFunction: Map> = new Map(); @@ -301,8 +302,8 @@ function generateWhereCommandTestsForEvalFunction( // TODO: not sure why there's this constraint... const supportedFunction = signatures.some( ({ returnType, params }) => - [...ESQL_NUMBER_TYPES, 'string'].includes(returnType) && - params.every(({ type }) => [...ESQL_NUMBER_TYPES, 'string'].includes(type)) + [...ESQL_NUMBER_TYPES, 'string'].includes(returnType as string) && + params.every(({ type }) => [...ESQL_NUMBER_TYPES, 'string'].includes(type as string)) ); if (!supportedFunction) { @@ -312,7 +313,7 @@ function generateWhereCommandTestsForEvalFunction( const supportedSignatures = signatures.filter(({ returnType }) => // TODO — not sure why the tests have this limitation... seems like any type // that can be part of a boolean expression should be allowed in a where clause - [...ESQL_NUMBER_TYPES, 'string'].includes(returnType) + [...ESQL_NUMBER_TYPES, 'string'].includes(returnType as string) ); for (const { params, returnType, ...restSign } of supportedSignatures) { const correctMapping = getFieldMapping(params); @@ -905,7 +906,7 @@ function generateStatsCommandTestsForGroupingFunction( fieldReplacedType // if a param of type time_literal or chrono_literal it will always be a literal // so no way to test the constantOnly thing - .filter((type) => !['time_literal', 'chrono_literal'].includes(type)) + .filter((type) => !['time_literal'].includes(type as string)) .map((type) => `Argument of [${name}] must be a constant, received [${type}Field]`) ); } @@ -965,7 +966,7 @@ function generateSortCommandTestsForAggFunction( const generateSortCommandTestsForGroupingFunction = generateSortCommandTestsForAggFunction; -const fieldTypesToConstants: Record = { +const fieldTypesToConstants: Record = { text: '"a"', keyword: '"a"', double: '5.5', @@ -984,14 +985,20 @@ const fieldTypesToConstants: Record = { geo_shape: 'to_geoshape("POINT (30 10)")', cartesian_point: 'to_cartesianpoint("POINT (30 10)")', cartesian_shape: 'to_cartesianshape("POINT (30 10)")', + null: 'NULL', + time_duration: '1 day', + // the following are never supplied + // by the ES function definitions. Just making types happy + time_literal: '1 day', + unsupported: '', }; -const supportedTypesAndFieldNames = supportedFieldTypes.map((type) => ({ +const supportedTypesAndFieldNames = fieldTypes.map((type) => ({ name: fieldNameFromType(type), type, })); -const supportedTypesAndConstants = supportedFieldTypes.map((type) => ({ +const supportedTypesAndConstants = dataTypes.map((type) => ({ name: fieldTypesToConstants[type], type, })); @@ -1029,7 +1036,7 @@ const toCartesianShapeSignature = evalFunctionDefinitions.find( const toVersionSignature = evalFunctionDefinitions.find(({ name }) => name === 'to_version')!; // We don't have full list for long, unsigned_long, etc. -const nestedFunctions: Record = { +const nestedFunctions: Record = { double: prepareNestedFunction(toDoubleSignature), integer: prepareNestedFunction(toInteger), text: prepareNestedFunction(toStringSignature), @@ -1046,7 +1053,7 @@ const nestedFunctions: Record = { }; function getFieldName( - typeString: SupportedFieldType, + typeString: SupportedDataType, { useNestedFunction, isStats }: { useNestedFunction: boolean; isStats: boolean } ) { if (useNestedFunction && isStats) { @@ -1082,7 +1089,7 @@ function tweakSignatureForRowCommand(signature: string): string { */ let ret = signature; for (const [type, value] of Object.entries(fieldTypesToConstants)) { - ret = ret.replace(new RegExp(fieldNameFromType(type as SupportedFieldType), 'g'), value); + ret = ret.replace(new RegExp(fieldNameFromType(type as SupportedDataType), 'g'), value); } return ret; } @@ -1101,8 +1108,8 @@ function getFieldMapping( }; return params.map(({ name: _name, type, constantOnly, literalOptions, ...rest }) => { - const typeString: string = type; - if (isSupportedFieldType(typeString)) { + const typeString: string = type as string; + if (isSupportedDataType(typeString)) { if (useLiterals && literalOptions) { return { name: `"${literalOptions[0]}"`, @@ -1146,7 +1153,7 @@ function generateIncorrectlyTypedParameters( name: string, signatures: FunctionDefinition['signatures'], currentParams: FunctionDefinition['signatures'][number]['params'], - availableFields: Array<{ name: string; type: SupportedFieldType }> + availableFields: Array<{ name: string; type: SupportedDataType }> ) { const literalValues = { string: `"a"`, @@ -1167,7 +1174,7 @@ function generateIncorrectlyTypedParameters( if (type !== 'any') { // try to find an unacceptable field - const unacceptableField: { name: string; type: SupportedFieldType } | undefined = + const unacceptableField: { name: string; type: SupportedDataType } | undefined = availableFields // sort to make the test deterministic .sort((a, b) => a.type.localeCompare(b.type)) @@ -1187,7 +1194,7 @@ function generateIncorrectlyTypedParameters( } // failed to find a bad field... they must all be acceptable - const acceptableField: { name: string; type: SupportedFieldType } | undefined = + const acceptableField: { name: string; type: SupportedDataType } | undefined = type === 'any' ? availableFields[0] : availableFields.find(({ type: fieldType }) => fieldType === type); diff --git a/packages/kbn-esql-validation-autocomplete/src/__tests__/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/__tests__/helpers.ts index 5f24d86e718bc..273679ab1f267 100644 --- a/packages/kbn-esql-validation-autocomplete/src/__tests__/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/__tests__/helpers.ts @@ -7,22 +7,27 @@ */ import { camelCase } from 'lodash'; -import { supportedFieldTypes } from '../definitions/types'; +import { ESQLRealField } from '../validation/types'; +import { fieldTypes } from '../definitions/types'; -export const fields = [ - ...supportedFieldTypes.map((type) => ({ name: `${camelCase(type)}Field`, type })), +export const fields: ESQLRealField[] = [ + ...fieldTypes + .map((type) => ({ name: `${camelCase(type)}Field`, type })) + .filter((f) => f.type !== 'unsupported'), { name: 'any#Char$Field', type: 'double' }, { name: 'kubernetes.something.something', type: 'double' }, { name: '@timestamp', type: 'date' }, ]; -export const enrichFields = [ +export const enrichFields: ESQLRealField[] = [ { name: 'otherField', type: 'text' }, { name: 'yetAnotherField', type: 'double' }, ]; // eslint-disable-next-line @typescript-eslint/naming-convention -export const unsupported_field = [{ name: 'unsupported_field', type: 'unsupported' }]; +export const unsupported_field: ESQLRealField[] = [ + { name: 'unsupported_field', type: 'unsupported' }, +]; export const indexes = [ 'a_index', @@ -58,7 +63,8 @@ export function getCallbackMocks() { return unsupported_field; } if (/dissect|grok/.test(query)) { - return [{ name: 'firstWord', type: 'text' }]; + const field: ESQLRealField = { name: 'firstWord', type: 'text' }; + return [field]; } return fields; }), diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts index a94fb0b8bead9..cdf4a6239a9ab 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts @@ -9,8 +9,6 @@ import { ESQL_COMMON_NUMERIC_TYPES, ESQL_NUMBER_TYPES } from '../../shared/esql_types'; import { setup, getFunctionSignaturesByReturnType, getFieldNamesByType } from './helpers'; -const ESQL_NUMERIC_TYPES = ESQL_NUMBER_TYPES as unknown as string[]; - const allAggFunctions = getFunctionSignaturesByReturnType('stats', 'any', { agg: true, }); @@ -84,51 +82,51 @@ describe('autocomplete.suggest', () => { scalar: true, }).map((s) => ({ ...s, text: `${s.text},` })), ]); - + const roundParameterTypes = ['double', 'integer', 'long', 'unsigned_long'] as const; await assertSuggestions('from a | stats round(/', [ - ...getFunctionSignaturesByReturnType('stats', ESQL_NUMERIC_TYPES, { + ...getFunctionSignaturesByReturnType('stats', roundParameterTypes, { agg: true, grouping: true, }), - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(roundParameterTypes), ...getFunctionSignaturesByReturnType( 'eval', - ESQL_NUMERIC_TYPES, + roundParameterTypes, { scalar: true }, undefined, ['round'] ), ]); await assertSuggestions('from a | stats round(round(/', [ - ...getFunctionSignaturesByReturnType('stats', ESQL_NUMERIC_TYPES, { agg: true }), - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFunctionSignaturesByReturnType('stats', roundParameterTypes, { agg: true }), + ...getFieldNamesByType(roundParameterTypes), ...getFunctionSignaturesByReturnType( 'eval', - ESQL_NUMERIC_TYPES, + ESQL_NUMBER_TYPES, { scalar: true }, undefined, ['round'] ), ]); await assertSuggestions('from a | stats avg(round(/', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(roundParameterTypes), ...getFunctionSignaturesByReturnType( 'eval', - ESQL_NUMERIC_TYPES, + ESQL_NUMBER_TYPES, { scalar: true }, undefined, ['round'] ), ]); await assertSuggestions('from a | stats avg(/', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), - ...getFunctionSignaturesByReturnType('eval', ESQL_NUMERIC_TYPES, { scalar: true }), + ...getFieldNamesByType(ESQL_NUMBER_TYPES), + ...getFunctionSignaturesByReturnType('eval', ESQL_NUMBER_TYPES, { scalar: true }), ]); await assertSuggestions('from a | stats round(avg(/', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(ESQL_NUMBER_TYPES), ...getFunctionSignaturesByReturnType( 'eval', - ESQL_NUMERIC_TYPES, + ESQL_NUMBER_TYPES, { scalar: true }, undefined, ['round'] @@ -142,7 +140,7 @@ describe('autocomplete.suggest', () => { ...getFieldNamesByType([...ESQL_COMMON_NUMERIC_TYPES, 'date', 'boolean', 'ip']), ...getFunctionSignaturesByReturnType( 'stats', - [...ESQL_COMMON_NUMERIC_TYPES, 'date', 'boolean', 'ip'], + [...ESQL_COMMON_NUMERIC_TYPES, 'date', 'date_period', 'boolean', 'ip'], { scalar: true, } @@ -158,7 +156,7 @@ describe('autocomplete.suggest', () => { const { assertSuggestions } = await setup(); await assertSuggestions('from a | stats avg(b/) by stringField', [ - ...getFieldNamesByType('double'), + ...getFieldNamesByType(ESQL_NUMBER_TYPES), ...getFunctionSignaturesByReturnType( 'eval', ['double', 'integer', 'long', 'unsigned_long'], diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts index 464239d3ae960..4c4ad9902ac8c 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts @@ -18,6 +18,14 @@ import type { ESQLCallbacks } from '../../shared/types'; import type { EditorContext, SuggestionRawDefinition } from '../types'; import { TIME_SYSTEM_PARAMS } from '../factories'; import { getFunctionSignatures } from '../../definitions/helpers'; +import { ESQLRealField } from '../../validation/types'; +import { + FieldType, + fieldTypes, + FunctionParameterType, + FunctionReturnType, + SupportedDataType, +} from '../../definitions/types'; export interface Integration { name: string; @@ -38,19 +46,8 @@ export const TIME_PICKER_SUGGESTION: PartialSuggestionWithText = { export const triggerCharacters = [',', '(', '=', ' ']; -export const fields: Array<{ name: string; type: string; suggestedAs?: string }> = [ - ...[ - 'string', - 'keyword', - 'double', - 'date', - 'boolean', - 'ip', - 'geo_point', - 'geo_shape', - 'cartesian_point', - 'cartesian_shape', - ].map((type) => ({ +export const fields: Array = [ + ...fieldTypes.map((type) => ({ name: `${camelCase(type)}Field`, type, })), @@ -125,7 +122,7 @@ export const policies = [ */ export function getFunctionSignaturesByReturnType( command: string, - _expectedReturnType: string | string[], + _expectedReturnType: Readonly>, { agg, grouping, @@ -141,7 +138,7 @@ export function getFunctionSignaturesByReturnType( builtin?: boolean; skipAssign?: boolean; } = {}, - paramsTypes?: string[], + paramsTypes?: Readonly, ignored?: string[], option?: string ): PartialSuggestionWithText[] { @@ -178,7 +175,7 @@ export function getFunctionSignaturesByReturnType( } const filteredByReturnType = signatures.filter( ({ returnType }) => - expectedReturnType.includes('any') || expectedReturnType.includes(returnType) + expectedReturnType.includes('any') || expectedReturnType.includes(returnType as string) ); if (!filteredByReturnType.length) { return false; @@ -227,14 +224,16 @@ export function getFunctionSignaturesByReturnType( }); } -export function getFieldNamesByType(_requestedType: string | string[]) { +export function getFieldNamesByType( + _requestedType: Readonly> +) { const requestedType = Array.isArray(_requestedType) ? _requestedType : [_requestedType]; return fields .filter(({ type }) => requestedType.includes('any') || requestedType.includes(type)) .map(({ name, suggestedAs }) => suggestedAs || name); } -export function getLiteralsByType(_type: string | string[]) { +export function getLiteralsByType(_type: SupportedDataType | SupportedDataType[]) { const type = Array.isArray(_type) ? _type : [_type]; if (type.includes('time_literal')) { // return only singular @@ -243,13 +242,13 @@ export function getLiteralsByType(_type: string | string[]) { return []; } -export function getDateLiteralsByFieldType(_requestedType: string | string[]) { +export function getDateLiteralsByFieldType(_requestedType: FieldType | FieldType[]) { const requestedType = Array.isArray(_requestedType) ? _requestedType : [_requestedType]; return requestedType.includes('date') ? [TIME_PICKER_SUGGESTION, ...TIME_SYSTEM_PARAMS] : []; } export function createCustomCallbackMocks( - customFields?: Array<{ name: string; type: string }>, + customFields?: ESQLRealField[], customSources?: Array<{ name: string; hidden: boolean }>, customPolicies?: Array<{ name: string; diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts index a6c2756914ce2..c816b49e66f78 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -18,7 +18,12 @@ import { } from './factories'; import { camelCase, partition } from 'lodash'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; -import { FunctionParameter, FunctionReturnType } from '../definitions/types'; +import { + FunctionParameter, + isFieldType, + isSupportedDataType, + SupportedDataType, +} from '../definitions/types'; import { getParamAtPosition } from './helper'; import { nonNullable } from '../shared/helpers'; import { @@ -34,14 +39,11 @@ import { TIME_PICKER_SUGGESTION, } from './__tests__/helpers'; import { METADATA_FIELDS } from '../shared/constants'; -import { - ESQL_COMMON_NUMERIC_TYPES as UNCASTED_ESQL_COMMON_NUMERIC_TYPES, - ESQL_NUMBER_TYPES, -} from '../shared/esql_types'; +import { ESQL_COMMON_NUMERIC_TYPES, ESQL_STRING_TYPES } from '../shared/esql_types'; -const ESQL_NUMERIC_TYPES = ESQL_NUMBER_TYPES as unknown as string[]; -const ESQL_COMMON_NUMERIC_TYPES = - UNCASTED_ESQL_COMMON_NUMERIC_TYPES as unknown as FunctionReturnType[]; +const roundParameterTypes = ['double', 'integer', 'long', 'unsigned_long'] as const; +const powParameterTypes = ['double', 'integer', 'long', 'unsigned_long'] as const; +const log10ParameterTypes = ['double', 'integer', 'long', 'unsigned_long'] as const; describe('autocomplete', () => { type TestArgs = [ @@ -166,60 +168,42 @@ describe('autocomplete', () => { 'var0', ...allEvalFns, ]); - testSuggestions('from a | where stringField ', [ - // all functions compatible with a stringField type - ...getFunctionSignaturesByReturnType( - 'where', - 'boolean', - { - builtin: true, - }, - ['string'] - ), - ]); - testSuggestions('from a | where textField >= ', [ - ...getFieldNamesByType('any'), - ...getFunctionSignaturesByReturnType('where', ['any'], { scalar: true }), - ]); - - testSuggestions('from a | where dateField >= ', [ - TIME_PICKER_SUGGESTION, - ...TIME_SYSTEM_PARAMS, - ...getFieldNamesByType('date'), - ...getFunctionSignaturesByReturnType('where', ['date'], { scalar: true }), - ]); - - // Skip these tests until the insensitive case equality gets restored back - testSuggestions.skip('from a | where stringField =~ ', [ - ...getFieldNamesByType('string'), - ...getFunctionSignaturesByReturnType('where', 'string', { scalar: true }), - ]); - testSuggestions('from a | where textField >= textField', [ - ...getFieldNamesByType('any'), - ...getFunctionSignaturesByReturnType('where', 'any', { scalar: true }), - ]); - testSuggestions.skip('from a | where stringField =~ stringField ', [ - '| ', + testSuggestions('from a | where keywordField ', [ + // all functions compatible with a keywordField type ...getFunctionSignaturesByReturnType( 'where', 'boolean', { builtin: true, }, - ['boolean'] + undefined, + ['and', 'or', 'not'] ), ]); + const expectedComparisonWithTextFieldSuggestions = [ + ...getFieldNamesByType(['text', 'keyword', 'ip', 'version']), + ...getFunctionSignaturesByReturnType('where', ['text', 'keyword', 'ip', 'version'], { + scalar: true, + }), + ]; + testSuggestions('from a | where textField >= ', expectedComparisonWithTextFieldSuggestions); + testSuggestions( + 'from a | where textField >= textField', + expectedComparisonWithTextFieldSuggestions + ); for (const op of ['and', 'or']) { - testSuggestions(`from a | where stringField >= stringField ${op} `, [ + testSuggestions(`from a | where keywordField >= keywordField ${op} `, [ ...getFieldNamesByType('any'), ...getFunctionSignaturesByReturnType('where', 'any', { scalar: true }), ]); - testSuggestions(`from a | where stringField >= stringField ${op} doubleField `, [ + testSuggestions(`from a | where keywordField >= keywordField ${op} doubleField `, [ ...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']), ]); - testSuggestions(`from a | where stringField >= stringField ${op} doubleField == `, [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), - ...getFunctionSignaturesByReturnType('where', ESQL_COMMON_NUMERIC_TYPES, { scalar: true }), + testSuggestions(`from a | where keywordField >= keywordField ${op} doubleField == `, [ + ...getFieldNamesByType(ESQL_COMMON_NUMERIC_TYPES), + ...getFunctionSignaturesByReturnType('where', ESQL_COMMON_NUMERIC_TYPES, { + scalar: true, + }), ]); } testSuggestions('from a | stats a=avg(doubleField) | where a ', [ @@ -242,10 +226,10 @@ describe('autocomplete', () => { testSuggestions( 'from a | where log10()', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(log10ParameterTypes), ...getFunctionSignaturesByReturnType( 'where', - ESQL_NUMERIC_TYPES, + log10ParameterTypes, { scalar: true }, undefined, ['log10'] @@ -260,10 +244,10 @@ describe('autocomplete', () => { testSuggestions( 'from a | WHERE pow(doubleField, )', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(powParameterTypes), ...getFunctionSignaturesByReturnType( 'where', - ESQL_NUMERIC_TYPES, + powParameterTypes, { scalar: true }, undefined, ['pow'] @@ -272,8 +256,8 @@ describe('autocomplete', () => { ',' ); - testSuggestions('from index | WHERE stringField not ', ['LIKE $0', 'RLIKE $0', 'IN $0']); - testSuggestions('from index | WHERE stringField NOT ', ['LIKE $0', 'RLIKE $0', 'IN $0']); + testSuggestions('from index | WHERE keywordField not ', ['LIKE $0', 'RLIKE $0', 'IN $0']); + testSuggestions('from index | WHERE keywordField NOT ', ['LIKE $0', 'RLIKE $0', 'IN $0']); testSuggestions('from index | WHERE not ', [ ...getFieldNamesByType('boolean'), ...getFunctionSignaturesByReturnType('eval', 'boolean', { scalar: true }), @@ -316,15 +300,19 @@ describe('autocomplete', () => { const constantPattern = '"%{WORD:firstWord}"'; const subExpressions = [ '', - `grok stringField |`, - `grok stringField ${constantPattern} |`, - `dissect stringField ${constantPattern} append_separator = ":" |`, - `dissect stringField ${constantPattern} |`, + `grok keywordField |`, + `grok keywordField ${constantPattern} |`, + `dissect keywordField ${constantPattern} append_separator = ":" |`, + `dissect keywordField ${constantPattern} |`, ]; for (const subExpression of subExpressions) { - testSuggestions(`from a | ${subExpression} grok `, getFieldNamesByType('string')); - testSuggestions(`from a | ${subExpression} grok stringField `, [constantPattern], ' '); - testSuggestions(`from a | ${subExpression} grok stringField ${constantPattern} `, ['| ']); + // Unskip once https://github.com/elastic/kibana/issues/190070 is fixed + testSuggestions.skip( + `from a | ${subExpression} grok `, + getFieldNamesByType(ESQL_STRING_TYPES) + ); + testSuggestions(`from a | ${subExpression} grok keywordField `, [constantPattern], ' '); + testSuggestions(`from a | ${subExpression} grok keywordField ${constantPattern} `, ['| ']); } }); @@ -332,24 +320,28 @@ describe('autocomplete', () => { const constantPattern = '"%{firstWord}"'; const subExpressions = [ '', - `dissect stringField |`, - `dissect stringField ${constantPattern} |`, - `dissect stringField ${constantPattern} append_separator = ":" |`, + `dissect keywordField |`, + `dissect keywordField ${constantPattern} |`, + `dissect keywordField ${constantPattern} append_separator = ":" |`, ]; for (const subExpression of subExpressions) { - testSuggestions(`from a | ${subExpression} dissect `, getFieldNamesByType('string')); - testSuggestions(`from a | ${subExpression} dissect stringField `, [constantPattern], ' '); + // Unskip once https://github.com/elastic/kibana/issues/190070 is fixed + testSuggestions.skip( + `from a | ${subExpression} dissect `, + getFieldNamesByType(ESQL_STRING_TYPES) + ); + testSuggestions(`from a | ${subExpression} dissect keywordField `, [constantPattern], ' '); testSuggestions( - `from a | ${subExpression} dissect stringField ${constantPattern} `, + `from a | ${subExpression} dissect keywordField ${constantPattern} `, ['APPEND_SEPARATOR = $0', '| '], ' ' ); testSuggestions( - `from a | ${subExpression} dissect stringField ${constantPattern} append_separator = `, + `from a | ${subExpression} dissect keywordField ${constantPattern} append_separator = `, ['":"', '";"'] ); testSuggestions( - `from a | ${subExpression} dissect stringField ${constantPattern} append_separator = ":" `, + `from a | ${subExpression} dissect keywordField ${constantPattern} append_separator = ":" `, ['| '] ); } @@ -360,10 +352,10 @@ describe('autocomplete', () => { ...getFieldNamesByType('any').map((name) => `${name} `), ...getFunctionSignaturesByReturnType('sort', 'any', { scalar: true }), ]); - testSuggestions('from a | sort stringField ', ['ASC ', 'DESC ', ',', '| ']); - testSuggestions('from a | sort stringField desc ', ['NULLS FIRST ', 'NULLS LAST ', ',', '| ']); + testSuggestions('from a | sort keywordField ', ['ASC ', 'DESC ', ',', '| ']); + testSuggestions('from a | sort keywordField desc ', ['NULLS FIRST ', 'NULLS LAST ', ',', '| ']); // @TODO: improve here - // testSuggestions('from a | sort stringField desc ', ['first', 'last']); + // testSuggestions('from a | sort keywordField desc ', ['first', 'last']); }); describe('limit', () => { @@ -378,21 +370,21 @@ describe('autocomplete', () => { describe('rename', () => { testSuggestions('from a | rename ', getFieldNamesByType('any')); - testSuggestions('from a | rename stringField ', ['AS $0'], ' '); - testSuggestions('from a | rename stringField as ', ['var0']); + testSuggestions('from a | rename keywordField ', ['AS $0'], ' '); + testSuggestions('from a | rename keywordField as ', ['var0']); }); for (const command of ['keep', 'drop']) { describe(command, () => { testSuggestions(`from a | ${command} `, getFieldNamesByType('any')); testSuggestions( - `from a | ${command} stringField, `, - getFieldNamesByType('any').filter((name) => name !== 'stringField') + `from a | ${command} keywordField, `, + getFieldNamesByType('any').filter((name) => name !== 'keywordField') ); testSuggestions( - `from a | ${command} stringField,`, - getFieldNamesByType('any').filter((name) => name !== 'stringField'), + `from a | ${command} keywordField,`, + getFieldNamesByType('any').filter((name) => name !== 'keywordField'), ',' ); @@ -431,20 +423,7 @@ describe('autocomplete', () => { testSuggestions(`from a ${prevCommand}| enrich _${camelCase(mode)}:`, policyNames, ':'); } testSuggestions(`from a ${prevCommand}| enrich policy `, ['ON $0', 'WITH $0', '| ']); - testSuggestions(`from a ${prevCommand}| enrich policy on `, [ - 'keywordField', - 'stringField', - 'doubleField', - 'dateField', - 'booleanField', - 'ipField', - 'geoPointField', - 'geoShapeField', - 'cartesianPointField', - 'cartesianShapeField', - '`any#Char$Field`', - 'kubernetes.something.something', - ]); + testSuggestions(`from a ${prevCommand}| enrich policy on `, getFieldNamesByType('any')); testSuggestions(`from a ${prevCommand}| enrich policy on b `, ['WITH $0', ',', '| ']); testSuggestions( `from a ${prevCommand}| enrich policy on b with `, @@ -455,21 +434,21 @@ describe('autocomplete', () => { testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = `, [ ...getPolicyFields('policy'), ]); - testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = stringField `, [ + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = keywordField `, [ ',', '| ', ]); - testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = stringField, `, [ + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = keywordField, `, [ 'var1 = ', ...getPolicyFields('policy'), ]); - testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = stringField, var1 `, [ + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = keywordField, var1 `, [ '= $0', ',', '| ', ]); testSuggestions( - `from a ${prevCommand}| enrich policy on b with var0 = stringField, var1 = `, + `from a ${prevCommand}| enrich policy on b with var0 = keywordField, var1 = `, [...getPolicyFields('policy')] ); testSuggestions( @@ -477,7 +456,7 @@ describe('autocomplete', () => { ['var0 = ', ...getPolicyFields('policy')], ' ' ); - testSuggestions(`from a ${prevCommand}| enrich policy with stringField `, [ + testSuggestions(`from a ${prevCommand}| enrich policy with keywordField `, [ '= $0', ',', '| ', @@ -498,8 +477,8 @@ describe('autocomplete', () => { ',', '| ', ]); - testSuggestions('from index | EVAL stringField not ', ['LIKE $0', 'RLIKE $0', 'IN $0']); - testSuggestions('from index | EVAL stringField NOT ', ['LIKE $0', 'RLIKE $0', 'IN $0']); + testSuggestions('from index | EVAL keywordField not ', ['LIKE $0', 'RLIKE $0', 'IN $0']); + testSuggestions('from index | EVAL keywordField NOT ', ['LIKE $0', 'RLIKE $0', 'IN $0']); testSuggestions('from index | EVAL doubleField in ', ['( $0 )']); testSuggestions( 'from index | EVAL doubleField in ( )', @@ -527,17 +506,17 @@ describe('autocomplete', () => { ...getFunctionSignaturesByReturnType('eval', 'any', { scalar: true }), ]); // Skip this test until the insensitive case equality gets restored back - testSuggestions.skip('from a | eval a=stringField =~ ', [ - ...getFieldNamesByType('string'), - ...getFunctionSignaturesByReturnType('eval', 'string', { scalar: true }), + testSuggestions.skip('from a | eval a=keywordField =~ ', [ + ...getFieldNamesByType(ESQL_STRING_TYPES), + ...getFunctionSignaturesByReturnType('eval', ESQL_STRING_TYPES, { scalar: true }), ]); testSuggestions( 'from a | eval a=round()', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(roundParameterTypes), ...getFunctionSignaturesByReturnType( 'eval', - ESQL_NUMERIC_TYPES, + roundParameterTypes, { scalar: true }, undefined, ['round'] @@ -588,6 +567,7 @@ describe('autocomplete', () => { testSuggestions( 'from a | eval round(doubleField, ', [ + ...getFieldNamesByType('integer'), ...getFunctionSignaturesByReturnType('eval', 'integer', { scalar: true }, undefined, [ 'round', ]), @@ -601,23 +581,31 @@ describe('autocomplete', () => { ...getFunctionSignaturesByReturnType('eval', 'any', { scalar: true }), ]); testSuggestions('from a | eval a=round(doubleField) + ', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), - ...getFunctionSignaturesByReturnType('eval', ESQL_COMMON_NUMERIC_TYPES, { scalar: true }), + ...getFieldNamesByType(ESQL_COMMON_NUMERIC_TYPES), + ...getFunctionSignaturesByReturnType('eval', ESQL_COMMON_NUMERIC_TYPES, { + scalar: true, + }), ]); testSuggestions('from a | eval a=round(doubleField)+ ', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), - ...getFunctionSignaturesByReturnType('eval', ESQL_COMMON_NUMERIC_TYPES, { scalar: true }), + ...getFieldNamesByType(ESQL_COMMON_NUMERIC_TYPES), + ...getFunctionSignaturesByReturnType('eval', ESQL_COMMON_NUMERIC_TYPES, { + scalar: true, + }), ]); testSuggestions('from a | eval a=doubleField+ ', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), - ...getFunctionSignaturesByReturnType('eval', ESQL_COMMON_NUMERIC_TYPES, { scalar: true }), + ...getFieldNamesByType(ESQL_COMMON_NUMERIC_TYPES), + ...getFunctionSignaturesByReturnType('eval', ESQL_COMMON_NUMERIC_TYPES, { + scalar: true, + }), ]); testSuggestions('from a | eval a=`any#Char$Field`+ ', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), - ...getFunctionSignaturesByReturnType('eval', ESQL_COMMON_NUMERIC_TYPES, { scalar: true }), + ...getFieldNamesByType(ESQL_COMMON_NUMERIC_TYPES), + ...getFunctionSignaturesByReturnType('eval', ESQL_COMMON_NUMERIC_TYPES, { + scalar: true, + }), ]); testSuggestions( - 'from a | stats avg(doubleField) by stringField | eval ', + 'from a | stats avg(doubleField) by keywordField | eval ', [ 'var0 = ', '`avg(doubleField)`', @@ -639,7 +627,7 @@ describe('autocomplete', () => { ' ' ); testSuggestions( - 'from a | stats avg(doubleField) by stringField | eval ', + 'from a | stats avg(doubleField) by keywordField | eval ', [ 'var0 = ', '`avg(doubleField)`', @@ -651,7 +639,7 @@ describe('autocomplete', () => { [[{ name: 'avg_doubleField_', type: 'double' }], undefined, undefined] ); testSuggestions( - 'from a | stats avg(doubleField), avg(kubernetes.something.something) by stringField | eval ', + 'from a | stats avg(doubleField), avg(kubernetes.something.something) by keywordField | eval ', [ 'var0 = ', '`avg(doubleField)`', @@ -670,13 +658,14 @@ describe('autocomplete', () => { undefined, ] ); + testSuggestions( 'from a | eval a=round(doubleField), b=round()', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(roundParameterTypes), ...getFunctionSignaturesByReturnType( 'eval', - ESQL_NUMERIC_TYPES, + roundParameterTypes, { scalar: true }, undefined, ['round'] @@ -713,14 +702,10 @@ describe('autocomplete', () => { testSuggestions( 'from a | eval a=cidr_match(ipField, textField, ', [ - ...getFieldNamesByType('keyword'), - ...getFunctionSignaturesByReturnType( - 'eval', - ['text', 'keyword'], - { scalar: true }, - undefined, - ['cidr_match'] - ), + ...getFieldNamesByType('text'), + ...getFunctionSignaturesByReturnType('eval', 'text', { scalar: true }, undefined, [ + 'cidr_match', + ]), ], ' ' ); @@ -749,14 +734,15 @@ describe('autocomplete', () => { // round(round( // round(round(round( // etc... + for (const nesting of [1, 2, 3, 4]) { testSuggestions( `from a | eval a=${Array(nesting).fill('round(').join('')}`, [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(roundParameterTypes), ...getFunctionSignaturesByReturnType( 'eval', - ESQL_NUMERIC_TYPES, + roundParameterTypes, { scalar: true }, undefined, ['round'] @@ -766,6 +752,8 @@ describe('autocomplete', () => { ); } + const absParameterTypes = ['double', 'integer', 'long', 'unsigned_long'] as const; + // Smoke testing for suggestions in previous position than the end of the statement testSuggestions( 'from a | eval var0 = abs(doubleField) | eval abs(var0)', @@ -782,10 +770,10 @@ describe('autocomplete', () => { testSuggestions( 'from a | eval var0 = abs(b) | eval abs(var0)', [ - ...getFieldNamesByType(ESQL_NUMERIC_TYPES), + ...getFieldNamesByType(absParameterTypes), ...getFunctionSignaturesByReturnType( 'eval', - ESQL_NUMERIC_TYPES, + absParameterTypes, { scalar: true }, undefined, ['abs'] @@ -798,7 +786,7 @@ describe('autocomplete', () => { // Test suggestions for each possible param, within each signature variation, for each function for (const fn of evalFunctionDefinitions) { // skip this fn for the moment as it's quite hard to test - if (!['bucket', 'date_extract', 'date_diff'].includes(fn.name)) { + if (!['bucket', 'date_extract', 'date_diff', 'case'].includes(fn.name)) { for (const signature of fn.signatures) { signature.params.forEach((param, i) => { if (i < signature.params.length) { @@ -816,11 +804,11 @@ describe('autocomplete', () => { // get all possible types for this param const [constantOnlyParamDefs, acceptsFieldParamDefs] = partition( allParamDefs, - (p) => p.constantOnly || /_literal/.test(p.type) + (p) => p.constantOnly || /_literal/.test(p.type as string) ); - const getTypesFromParamDefs = (paramDefs: FunctionParameter[]) => - Array.from(new Set(paramDefs.map((p) => p.type))); + const getTypesFromParamDefs = (paramDefs: FunctionParameter[]): SupportedDataType[] => + Array.from(new Set(paramDefs.map((p) => p.type))).filter(isSupportedDataType); const suggestedConstants = param.literalSuggestions || param.literalOptions; @@ -837,8 +825,12 @@ describe('autocomplete', () => { suggestedConstants?.length ? suggestedConstants.map((option) => `"${option}"${requiresMoreArgs ? ', ' : ''}`) : [ - ...getDateLiteralsByFieldType(getTypesFromParamDefs(acceptsFieldParamDefs)), - ...getFieldNamesByType(getTypesFromParamDefs(acceptsFieldParamDefs)), + ...getDateLiteralsByFieldType( + getTypesFromParamDefs(acceptsFieldParamDefs).filter(isFieldType) + ), + ...getFieldNamesByType( + getTypesFromParamDefs(acceptsFieldParamDefs).filter(isFieldType) + ), ...getFunctionSignaturesByReturnType( 'eval', getTypesFromParamDefs(acceptsFieldParamDefs), @@ -857,8 +849,12 @@ describe('autocomplete', () => { suggestedConstants?.length ? suggestedConstants.map((option) => `"${option}"${requiresMoreArgs ? ', ' : ''}`) : [ - ...getDateLiteralsByFieldType(getTypesFromParamDefs(acceptsFieldParamDefs)), - ...getFieldNamesByType(getTypesFromParamDefs(acceptsFieldParamDefs)), + ...getDateLiteralsByFieldType( + getTypesFromParamDefs(acceptsFieldParamDefs).filter(isFieldType) + ), + ...getFieldNamesByType( + getTypesFromParamDefs(acceptsFieldParamDefs).filter(isFieldType) + ), ...getFunctionSignaturesByReturnType( 'eval', getTypesFromParamDefs(acceptsFieldParamDefs), @@ -967,7 +963,7 @@ describe('autocomplete', () => { describe('callbacks', () => { it('should send the fields query without the last command', async () => { const callbackMocks = createCustomCallbackMocks(undefined, undefined, undefined); - const statement = 'from a | drop stringField | eval var0 = abs(doubleField) '; + const statement = 'from a | drop keywordField | eval var0 = abs(doubleField) '; const triggerOffset = statement.lastIndexOf(' '); const context = createCompletionContext(statement[triggerOffset]); await suggest( @@ -978,7 +974,7 @@ describe('autocomplete', () => { callbackMocks ); expect(callbackMocks.getFieldsFor).toHaveBeenCalledWith({ - query: 'from a | drop stringField', + query: 'from a | drop keywordField', }); }); it('should send the fields query aware of the location', async () => { @@ -1101,7 +1097,13 @@ describe('autocomplete', () => { ); // DISSECT field - testSuggestions('FROM index1 | DISSECT b', getFieldNamesByType('string'), undefined, 23); + // enable once https://github.com/elastic/kibana/issues/190070 is fixed + testSuggestions.skip( + 'FROM index1 | DISSECT b', + getFieldNamesByType(ESQL_STRING_TYPES), + undefined, + 23 + ); // DROP (first field) testSuggestions('FROM index1 | DROP f', getFieldNamesByType('any'), undefined, 20); @@ -1139,7 +1141,13 @@ describe('autocomplete', () => { ); // GROK field - testSuggestions('FROM index1 | GROK f', getFieldNamesByType('string'), undefined, 20); + // enable once https://github.com/elastic/kibana/issues/190070 + testSuggestions.skip( + 'FROM index1 | GROK f', + getFieldNamesByType(ESQL_STRING_TYPES), + undefined, + 20 + ); // KEEP (first field) testSuggestions('FROM index1 | KEEP f', getFieldNamesByType('any'), undefined, 20); @@ -1182,18 +1190,18 @@ describe('autocomplete', () => { // SORT field order testSuggestions( - 'FROM index1 | SORT stringField a', + 'FROM index1 | SORT keywordField a', ['ASC ', 'DESC ', ',', '| '], undefined, - 32 + 33 ); // SORT field order nulls testSuggestions( - 'FROM index1 | SORT stringField ASC n', + 'FROM index1 | SORT keywordField ASC n', ['NULLS FIRST ', 'NULLS LAST ', ',', '| '], undefined, - 36 + 37 ); // STATS argument @@ -1235,17 +1243,18 @@ describe('autocomplete', () => { // WHERE argument comparison testSuggestions( - 'FROM index1 | WHERE stringField i', + 'FROM index1 | WHERE keywordField i', getFunctionSignaturesByReturnType( 'where', 'boolean', { builtin: true, }, - ['string'] + undefined, + ['and', 'or', 'not'] ), undefined, - 33 + 34 ); }); @@ -1299,12 +1308,16 @@ describe('autocomplete', () => { // field parameter const expectedStringSuggestionsWhenMoreArgsAreNeeded = [ - ...getFieldNamesByType('keyword') + ...getFieldNamesByType(ESQL_STRING_TYPES) .map((field) => `${field}, `) .map(attachTriggerCommand), - ...getFunctionSignaturesByReturnType('eval', 'keyword', { scalar: true }, undefined, [ - 'replace', - ]).map((s) => ({ + ...getFunctionSignaturesByReturnType( + 'eval', + ESQL_STRING_TYPES, + { scalar: true }, + undefined, + ['replace'] + ).map((s) => ({ ...s, text: `${s.text},`, })), @@ -1319,23 +1332,30 @@ describe('autocomplete', () => { // subsequent parameter testSuggestions( - 'FROM a | EVAL REPLACE(stringField, )', + 'FROM a | EVAL REPLACE(keywordField, )', expectedStringSuggestionsWhenMoreArgsAreNeeded, undefined, - 35 + 36 ); // final parameter — should not advance! testSuggestions( - 'FROM a | EVAL REPLACE(stringField, stringField, )', + 'FROM a | EVAL REPLACE(keywordField, keywordField, )', [ - ...getFieldNamesByType('keyword').map((field) => ({ text: field, command: undefined })), - ...getFunctionSignaturesByReturnType('eval', 'keyword', { scalar: true }, undefined, [ - 'replace', - ]), + ...getFieldNamesByType(ESQL_STRING_TYPES).map((field) => ({ + text: field, + command: undefined, + })), + ...getFunctionSignaturesByReturnType( + 'eval', + ESQL_STRING_TYPES, + { scalar: true }, + undefined, + ['replace'] + ), ], undefined, - 48 + 50 ); // Trigger character because this is how it will actually be... the user will press @@ -1495,17 +1515,17 @@ describe('autocomplete', () => { // WHERE argument comparison testSuggestions( - 'FROM a | WHERE stringField ', + 'FROM a | WHERE keywordField ', getFunctionSignaturesByReturnType( 'where', 'boolean', { builtin: true, }, - ['string'] + ['keyword'] ).map((s) => (s.text.toLowerCase().includes('null') ? s : attachTriggerCommand(s))), undefined, - 27 + 28 ); }); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index 67af737d34da0..36d3664b5617a 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -95,7 +95,7 @@ import { isAggFunctionUsedAlready, removeQuoteForSuggestedSources, } from './helper'; -import { FunctionParameter, FunctionReturnType, SupportedFieldType } from '../definitions/types'; +import { FunctionParameter, FunctionReturnType, SupportedDataType } from '../definitions/types'; type GetSourceFn = () => Promise; type GetDataStreamsForIntegrationFn = ( @@ -441,7 +441,7 @@ function extractFinalTypeFromArg( references: Pick ): | ESQLLiteral['literalType'] - | SupportedFieldType + | SupportedDataType | FunctionReturnType | 'timeInterval' | string // @TODO remove this @@ -787,7 +787,7 @@ async function getExpressionSuggestionsByType( option, argDef, nodeArg, - nodeArgType || 'any', + (nodeArgType as string) || 'any', references, getFieldsByType )) @@ -882,7 +882,7 @@ async function getExpressionSuggestionsByType( option, argDef, nodeArg, - nodeArgType, + nodeArgType as string, references, getFieldsByType )) @@ -1024,11 +1024,15 @@ async function getBuiltinFunctionNextArgument( if (isFnComplete.reason === 'fewArgs') { const fnDef = getFunctionDefinition(nodeArg.name); - if (fnDef?.signatures.every(({ params }) => params.some(({ type }) => isArrayType(type)))) { + if ( + fnDef?.signatures.every(({ params }) => + params.some(({ type }) => isArrayType(type as string)) + ) + ) { suggestions.push(listCompleteItem); } else { const finalType = nestedType || nodeArgType || 'any'; - const supportedTypes = getSupportedTypesForBinaryOperators(fnDef, finalType); + const supportedTypes = getSupportedTypesForBinaryOperators(fnDef, finalType as string); suggestions.push( ...(await getFieldsOrFunctionsSuggestions( // this is a special case with AND/OR @@ -1037,7 +1041,7 @@ async function getBuiltinFunctionNextArgument( // to actually suggest a wider set of fields/functions finalType === 'boolean' && getFunctionDefinition(nodeArg.name)?.type === 'builtin' ? ['any'] - : supportedTypes, + : (supportedTypes as string[]), command.name, option?.name, getFieldsByType, @@ -1146,11 +1150,7 @@ async function getFieldsOrFunctionsSuggestions( } } - // could also be in stats (bucket) but our autocomplete is not great yet - const displayDateSuggestions = types.includes('date') && ['where', 'eval'].includes(commandName); - const suggestions = filteredFieldsByType.concat( - displayDateSuggestions ? getDateLiterals() : [], functions ? getCompatibleFunctionDefinition(commandName, optionName, types, ignoreFn) : [], variables ? pushItUpInTheList(buildVariablesDefinitions(filteredVariablesByType), functions) @@ -1321,7 +1321,7 @@ async function getFunctionArgsSuggestions( // const [constantOnlyParamDefs, paramDefsWhichSupportFields] = partition( allParamDefinitionsForThisPosition, - (paramDef) => paramDef.constantOnly || /_literal$/.test(paramDef.type) + (paramDef) => paramDef.constantOnly || /_literal$/.test(paramDef.type as string) ); const getTypesFromParamDefs = (paramDefs: FunctionParameter[]) => { @@ -1332,7 +1332,7 @@ async function getFunctionArgsSuggestions( suggestions.push( ...getCompatibleLiterals( command.name, - getTypesFromParamDefs(constantOnlyParamDefs), + getTypesFromParamDefs(constantOnlyParamDefs) as string[], undefined, { addComma: shouldAddComma, advanceCursorAndOpenSuggestions: hasMoreMandatoryArgs } ) @@ -1341,7 +1341,7 @@ async function getFunctionArgsSuggestions( // Fields suggestions.push( ...pushItUpInTheList( - await getFieldsByType(getTypesFromParamDefs(paramDefsWhichSupportFields), [], { + await getFieldsByType(getTypesFromParamDefs(paramDefsWhichSupportFields) as string[], [], { addComma: shouldAddComma, advanceCursorAndOpenSuggestions: hasMoreMandatoryArgs, }), @@ -1354,7 +1354,7 @@ async function getFunctionArgsSuggestions( ...getCompatibleFunctionDefinition( command.name, option?.name, - getTypesFromParamDefs(paramDefsWhichSupportFields), + getTypesFromParamDefs(paramDefsWhichSupportFields) as string[], fnToIgnore ).map((suggestion) => ({ ...suggestion, @@ -1435,7 +1435,7 @@ async function getListArgsSuggestions( const otherArgs = node.args.filter(Array.isArray).flat().filter(isColumnItem); suggestions.push( ...(await getFieldsOrFunctionsSuggestions( - [argType], + [argType as string], command.name, undefined, getFieldsByType, @@ -1639,7 +1639,7 @@ async function getOptionArgsSuggestions( option, { type: argDef?.type || 'any' }, nodeArg, - nodeArgType, + nodeArgType as string, references, getFieldsByType )) diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts index 88acf1c207f09..4f7e919c84361 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts @@ -16,6 +16,7 @@ import { TRIGGER_SUGGESTION_COMMAND, buildConstantsDefinitions, } from './factories'; +import { FunctionParameterType, FunctionReturnType } from '../definitions/types'; export function getAssignmentDefinitionCompletitionItem() { const assignFn = builtinFunctions.find(({ name }) => name === '=')!; @@ -54,8 +55,8 @@ export const getNextTokenForNot = ( export const getBuiltinCompatibleFunctionDefinition = ( command: string, option: string | undefined, - argType: string, - returnTypes?: string[], + argType: FunctionParameterType, + returnTypes?: FunctionReturnType[], { skipAssign }: { skipAssign?: boolean } = {} ): SuggestionRawDefinition[] => { const compatibleFunctions = builtinFunctions.filter( diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index 13a3c76b389f0..c9d0185d5c301 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -102,7 +102,8 @@ export const getCompatibleFunctionDefinition = ( return fnSupportedByCommand .filter((mathDefinition) => mathDefinition.signatures.some( - (signature) => returnTypes[0] === 'any' || returnTypes.includes(signature.returnType) + (signature) => + returnTypes[0] === 'any' || returnTypes.includes(signature.returnType as string) ) ) .map(getSuggestionFunctionDefinition); diff --git a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts index a4ff739297201..cca1197ed629b 100644 --- a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts @@ -11,32 +11,39 @@ import { validateQuery } from '../validation/validation'; import { getAllFunctions } from '../shared/helpers'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; import { CodeActionOptions } from './types'; +import { ESQLRealField } from '../validation/types'; +import { FieldType } from '../definitions/types'; function getCallbackMocks() { return { - getFieldsFor: jest.fn(async ({ query }) => - /enrich/.test(query) - ? [ - { name: 'otherField', type: 'string' }, - { name: 'yetAnotherField', type: 'number' }, - ] - : /unsupported_index/.test(query) - ? [{ name: 'unsupported_field', type: 'unsupported' }] - : [ - ...['string', 'number', 'date', 'boolean', 'ip'].map((type) => ({ - name: `${type}Field`, - type, - })), - { name: 'geoPointField', type: 'geo_point' }, - { name: 'any#Char$Field', type: 'number' }, - { name: 'kubernetes.something.something', type: 'number' }, - { - name: `listField`, - type: `list`, - }, - { name: '@timestamp', type: 'date' }, - ] - ), + getFieldsFor: jest.fn, any>(async ({ query }) => { + if (/enrich/.test(query)) { + const fields: ESQLRealField[] = [ + { name: 'otherField', type: 'keyword' }, + { name: 'yetAnotherField', type: 'double' }, + ]; + return fields; + } + + if (/unsupported_index/.test(query)) { + const fields: ESQLRealField[] = [{ name: 'unsupported_field', type: 'unsupported' }]; + return fields; + } + + const localDataTypes: FieldType[] = ['keyword', 'double', 'date', 'boolean', 'ip']; + const fields: ESQLRealField[] = [ + ...localDataTypes.map((type) => ({ + name: `${type}Field`, + type, + })), + { name: 'geoPointField', type: 'geo_point' }, + { name: 'any#Char$Field', type: 'double' }, + { name: 'kubernetes.something.something', type: 'double' }, + { name: '@timestamp', type: 'date' }, + ]; + + return fields; + }), getSources: jest.fn(async () => ['index', '.secretIndex', 'my-index'].map((name) => ({ name, @@ -162,29 +169,29 @@ describe('quick fixes logic', () => { { relaxOnMissingCallbacks: false }, ]) { for (const command of ['KEEP', 'DROP', 'EVAL']) { - testQuickFixes(`FROM index | ${command} stringField`, [], options); - // strongField => stringField - testQuickFixes(`FROM index | ${command} strongField`, ['stringField'], options); + testQuickFixes(`FROM index | ${command} keywordField`, [], options); + // koywordField => keywordField + testQuickFixes(`FROM index | ${command} koywordField`, ['keywordField'], options); testQuickFixes( - `FROM index | ${command} numberField, strongField`, - ['stringField'], + `FROM index | ${command} numberField, koywordField`, + ['keywordField'], options ); } - testQuickFixes(`FROM index | EVAL round(strongField)`, ['stringField'], options); - testQuickFixes(`FROM index | EVAL var0 = round(strongField)`, ['stringField'], options); - testQuickFixes(`FROM index | WHERE round(strongField) > 0`, ['stringField'], options); - testQuickFixes(`FROM index | WHERE 0 < round(strongField)`, ['stringField'], options); - testQuickFixes(`FROM index | RENAME strongField as newField`, ['stringField'], options); + testQuickFixes(`FROM index | EVAL round(koywordField)`, ['keywordField'], options); + testQuickFixes(`FROM index | EVAL var0 = round(koywordField)`, ['keywordField'], options); + testQuickFixes(`FROM index | WHERE round(koywordField) > 0`, ['keywordField'], options); + testQuickFixes(`FROM index | WHERE 0 < round(koywordField)`, ['keywordField'], options); + testQuickFixes(`FROM index | RENAME koywordField as newField`, ['keywordField'], options); // This levarage the knowledge of the enrich policy fields to suggest the right field testQuickFixes( `FROM index | ENRICH policy | KEEP yetAnotherField2`, ['yetAnotherField'], options ); - testQuickFixes(`FROM index | ENRICH policy ON strongField`, ['stringField'], options); + testQuickFixes(`FROM index | ENRICH policy ON koywordField`, ['keywordField'], options); testQuickFixes( - `FROM index | ENRICH policy ON stringField WITH yetAnotherField2`, + `FROM index | ENRICH policy ON keywordField WITH yetAnotherField2`, ['yetAnotherField'], options ); @@ -209,29 +216,29 @@ describe('quick fixes logic', () => { { relaxOnMissingCallbacks: false }, ]) { for (const command of ['KEEP', 'DROP', 'EVAL']) { - testQuickFixes(`FROM index | ${command} stringField`, [], options); - // strongField => stringField - testQuickFixes(`FROM index | ${command} strongField`, ['stringField'], options); + testQuickFixes(`FROM index | ${command} keywordField`, [], options); + // koywordField => keywordField + testQuickFixes(`FROM index | ${command} koywordField`, ['keywordField'], options); testQuickFixes( - `FROM index | ${command} numberField, strongField`, - ['stringField'], + `FROM index | ${command} numberField, koywordField`, + ['keywordField'], options ); } - testQuickFixes(`FROM index | EVAL round(strongField)`, ['stringField'], options); - testQuickFixes(`FROM index | EVAL var0 = round(strongField)`, ['stringField'], options); - testQuickFixes(`FROM index | WHERE round(strongField) > 0`, ['stringField'], options); - testQuickFixes(`FROM index | WHERE 0 < round(strongField)`, ['stringField'], options); - testQuickFixes(`FROM index | RENAME strongField as newField`, ['stringField'], options); + testQuickFixes(`FROM index | EVAL round(koywordField)`, ['keywordField'], options); + testQuickFixes(`FROM index | EVAL var0 = round(koywordField)`, ['keywordField'], options); + testQuickFixes(`FROM index | WHERE round(koywordField) > 0`, ['keywordField'], options); + testQuickFixes(`FROM index | WHERE 0 < round(koywordField)`, ['keywordField'], options); + testQuickFixes(`FROM index | RENAME koywordField as newField`, ['keywordField'], options); // This levarage the knowledge of the enrich policy fields to suggest the right field testQuickFixes( `FROM index | ENRICH policy | KEEP yetAnotherField2`, ['yetAnotherField'], options ); - testQuickFixes(`FROM index | ENRICH policy ON strongField`, ['stringField'], options); + testQuickFixes(`FROM index | ENRICH policy ON koywordField`, ['keywordField'], options); testQuickFixes( - `FROM index | ENRICH policy ON stringField WITH yetAnotherField2`, + `FROM index | ENRICH policy ON keywordField WITH yetAnotherField2`, ['yetAnotherField'], options ); @@ -329,8 +336,8 @@ describe('quick fixes logic', () => { { relaxOnMissingCallbacks: false }, { relaxOnMissingCallbacks: false }, ]) { - testQuickFixes(`FROM index | WHERE stringField like 'asda'`, ['"asda"'], options); - testQuickFixes(`FROM index | WHERE stringField not like 'asda'`, ['"asda"'], options); + testQuickFixes(`FROM index | WHERE keywordField like 'asda'`, ['"asda"'], options); + testQuickFixes(`FROM index | WHERE keywordField not like 'asda'`, ['"asda"'], options); } }); @@ -407,7 +414,7 @@ describe('quick fixes logic', () => { describe('callbacks', () => { it('should not crash if specific callback functions are not passed', async () => { const callbackMocks = getCallbackMocks(); - const statement = `from a | eval b = a | enrich policy | dissect stringField "%{firstWord}"`; + const statement = `from a | eval b = a | enrich policy | dissect keywordField "%{firstWord}"`; const { errors } = await validateQuery( statement, getAstAndSyntaxErrors, @@ -427,7 +434,7 @@ describe('quick fixes logic', () => { it('should not crash if specific callback functions are not passed with relaxed option', async () => { const callbackMocks = getCallbackMocks(); - const statement = `from a | eval b = a | enrich policy | dissect stringField "%{firstWord}"`; + const statement = `from a | eval b = a | enrich policy | dissect keywordField "%{firstWord}"`; const { errors } = await validateQuery( statement, getAstAndSyntaxErrors, @@ -453,7 +460,7 @@ describe('quick fixes logic', () => { it('should not crash no callbacks are passed', async () => { const callbackMocks = getCallbackMocks(); - const statement = `from a | eval b = a | enrich policy | dissect stringField "%{firstWord}"`; + const statement = `from a | eval b = a | enrich policy | dissect keywordField "%{firstWord}"`; const { errors } = await validateQuery( statement, getAstAndSyntaxErrors, @@ -469,7 +476,7 @@ describe('quick fixes logic', () => { it('should not crash no callbacks are passed with relaxed option', async () => { const callbackMocks = getCallbackMocks(); - const statement = `from a | eval b = a | enrich policy | dissect stringField "%{firstWord}"`; + const statement = `from a | eval b = a | enrich policy | dissect keywordField "%{firstWord}"`; const { errors } = await validateQuery( statement, getAstAndSyntaxErrors, diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts index 10945d1c6b135..45d32d8e3282d 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts @@ -308,13 +308,13 @@ const comparisonFunctions: FunctionDefinition[] = [ { params: [ { name: 'left', type: 'boolean' as const }, - { name: 'right', type: 'string' as const, constantOnly: true }, + { name: 'right', type: 'keyword' as const, constantOnly: true }, ], returnType: 'boolean' as const, }, { params: [ - { name: 'left', type: 'string' as const, constantOnly: true }, + { name: 'left', type: 'keyword' as const, constantOnly: true }, { name: 'right', type: 'boolean' as const }, ], returnType: 'boolean' as const, @@ -338,13 +338,13 @@ const comparisonFunctions: FunctionDefinition[] = [ { params: [ { name: 'left', type: 'boolean' as const }, - { name: 'right', type: 'string' as const, constantOnly: true }, + { name: 'right', type: 'keyword' as const, constantOnly: true }, ], returnType: 'boolean' as const, }, { params: [ - { name: 'left', type: 'string' as const, constantOnly: true }, + { name: 'left', type: 'keyword' as const, constantOnly: true }, { name: 'right', type: 'boolean' as const }, ], returnType: 'boolean' as const, diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/helpers.ts index a44db712ab230..3773a7c30e3d1 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/helpers.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { CommandDefinition, FunctionDefinition } from './types'; +import type { CommandDefinition, FunctionDefinition, FunctionParameterType } from './types'; /** * Given a function definition, this function will return a list of function signatures @@ -104,7 +104,7 @@ export function printArguments( optional, }: { name: string; - type: string | string[]; + type: FunctionParameterType | FunctionParameterType[]; optional?: boolean; }, withTypes: boolean diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts index 660bb1c7aca81..398a26e7f152d 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts @@ -8,42 +8,67 @@ import type { ESQLCommand, ESQLCommandOption, ESQLFunction, ESQLMessage } from '@kbn/esql-ast'; -// Currently, partial of the full list -// https://github.com/elastic/elasticsearch/blob/main/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java -export const supportedFieldTypes = [ +/** + * All supported field types in ES|QL. This is all the types + * that can come back in the table from a query. + */ +export const fieldTypes = [ + 'boolean', + 'date', 'double', - 'unsigned_long', - 'long', + 'ip', + 'keyword', 'integer', - 'counter_integer', - 'counter_long', - 'counter_double', - 'date', - 'date_period', + 'long', 'text', - 'keyword', - 'boolean', - 'ip', + 'unsigned_long', + 'version', 'cartesian_point', 'cartesian_shape', 'geo_point', 'geo_shape', - 'version', + 'counter_integer', + 'counter_long', + 'counter_double', + 'unsupported', +] as const; + +export type FieldType = (typeof fieldTypes)[number]; + +export const isFieldType = (type: string | FunctionParameterType): type is FieldType => + fieldTypes.includes(type as FieldType); + +/** + * This is the list of all data types that are supported in ES|QL. + * + * Not all of these can be used as field types. Some can only be literals, + * others may be the value of a field, but cannot be used in the index mapping. + * + * This is a partial list. The full list is here and we may need to expand this type as + * the capabilities of the client-side engines grow. + * https://github.com/elastic/elasticsearch/blob/main/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java + */ +export const dataTypes = [ + ...fieldTypes, + 'null', + 'time_literal', // @TODO consider merging time_literal with time_duration + 'time_duration', + 'date_period', ] as const; -export const isSupportedFieldType = (type: string): type is SupportedFieldType => - supportedFieldTypes.includes(type as SupportedFieldType); +export type SupportedDataType = (typeof dataTypes)[number]; -export type SupportedFieldType = (typeof supportedFieldTypes)[number]; +export const isSupportedDataType = ( + type: string | FunctionParameterType +): type is SupportedDataType => dataTypes.includes(type as SupportedDataType); -export type FunctionParameterType = - | SupportedFieldType - | 'string' - | 'null' - | 'any' - | 'chrono_literal' - | 'time_literal' - | 'time_duration' +/** + * This is a set of array types. These aren't official ES|QL types, but they are + * currently used in the function definitions in a couple of specific scenarios. + * + * The fate of these is uncertain. They may be removed in the future. + */ +type ArrayType = | 'double[]' | 'unsigned_long[]' | 'long[]' @@ -51,38 +76,22 @@ export type FunctionParameterType = | 'counter_integer[]' | 'counter_long[]' | 'counter_double[]' - | 'string[]' | 'keyword[]' | 'text[]' | 'boolean[]' | 'any[]' - | 'datetime[]' + | 'date[]' | 'date_period[]'; -export type FunctionReturnType = - | 'double' - | 'unsigned_long' - | 'long' - | 'integer' - | 'int' - | 'counter_integer' - | 'counter_long' - | 'counter_double' - | 'date' - | 'date_period' - | 'time_duration' - | 'any' - | 'boolean' - | 'text' - | 'keyword' - | 'string' - | 'cartesian_point' - | 'cartesian_shape' - | 'geo_point' - | 'geo_shape' - | 'ip' - | 'version' - | 'void'; +/** + * This is the type of a parameter in a function definition. + */ +export type FunctionParameterType = Omit | ArrayType | 'any'; + +/** + * This is the return type of a function definition. + */ +export type FunctionReturnType = Omit | 'any' | 'void'; export interface FunctionDefinition { type: 'builtin' | 'agg' | 'eval'; diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts index 1c9c82f676087..4446b4e32908d 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -277,7 +277,6 @@ const arrayToSingularMap: Map = ne ['counter_integer[]', 'counter_integer'], ['counter_long[]', 'counter_long'], ['counter_double[]', 'counter_double'], - ['string[]', 'string'], ['keyword[]', 'keyword'], ['text[]', 'text'], ['datetime[]', 'date'], @@ -431,7 +430,7 @@ export function checkFunctionArgMatchesDefinition( return true; } if (arg.type === 'literal') { - const matched = compareLiteralType(argType, arg); + const matched = compareLiteralType(argType as string, arg); return matched; } if (arg.type === 'function') { @@ -457,7 +456,7 @@ export function checkFunctionArgMatchesDefinition( (ct) => ['any', 'null'].includes(ct) || argType === ct || - (ct === 'string' && ['text', 'keyword'].includes(argType)) + (ct === 'string' && ['text', 'keyword'].includes(argType as string)) ); } if (arg.type === 'inlineCast') { diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/variables.ts b/packages/kbn-esql-validation-autocomplete/src/shared/variables.ts index ee1a912c688ea..ca99615f31136 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/variables.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/variables.ts @@ -107,7 +107,7 @@ function addVariableFromAssignment( const rightHandSideArgType = getAssignRightHandSideType(assignOperation.args[1], fields); addToVariableOccurrencies(variables, { name: assignOperation.args[0].name, - type: rightHandSideArgType || 'double' /* fallback to number */, + type: (rightHandSideArgType as string) || 'double' /* fallback to number */, location: assignOperation.args[0].location, }); } diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json index 5be61a8c873a2..84f16cedf03b9 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json +++ b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json @@ -9,56 +9,44 @@ ], "fields": [ { - "name": "doubleField", - "type": "double" - }, - { - "name": "unsignedLongField", - "type": "unsigned_long" - }, - { - "name": "longField", - "type": "long" + "name": "booleanField", + "type": "boolean" }, { - "name": "integerField", - "type": "integer" + "name": "dateField", + "type": "date" }, { - "name": "counterIntegerField", - "type": "counter_integer" + "name": "doubleField", + "type": "double" }, { - "name": "counterLongField", - "type": "counter_long" + "name": "ipField", + "type": "ip" }, { - "name": "counterDoubleField", - "type": "counter_double" + "name": "keywordField", + "type": "keyword" }, { - "name": "dateField", - "type": "date" + "name": "integerField", + "type": "integer" }, { - "name": "datePeriodField", - "type": "date_period" + "name": "longField", + "type": "long" }, { "name": "textField", "type": "text" }, { - "name": "keywordField", - "type": "keyword" - }, - { - "name": "booleanField", - "type": "boolean" + "name": "unsignedLongField", + "type": "unsigned_long" }, { - "name": "ipField", - "type": "ip" + "name": "versionField", + "type": "version" }, { "name": "cartesianPointField", @@ -77,8 +65,16 @@ "type": "geo_shape" }, { - "name": "versionField", - "type": "version" + "name": "counterIntegerField", + "type": "counter_integer" + }, + { + "name": "counterLongField", + "type": "counter_long" + }, + { + "name": "counterDoubleField", + "type": "counter_double" }, { "name": "any#Char$Field", @@ -2323,13 +2319,6 @@ ], "warning": [] }, - { - "query": "from unsupported_index | keep unsupported_field", - "error": [], - "warning": [ - "Field [unsupported_field] cannot be retrieved, it is unsupported or not indexed; returning null" - ] - }, { "query": "FROM index | STATS ROUND(AVG(doubleField * 1.5)), COUNT(*), MIN(doubleField * 10) | KEEP `MIN(doubleField * 10)`", "error": [], @@ -3721,362 +3710,282 @@ "warning": [] }, { - "query": "from a_index | where doubleField IS NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where doubleField IS null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where doubleField is null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where doubleField is NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where doubleField IS NOT NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where doubleField IS NOT null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where doubleField IS not NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where doubleField Is nOt NuLL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where unsignedLongField IS NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where unsignedLongField IS null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where unsignedLongField is null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where unsignedLongField is NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where unsignedLongField IS NOT NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where unsignedLongField IS NOT null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where unsignedLongField IS not NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where unsignedLongField Is nOt NuLL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where longField IS NULL", + "query": "from a_index | where booleanField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where longField IS null", + "query": "from a_index | where booleanField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where longField is null", + "query": "from a_index | where booleanField is null", "error": [], "warning": [] }, { - "query": "from a_index | where longField is NULL", + "query": "from a_index | where booleanField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where longField IS NOT NULL", + "query": "from a_index | where booleanField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where longField IS NOT null", + "query": "from a_index | where booleanField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where longField IS not NULL", + "query": "from a_index | where booleanField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where longField Is nOt NuLL", + "query": "from a_index | where booleanField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | where integerField IS NULL", + "query": "from a_index | where dateField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where integerField IS null", + "query": "from a_index | where dateField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where integerField is null", + "query": "from a_index | where dateField is null", "error": [], "warning": [] }, { - "query": "from a_index | where integerField is NULL", + "query": "from a_index | where dateField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where integerField IS NOT NULL", + "query": "from a_index | where dateField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where integerField IS NOT null", + "query": "from a_index | where dateField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where integerField IS not NULL", + "query": "from a_index | where dateField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where integerField Is nOt NuLL", + "query": "from a_index | where dateField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | where counterIntegerField IS NULL", + "query": "from a_index | where doubleField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterIntegerField IS null", + "query": "from a_index | where doubleField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where counterIntegerField is null", + "query": "from a_index | where doubleField is null", "error": [], "warning": [] }, { - "query": "from a_index | where counterIntegerField is NULL", + "query": "from a_index | where doubleField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterIntegerField IS NOT NULL", + "query": "from a_index | where doubleField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterIntegerField IS NOT null", + "query": "from a_index | where doubleField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where counterIntegerField IS not NULL", + "query": "from a_index | where doubleField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterIntegerField Is nOt NuLL", + "query": "from a_index | where doubleField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | where counterLongField IS NULL", + "query": "from a_index | where ipField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterLongField IS null", + "query": "from a_index | where ipField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where counterLongField is null", + "query": "from a_index | where ipField is null", "error": [], "warning": [] }, { - "query": "from a_index | where counterLongField is NULL", + "query": "from a_index | where ipField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterLongField IS NOT NULL", + "query": "from a_index | where ipField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterLongField IS NOT null", + "query": "from a_index | where ipField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where counterLongField IS not NULL", + "query": "from a_index | where ipField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterLongField Is nOt NuLL", + "query": "from a_index | where ipField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | where counterDoubleField IS NULL", + "query": "from a_index | where keywordField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterDoubleField IS null", + "query": "from a_index | where keywordField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where counterDoubleField is null", + "query": "from a_index | where keywordField is null", "error": [], "warning": [] }, { - "query": "from a_index | where counterDoubleField is NULL", + "query": "from a_index | where keywordField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterDoubleField IS NOT NULL", + "query": "from a_index | where keywordField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterDoubleField IS NOT null", + "query": "from a_index | where keywordField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where counterDoubleField IS not NULL", + "query": "from a_index | where keywordField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where counterDoubleField Is nOt NuLL", + "query": "from a_index | where keywordField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS NULL", + "query": "from a_index | where integerField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS null", + "query": "from a_index | where integerField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where dateField is null", + "query": "from a_index | where integerField is null", "error": [], "warning": [] }, { - "query": "from a_index | where dateField is NULL", + "query": "from a_index | where integerField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS NOT NULL", + "query": "from a_index | where integerField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS NOT null", + "query": "from a_index | where integerField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where dateField IS not NULL", + "query": "from a_index | where integerField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where dateField Is nOt NuLL", + "query": "from a_index | where integerField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | where datePeriodField IS NULL", + "query": "from a_index | where longField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where datePeriodField IS null", + "query": "from a_index | where longField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where datePeriodField is null", + "query": "from a_index | where longField is null", "error": [], "warning": [] }, { - "query": "from a_index | where datePeriodField is NULL", + "query": "from a_index | where longField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where datePeriodField IS NOT NULL", + "query": "from a_index | where longField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where datePeriodField IS NOT null", + "query": "from a_index | where longField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where datePeriodField IS not NULL", + "query": "from a_index | where longField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where datePeriodField Is nOt NuLL", + "query": "from a_index | where longField Is nOt NuLL", "error": [], "warning": [] }, @@ -4121,122 +4030,82 @@ "warning": [] }, { - "query": "from a_index | where keywordField IS NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where keywordField IS null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where keywordField is null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where keywordField is NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where keywordField IS NOT NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where keywordField IS NOT null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where keywordField IS not NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where keywordField Is nOt NuLL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | where booleanField IS NULL", + "query": "from a_index | where unsignedLongField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS null", + "query": "from a_index | where unsignedLongField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField is null", + "query": "from a_index | where unsignedLongField is null", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField is NULL", + "query": "from a_index | where unsignedLongField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS NOT NULL", + "query": "from a_index | where unsignedLongField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS NOT null", + "query": "from a_index | where unsignedLongField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField IS not NULL", + "query": "from a_index | where unsignedLongField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where booleanField Is nOt NuLL", + "query": "from a_index | where unsignedLongField Is nOt NuLL", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS NULL", + "query": "from a_index | where versionField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS null", + "query": "from a_index | where versionField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where ipField is null", + "query": "from a_index | where versionField is null", "error": [], "warning": [] }, { - "query": "from a_index | where ipField is NULL", + "query": "from a_index | where versionField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS NOT NULL", + "query": "from a_index | where versionField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS NOT null", + "query": "from a_index | where versionField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where ipField IS not NULL", + "query": "from a_index | where versionField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where ipField Is nOt NuLL", + "query": "from a_index | where versionField Is nOt NuLL", "error": [], "warning": [] }, @@ -4401,42 +4270,122 @@ "warning": [] }, { - "query": "from a_index | where versionField IS NULL", + "query": "from a_index | where counterIntegerField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS null", + "query": "from a_index | where counterIntegerField IS null", "error": [], "warning": [] }, { - "query": "from a_index | where versionField is null", + "query": "from a_index | where counterIntegerField is null", "error": [], "warning": [] }, { - "query": "from a_index | where versionField is NULL", + "query": "from a_index | where counterIntegerField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS NOT NULL", + "query": "from a_index | where counterIntegerField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS NOT null", + "query": "from a_index | where counterIntegerField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | where versionField IS not NULL", + "query": "from a_index | where counterIntegerField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | where versionField Is nOt NuLL", + "query": "from a_index | where counterIntegerField Is nOt NuLL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterLongField IS NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterLongField IS null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterLongField is null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterLongField is NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterLongField IS NOT NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterLongField IS NOT null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterLongField IS not NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterLongField Is nOt NuLL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterDoubleField IS NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterDoubleField IS null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterDoubleField is null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterDoubleField is NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterDoubleField IS NOT NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterDoubleField IS NOT null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterDoubleField IS not NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | where counterDoubleField Is nOt NuLL", "error": [], "warning": [] }, @@ -4572,317 +4521,247 @@ "warning": [] }, { - "query": "from a_index | eval doubleField IS NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval doubleField IS null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval doubleField is null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval doubleField is NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval doubleField IS NOT NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval doubleField IS NOT null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval doubleField IS not NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval unsignedLongField IS NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval unsignedLongField IS null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval unsignedLongField is null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval unsignedLongField is NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval unsignedLongField IS NOT NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval unsignedLongField IS NOT null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval unsignedLongField IS not NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval longField IS NULL", + "query": "from a_index | eval booleanField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval longField IS null", + "query": "from a_index | eval booleanField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval longField is null", + "query": "from a_index | eval booleanField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval longField is NULL", + "query": "from a_index | eval booleanField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval longField IS NOT NULL", + "query": "from a_index | eval booleanField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval longField IS NOT null", + "query": "from a_index | eval booleanField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval longField IS not NULL", + "query": "from a_index | eval booleanField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval integerField IS NULL", + "query": "from a_index | eval dateField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval integerField IS null", + "query": "from a_index | eval dateField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval integerField is null", + "query": "from a_index | eval dateField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval integerField is NULL", + "query": "from a_index | eval dateField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval integerField IS NOT NULL", + "query": "from a_index | eval dateField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval integerField IS NOT null", + "query": "from a_index | eval dateField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval integerField IS not NULL", + "query": "from a_index | eval dateField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterIntegerField IS NULL", + "query": "from a_index | eval doubleField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterIntegerField IS null", + "query": "from a_index | eval doubleField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterIntegerField is null", + "query": "from a_index | eval doubleField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterIntegerField is NULL", + "query": "from a_index | eval doubleField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterIntegerField IS NOT NULL", + "query": "from a_index | eval doubleField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterIntegerField IS NOT null", + "query": "from a_index | eval doubleField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterIntegerField IS not NULL", + "query": "from a_index | eval doubleField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterLongField IS NULL", + "query": "from a_index | eval ipField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterLongField IS null", + "query": "from a_index | eval ipField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterLongField is null", + "query": "from a_index | eval ipField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterLongField is NULL", + "query": "from a_index | eval ipField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterLongField IS NOT NULL", + "query": "from a_index | eval ipField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterLongField IS NOT null", + "query": "from a_index | eval ipField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterLongField IS not NULL", + "query": "from a_index | eval ipField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterDoubleField IS NULL", + "query": "from a_index | eval keywordField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterDoubleField IS null", + "query": "from a_index | eval keywordField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterDoubleField is null", + "query": "from a_index | eval keywordField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterDoubleField is NULL", + "query": "from a_index | eval keywordField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterDoubleField IS NOT NULL", + "query": "from a_index | eval keywordField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval counterDoubleField IS NOT null", + "query": "from a_index | eval keywordField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval counterDoubleField IS not NULL", + "query": "from a_index | eval keywordField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS NULL", + "query": "from a_index | eval integerField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS null", + "query": "from a_index | eval integerField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField is null", + "query": "from a_index | eval integerField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField is NULL", + "query": "from a_index | eval integerField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS NOT NULL", + "query": "from a_index | eval integerField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS NOT null", + "query": "from a_index | eval integerField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval dateField IS not NULL", + "query": "from a_index | eval integerField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval datePeriodField IS NULL", + "query": "from a_index | eval longField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval datePeriodField IS null", + "query": "from a_index | eval longField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval datePeriodField is null", + "query": "from a_index | eval longField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval datePeriodField is NULL", + "query": "from a_index | eval longField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval datePeriodField IS NOT NULL", + "query": "from a_index | eval longField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval datePeriodField IS NOT null", + "query": "from a_index | eval longField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval datePeriodField IS not NULL", + "query": "from a_index | eval longField IS not NULL", "error": [], "warning": [] }, @@ -4922,107 +4801,72 @@ "warning": [] }, { - "query": "from a_index | eval keywordField IS NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval keywordField IS null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval keywordField is null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval keywordField is NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval keywordField IS NOT NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval keywordField IS NOT null", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval keywordField IS not NULL", - "error": [], - "warning": [] - }, - { - "query": "from a_index | eval booleanField IS NULL", + "query": "from a_index | eval unsignedLongField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS null", + "query": "from a_index | eval unsignedLongField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField is null", + "query": "from a_index | eval unsignedLongField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField is NULL", + "query": "from a_index | eval unsignedLongField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS NOT NULL", + "query": "from a_index | eval unsignedLongField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS NOT null", + "query": "from a_index | eval unsignedLongField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval booleanField IS not NULL", + "query": "from a_index | eval unsignedLongField IS not NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS NULL", + "query": "from a_index | eval versionField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS null", + "query": "from a_index | eval versionField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField is null", + "query": "from a_index | eval versionField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField is NULL", + "query": "from a_index | eval versionField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS NOT NULL", + "query": "from a_index | eval versionField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS NOT null", + "query": "from a_index | eval versionField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval ipField IS not NULL", + "query": "from a_index | eval versionField IS not NULL", "error": [], "warning": [] }, @@ -5167,37 +5011,107 @@ "warning": [] }, { - "query": "from a_index | eval versionField IS NULL", + "query": "from a_index | eval counterIntegerField IS NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS null", + "query": "from a_index | eval counterIntegerField IS null", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField is null", + "query": "from a_index | eval counterIntegerField is null", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField is NULL", + "query": "from a_index | eval counterIntegerField is NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS NOT NULL", + "query": "from a_index | eval counterIntegerField IS NOT NULL", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS NOT null", + "query": "from a_index | eval counterIntegerField IS NOT null", "error": [], "warning": [] }, { - "query": "from a_index | eval versionField IS not NULL", + "query": "from a_index | eval counterIntegerField IS not NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterLongField IS NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterLongField IS null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterLongField is null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterLongField is NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterLongField IS NOT NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterLongField IS NOT null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterLongField IS not NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterDoubleField IS NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterDoubleField IS null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterDoubleField is null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterDoubleField is NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterDoubleField IS NOT NULL", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterDoubleField IS NOT null", + "error": [], + "warning": [] + }, + { + "query": "from a_index | eval counterDoubleField IS not NULL", "error": [], "warning": [] }, @@ -31561,16 +31475,6 @@ "error": [], "warning": [] }, - { - "query": "from a_index | stats var = max(datePeriodField)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats max(datePeriodField)", - "error": [], - "warning": [] - }, { "query": "from a_index | stats var = max(booleanField)", "error": [], @@ -31654,20 +31558,6 @@ ], "warning": [] }, - { - "query": "from a_index | where max(datePeriodField)", - "error": [ - "WHERE does not support function max" - ], - "warning": [] - }, - { - "query": "from a_index | where max(datePeriodField) > 0", - "error": [ - "WHERE does not support function max" - ], - "warning": [] - }, { "query": "from a_index | where max(booleanField)", "error": [ @@ -31808,34 +31698,6 @@ ], "warning": [] }, - { - "query": "from a_index | eval var = max(datePeriodField)", - "error": [ - "EVAL does not support function max" - ], - "warning": [] - }, - { - "query": "from a_index | eval var = max(datePeriodField) > 0", - "error": [ - "EVAL does not support function max" - ], - "warning": [] - }, - { - "query": "from a_index | eval max(datePeriodField)", - "error": [ - "EVAL does not support function max" - ], - "warning": [] - }, - { - "query": "from a_index | eval max(datePeriodField) > 0", - "error": [ - "EVAL does not support function max" - ], - "warning": [] - }, { "query": "from a_index | eval var = max(booleanField)", "error": [ @@ -32197,16 +32059,6 @@ "error": [], "warning": [] }, - { - "query": "from a_index | stats var = min(datePeriodField)", - "error": [], - "warning": [] - }, - { - "query": "from a_index | stats min(datePeriodField)", - "error": [], - "warning": [] - }, { "query": "from a_index | stats var = min(booleanField)", "error": [], @@ -32290,20 +32142,6 @@ ], "warning": [] }, - { - "query": "from a_index | where min(datePeriodField)", - "error": [ - "WHERE does not support function min" - ], - "warning": [] - }, - { - "query": "from a_index | where min(datePeriodField) > 0", - "error": [ - "WHERE does not support function min" - ], - "warning": [] - }, { "query": "from a_index | where min(booleanField)", "error": [ @@ -32444,34 +32282,6 @@ ], "warning": [] }, - { - "query": "from a_index | eval var = min(datePeriodField)", - "error": [ - "EVAL does not support function min" - ], - "warning": [] - }, - { - "query": "from a_index | eval var = min(datePeriodField) > 0", - "error": [ - "EVAL does not support function min" - ], - "warning": [] - }, - { - "query": "from a_index | eval min(datePeriodField)", - "error": [ - "EVAL does not support function min" - ], - "warning": [] - }, - { - "query": "from a_index | eval min(datePeriodField) > 0", - "error": [ - "EVAL does not support function min" - ], - "warning": [] - }, { "query": "from a_index | eval var = min(booleanField)", "error": [ @@ -34459,20 +34269,6 @@ ], "warning": [] }, - { - "query": "from a_index | stats by bucket(dateField, datePeriodField)", - "error": [ - "Argument of [bucket] must be a constant, received [datePeriodField]" - ], - "warning": [] - }, - { - "query": "from a_index | stats by bin(dateField, datePeriodField)", - "error": [ - "Argument of [bin] must be a constant, received [datePeriodField]" - ], - "warning": [] - }, { "query": "from a_index | stats by bucket(dateField, integerField, now(), now())", "error": [ @@ -34997,28 +34793,6 @@ ], "warning": [] }, - { - "query": "from a_index | sort bucket(dateField, datePeriodField)", - "error": [ - "SORT does not support function bucket" - ], - "warning": [] - }, - { - "query": "from a_index | stats bucket(\"2022\", datePeriodField)", - "error": [ - "Argument of [bucket] must be a constant, received [datePeriodField]" - ], - "warning": [] - }, - { - "query": "from a_index | stats bucket(concat(\"20\", \"22\"), datePeriodField)", - "error": [ - "Argument of [bucket] must be [date], found value [concat(\"20\",\"22\")] type [keyword]", - "Argument of [bucket] must be a constant, received [datePeriodField]" - ], - "warning": [] - }, { "query": "from a_index | stats var = percentile(doubleField, doubleField)", "error": [ diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/types.ts b/packages/kbn-esql-validation-autocomplete/src/validation/types.ts index 41a0c9b2dfd6f..f6654540bcf86 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/types.ts @@ -7,6 +7,7 @@ */ import type { ESQLMessage, ESQLLocation } from '@kbn/esql-ast'; +import { FieldType } from '../definitions/types'; import type { EditorError } from '../types'; export interface ESQLVariable { @@ -17,10 +18,9 @@ export interface ESQLVariable { export interface ESQLRealField { name: string; - type: string; + type: FieldType; metadata?: { description?: string; - type?: string; }; } diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index 80b560bd66c4f..5e61c2631d9e1 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -11,7 +11,13 @@ import { writeFile, readFile } from 'fs/promises'; import { ignoreErrorsMap, validateQuery } from './validation'; import { evalFunctionDefinitions } from '../definitions/functions'; import { getFunctionSignatures } from '../definitions/helpers'; -import { FunctionDefinition, SupportedFieldType, supportedFieldTypes } from '../definitions/types'; +import { + FieldType, + FunctionDefinition, + SupportedDataType, + dataTypes, + fieldTypes as _fieldTypes, +} from '../definitions/types'; import { timeUnits, timeUnitsToSuggest } from '../definitions/literals'; import { statsAggregationFunctionDefinitions } from '../definitions/aggs'; import capitalize from 'lodash/capitalize'; @@ -30,6 +36,8 @@ import { import { validationFromCommandTestSuite as runFromTestSuite } from './__tests__/test_suites/validation.command.from'; import { Setup, setup } from './__tests__/helpers'; +const fieldTypes = _fieldTypes.filter((type) => type !== 'unsupported'); + const NESTING_LEVELS = 4; const NESTED_DEPTHS = Array(NESTING_LEVELS) .fill(0) @@ -76,7 +84,7 @@ function getLiteralType(typeString: 'time_literal') { return `1 ${literals[typeString]}`; } -export const fieldNameFromType = (type: SupportedFieldType) => `${camelCase(type)}Field`; +export const fieldNameFromType = (type: FieldType) => `${camelCase(type)}Field`; function getFieldName( typeString: string, @@ -127,8 +135,8 @@ function getFieldMapping( date: 'now()', }; return params.map(({ name: _name, type, constantOnly, literalOptions, ...rest }) => { - const typeString: string = type; - if (supportedFieldTypes.includes(typeString as SupportedFieldType)) { + const typeString: string = type as string; + if (dataTypes.includes(typeString as SupportedDataType)) { if (useLiterals && literalOptions) { return { name: `"${literalOptions[0]}"`, @@ -541,13 +549,6 @@ describe('validation logic', () => { testErrorsAndWarnings('from index | keep m*', ['Unknown column [m*]']); testErrorsAndWarnings('from index | keep *m', ['Unknown column [*m]']); testErrorsAndWarnings('from index | keep d*m', ['Unknown column [d*m]']); - testErrorsAndWarnings( - 'from unsupported_index | keep unsupported_field', - [], - [ - 'Field [unsupported_field] cannot be retrieved, it is unsupported or not indexed; returning null', - ] - ); testErrorsAndWarnings( `FROM index | STATS ROUND(AVG(doubleField * 1.5)), COUNT(*), MIN(doubleField * 10) | KEEP \`MIN(doubleField * 10)\``, @@ -874,7 +875,7 @@ describe('validation logic', () => { [] ); - for (const field of supportedFieldTypes) { + for (const field of fieldTypes) { testErrorsAndWarnings(`from a_index | where ${fieldNameFromType(field)} IS NULL`, []); testErrorsAndWarnings(`from a_index | where ${fieldNameFromType(field)} IS null`, []); testErrorsAndWarnings(`from a_index | where ${fieldNameFromType(field)} is null`, []); @@ -937,7 +938,7 @@ describe('validation logic', () => { testErrorsAndWarnings('from a_index | eval a=["a", "b"]', []); testErrorsAndWarnings('from a_index | eval a=null', []); - for (const field of supportedFieldTypes) { + for (const field of fieldTypes) { testErrorsAndWarnings(`from a_index | eval ${fieldNameFromType(field)} IS NULL`, []); testErrorsAndWarnings(`from a_index | eval ${fieldNameFromType(field)} IS null`, []); testErrorsAndWarnings(`from a_index | eval ${fieldNameFromType(field)} is null`, []); @@ -12110,8 +12111,6 @@ describe('validation logic', () => { testErrorsAndWarnings('from a_index | stats var = max(dateField)', []); testErrorsAndWarnings('from a_index | stats max(dateField)', []); - testErrorsAndWarnings('from a_index | stats var = max(datePeriodField)', []); - testErrorsAndWarnings('from a_index | stats max(datePeriodField)', []); testErrorsAndWarnings('from a_index | stats var = max(booleanField)', []); testErrorsAndWarnings('from a_index | stats max(booleanField)', []); testErrorsAndWarnings('from a_index | stats var = max(ipField)', []); @@ -12153,14 +12152,6 @@ describe('validation logic', () => { 'WHERE does not support function max', ]); - testErrorsAndWarnings('from a_index | where max(datePeriodField)', [ - 'WHERE does not support function max', - ]); - - testErrorsAndWarnings('from a_index | where max(datePeriodField) > 0', [ - 'WHERE does not support function max', - ]); - testErrorsAndWarnings('from a_index | where max(booleanField)', [ 'WHERE does not support function max', ]); @@ -12240,23 +12231,6 @@ describe('validation logic', () => { testErrorsAndWarnings('from a_index | eval max(dateField) > 0', [ 'EVAL does not support function max', ]); - - testErrorsAndWarnings('from a_index | eval var = max(datePeriodField)', [ - 'EVAL does not support function max', - ]); - - testErrorsAndWarnings('from a_index | eval var = max(datePeriodField) > 0', [ - 'EVAL does not support function max', - ]); - - testErrorsAndWarnings('from a_index | eval max(datePeriodField)', [ - 'EVAL does not support function max', - ]); - - testErrorsAndWarnings('from a_index | eval max(datePeriodField) > 0', [ - 'EVAL does not support function max', - ]); - testErrorsAndWarnings('from a_index | eval var = max(booleanField)', [ 'EVAL does not support function max', ]); @@ -12459,8 +12433,6 @@ describe('validation logic', () => { testErrorsAndWarnings('from a_index | stats var = min(dateField)', []); testErrorsAndWarnings('from a_index | stats min(dateField)', []); - testErrorsAndWarnings('from a_index | stats var = min(datePeriodField)', []); - testErrorsAndWarnings('from a_index | stats min(datePeriodField)', []); testErrorsAndWarnings('from a_index | stats var = min(booleanField)', []); testErrorsAndWarnings('from a_index | stats min(booleanField)', []); testErrorsAndWarnings('from a_index | stats var = min(ipField)', []); @@ -12501,15 +12473,6 @@ describe('validation logic', () => { testErrorsAndWarnings('from a_index | where min(dateField) > 0', [ 'WHERE does not support function min', ]); - - testErrorsAndWarnings('from a_index | where min(datePeriodField)', [ - 'WHERE does not support function min', - ]); - - testErrorsAndWarnings('from a_index | where min(datePeriodField) > 0', [ - 'WHERE does not support function min', - ]); - testErrorsAndWarnings('from a_index | where min(booleanField)', [ 'WHERE does not support function min', ]); @@ -12590,22 +12553,6 @@ describe('validation logic', () => { 'EVAL does not support function min', ]); - testErrorsAndWarnings('from a_index | eval var = min(datePeriodField)', [ - 'EVAL does not support function min', - ]); - - testErrorsAndWarnings('from a_index | eval var = min(datePeriodField) > 0', [ - 'EVAL does not support function min', - ]); - - testErrorsAndWarnings('from a_index | eval min(datePeriodField)', [ - 'EVAL does not support function min', - ]); - - testErrorsAndWarnings('from a_index | eval min(datePeriodField) > 0', [ - 'EVAL does not support function min', - ]); - testErrorsAndWarnings('from a_index | eval var = min(booleanField)', [ 'EVAL does not support function min', ]); @@ -14101,14 +14048,6 @@ describe('validation logic', () => { ] ); - testErrorsAndWarnings('from a_index | stats by bucket(dateField, datePeriodField)', [ - 'Argument of [bucket] must be a constant, received [datePeriodField]', - ]); - - testErrorsAndWarnings('from a_index | stats by bin(dateField, datePeriodField)', [ - 'Argument of [bin] must be a constant, received [datePeriodField]', - ]); - testErrorsAndWarnings( 'from a_index | stats by bucket(dateField, integerField, now(), now())', ['Argument of [bucket] must be a constant, received [integerField]'] @@ -14610,18 +14549,6 @@ describe('validation logic', () => { 'Argument of [bin] must be a constant, received [longField]', ] ); - - testErrorsAndWarnings('from a_index | sort bucket(dateField, datePeriodField)', [ - 'SORT does not support function bucket', - ]); - - testErrorsAndWarnings('from a_index | stats bucket("2022", datePeriodField)', [ - 'Argument of [bucket] must be a constant, received [datePeriodField]', - ]); - testErrorsAndWarnings('from a_index | stats bucket(concat("20", "22"), datePeriodField)', [ - 'Argument of [bucket] must be [date], found value [concat("20","22")] type [keyword]', - 'Argument of [bucket] must be a constant, received [datePeriodField]', - ]); }); describe('percentile', () => { diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index 6cc515dc4ac74..a21c306d5d12e 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -111,7 +111,7 @@ function validateFunctionLiteralArg( messageId: 'wrongArgumentType', values: { name: astFunction.name, - argType: argDef.type, + argType: argDef.type as string, value: typeof actualArg.value === 'number' ? actualArg.value : String(actualArg.value), givenType: actualArg.literalType, }, @@ -139,7 +139,7 @@ function validateFunctionLiteralArg( messageId: 'wrongArgumentType', values: { name: astFunction.name, - argType: argDef.type, + argType: argDef.type as string, value: actualArg.name, givenType: 'duration', }, @@ -169,7 +169,7 @@ function validateInlineCastArg( messageId: 'wrongArgumentType', values: { name: astFunction.name, - argType: parameterDefinition.type, + argType: parameterDefinition.type as string, value: arg.text, givenType: arg.castType, }, @@ -206,7 +206,7 @@ function validateNestedFunctionArg( messages.push( getMessageFromId({ messageId: 'noNestedArgumentSupport', - values: { name: actualArg.text, argType: argFn.signatures[0].returnType }, + values: { name: actualArg.text, argType: argFn.signatures[0].returnType as string }, locations: actualArg.location, }) ); @@ -219,9 +219,9 @@ function validateNestedFunctionArg( messageId: 'wrongArgumentType', values: { name: astFunction.name, - argType: parameterDefinition.type, + argType: parameterDefinition.type as string, value: actualArg.text, - givenType: argFn.signatures[0].returnType, + givenType: argFn.signatures[0].returnType as string, }, locations: actualArg.location, }) @@ -301,7 +301,7 @@ function validateFunctionColumnArg( messageId: 'wrongArgumentType', values: { name: astFunction.name, - argType: parameterDefinition.type, + argType: parameterDefinition.type as string, value: actualArg.name, givenType: columnHit!.type, }, @@ -534,14 +534,14 @@ function validateFunction( }); }); - const shouldCollapseMessages = isArrayType(argDef.type) && hasMultipleElements; + const shouldCollapseMessages = isArrayType(argDef.type as string) && hasMultipleElements; failingSignature.push( ...(shouldCollapseMessages ? collapseWrongArgumentTypeMessages( messagesFromAllArgElements, outerArg, astFunction.name, - argDef.type, + argDef.type as string, parentCommand, references ) @@ -1076,15 +1076,17 @@ function validateUnsupportedTypeFields(fields: Map) { const messages: ESQLMessage[] = []; for (const field of fields.values()) { if (field.type === 'unsupported') { - messages.push( - getMessageFromId({ - messageId: 'unsupportedFieldType', - values: { - field: field.name, - }, - locations: { min: 1, max: 1 }, - }) - ); + // Removed temporarily to supress all these warnings + // Issue to re-enable in a better way: https://github.com/elastic/kibana/issues/189666 + // messages.push( + // getMessageFromId({ + // messageId: 'unsupportedFieldType', + // values: { + // field: field.name, + // }, + // locations: { min: 1, max: 1 }, + // }) + // ); } } return messages; diff --git a/packages/kbn-monaco/src/esql/lib/hover/hover.test.ts b/packages/kbn-monaco/src/esql/lib/hover/hover.test.ts index 141653c2b2cf6..d49fb150d7c12 100644 --- a/packages/kbn-monaco/src/esql/lib/hover/hover.test.ts +++ b/packages/kbn-monaco/src/esql/lib/hover/hover.test.ts @@ -11,17 +11,21 @@ import { getHoverItem } from './hover'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; import { ENRICH_MODES, + ESQLRealField, getFunctionDefinition, getFunctionSignatures, } from '@kbn/esql-validation-autocomplete'; +import { FieldType } from '@kbn/esql-validation-autocomplete/src/definitions/types'; -const fields: Array<{ name: string; type: string; suggestedAs?: string }> = [ - ...['string', 'number', 'date', 'boolean', 'ip'].map((type) => ({ +const types: FieldType[] = ['keyword', 'double', 'date', 'boolean', 'ip']; + +const fields: Array = [ + ...types.map((type) => ({ name: `${type}Field`, type, })), - { name: 'any#Char$Field', type: 'number', suggestedAs: '`any#Char$Field`' }, - { name: 'kubernetes.something.something', type: 'number' }, + { name: 'any#Char$Field', type: 'double', suggestedAs: '`any#Char$Field`' }, + { name: 'kubernetes.something.something', type: 'double' }, ]; const indexes = ( @@ -56,7 +60,7 @@ const policies = [ ]; function createCustomCallbackMocks( - customFields: Array<{ name: string; type: string }> | undefined, + customFields: ESQLRealField[] | undefined, customSources: Array<{ name: string; hidden: boolean }> | undefined, customPolicies: | Array<{ diff --git a/packages/kbn-text-based-editor/src/ecs_metadata_helper.test.ts b/packages/kbn-text-based-editor/src/ecs_metadata_helper.test.ts index 4cfebe1597607..511d14d2da3f0 100644 --- a/packages/kbn-text-based-editor/src/ecs_metadata_helper.test.ts +++ b/packages/kbn-text-based-editor/src/ecs_metadata_helper.test.ts @@ -7,15 +7,15 @@ */ import { getColumnsWithMetadata } from './ecs_metadata_helper'; -import type { DatatableColumnType } from '@kbn/expressions-plugin/common'; import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; +import { ESQLRealField } from '@kbn/esql-validation-autocomplete'; describe('getColumnsWithMetadata', () => { it('should return original columns if fieldsMetadata is not provided', async () => { - const columns = [ - { name: 'ecs.version', type: 'keyword' as DatatableColumnType }, - { name: 'field1', type: 'text' as DatatableColumnType }, - { name: 'field2', type: 'double' as DatatableColumnType }, + const columns: ESQLRealField[] = [ + { name: 'ecs.version', type: 'keyword' }, + { name: 'field1', type: 'text' }, + { name: 'field2', type: 'double' }, ]; const result = await getColumnsWithMetadata(columns); @@ -23,10 +23,10 @@ describe('getColumnsWithMetadata', () => { }); it('should return columns with metadata if both name and type match with ECS fields', async () => { - const columns = [ - { name: 'ecs.field', type: 'text' as DatatableColumnType }, - { name: 'ecs.fakeBooleanField', type: 'boolean' as DatatableColumnType }, - { name: 'field2', type: 'double' as DatatableColumnType }, + const columns: ESQLRealField[] = [ + { name: 'ecs.field', type: 'text' }, + { name: 'ecs.fakeBooleanField', type: 'boolean' }, + { name: 'field2', type: 'double' }, ]; const fieldsMetadata = { getClient: jest.fn().mockResolvedValue({ @@ -57,10 +57,10 @@ describe('getColumnsWithMetadata', () => { }); it('should handle keyword suffix correctly', async () => { - const columns = [ - { name: 'ecs.version', type: 'keyword' as DatatableColumnType }, - { name: 'ecs.version.keyword', type: 'keyword' as DatatableColumnType }, - { name: 'field2', type: 'double' as DatatableColumnType }, + const columns: ESQLRealField[] = [ + { name: 'ecs.version', type: 'keyword' }, + { name: 'ecs.version.keyword', type: 'keyword' }, + { name: 'field2', type: 'double' }, ]; const fieldsMetadata = { getClient: jest.fn().mockResolvedValue({ diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index e67ffeac3c177..326dc471a86c1 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -29,6 +29,8 @@ import memoize from 'lodash/memoize'; import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { css } from '@emotion/react'; +import { ESQLRealField } from '@kbn/esql-validation-autocomplete'; +import { FieldType } from '@kbn/esql-validation-autocomplete/src/definitions/types'; import { EditorFooter } from './editor_footer'; import { fetchFieldsFromESQL } from './fetch_fields_from_esql'; import { @@ -322,13 +324,12 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ undefined, abortController ).result; - const columns = + const columns: ESQLRealField[] = table?.columns.map((c) => { - // Casting unsupported as unknown to avoid plethora of warnings - // Remove when addressed https://github.com/elastic/kibana/issues/189666 - if (!c.meta.esType || c.meta.esType === 'unsupported') - return { name: c.name, type: 'unknown' }; - return { name: c.name, type: c.meta.esType }; + return { + name: c.name, + type: c.meta.esType as FieldType, + }; }) || []; return await getRateLimitedColumnsWithMetadata(columns, fieldsMetadata); } catch (e) { diff --git a/test/api_integration/apis/esql/errors.ts b/test/api_integration/apis/esql/errors.ts index 193d48c478209..bf2d7e2139a91 100644 --- a/test/api_integration/apis/esql/errors.ts +++ b/test/api_integration/apis/esql/errors.ts @@ -189,7 +189,12 @@ export default function ({ getService }: FtrProviderContext) { const fieldsExcludingCounterType = config.fields.filter( // ES|QL supports counter_integer, counter_long, counter_double, date_period, etc. // but they are not types suitable for Elasticsearch indices - (c: { type: string }) => !c.type.startsWith('counter_') && c.type !== 'date_period' + (c: { type: string }) => + !c.type.startsWith('counter_') && + c.type !== 'date_period' && + c.type !== 'time_duration' && + c.type !== 'null' && + c.type !== 'time_literal' ); await es.indices.create( createIndexRequest(