mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[ES|QL] Remove command option definitions (#215425)](https://github.com/elastic/kibana/pull/215425) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Drew Tate","email":"drew.tate@elastic.co"},"sourceCommit":{"committedDate":"2025-03-21T11:04:33Z","message":"[ES|QL] Remove command option definitions (#215425)\n\n## Summary\n\nThis PR removes the declarative objects that were meant to describe the\nbehavior of \"options\" (see details section below if you don't know what\nI'm talking about). **It does not remove \"options\" as a concept from our\nAST.** \"Option\" is probably the wrong name for the subcommands in the\nAST but, at the moment, it is working fine how it is.\n\nHere is a list of what these definitions were being used for and where I\nended up.\n\n| Use | How it worked | What I did |\n\n|---------------------------------------------------------------------|---------------|------------|\n| To generate command declarations for display in suggestions menu | It\nhad some complex logic to try to construct a declaration string from the\ninformation in the `signature` property | I replaced this with\nstatically declared declaration strings on the command definitions. I\ntook most of them directly from our docs. They are a better result than\nthe autogenerated stuff |\n| To build the `METADATA` suggestion | the definition was passed into\n`buildOptionDefinition` | I declared the `METADATA` suggestion\nstatically in the `FROM` autocomplete code. |\n| To check for field correctness in `METADATA` | This logic lived in the\noption definition's `validate` method | I moved it to the `FROM`\ncommand's validate method |\n| To validate the type of the value assigned to `APPEND_SEPARATOR` in\n`DISSECT` | This logic lived in the option definition's `validate`\nmethod | I moved it to the `DISSECT` command's validate method |\n| To check if the left side of the equals sign in `DISSECT` is\n\"APPEND_SEPARATOR | In most cases, the parser catches stuff like this,\nbut for some reason `DISSECT`'s grammar is very loose so we have been\nstepping in with our own validation (maybe we should suggest changing\nthis). This was the only case that was triggering the \"Unknown option\"\nmessage. | I moved it to the `DISSECT` command's validate method |\n| To prevent default column validation for `METADATA` | This was the\nonly true use of the `skipCommonValidation` property which would prevent\nthe validator trying to find metadata fields in the standard field list\n| I inserted an option name check directly into the validation code.\nIt's not a good long-term solution, but it is actually an improvement\nsince the former code pretended to be general but was actually just for\n`METADATA`. At least now it is clear what the exception is for. |\n| To filter functions and operators that are available after `BY` |\nFunction definitions sometimes declare that they are supported in a `by`\nstatement. The validator checks if the function does. | This didn't\nchange. The option nodes in the AST are still there and we are still\nrelying on the `supportedCommands` and `supportedOptions` properties in\nthe function definitions. |\n\n#### Pictures\n\n<img width=\"859\" alt=\"Screenshot 2025-03-20 at 1 47 36 PM\"\nsrc=\"https://github.com/user-attachments/assets/3bd3c3c6-6066-466e-b33b-9444ab58670a\"\n/>\n\n_New, statically-defined declarations_\n\n<img width=\"783\" alt=\"Screenshot 2025-03-20 at 2 12 28 PM\"\nsrc=\"https://github.com/user-attachments/assets/94550b25-5da9-4c82-9586-11b3515debd7\"\n/>\n\n_In cases besides `APPEND_SEPARATOR`, incorrect keywords produce syntax\nerrors._\n\n<img width=\"700\" alt=\"Screenshot 2025-03-20 at 2 09 05 PM\"\nsrc=\"https://github.com/user-attachments/assets/de1a23f4-2509-4c6e-84ec-a807e96b65a5\"\n/>\n\n_Didn't break the `APPEND_SEPARATOR` datatype validation_\n\n<img width=\"791\" alt=\"Screenshot 2025-03-20 at 2 03 28 PM\"\nsrc=\"https://github.com/user-attachments/assets/169aaa15-52f3-4d22-ab77-26a560cd9359\"\n/>\n\n_Didn't break `METADATA` fields validation_\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n\n### Background/details\n\nTill now, \"options\" have been a concept in our code. Their definition\nisn't clear, but it essentially comes down to any capitalized keyword\nafter the command name. For example `STATS... >BY<`, `DISSECT...\n>APPEND_SEPARATOR<`. You could think of them as roughly subcommands or\nsubstatements.\n\nThere was a hope that commands would be uniform enough that these\n\"options\" would deserve to be their own special first-class citizen. But\nthey break conceptually...\n\nFor example `APPEND_SEPARATOR` is not a keyword with an expression after\nit... it is a variable `APPEND_SEPARATOR=\":\"`... or filtering in\nstats.... `STATS AVG(bytes) >WHERE<` .... so is WHERE an option now?\n\n`FORK` will break this even further.\n\nSo, we are moving the architecture to allow for complexity and variance\namong the commands. Command-specific logic will have the final say in\nhow autocomplete and validation work for anything with that command.","sha":"b7854a8759ca91255fe318c8d7a33b91996bf990","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Feature:ES|QL","Team:ESQL","backport:version","v9.1.0","v8.19.0"],"title":"[ES|QL] Remove command option definitions","number":215425,"url":"https://github.com/elastic/kibana/pull/215425","mergeCommit":{"message":"[ES|QL] Remove command option definitions (#215425)\n\n## Summary\n\nThis PR removes the declarative objects that were meant to describe the\nbehavior of \"options\" (see details section below if you don't know what\nI'm talking about). **It does not remove \"options\" as a concept from our\nAST.** \"Option\" is probably the wrong name for the subcommands in the\nAST but, at the moment, it is working fine how it is.\n\nHere is a list of what these definitions were being used for and where I\nended up.\n\n| Use | How it worked | What I did |\n\n|---------------------------------------------------------------------|---------------|------------|\n| To generate command declarations for display in suggestions menu | It\nhad some complex logic to try to construct a declaration string from the\ninformation in the `signature` property | I replaced this with\nstatically declared declaration strings on the command definitions. I\ntook most of them directly from our docs. They are a better result than\nthe autogenerated stuff |\n| To build the `METADATA` suggestion | the definition was passed into\n`buildOptionDefinition` | I declared the `METADATA` suggestion\nstatically in the `FROM` autocomplete code. |\n| To check for field correctness in `METADATA` | This logic lived in the\noption definition's `validate` method | I moved it to the `FROM`\ncommand's validate method |\n| To validate the type of the value assigned to `APPEND_SEPARATOR` in\n`DISSECT` | This logic lived in the option definition's `validate`\nmethod | I moved it to the `DISSECT` command's validate method |\n| To check if the left side of the equals sign in `DISSECT` is\n\"APPEND_SEPARATOR | In most cases, the parser catches stuff like this,\nbut for some reason `DISSECT`'s grammar is very loose so we have been\nstepping in with our own validation (maybe we should suggest changing\nthis). This was the only case that was triggering the \"Unknown option\"\nmessage. | I moved it to the `DISSECT` command's validate method |\n| To prevent default column validation for `METADATA` | This was the\nonly true use of the `skipCommonValidation` property which would prevent\nthe validator trying to find metadata fields in the standard field list\n| I inserted an option name check directly into the validation code.\nIt's not a good long-term solution, but it is actually an improvement\nsince the former code pretended to be general but was actually just for\n`METADATA`. At least now it is clear what the exception is for. |\n| To filter functions and operators that are available after `BY` |\nFunction definitions sometimes declare that they are supported in a `by`\nstatement. The validator checks if the function does. | This didn't\nchange. The option nodes in the AST are still there and we are still\nrelying on the `supportedCommands` and `supportedOptions` properties in\nthe function definitions. |\n\n#### Pictures\n\n<img width=\"859\" alt=\"Screenshot 2025-03-20 at 1 47 36 PM\"\nsrc=\"https://github.com/user-attachments/assets/3bd3c3c6-6066-466e-b33b-9444ab58670a\"\n/>\n\n_New, statically-defined declarations_\n\n<img width=\"783\" alt=\"Screenshot 2025-03-20 at 2 12 28 PM\"\nsrc=\"https://github.com/user-attachments/assets/94550b25-5da9-4c82-9586-11b3515debd7\"\n/>\n\n_In cases besides `APPEND_SEPARATOR`, incorrect keywords produce syntax\nerrors._\n\n<img width=\"700\" alt=\"Screenshot 2025-03-20 at 2 09 05 PM\"\nsrc=\"https://github.com/user-attachments/assets/de1a23f4-2509-4c6e-84ec-a807e96b65a5\"\n/>\n\n_Didn't break the `APPEND_SEPARATOR` datatype validation_\n\n<img width=\"791\" alt=\"Screenshot 2025-03-20 at 2 03 28 PM\"\nsrc=\"https://github.com/user-attachments/assets/169aaa15-52f3-4d22-ab77-26a560cd9359\"\n/>\n\n_Didn't break `METADATA` fields validation_\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n\n### Background/details\n\nTill now, \"options\" have been a concept in our code. Their definition\nisn't clear, but it essentially comes down to any capitalized keyword\nafter the command name. For example `STATS... >BY<`, `DISSECT...\n>APPEND_SEPARATOR<`. You could think of them as roughly subcommands or\nsubstatements.\n\nThere was a hope that commands would be uniform enough that these\n\"options\" would deserve to be their own special first-class citizen. But\nthey break conceptually...\n\nFor example `APPEND_SEPARATOR` is not a keyword with an expression after\nit... it is a variable `APPEND_SEPARATOR=\":\"`... or filtering in\nstats.... `STATS AVG(bytes) >WHERE<` .... so is WHERE an option now?\n\n`FORK` will break this even further.\n\nSo, we are moving the architecture to allow for complexity and variance\namong the commands. Command-specific logic will have the final say in\nhow autocomplete and validation work for anything with that command.","sha":"b7854a8759ca91255fe318c8d7a33b91996bf990"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/215425","number":215425,"mergeCommit":{"message":"[ES|QL] Remove command option definitions (#215425)\n\n## Summary\n\nThis PR removes the declarative objects that were meant to describe the\nbehavior of \"options\" (see details section below if you don't know what\nI'm talking about). **It does not remove \"options\" as a concept from our\nAST.** \"Option\" is probably the wrong name for the subcommands in the\nAST but, at the moment, it is working fine how it is.\n\nHere is a list of what these definitions were being used for and where I\nended up.\n\n| Use | How it worked | What I did |\n\n|---------------------------------------------------------------------|---------------|------------|\n| To generate command declarations for display in suggestions menu | It\nhad some complex logic to try to construct a declaration string from the\ninformation in the `signature` property | I replaced this with\nstatically declared declaration strings on the command definitions. I\ntook most of them directly from our docs. They are a better result than\nthe autogenerated stuff |\n| To build the `METADATA` suggestion | the definition was passed into\n`buildOptionDefinition` | I declared the `METADATA` suggestion\nstatically in the `FROM` autocomplete code. |\n| To check for field correctness in `METADATA` | This logic lived in the\noption definition's `validate` method | I moved it to the `FROM`\ncommand's validate method |\n| To validate the type of the value assigned to `APPEND_SEPARATOR` in\n`DISSECT` | This logic lived in the option definition's `validate`\nmethod | I moved it to the `DISSECT` command's validate method |\n| To check if the left side of the equals sign in `DISSECT` is\n\"APPEND_SEPARATOR | In most cases, the parser catches stuff like this,\nbut for some reason `DISSECT`'s grammar is very loose so we have been\nstepping in with our own validation (maybe we should suggest changing\nthis). This was the only case that was triggering the \"Unknown option\"\nmessage. | I moved it to the `DISSECT` command's validate method |\n| To prevent default column validation for `METADATA` | This was the\nonly true use of the `skipCommonValidation` property which would prevent\nthe validator trying to find metadata fields in the standard field list\n| I inserted an option name check directly into the validation code.\nIt's not a good long-term solution, but it is actually an improvement\nsince the former code pretended to be general but was actually just for\n`METADATA`. At least now it is clear what the exception is for. |\n| To filter functions and operators that are available after `BY` |\nFunction definitions sometimes declare that they are supported in a `by`\nstatement. The validator checks if the function does. | This didn't\nchange. The option nodes in the AST are still there and we are still\nrelying on the `supportedCommands` and `supportedOptions` properties in\nthe function definitions. |\n\n#### Pictures\n\n<img width=\"859\" alt=\"Screenshot 2025-03-20 at 1 47 36 PM\"\nsrc=\"https://github.com/user-attachments/assets/3bd3c3c6-6066-466e-b33b-9444ab58670a\"\n/>\n\n_New, statically-defined declarations_\n\n<img width=\"783\" alt=\"Screenshot 2025-03-20 at 2 12 28 PM\"\nsrc=\"https://github.com/user-attachments/assets/94550b25-5da9-4c82-9586-11b3515debd7\"\n/>\n\n_In cases besides `APPEND_SEPARATOR`, incorrect keywords produce syntax\nerrors._\n\n<img width=\"700\" alt=\"Screenshot 2025-03-20 at 2 09 05 PM\"\nsrc=\"https://github.com/user-attachments/assets/de1a23f4-2509-4c6e-84ec-a807e96b65a5\"\n/>\n\n_Didn't break the `APPEND_SEPARATOR` datatype validation_\n\n<img width=\"791\" alt=\"Screenshot 2025-03-20 at 2 03 28 PM\"\nsrc=\"https://github.com/user-attachments/assets/169aaa15-52f3-4d22-ab77-26a560cd9359\"\n/>\n\n_Didn't break `METADATA` fields validation_\n\n### Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers should verify this PR satisfies this list as well.\n\n- [x] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [x]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n\n### Background/details\n\nTill now, \"options\" have been a concept in our code. Their definition\nisn't clear, but it essentially comes down to any capitalized keyword\nafter the command name. For example `STATS... >BY<`, `DISSECT...\n>APPEND_SEPARATOR<`. You could think of them as roughly subcommands or\nsubstatements.\n\nThere was a hope that commands would be uniform enough that these\n\"options\" would deserve to be their own special first-class citizen. But\nthey break conceptually...\n\nFor example `APPEND_SEPARATOR` is not a keyword with an expression after\nit... it is a variable `APPEND_SEPARATOR=\":\"`... or filtering in\nstats.... `STATS AVG(bytes) >WHERE<` .... so is WHERE an option now?\n\n`FORK` will break this even further.\n\nSo, we are moving the architecture to allow for complexity and variance\namong the commands. Command-specific logic will have the final say in\nhow autocomplete and validation work for anything with that command.","sha":"b7854a8759ca91255fe318c8d7a33b91996bf990"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
This commit is contained in:
parent
95782f6d3a
commit
315e9b19ca
19 changed files with 213 additions and 429 deletions
|
@ -8,12 +8,7 @@
|
|||
*/
|
||||
|
||||
export type { SuggestionRawDefinition, ItemKind } from './src/autocomplete/types';
|
||||
export type {
|
||||
FunctionDefinition,
|
||||
CommandDefinition,
|
||||
CommandOptionsDefinition,
|
||||
Literals,
|
||||
} from './src/definitions/types';
|
||||
export type { FunctionDefinition, CommandDefinition, Literals } from './src/definitions/types';
|
||||
export type { ESQLCallbacks } from './src/shared/types';
|
||||
|
||||
/**
|
||||
|
@ -44,7 +39,6 @@ export {
|
|||
getFunctionDefinition,
|
||||
getCommandDefinition,
|
||||
getAllCommands,
|
||||
getCommandOption,
|
||||
getColumnForASTNode as lookupColumn,
|
||||
shouldBeQuotedText,
|
||||
printFunctionSignature,
|
||||
|
|
|
@ -77,7 +77,7 @@ describe('autocomplete.suggest', () => {
|
|||
});
|
||||
const { assertSuggestions } = await setup();
|
||||
const expected = [
|
||||
'METADATA $0',
|
||||
'METADATA ',
|
||||
',',
|
||||
'| ',
|
||||
...recommendedQueries.map((query) => query.queryString),
|
||||
|
@ -89,7 +89,7 @@ describe('autocomplete.suggest', () => {
|
|||
test('partially-typed METADATA keyword', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
|
||||
assertSuggestions('FROM index1 MET/', ['METADATA $0']);
|
||||
assertSuggestions('FROM index1 MET/', ['METADATA ']);
|
||||
});
|
||||
|
||||
test('not before first index', async () => {
|
||||
|
|
|
@ -319,7 +319,7 @@ describe('autocomplete', () => {
|
|||
|
||||
// FROM source METADATA
|
||||
recommendedQuerySuggestions = getRecommendedQueriesSuggestions('', 'dateField');
|
||||
testSuggestions('FROM index1 M/', ['METADATA $0']);
|
||||
testSuggestions('FROM index1 M/', ['METADATA ']);
|
||||
|
||||
// FROM source METADATA field
|
||||
testSuggestions('FROM index1 METADATA _/', METADATA_FIELDS);
|
||||
|
@ -570,7 +570,7 @@ describe('autocomplete', () => {
|
|||
testSuggestions('FROM a /', [
|
||||
attachTriggerCommand('| '),
|
||||
',',
|
||||
attachAsSnippet(attachTriggerCommand('METADATA $0')),
|
||||
attachTriggerCommand('METADATA '),
|
||||
...recommendedQuerySuggestions.map((q) => q.queryString),
|
||||
]);
|
||||
|
||||
|
@ -675,7 +675,6 @@ describe('autocomplete', () => {
|
|||
{
|
||||
text: 'foo$bar METADATA ',
|
||||
filterText: 'foo$bar',
|
||||
asSnippet: false, // important because the text includes "$"
|
||||
command: TRIGGER_SUGGESTION_COMMAND,
|
||||
rangeToReplace: { start: 6, end: 13 },
|
||||
},
|
||||
|
@ -708,7 +707,7 @@ describe('autocomplete', () => {
|
|||
|
||||
recommendedQuerySuggestions = getRecommendedQueriesSuggestions('', 'dateField');
|
||||
// FROM source METADATA
|
||||
testSuggestions('FROM index1 M/', [attachAsSnippet(attachTriggerCommand('METADATA $0'))]);
|
||||
testSuggestions('FROM index1 M/', [attachTriggerCommand('METADATA ')]);
|
||||
|
||||
describe('ENRICH', () => {
|
||||
testSuggestions(
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
*/
|
||||
|
||||
import { ESQLCommandOption } from '@kbn/esql-ast';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { isMarkerNode } from '../../../shared/context';
|
||||
import { metadataOption } from '../../../definitions/options';
|
||||
import type { SuggestionRawDefinition } from '../../types';
|
||||
import { getOverlapRange, handleFragment, removeQuoteForSuggestedSources } from '../../helper';
|
||||
import { CommandSuggestParams } from '../../../definitions/types';
|
||||
|
@ -23,7 +23,6 @@ import {
|
|||
import {
|
||||
TRIGGER_SUGGESTION_COMMAND,
|
||||
buildFieldsDefinitions,
|
||||
buildOptionDefinition,
|
||||
buildSourcesDefinitions,
|
||||
} from '../../factories';
|
||||
import { ESQLSourceResult } from '../../../shared/types';
|
||||
|
@ -70,7 +69,7 @@ export async function suggest({
|
|||
}
|
||||
// FROM something /
|
||||
else if (indexes.length > 0 && /\s$/.test(innerText) && !isRestartingExpression(innerText)) {
|
||||
suggestions.push(buildOptionDefinition(metadataOption));
|
||||
suggestions.push(metadataSuggestion);
|
||||
suggestions.push(commaCompleteItem);
|
||||
suggestions.push(pipeCompleteItem);
|
||||
suggestions.push(...(await getRecommendedQueriesSuggestions()));
|
||||
|
@ -81,7 +80,7 @@ export async function suggest({
|
|||
/^FROM\s+\S+\s+/i.test(innerText) &&
|
||||
metadataOverlap.start !== metadataOverlap.end
|
||||
) {
|
||||
suggestions.push(buildOptionDefinition(metadataOption));
|
||||
suggestions.push(metadataSuggestion);
|
||||
}
|
||||
// FROM someth/
|
||||
// FROM something/
|
||||
|
@ -127,10 +126,9 @@ export async function suggest({
|
|||
rangeToReplace,
|
||||
},
|
||||
{
|
||||
...buildOptionDefinition(metadataOption),
|
||||
...metadataSuggestion,
|
||||
filterText: fragment,
|
||||
text: fragment + ' METADATA ',
|
||||
asSnippet: false, // turn this off because $ could be contained within the source name
|
||||
rangeToReplace,
|
||||
},
|
||||
...recommendedQuerySuggestions.map((suggestion) => ({
|
||||
|
@ -161,6 +159,17 @@ function getSourceSuggestions(sources: ESQLSourceResult[]) {
|
|||
);
|
||||
}
|
||||
|
||||
const metadataSuggestion: SuggestionRawDefinition = {
|
||||
label: 'METADATA',
|
||||
text: 'METADATA ',
|
||||
kind: 'Reference',
|
||||
detail: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.metadataDoc', {
|
||||
defaultMessage: 'Metadata',
|
||||
}),
|
||||
sortText: '1',
|
||||
command: TRIGGER_SUGGESTION_COMMAND,
|
||||
};
|
||||
|
||||
async function suggestForMetadata(metadata: ESQLCommandOption, innerText: string) {
|
||||
const existingFields = new Set(metadata.args.filter(isColumnItem).map(({ name }) => name));
|
||||
const filteredMetaFields = METADATA_FIELDS.filter((name) => !existingFields.has(name));
|
||||
|
|
|
@ -13,7 +13,6 @@ import { operatorsDefinitions } from '../definitions/all_operators';
|
|||
import { getOperatorSuggestion, TRIGGER_SUGGESTION_COMMAND } from './factories';
|
||||
import { CommandDefinition, CommandTypeDefinition } from '../definitions/types';
|
||||
import { getCommandDefinition } from '../shared/helpers';
|
||||
import { getCommandSignature } from '../definitions/helpers';
|
||||
import { buildDocumentation } from './documentation_util';
|
||||
|
||||
const techPreviewLabel = i18n.translate(
|
||||
|
@ -55,7 +54,6 @@ export const getCommandAutocompleteDefinitions = (
|
|||
if (commandDefinition.preview) {
|
||||
detail = `[${techPreviewLabel}] ${detail}`;
|
||||
}
|
||||
const commandSignature = getCommandSignature(commandDefinition, type.name);
|
||||
const suggestion: SuggestionRawDefinition = {
|
||||
label: type.name ? `${type.name.toLocaleUpperCase()} ${label}` : label,
|
||||
text: type.name ? `${type.name.toLocaleUpperCase()} ${text}` : text,
|
||||
|
@ -63,7 +61,7 @@ export const getCommandAutocompleteDefinitions = (
|
|||
kind: 'Method',
|
||||
detail,
|
||||
documentation: {
|
||||
value: buildDocumentation(commandSignature.declaration, commandSignature.examples),
|
||||
value: buildDocumentation(commandDefinition.declaration, commandDefinition.examples),
|
||||
},
|
||||
sortText: 'A-' + label + '-' + type.name,
|
||||
command: TRIGGER_SUGGESTION_COMMAND,
|
||||
|
|
|
@ -18,7 +18,6 @@ import { getFunctionSignatures } from '../definitions/helpers';
|
|||
import { timeUnitsToSuggest } from '../definitions/literals';
|
||||
import {
|
||||
FunctionDefinition,
|
||||
CommandOptionsDefinition,
|
||||
FunctionParameterType,
|
||||
FunctionDefinitionTypes,
|
||||
} from '../definitions/types';
|
||||
|
@ -366,28 +365,6 @@ export const buildPoliciesDefinitions = (
|
|||
command: TRIGGER_SUGGESTION_COMMAND,
|
||||
}));
|
||||
|
||||
/** @deprecated — options will be removed */
|
||||
export const buildOptionDefinition = (
|
||||
option: CommandOptionsDefinition,
|
||||
isAssignType: boolean = false
|
||||
) => {
|
||||
const completeItem: SuggestionRawDefinition = {
|
||||
label: option.name.toUpperCase(),
|
||||
text: option.name.toUpperCase(),
|
||||
kind: 'Reference',
|
||||
detail: option.description,
|
||||
sortText: '1',
|
||||
};
|
||||
if (isAssignType || option.signature.params.length) {
|
||||
completeItem.text = isAssignType
|
||||
? `${option.name.toUpperCase()} = $0`
|
||||
: `${option.name.toUpperCase()} $0`;
|
||||
completeItem.asSnippet = true;
|
||||
completeItem.command = TRIGGER_SUGGESTION_COMMAND;
|
||||
}
|
||||
return completeItem;
|
||||
};
|
||||
|
||||
export function getUnitDuration(unit: number = 1) {
|
||||
const filteredTimeLiteral = timeUnitsToSuggest.filter(({ name }) => {
|
||||
const result = /s$/.test(name);
|
||||
|
|
|
@ -16,22 +16,18 @@ import {
|
|||
isFunctionExpression,
|
||||
isWhereExpression,
|
||||
ESQLCommandMode,
|
||||
ESQLCommandOption,
|
||||
} from '@kbn/esql-ast';
|
||||
import {
|
||||
isAssignment,
|
||||
isColumnItem,
|
||||
isFunctionItem,
|
||||
isInlineCastItem,
|
||||
isLiteralItem,
|
||||
isOptionItem,
|
||||
isSingleItem,
|
||||
noCaseCompare,
|
||||
} from '../shared/helpers';
|
||||
import {
|
||||
appendSeparatorOption,
|
||||
asOption,
|
||||
byOption,
|
||||
metadataOption,
|
||||
onOption,
|
||||
withOption,
|
||||
} from './options';
|
||||
|
||||
import { type CommandDefinition } from './types';
|
||||
import { ENRICH_MODES, checkAggExistence, checkFunctionContent } from './commands_helpers';
|
||||
|
@ -54,6 +50,7 @@ import { suggest as suggestForStats } from '../autocomplete/commands/stats';
|
|||
import { suggest as suggestForWhere } from '../autocomplete/commands/where';
|
||||
|
||||
import { getMessageFromId } from '../validation/errors';
|
||||
import { METADATA_FIELDS } from '../shared/constants';
|
||||
|
||||
const statsValidator = (command: ESQLCommand) => {
|
||||
const messages: ESQLMessage[] = [];
|
||||
|
@ -147,6 +144,7 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Produces a row with one or more columns with values that you specify. This can be useful for testing.',
|
||||
}),
|
||||
declaration: 'ROW column1 = value1[, ..., columnN = valueN]',
|
||||
examples: ['ROW a=1', 'ROW a=1, b=2'],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
|
@ -154,7 +152,6 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
params: [{ name: 'assignment', type: 'any' }],
|
||||
},
|
||||
suggest: suggestForRow,
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
name: 'from',
|
||||
|
@ -162,21 +159,49 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Retrieves data from one or more data streams, indices, or aliases. In a query or subquery, you must use the from command first and it does not need a leading pipe. For example, to retrieve data from an index:',
|
||||
}),
|
||||
examples: ['from logs', 'from logs-*', 'from logs_*, events-*'],
|
||||
options: [metadataOption],
|
||||
declaration: 'FROM index_pattern [METADATA fields]',
|
||||
examples: ['FROM logs', 'FROM logs-*', 'FROM logs_*, events-*'],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'index', type: 'source', wildcards: true }],
|
||||
},
|
||||
suggest: suggestForFrom,
|
||||
validate: (command: ESQLCommand) => {
|
||||
const metadataStatement = command.args.find(
|
||||
(arg) => isOptionItem(arg) && arg.name === 'metadata'
|
||||
) as ESQLCommandOption | undefined;
|
||||
|
||||
if (!metadataStatement) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const messages: ESQLMessage[] = [];
|
||||
|
||||
const fields = metadataStatement.args.filter(isColumnItem);
|
||||
for (const field of fields) {
|
||||
if (!METADATA_FIELDS.includes(field.name)) {
|
||||
messages.push(
|
||||
getMessageFromId({
|
||||
messageId: 'unknownMetadataField',
|
||||
values: {
|
||||
value: field.name,
|
||||
availableFields: Array.from(METADATA_FIELDS).join(', '),
|
||||
},
|
||||
locations: field.location,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'show',
|
||||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.showDoc', {
|
||||
defaultMessage: 'Returns information about the deployment and its capabilities',
|
||||
}),
|
||||
declaration: 'SHOW item',
|
||||
examples: ['SHOW INFO'],
|
||||
options: [],
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [{ name: 'functions', type: 'function' }],
|
||||
|
@ -195,16 +220,16 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
'The command returns only the fields in the aggregation, and you can use a wide range of statistical functions with the stats command. ' +
|
||||
'When you perform more than one aggregation, separate each aggregation with a comma.',
|
||||
}),
|
||||
declaration: '',
|
||||
examples: [
|
||||
'metrics index',
|
||||
'metrics index, index2',
|
||||
'metrics index avg = avg(a)',
|
||||
'metrics index sum(b) by b',
|
||||
'metrics index, index2 sum(b) by b % 2',
|
||||
'metrics <sources> [ <aggregates> [ by <grouping> ]]',
|
||||
'metrics src1, src2 agg1, agg2 by field1, field2',
|
||||
'METRICS index',
|
||||
'METRICS index, index2',
|
||||
'METRICS index avg = avg(a)',
|
||||
'METRICS index sum(b) by b',
|
||||
'METRICS index, index2 sum(b) by b % 2',
|
||||
'METRICS <sources> [ <aggregates> [ by <grouping> ]]',
|
||||
'METRICS src1, src2 agg1, agg2 by field1, field2',
|
||||
],
|
||||
options: [],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [
|
||||
|
@ -220,12 +245,15 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Calculates aggregate statistics, such as average, count, and sum, over the incoming search results set. Similar to SQL aggregation, if the stats command is used without a BY clause, only one row is returned, which is the aggregation over the entire incoming search results set. When you use a BY clause, one row is returned for each distinct value in the field specified in the BY clause. The stats command returns only the fields in the aggregation, and you can use a wide range of statistical functions with the stats command. When you perform more than one aggregation, separate each aggregation with a comma.',
|
||||
}),
|
||||
declaration: `STATS [column1 =] expression1 [WHERE boolean_expression1][,
|
||||
...,
|
||||
[columnN =] expressionN [WHERE boolean_expressionN]]
|
||||
[BY grouping_expression1[, ..., grouping_expressionN]]`,
|
||||
examples: ['… | stats avg = avg(a)', '… | stats sum(b) by b', '… | stats sum(b) by b % 2'],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'expression', type: 'function', optional: true }],
|
||||
},
|
||||
options: [byOption],
|
||||
validate: statsValidator,
|
||||
suggest: suggestForStats,
|
||||
},
|
||||
|
@ -239,12 +267,12 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
'Calculates an aggregate result and merges that result back into the stream of input data. Without the optional `BY` clause this will produce a single result which is appended to each row. With a `BY` clause this will produce one result per grouping and merge the result into the stream based on matching group keys.',
|
||||
}
|
||||
),
|
||||
declaration: '',
|
||||
examples: ['… | EVAL bar = a * b | INLINESTATS m = MAX(bar) BY b'],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'expression', type: 'function', optional: true }],
|
||||
},
|
||||
options: [byOption],
|
||||
// Reusing the same validation logic as stats command
|
||||
validate: statsValidator,
|
||||
suggest: () => [],
|
||||
|
@ -256,17 +284,17 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Calculates an expression and puts the resulting value into a search results field.',
|
||||
}),
|
||||
declaration: 'EVAL [column1 =] value1[, ..., [columnN =] valueN]',
|
||||
examples: [
|
||||
'… | eval b * c',
|
||||
'… | eval a = b * c',
|
||||
'… | eval then = now() + 1 year + 2 weeks',
|
||||
'… | eval a = b * c, d = e * f',
|
||||
'… | EVAL b * c',
|
||||
'… | EVAL a = b * c',
|
||||
'… | EVAL then = NOW() + 1 year + 2 weeks',
|
||||
'… | EVAL a = b * c, d = e * f',
|
||||
],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'expression', type: 'any' }],
|
||||
},
|
||||
options: [],
|
||||
suggest: suggestForEval,
|
||||
},
|
||||
{
|
||||
|
@ -274,12 +302,12 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.renameDoc', {
|
||||
defaultMessage: 'Renames an old column to a new one',
|
||||
}),
|
||||
examples: ['… | rename old as new', '… | rename old as new, a as b'],
|
||||
declaration: 'RENAME old_name1 AS new_name1[, ..., old_nameN AS new_nameN]',
|
||||
examples: ['… | RENAME old AS new', '… | RENAME old AS new, a AS b'],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'renameClause', type: 'column' }],
|
||||
},
|
||||
options: [asOption],
|
||||
suggest: suggestForRename,
|
||||
},
|
||||
{
|
||||
|
@ -288,12 +316,12 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Returns the first search results, in search order, based on the "limit" specified.',
|
||||
}),
|
||||
examples: ['… | limit 100', '… | limit 0'],
|
||||
declaration: 'LIMIT max_number_of_rows',
|
||||
examples: ['… | LIMIT 100', '… | LIMIT 1'],
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [{ name: 'size', type: 'integer', constantOnly: true }],
|
||||
},
|
||||
options: [],
|
||||
suggest: suggestForLimit,
|
||||
},
|
||||
{
|
||||
|
@ -302,9 +330,9 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Rearranges fields in the Results table by applying the keep clauses in fields',
|
||||
}),
|
||||
examples: ['… | keep a', '… | keep a,b'],
|
||||
declaration: 'KEEP column1[, ..., columnN]',
|
||||
examples: ['… | KEEP a', '… | KEEP a, b'],
|
||||
suggest: suggestForKeep,
|
||||
options: [],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'column', type: 'column', wildcards: true }],
|
||||
|
@ -315,8 +343,8 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.dropDoc', {
|
||||
defaultMessage: 'Drops columns',
|
||||
}),
|
||||
examples: ['… | drop a', '… | drop a,b'],
|
||||
options: [],
|
||||
declaration: 'DROP column1[, ..., columnN]',
|
||||
examples: ['… | DROP a', '… | DROP a, b'],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'column', type: 'column', wildcards: true }],
|
||||
|
@ -366,32 +394,32 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Sorts all results by the specified fields. By default, null values are treated as being larger than any other value. With an ascending sort order, null values are sorted last, and with a descending sort order, null values are sorted first. You can change that by providing NULLS FIRST or NULLS LAST',
|
||||
}),
|
||||
declaration:
|
||||
'SORT column1 [ASC/DESC][NULLS FIRST/NULLS LAST][, ..., columnN [ASC/DESC][NULLS FIRST/NULLS LAST]]',
|
||||
examples: [
|
||||
'… | sort a desc, b nulls last, c asc nulls first',
|
||||
'… | sort b nulls last',
|
||||
'… | sort c asc nulls first',
|
||||
'… | sort a - abs(b)',
|
||||
'… | SORT a DESC, b NULLS LAST, c ASC NULLS FIRST',
|
||||
'… | SORT b NULLS LAST',
|
||||
'… | SORT c ASC NULLS FIRST',
|
||||
'… | SORT a - abs(b)',
|
||||
],
|
||||
options: [],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'expression', type: 'any' }],
|
||||
},
|
||||
suggest: suggestForSort,
|
||||
},
|
||||
|
||||
{
|
||||
name: 'where',
|
||||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.whereDoc', {
|
||||
defaultMessage:
|
||||
'Uses "predicate-expressions" to filter search results. A predicate expression, when evaluated, returns TRUE or FALSE. The where command only returns the results that evaluate to TRUE. For example, to filter results for a specific field value',
|
||||
}),
|
||||
examples: ['… | where status_code == 200'],
|
||||
declaration: 'WHERE expression',
|
||||
examples: ['… | WHERE status_code == 200'],
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [{ name: 'expression', type: 'boolean' }],
|
||||
},
|
||||
options: [],
|
||||
suggest: suggestForWhere,
|
||||
},
|
||||
{
|
||||
|
@ -400,8 +428,8 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Extracts multiple string values from a single string input, based on a pattern',
|
||||
}),
|
||||
declaration: 'DISSECT input "pattern" [APPEND_SEPARATOR="<separator>"]',
|
||||
examples: ['… | DISSECT a "%{b} %{c}" APPEND_SEPARATOR = ":"'],
|
||||
options: [appendSeparatorOption],
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [
|
||||
|
@ -410,6 +438,43 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
],
|
||||
},
|
||||
suggest: suggestForDissect,
|
||||
validate: (command: ESQLCommand) => {
|
||||
const appendSeparatorClause = command.args.find((arg) => isOptionItem(arg)) as
|
||||
| ESQLCommandOption
|
||||
| undefined;
|
||||
|
||||
if (!appendSeparatorClause) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (appendSeparatorClause.name !== 'append_separator') {
|
||||
return [
|
||||
getMessageFromId({
|
||||
messageId: 'unknownDissectKeyword',
|
||||
values: { keyword: appendSeparatorClause.name },
|
||||
locations: appendSeparatorClause.location,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
const messages: ESQLMessage[] = [];
|
||||
const [firstArg] = appendSeparatorClause.args;
|
||||
if (
|
||||
!Array.isArray(firstArg) &&
|
||||
(!isLiteralItem(firstArg) || firstArg.literalType !== 'keyword')
|
||||
) {
|
||||
const value =
|
||||
'value' in firstArg && !isInlineCastItem(firstArg) ? firstArg.value : firstArg.name;
|
||||
messages.push(
|
||||
getMessageFromId({
|
||||
messageId: 'wrongDissectOptionArgumentType',
|
||||
values: { value: value ?? '' },
|
||||
locations: firstArg.location,
|
||||
})
|
||||
);
|
||||
}
|
||||
return messages;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'grok',
|
||||
|
@ -417,8 +482,8 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Extracts multiple string values from a single string input, based on a pattern',
|
||||
}),
|
||||
declaration: 'GROK input "pattern"',
|
||||
examples: ['… | GROK a "%{IP:b} %{NUMBER:c}"'],
|
||||
options: [],
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [
|
||||
|
@ -433,8 +498,8 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mvExpandDoc', {
|
||||
defaultMessage: 'Expands multivalued fields into one row per value, duplicating other fields',
|
||||
}),
|
||||
examples: ['row a=[1,2,3] | mv_expand a'],
|
||||
options: [],
|
||||
declaration: 'MV_EXPAND column',
|
||||
examples: ['ROW a=[1,2,3] | MV_EXPAND a'],
|
||||
preview: true,
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
|
@ -448,12 +513,13 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Enrich table with another table. Before you can use enrich, you need to create and execute an enrich policy.',
|
||||
}),
|
||||
declaration:
|
||||
'ENRICH policy [ON match_field] [WITH [new_name1 = ]field1, [new_name2 = ]field2, ...]',
|
||||
examples: [
|
||||
'… | enrich my-policy',
|
||||
'… | enrich my-policy on pivotField',
|
||||
'… | enrich my-policy on pivotField with a = enrichFieldA, b = enrichFieldB',
|
||||
'… | ENRICH my-policy',
|
||||
'… | ENRICH my-policy ON pivotField',
|
||||
'… | ENRICH my-policy ON pivotField WITH a = enrichFieldA, b = enrichFieldB',
|
||||
],
|
||||
options: [onOption, withOption],
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [{ name: 'policyName', type: 'source', innerTypes: ['policy'] }],
|
||||
|
@ -489,9 +555,9 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
{
|
||||
name: 'hidden_command',
|
||||
description: 'A test fixture to test hidden-ness',
|
||||
declaration: '',
|
||||
hidden: true,
|
||||
examples: [],
|
||||
options: [],
|
||||
signature: {
|
||||
params: [],
|
||||
multipleParams: false,
|
||||
|
@ -535,6 +601,7 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.joinDoc', {
|
||||
defaultMessage: 'Join table with another table.',
|
||||
}),
|
||||
declaration: `LOOKUP JOIN <lookup_index> ON <field_name>`,
|
||||
preview: true,
|
||||
examples: [
|
||||
'… | LOOKUP JOIN lookup_index ON join_field',
|
||||
|
@ -547,7 +614,6 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
multipleParams: true,
|
||||
params: [{ name: 'index', type: 'source', wildcards: true }],
|
||||
},
|
||||
options: [onOption],
|
||||
suggest: suggestForJoin,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { CommandDefinition, FunctionDefinition, FunctionParameterType } from './types';
|
||||
import type { FunctionDefinition, FunctionParameterType } from './types';
|
||||
|
||||
/**
|
||||
* Given a function definition, this function will return a list of function signatures
|
||||
|
@ -55,52 +55,6 @@ function handleAdditionalArgs(
|
|||
: '';
|
||||
}
|
||||
|
||||
export function getCommandSignature(
|
||||
{ name, signature, options, examples }: CommandDefinition<string>,
|
||||
typeName?: string,
|
||||
{ withTypes }: { withTypes: boolean } = { withTypes: true }
|
||||
) {
|
||||
const commandName = typeName
|
||||
? `${typeName.toUpperCase()} ${name.toUpperCase()}`
|
||||
: name.toUpperCase();
|
||||
return {
|
||||
declaration: `${commandName} ${printCommandArguments(signature, withTypes)} ${(
|
||||
options || []
|
||||
).map(
|
||||
(option) =>
|
||||
`${
|
||||
option.wrapped ? option.wrapped[0] : ''
|
||||
}${option.name.toUpperCase()} ${printCommandArguments(option.signature, withTypes)}${
|
||||
option.wrapped ? option.wrapped[1] : ''
|
||||
}`
|
||||
)}`,
|
||||
examples,
|
||||
};
|
||||
}
|
||||
|
||||
function printCommandArguments(
|
||||
{ multipleParams, params }: CommandDefinition<string>['signature'],
|
||||
withTypes: boolean
|
||||
): string {
|
||||
return `${params.map((arg) => printCommandArgument(arg, withTypes)).join(', `')}${
|
||||
multipleParams
|
||||
? ` ,[...${params.map((arg) => printCommandArgument(arg, withTypes)).join(', `')}]`
|
||||
: ''
|
||||
}`;
|
||||
}
|
||||
|
||||
function printCommandArgument(
|
||||
param: CommandDefinition<string>['signature']['params'][number],
|
||||
withTypes: boolean
|
||||
): string {
|
||||
if (!withTypes) {
|
||||
return param.name || '';
|
||||
}
|
||||
return `${param.name}${param.optional ? ':?' : ':'} ${param.type}${
|
||||
param.innerTypes ? `{${param.innerTypes}}` : ''
|
||||
}`;
|
||||
}
|
||||
|
||||
export function printArguments(
|
||||
{
|
||||
name,
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { ESQLCommandOption, ESQLMessage } from '@kbn/esql-ast';
|
||||
import { isLiteralItem, isColumnItem, isInlineCastItem } from '../shared/helpers';
|
||||
import { getMessageFromId } from '../validation/errors';
|
||||
import type { CommandOptionsDefinition } from './types';
|
||||
|
||||
/** @deprecated — options are going away */
|
||||
export const byOption: CommandOptionsDefinition = {
|
||||
name: 'by',
|
||||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.byDoc', {
|
||||
defaultMessage: 'By',
|
||||
}),
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'expression', type: 'any' }],
|
||||
},
|
||||
optional: true,
|
||||
};
|
||||
|
||||
/** @deprecated — options are going away */
|
||||
export const metadataOption: CommandOptionsDefinition = {
|
||||
name: 'metadata',
|
||||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.metadataDoc', {
|
||||
defaultMessage: 'Metadata',
|
||||
}),
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'column', type: 'column' }],
|
||||
},
|
||||
optional: true,
|
||||
skipCommonValidation: true,
|
||||
validate: (option, command, references) => {
|
||||
const messages: ESQLMessage[] = [];
|
||||
// need to test the parent command here
|
||||
if (/\[metadata/i.test(command.text)) {
|
||||
messages.push(
|
||||
getMessageFromId({
|
||||
messageId: 'metadataBracketsDeprecation',
|
||||
values: {},
|
||||
locations: option.location,
|
||||
})
|
||||
);
|
||||
}
|
||||
const fields = option.args.filter(isColumnItem);
|
||||
const metadataFieldsAvailable = references as unknown as Set<string>;
|
||||
if (metadataFieldsAvailable.size > 0) {
|
||||
for (const field of fields) {
|
||||
if (!metadataFieldsAvailable.has(field.name)) {
|
||||
messages.push(
|
||||
getMessageFromId({
|
||||
messageId: 'unknownMetadataField',
|
||||
values: {
|
||||
value: field.name,
|
||||
availableFields: Array.from(metadataFieldsAvailable).join(', '),
|
||||
},
|
||||
locations: field.location,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
},
|
||||
};
|
||||
|
||||
/** @deprecated — options are going away */
|
||||
export const asOption: CommandOptionsDefinition = {
|
||||
name: 'as',
|
||||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.asDoc', {
|
||||
defaultMessage: 'As',
|
||||
}),
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [
|
||||
{ name: 'oldName', type: 'column' },
|
||||
{ name: 'newName', type: 'column' },
|
||||
],
|
||||
},
|
||||
optional: false,
|
||||
};
|
||||
|
||||
/** @deprecated — options are going away */
|
||||
export const onOption: CommandOptionsDefinition = {
|
||||
name: 'on',
|
||||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.onDoc', {
|
||||
defaultMessage: 'On',
|
||||
}),
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [{ name: 'matchingColumn', type: 'column' }],
|
||||
},
|
||||
optional: true,
|
||||
};
|
||||
|
||||
/** @deprecated — options are going away */
|
||||
export const withOption: CommandOptionsDefinition = {
|
||||
name: 'with',
|
||||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.withDoc', {
|
||||
defaultMessage: 'With',
|
||||
}),
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'assignment', type: 'any' }],
|
||||
},
|
||||
optional: true,
|
||||
};
|
||||
|
||||
/** @deprecated — options are going away */
|
||||
export const appendSeparatorOption: CommandOptionsDefinition = {
|
||||
name: 'append_separator',
|
||||
description: i18n.translate(
|
||||
'kbn-esql-validation-autocomplete.esql.definitions.appendSeparatorDoc',
|
||||
{
|
||||
defaultMessage:
|
||||
'The character(s) that separate the appended fields. Default to empty string ("").',
|
||||
}
|
||||
),
|
||||
signature: {
|
||||
multipleParams: false,
|
||||
params: [{ name: 'separator', type: 'string' }],
|
||||
},
|
||||
optional: true,
|
||||
skipCommonValidation: true, // tell the validation engine to use only the validate function here
|
||||
validate: (option: ESQLCommandOption) => {
|
||||
const messages: ESQLMessage[] = [];
|
||||
const [firstArg] = option.args;
|
||||
if (
|
||||
!Array.isArray(firstArg) &&
|
||||
(!isLiteralItem(firstArg) || firstArg.literalType !== 'keyword')
|
||||
) {
|
||||
const value =
|
||||
'value' in firstArg && !isInlineCastItem(firstArg) ? firstArg.value : firstArg.name;
|
||||
messages.push(
|
||||
getMessageFromId({
|
||||
messageId: 'wrongDissectOptionArgumentType',
|
||||
values: { value: value ?? '' },
|
||||
locations: firstArg.location,
|
||||
})
|
||||
);
|
||||
}
|
||||
return messages;
|
||||
},
|
||||
};
|
|
@ -9,7 +9,6 @@
|
|||
import type {
|
||||
ESQLAstItem,
|
||||
ESQLCommand,
|
||||
ESQLCommandOption,
|
||||
ESQLFunction,
|
||||
ESQLMessage,
|
||||
ESQLSource,
|
||||
|
@ -280,12 +279,16 @@ export type CommandSuggestFunction<CommandName extends string> = (
|
|||
params: CommandSuggestParams<CommandName>
|
||||
) => Promise<SuggestionRawDefinition[]> | SuggestionRawDefinition[];
|
||||
|
||||
/**
|
||||
* @deprecated — use CommandDefinition instead
|
||||
*/
|
||||
export interface CommandBaseDefinition<CommandName extends string> {
|
||||
export interface CommandDefinition<CommandName extends string> {
|
||||
name: CommandName;
|
||||
|
||||
examples: string[];
|
||||
|
||||
/**
|
||||
* The pattern for declaring this command statement.
|
||||
*/
|
||||
declaration: string;
|
||||
|
||||
/**
|
||||
* Command name prefix, such as "LEFT" or "RIGHT" for JOIN command.
|
||||
*/
|
||||
|
@ -293,14 +296,29 @@ export interface CommandBaseDefinition<CommandName extends string> {
|
|||
|
||||
alias?: string;
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* Displays a Technical preview label in the autocomplete
|
||||
*/
|
||||
preview?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to show or hide in autocomplete suggestion list
|
||||
*/
|
||||
hidden?: boolean;
|
||||
|
||||
/**
|
||||
* This method is run when the command is being validated, but it does not
|
||||
* prevent the default behavior. If you need a full override, we are currently
|
||||
* doing those directly in the validateCommand function in the validation module.
|
||||
*/
|
||||
validate?: (command: ESQLCommand<CommandName>, references: ReferenceMaps) => ESQLMessage[];
|
||||
|
||||
/**
|
||||
* This method is called to load suggestions when the cursor is within this command.
|
||||
*/
|
||||
suggest: CommandSuggestFunction<CommandName>;
|
||||
|
||||
/** @deprecated this property will disappear in the future */
|
||||
signature: {
|
||||
multipleParams: boolean;
|
||||
|
@ -324,43 +342,9 @@ export interface CommandTypeDefinition {
|
|||
description?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated options are going away
|
||||
*/
|
||||
export interface CommandOptionsDefinition<CommandName extends string = string>
|
||||
extends CommandBaseDefinition<CommandName> {
|
||||
wrapped?: string[];
|
||||
optional: boolean;
|
||||
skipCommonValidation?: boolean;
|
||||
validate?: (
|
||||
option: ESQLCommandOption,
|
||||
command: ESQLCommand,
|
||||
references?: unknown
|
||||
) => ESQLMessage[];
|
||||
}
|
||||
|
||||
export interface CommandDefinition<CommandName extends string>
|
||||
extends CommandBaseDefinition<CommandName> {
|
||||
examples: string[];
|
||||
/**
|
||||
* This function is run when the command is being validated, but it does not
|
||||
* prevent the default behavior. If you need a full override, we are currently
|
||||
* doing those directly in the validateCommand function in the validation module.
|
||||
*/
|
||||
validate?: (command: ESQLCommand<CommandName>, references: ReferenceMaps) => ESQLMessage[];
|
||||
suggest: CommandSuggestFunction<CommandName>;
|
||||
/** @deprecated this property will disappear in the future */
|
||||
options: CommandOptionsDefinition[];
|
||||
}
|
||||
|
||||
export interface Literals {
|
||||
name: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export type SignatureType =
|
||||
| FunctionDefinition['signatures'][number]
|
||||
| CommandOptionsDefinition['signature'];
|
||||
export type SignatureArgType = SignatureType['params'][number];
|
||||
|
||||
export type FunctionParameter = FunctionDefinition['signatures'][number]['params'][number];
|
||||
|
|
|
@ -32,17 +32,8 @@ import { groupingFunctionDefinitions } from '../definitions/generated/grouping_f
|
|||
import { getTestFunctions } from './test_functions';
|
||||
import { getFunctionSignatures } from '../definitions/helpers';
|
||||
import { timeUnits } from '../definitions/literals';
|
||||
import {
|
||||
byOption,
|
||||
metadataOption,
|
||||
asOption,
|
||||
onOption,
|
||||
withOption,
|
||||
appendSeparatorOption,
|
||||
} from '../definitions/options';
|
||||
import {
|
||||
CommandDefinition,
|
||||
CommandOptionsDefinition,
|
||||
FunctionParameter,
|
||||
FunctionDefinition,
|
||||
FunctionParameterType,
|
||||
|
@ -221,12 +212,6 @@ export function getAllCommands() {
|
|||
return Array.from(buildCommandLookup().values());
|
||||
}
|
||||
|
||||
export function getCommandOption(optionName: CommandOptionsDefinition<string>['name']) {
|
||||
return [byOption, metadataOption, asOption, onOption, withOption, appendSeparatorOption].find(
|
||||
({ name }) => name === optionName
|
||||
);
|
||||
}
|
||||
|
||||
function doesLiteralMatchParameterType(argType: FunctionParameterType, item: ESQLLiteral) {
|
||||
if (item.literalType === argType) {
|
||||
return true;
|
||||
|
|
|
@ -154,15 +154,17 @@ function getMessageAndTypeFromId<K extends ErrorTypes>({
|
|||
}
|
||||
),
|
||||
};
|
||||
case 'unknownOption':
|
||||
case 'unknownDissectKeyword':
|
||||
return {
|
||||
message: i18n.translate('kbn-esql-validation-autocomplete.esql.validation.unknownOption', {
|
||||
defaultMessage: 'Invalid option for {command}: [{option}]',
|
||||
values: {
|
||||
command: out.command,
|
||||
option: out.option,
|
||||
},
|
||||
}),
|
||||
message: i18n.translate(
|
||||
'kbn-esql-validation-autocomplete.esql.validation.unknownDissectKeyword',
|
||||
{
|
||||
defaultMessage: 'Expected [APPEND_SEPARATOR] in [DISSECT] but found [{keyword}]',
|
||||
values: {
|
||||
keyword: out.keyword,
|
||||
},
|
||||
}
|
||||
),
|
||||
};
|
||||
case 'unsupportedFunctionForCommand':
|
||||
return {
|
||||
|
@ -372,7 +374,7 @@ function getMessageAndTypeFromId<K extends ErrorTypes>({
|
|||
'kbn-esql-validation-autocomplete.esql.validation.wrongDissectOptionArgumentType',
|
||||
{
|
||||
defaultMessage:
|
||||
'Invalid value for DISSECT append_separator: expected a string, but was [{value}]',
|
||||
'Invalid value for DISSECT APPEND_SEPARATOR: expected a string, but was [{value}]',
|
||||
values: {
|
||||
value: out.value,
|
||||
},
|
||||
|
|
|
@ -2711,7 +2711,8 @@
|
|||
{
|
||||
"query": "from a_index | dissect textField \"%{firstWord}\" option ",
|
||||
"error": [
|
||||
"SyntaxError: mismatched input '<EOF>' expecting '='"
|
||||
"SyntaxError: mismatched input '<EOF>' expecting '='",
|
||||
"Expected [APPEND_SEPARATOR] in [DISSECT] but found [option]"
|
||||
],
|
||||
"warning": []
|
||||
},
|
||||
|
@ -2719,14 +2720,14 @@
|
|||
"query": "from a_index | dissect textField \"%{firstWord}\" option = ",
|
||||
"error": [
|
||||
"SyntaxError: mismatched input '<EOF>' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, '['}",
|
||||
"Invalid option for DISSECT: [option]"
|
||||
"Expected [APPEND_SEPARATOR] in [DISSECT] but found [option]"
|
||||
],
|
||||
"warning": []
|
||||
},
|
||||
{
|
||||
"query": "from a_index | dissect textField \"%{firstWord}\" option = 1",
|
||||
"error": [
|
||||
"Invalid option for DISSECT: [option]"
|
||||
"Expected [APPEND_SEPARATOR] in [DISSECT] but found [option]"
|
||||
],
|
||||
"warning": []
|
||||
},
|
||||
|
@ -2738,14 +2739,14 @@
|
|||
{
|
||||
"query": "from a_index | dissect textField \"%{firstWord}\" ignore_missing = true",
|
||||
"error": [
|
||||
"Invalid option for DISSECT: [ignore_missing]"
|
||||
"Expected [APPEND_SEPARATOR] in [DISSECT] but found [ignore_missing]"
|
||||
],
|
||||
"warning": []
|
||||
},
|
||||
{
|
||||
"query": "from a_index | dissect textField \"%{firstWord}\" append_separator = true",
|
||||
"error": [
|
||||
"Invalid value for DISSECT append_separator: expected a string, but was [true]"
|
||||
"Invalid value for DISSECT APPEND_SEPARATOR: expected a string, but was [true]"
|
||||
],
|
||||
"warning": []
|
||||
},
|
||||
|
|
|
@ -123,9 +123,9 @@ export interface ValidationErrors {
|
|||
message: string;
|
||||
type: { command: string; type: string; typeCount: number; givenType: string; column: string };
|
||||
};
|
||||
unknownOption: {
|
||||
unknownDissectKeyword: {
|
||||
message: string;
|
||||
type: { command: string; option: string };
|
||||
type: { keyword: string };
|
||||
};
|
||||
wrongOptionArgumentType: {
|
||||
message: string;
|
||||
|
|
|
@ -714,13 +714,14 @@ describe('validation logic', () => {
|
|||
]);
|
||||
testErrorsAndWarnings('from a_index | dissect textField "%{firstWord}" option ', [
|
||||
"SyntaxError: mismatched input '<EOF>' expecting '='",
|
||||
'Expected [APPEND_SEPARATOR] in [DISSECT] but found [option]',
|
||||
]);
|
||||
testErrorsAndWarnings('from a_index | dissect textField "%{firstWord}" option = ', [
|
||||
"SyntaxError: mismatched input '<EOF>' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, '['}",
|
||||
'Invalid option for DISSECT: [option]',
|
||||
'Expected [APPEND_SEPARATOR] in [DISSECT] but found [option]',
|
||||
]);
|
||||
testErrorsAndWarnings('from a_index | dissect textField "%{firstWord}" option = 1', [
|
||||
'Invalid option for DISSECT: [option]',
|
||||
'Expected [APPEND_SEPARATOR] in [DISSECT] but found [option]',
|
||||
]);
|
||||
testErrorsAndWarnings(
|
||||
'from a_index | dissect textField "%{firstWord}" append_separator = "-"',
|
||||
|
@ -728,11 +729,11 @@ describe('validation logic', () => {
|
|||
);
|
||||
testErrorsAndWarnings(
|
||||
'from a_index | dissect textField "%{firstWord}" ignore_missing = true',
|
||||
['Invalid option for DISSECT: [ignore_missing]']
|
||||
['Expected [APPEND_SEPARATOR] in [DISSECT] but found [ignore_missing]']
|
||||
);
|
||||
testErrorsAndWarnings(
|
||||
'from a_index | dissect textField "%{firstWord}" append_separator = true',
|
||||
['Invalid value for DISSECT append_separator: expected a string, but was [true]']
|
||||
['Invalid value for DISSECT APPEND_SEPARATOR: expected a string, but was [true]']
|
||||
);
|
||||
testErrorsAndWarnings('from a_index | dissect textField "%{firstWord}" | keep firstWord', []);
|
||||
// testErrorsAndWarnings('from a_index | dissect s* "%{a}"', [
|
||||
|
|
|
@ -20,8 +20,6 @@ import {
|
|||
walk,
|
||||
} from '@kbn/esql-ast';
|
||||
import type { ESQLAstJoinCommand, ESQLIdentifier } from '@kbn/esql-ast/src/types';
|
||||
import { CommandOptionsDefinition } from '../definitions/types';
|
||||
import { METADATA_FIELDS } from '../shared/constants';
|
||||
import { compareTypesWithLiterals } from '../shared/esql_types';
|
||||
import {
|
||||
areFieldAndVariableTypesCompatible,
|
||||
|
@ -234,9 +232,8 @@ function validateCommand(
|
|||
}
|
||||
default: {
|
||||
// Now validate arguments
|
||||
for (const commandArg of command.args) {
|
||||
const wrappedArg = Array.isArray(commandArg) ? commandArg : [commandArg];
|
||||
for (const arg of wrappedArg) {
|
||||
for (const arg of command.args) {
|
||||
if (!Array.isArray(arg)) {
|
||||
if (isFunctionItem(arg)) {
|
||||
messages.push(
|
||||
...validateFunction({
|
||||
|
@ -249,14 +246,7 @@ function validateCommand(
|
|||
})
|
||||
);
|
||||
} else if (isOptionItem(arg)) {
|
||||
messages.push(
|
||||
...validateOption(
|
||||
arg,
|
||||
commandDef.options.find(({ name }) => name === arg.name),
|
||||
command,
|
||||
references
|
||||
)
|
||||
);
|
||||
messages.push(...validateOption(arg, command, references));
|
||||
} else if (isColumnItem(arg) || isIdentifier(arg)) {
|
||||
if (command.name === 'stats' || command.name === 'inlinestats') {
|
||||
messages.push(errors.unknownAggFunction(arg));
|
||||
|
@ -290,54 +280,36 @@ function validateCommand(
|
|||
|
||||
function validateOption(
|
||||
option: ESQLCommandOption,
|
||||
optionDef: CommandOptionsDefinition | undefined,
|
||||
command: ESQLCommand,
|
||||
referenceMaps: ReferenceMaps
|
||||
): ESQLMessage[] {
|
||||
// check if the arguments of the option are of the correct type
|
||||
const messages: ESQLMessage[] = [];
|
||||
if (option.incomplete || command.incomplete) {
|
||||
if (option.incomplete || command.incomplete || option.name === 'metadata') {
|
||||
return messages;
|
||||
}
|
||||
if (!optionDef) {
|
||||
messages.push(
|
||||
getMessageFromId({
|
||||
messageId: 'unknownOption',
|
||||
values: { command: command.name.toUpperCase(), option: option.name },
|
||||
locations: option.location,
|
||||
})
|
||||
);
|
||||
|
||||
if (option.name === 'metadata') {
|
||||
// Validation for the metadata statement is handled in the FROM command's validate method
|
||||
return messages;
|
||||
}
|
||||
// use dedicate validate fn if provided
|
||||
if (optionDef.validate) {
|
||||
const fields = METADATA_FIELDS;
|
||||
messages.push(...optionDef.validate(option, command, new Set(fields)));
|
||||
}
|
||||
if (!optionDef.skipCommonValidation) {
|
||||
option.args.forEach((arg) => {
|
||||
if (!Array.isArray(arg)) {
|
||||
if (!optionDef.signature.multipleParams) {
|
||||
if (isColumnItem(arg)) {
|
||||
messages.push(...validateColumnForCommand(arg, command.name, referenceMaps));
|
||||
}
|
||||
} else {
|
||||
if (isColumnItem(arg)) {
|
||||
messages.push(...validateColumnForCommand(arg, command.name, referenceMaps));
|
||||
}
|
||||
if (isFunctionItem(arg)) {
|
||||
messages.push(
|
||||
...validateFunction({
|
||||
fn: arg,
|
||||
parentCommand: command.name,
|
||||
parentOption: option.name,
|
||||
references: referenceMaps,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const arg of option.args) {
|
||||
if (Array.isArray(arg)) {
|
||||
continue;
|
||||
}
|
||||
if (isColumnItem(arg)) {
|
||||
messages.push(...validateColumnForCommand(arg, command.name, referenceMaps));
|
||||
} else if (isFunctionItem(arg)) {
|
||||
messages.push(
|
||||
...validateFunction({
|
||||
fn: arg,
|
||||
parentCommand: command.name,
|
||||
parentOption: option.name,
|
||||
references: referenceMaps,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
|
|
|
@ -5646,7 +5646,6 @@
|
|||
"kbn-esql-validation-autocomplete.esql.definitions.atan2": "L'angle entre l'axe positif des x et le rayon allant de l'origine au point (x , y) dans le plan cartésien, exprimé en radians.",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.avg": "La moyenne d'un champ numérique.",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.bit_length": "Renvoie la longueur d'une chaîne en bits.",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.byDoc": "Par",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.byte_length": "Renvoie la longueur d'une chaîne en octets.",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.case": "Accepte les paires de conditions et de valeurs. La fonction renvoie la valeur correspondant à la première condition évaluée à `true` (vraie). Si le nombre d'arguments est impair, le dernier argument est la valeur par défaut qui est renvoyée si aucune condition ne correspond.",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.categorize": "Regroupe les messages textuels en catégories de valeurs textuelles au format similaire.",
|
||||
|
@ -5855,7 +5854,6 @@
|
|||
"kbn-esql-validation-autocomplete.esql.validation.unknownColumnType": "Type inconnu",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownIndex": "Index inconnu [{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownInterval": "Qualificatif d'intervalle de temps inattendu : \"{value}\"",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownOption": "Option non valide pour {command} : [{option}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownPolicy": "Politique [{name}] inconnue",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unsupportedColumnTypeForCommand": "{command} ne prend en charge que les valeurs {type} {typeCount, plural, one {type} other {types}}, [{column}] de type [{givenType}] trouvé",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unsupportedFieldType": "Le champ [{field}] ne peut pas être récupéré, il n'est pas pris en charge ou n'est pas indexé ; renvoi de valeur null",
|
||||
|
|
|
@ -5641,7 +5641,6 @@
|
|||
"kbn-esql-validation-autocomplete.esql.definitions.atan2": "直交平面上の原点から点(x , y)に向かう光線と正のx軸のなす角(ラジアン表記)。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.avg": "数値フィールドの平均。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.bit_length": "文字列のビット長を返します。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.byDoc": "グループ基準",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.byte_length": "文字列のバイト長を返します。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.case": "条件と値のペアを指定できます。この関数は、最初にtrueと評価された条件に属する値を返します。引数の数が奇数の場合、最後の引数は条件に一致しない場合に返されるデフォルト値になります。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.categorize": "テキストメッセージを、同様の書式のテキスト値のカテゴリに分類します。",
|
||||
|
@ -5851,7 +5850,6 @@
|
|||
"kbn-esql-validation-autocomplete.esql.validation.unknownColumnType": "不明なタイプ",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownIndex": "不明なインデックス[{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownInterval": "想定されていない時間間隔修飾子:''{value}''",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownOption": "{command}の無効なオプション:[{option}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownPolicy": "不明なポリシー[{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unsupportedColumnTypeForCommand": "{command}は{type} {typeCount, plural, other {型}}の値のみをサポートしていますが、[{givenType}]型の[{column}]が見つかりました",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unsupportedFieldType": "フィールド[{field}]を取得できません。サポートされていないか、インデックス化されていません。NULLが返されます",
|
||||
|
|
|
@ -5651,7 +5651,6 @@
|
|||
"kbn-esql-validation-autocomplete.esql.definitions.atan2": "笛卡儿平面中正 x 轴与从原点到点 (x , y) 构成的射线之间的角度,以弧度表示。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.avg": "数字字段的平均值。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.bit_length": "返回字符串的位长。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.byDoc": "依据",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.byte_length": "返回字符串的字节长度。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.case": "接受成对的条件和值。此函数返回属于第一个评估为 `true` 的条件的值。如果参数数量为奇数,则最后一个参数为在无条件匹配时返回的默认值。",
|
||||
"kbn-esql-validation-autocomplete.esql.definitions.categorize": "将文本消息分组为格式类似的文本值类别。",
|
||||
|
@ -5861,7 +5860,6 @@
|
|||
"kbn-esql-validation-autocomplete.esql.validation.unknownColumnType": "未知类型",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownIndex": "未知索引 [{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownInterval": "意外的时间间隔修饰词:“{value}”",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownOption": "{command} 的选项无效:[{option}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownPolicy": "未知策略 [{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unsupportedColumnTypeForCommand": "{command} 只支持 {type} 种{typeCount, plural, other {类型}}的值,找到了 [{givenType}] 类型的 [{column}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unsupportedFieldType": "无法检索字段 [{field}],它不受支持或未进行索引;正返回 null",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue