mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[ES|QL] Add support for client-side INLINESTATS validation (#189827)
## Summary Addresses https://github.com/elastic/kibana/issues/189356. This PR adds support for client-side INLINESTATS validation in the text based editor. Changes include: - Add INLINESTATS context in AST package - Update function definitions to include INLINESTATS - Hide INLINESTATS from list of suggestions (which we will revert after command is merged in tech preview) Before:  After: https://github.com/user-attachments/assets/4723735d-ab40-49c3-a1d9-51482c6fb441 ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
83e78ea5da
commit
a5d0321f25
21 changed files with 732 additions and 278 deletions
|
@ -18,6 +18,7 @@ import {
|
|||
EuiFormRow,
|
||||
EuiButton,
|
||||
} from '@elastic/eui';
|
||||
import { EuiProvider } from '@elastic/eui';
|
||||
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
|
||||
|
@ -42,48 +43,50 @@ export const App = (props: { core: CoreStart; plugins: StartDependencies }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<EuiPage>
|
||||
<EuiPageBody style={{ maxWidth: 800, margin: '0 auto' }}>
|
||||
<EuiPageHeader paddingSize="s" bottomBorder={true} pageTitle="ES|QL AST Inspector" />
|
||||
<EuiPageSection paddingSize="s">
|
||||
<p>This app gives you the AST for a particular ES|QL query.</p>
|
||||
<EuiProvider>
|
||||
<EuiPage>
|
||||
<EuiPageBody style={{ maxWidth: 800, margin: '0 auto' }}>
|
||||
<EuiPageHeader paddingSize="s" bottomBorder={true} pageTitle="ES|QL AST Inspector" />
|
||||
<EuiPageSection paddingSize="s">
|
||||
<p>This app gives you the AST for a particular ES|QL query.</p>
|
||||
|
||||
<EuiSpacer />
|
||||
<EuiSpacer />
|
||||
|
||||
<EuiForm>
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
label="Query"
|
||||
isInvalid={Boolean(currentErrors.length)}
|
||||
error={currentErrors.map((error) => error.message)}
|
||||
>
|
||||
<EuiTextArea
|
||||
inputRef={(node) => {
|
||||
inputRef.current = node;
|
||||
}}
|
||||
isInvalid={Boolean(currentErrors.length)}
|
||||
<EuiForm>
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
value={currentQuery}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
css={{
|
||||
height: '5em',
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiButton fullWidth onClick={() => parseQuery(inputRef.current?.value ?? '')}>
|
||||
Parse
|
||||
</EuiButton>
|
||||
</EuiFormRow>
|
||||
</EuiForm>
|
||||
<EuiSpacer />
|
||||
<CodeEditor
|
||||
allowFullScreen={true}
|
||||
languageId={'json'}
|
||||
value={JSON.stringify(ast, null, 2)}
|
||||
/>
|
||||
</EuiPageSection>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
label="Query"
|
||||
isInvalid={Boolean(currentErrors.length)}
|
||||
error={currentErrors.map((error) => error.message)}
|
||||
>
|
||||
<EuiTextArea
|
||||
inputRef={(node) => {
|
||||
inputRef.current = node;
|
||||
}}
|
||||
isInvalid={Boolean(currentErrors.length)}
|
||||
fullWidth
|
||||
value={currentQuery}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
css={{
|
||||
height: '5em',
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiButton fullWidth onClick={() => parseQuery(inputRef.current?.value ?? '')}>
|
||||
Parse
|
||||
</EuiButton>
|
||||
</EuiFormRow>
|
||||
</EuiForm>
|
||||
<EuiSpacer />
|
||||
<CodeEditor
|
||||
allowFullScreen={true}
|
||||
languageId={'json'}
|
||||
value={JSON.stringify(ast, null, 2)}
|
||||
/>
|
||||
</EuiPageSection>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</EuiProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -30,6 +30,7 @@ import {
|
|||
type MetaCommandContext,
|
||||
type MetricsCommandContext,
|
||||
IndexPatternContext,
|
||||
InlinestatsCommandContext,
|
||||
} from './antlr/esql_parser';
|
||||
import { default as ESQLParserListener } from './antlr/esql_parser_listener';
|
||||
import {
|
||||
|
@ -197,6 +198,23 @@ export class AstListener implements ESQLParserListener {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit a parse tree produced by `esql_parser.inlinestatsCommand`.
|
||||
* @param ctx the parse tree
|
||||
*/
|
||||
exitInlinestatsCommand(ctx: InlinestatsCommandContext) {
|
||||
const command = createCommand('inlinestats', ctx);
|
||||
this.ast.push(command);
|
||||
|
||||
// STATS expression is optional
|
||||
if (ctx._stats) {
|
||||
command.args.push(...collectAllFields(ctx.fields(0)));
|
||||
}
|
||||
if (ctx._grouping) {
|
||||
command.args.push(...visitByOption(ctx, ctx._stats ? ctx.fields(1) : ctx.fields(0)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit a parse tree produced by `esql_parser.limitCommand`.
|
||||
* @param ctx the parse tree
|
||||
|
|
|
@ -61,6 +61,7 @@ import {
|
|||
InputNamedOrPositionalParamContext,
|
||||
InputParamContext,
|
||||
IndexPatternContext,
|
||||
InlinestatsCommandContext,
|
||||
} from './antlr/esql_parser';
|
||||
import {
|
||||
createSource,
|
||||
|
@ -594,7 +595,10 @@ export function collectAllFields(ctx: FieldsContext | undefined): ESQLAstField[]
|
|||
return ast;
|
||||
}
|
||||
|
||||
export function visitByOption(ctx: StatsCommandContext, expr: FieldsContext | undefined) {
|
||||
export function visitByOption(
|
||||
ctx: StatsCommandContext | InlinestatsCommandContext,
|
||||
expr: FieldsContext | undefined
|
||||
) {
|
||||
if (!ctx.BY() || !expr) {
|
||||
return [];
|
||||
}
|
||||
|
|
|
@ -118,11 +118,10 @@ export class GlobalVisitorContext<
|
|||
if (!this.methods.visitStatsCommand) break;
|
||||
return this.visitStatsCommand(parent, commandNode, input as any);
|
||||
}
|
||||
// TODO: uncomment this when the command is implemented
|
||||
// case 'inline_stats': {
|
||||
// if (!this.methods.visitInlineStatsCommand) break;
|
||||
// return this.visitInlineStatsCommand(parent, commandNode, input as any);
|
||||
// }
|
||||
case 'inline_stats': {
|
||||
if (!this.methods.visitInlineStatsCommand) break;
|
||||
return this.visitInlineStatsCommand(parent, commandNode, input as any);
|
||||
}
|
||||
case 'lookup': {
|
||||
if (!this.methods.visitLookupCommand) break;
|
||||
return this.visitLookupCommand(parent, commandNode, input as any);
|
||||
|
|
|
@ -25,7 +25,7 @@ const aliasTable: Record<string, string[]> = {
|
|||
const aliases = new Set(Object.values(aliasTable).flat());
|
||||
|
||||
const evalSupportedCommandsAndOptions = {
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { suggest } from './autocomplete';
|
||||
import { evalFunctionDefinitions } from '../definitions/functions';
|
||||
import { timeUnitsToSuggest } from '../definitions/literals';
|
||||
import { commandDefinitions } from '../definitions/commands';
|
||||
import { commandDefinitions as unmodifiedCommandDefinitions } from '../definitions/commands';
|
||||
import {
|
||||
getSafeInsertText,
|
||||
getUnitDuration,
|
||||
|
@ -45,6 +45,7 @@ const roundParameterTypes = ['double', 'integer', 'long', 'unsigned_long'] as co
|
|||
const powParameterTypes = ['double', 'integer', 'long', 'unsigned_long'] as const;
|
||||
const log10ParameterTypes = ['double', 'integer', 'long', 'unsigned_long'] as const;
|
||||
|
||||
const commandDefinitions = unmodifiedCommandDefinitions.filter(({ hidden }) => !hidden);
|
||||
describe('autocomplete', () => {
|
||||
type TestArgs = [
|
||||
string,
|
||||
|
|
|
@ -246,6 +246,7 @@ export async function suggest(
|
|||
if (!ast.length) {
|
||||
return suggestions.filter(isSourceCommand);
|
||||
}
|
||||
|
||||
return suggestions.filter((def) => !isSourceCommand(def));
|
||||
}
|
||||
|
||||
|
|
|
@ -82,9 +82,9 @@ export const getBuiltinCompatibleFunctionDefinition = (
|
|||
.map(getSuggestionBuiltinDefinition);
|
||||
};
|
||||
|
||||
export const commandAutocompleteDefinitions: SuggestionRawDefinition[] = getAllCommands().map(
|
||||
getSuggestionCommandDefinition
|
||||
);
|
||||
export const commandAutocompleteDefinitions: SuggestionRawDefinition[] = getAllCommands()
|
||||
.filter(({ hidden }) => !hidden)
|
||||
.map(getSuggestionCommandDefinition);
|
||||
|
||||
function buildCharCompleteItem(
|
||||
label: string,
|
||||
|
|
|
@ -31,7 +31,7 @@ function createNumericAggDefinition({
|
|||
name,
|
||||
type: 'agg',
|
||||
description,
|
||||
supportedCommands: ['stats', 'metrics'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics'],
|
||||
signatures: [
|
||||
...ESQL_NUMBER_TYPES.map((numericType) => ({
|
||||
params: [
|
||||
|
@ -105,7 +105,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [
|
|||
}
|
||||
),
|
||||
type: 'agg',
|
||||
supportedCommands: ['stats', 'metrics'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics'],
|
||||
signatures: [
|
||||
...ESQL_COMMON_NUMERIC_TYPES.map((numericType: FunctionParameterType) => {
|
||||
return ESQL_COMMON_NUMERIC_TYPES.map((weightType: FunctionParameterType) => ({
|
||||
|
@ -133,7 +133,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [
|
|||
defaultMessage: 'Returns the maximum value in a field.',
|
||||
}),
|
||||
type: 'agg',
|
||||
supportedCommands: ['stats', 'metrics'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics'],
|
||||
signatures: [
|
||||
...ESQL_COMMON_NUMERIC_TYPES.map((type) => ({
|
||||
params: [{ name: 'column', type, noNestingFunctions: true }],
|
||||
|
@ -164,7 +164,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [
|
|||
defaultMessage: 'Returns the minimum value in a field.',
|
||||
}),
|
||||
type: 'agg',
|
||||
supportedCommands: ['stats', 'metrics'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics'],
|
||||
signatures: [
|
||||
...ESQL_COMMON_NUMERIC_TYPES.map((type) => ({
|
||||
params: [{ name: 'column', type, noNestingFunctions: true }],
|
||||
|
@ -197,7 +197,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [
|
|||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.countDoc', {
|
||||
defaultMessage: 'Returns the count of the values in a field.',
|
||||
}),
|
||||
supportedCommands: ['stats', 'metrics'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics'],
|
||||
signatures: [
|
||||
{
|
||||
params: [
|
||||
|
@ -223,7 +223,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [
|
|||
defaultMessage: 'Returns the count of distinct values in a field.',
|
||||
}
|
||||
),
|
||||
supportedCommands: ['stats', 'metrics'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics'],
|
||||
signatures: [
|
||||
{
|
||||
params: [
|
||||
|
@ -252,7 +252,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [
|
|||
defaultMessage: 'Returns the count of distinct values in a field.',
|
||||
}
|
||||
),
|
||||
supportedCommands: ['stats', 'metrics'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics'],
|
||||
signatures: [
|
||||
{
|
||||
params: [{ name: 'column', type: 'cartesian_point', noNestingFunctions: true }],
|
||||
|
@ -338,7 +338,7 @@ export const statsAggregationFunctionDefinitions: FunctionDefinition[] = [
|
|||
'An aggregation that computes the weighted average of numeric values that are extracted from the aggregated documents.',
|
||||
}
|
||||
),
|
||||
supportedCommands: ['stats', 'metrics'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics'],
|
||||
signatures: [
|
||||
...ESQL_COMMON_NUMERIC_TYPES.map((numericType: FunctionParameterType) => {
|
||||
return ESQL_COMMON_NUMERIC_TYPES.map((weightType: FunctionParameterType) => ({
|
||||
|
|
|
@ -591,7 +591,16 @@ const otherDefinitions: FunctionDefinition[] = [
|
|||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.assignDoc', {
|
||||
defaultMessage: 'Assign (=)',
|
||||
}),
|
||||
supportedCommands: ['eval', 'stats', 'metrics', 'row', 'dissect', 'where', 'enrich'],
|
||||
supportedCommands: [
|
||||
'eval',
|
||||
'stats',
|
||||
'inlinestats',
|
||||
'metrics',
|
||||
'row',
|
||||
'dissect',
|
||||
'where',
|
||||
'enrich',
|
||||
],
|
||||
supportedOptions: ['by', 'with'],
|
||||
signatures: [
|
||||
{
|
||||
|
|
|
@ -32,6 +32,121 @@ import {
|
|||
} from './options';
|
||||
import type { CommandDefinition } from './types';
|
||||
|
||||
const statsValidator = (command: ESQLCommand) => {
|
||||
const messages: ESQLMessage[] = [];
|
||||
const commandName = command.name.toUpperCase();
|
||||
if (!command.args.length) {
|
||||
messages.push({
|
||||
location: command.location,
|
||||
text: i18n.translate('kbn-esql-validation-autocomplete.esql.validation.statsNoArguments', {
|
||||
defaultMessage:
|
||||
'At least one aggregation or grouping expression required in [{commandName}]',
|
||||
values: { commandName },
|
||||
}),
|
||||
type: 'error',
|
||||
code: 'statsNoArguments',
|
||||
});
|
||||
}
|
||||
|
||||
// now that all functions are supported, there's a specific check to perform
|
||||
// unfortunately the logic here is a bit complex as it needs to dig deeper into the args
|
||||
// until an agg function is detected
|
||||
// in the long run this might be integrated into the validation function
|
||||
const statsArg = command.args
|
||||
.flatMap((arg) => (isAssignment(arg) ? arg.args[1] : arg))
|
||||
.filter(isFunctionItem);
|
||||
|
||||
if (statsArg.length) {
|
||||
function isAggFunction(arg: ESQLAstItem): arg is ESQLFunction {
|
||||
return isFunctionItem(arg) && getFunctionDefinition(arg.name)?.type === 'agg';
|
||||
}
|
||||
function isOtherFunction(arg: ESQLAstItem): arg is ESQLFunction {
|
||||
return isFunctionItem(arg) && getFunctionDefinition(arg.name)?.type !== 'agg';
|
||||
}
|
||||
|
||||
function checkAggExistence(arg: ESQLFunction): boolean {
|
||||
// TODO the grouping function check may not
|
||||
// hold true for all future cases
|
||||
if (isAggFunction(arg)) {
|
||||
return true;
|
||||
}
|
||||
if (isOtherFunction(arg)) {
|
||||
return (arg as ESQLFunction).args.filter(isFunctionItem).some(checkAggExistence);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// first check: is there an agg function somewhere?
|
||||
const noAggsExpressions = statsArg.filter((arg) => !checkAggExistence(arg));
|
||||
|
||||
if (noAggsExpressions.length) {
|
||||
messages.push(
|
||||
...noAggsExpressions.map((fn) => ({
|
||||
location: fn.location,
|
||||
text: i18n.translate(
|
||||
'kbn-esql-validation-autocomplete.esql.validation.statsNoAggFunction',
|
||||
{
|
||||
defaultMessage:
|
||||
'At least one aggregation function required in [{commandName}], found [{expression}]',
|
||||
values: {
|
||||
expression: fn.text,
|
||||
commandName,
|
||||
},
|
||||
}
|
||||
),
|
||||
type: 'error' as const,
|
||||
code: 'statsNoAggFunction',
|
||||
}))
|
||||
);
|
||||
} else {
|
||||
function isConstantOrAggFn(arg: ESQLAstItem): boolean {
|
||||
return isLiteralItem(arg) || isAggFunction(arg);
|
||||
}
|
||||
// now check that:
|
||||
// * the agg function is at root level
|
||||
// * or if it's a builtin function, then all operands are agg functions or literals
|
||||
// * or if it's a eval function then all arguments are agg functions or literals
|
||||
function checkFunctionContent(arg: ESQLFunction) {
|
||||
// TODO the grouping function check may not
|
||||
// hold true for all future cases
|
||||
if (isAggFunction(arg)) {
|
||||
return true;
|
||||
}
|
||||
return (arg as ESQLFunction).args.every(
|
||||
(subArg): boolean =>
|
||||
isConstantOrAggFn(subArg) ||
|
||||
(isOtherFunction(subArg) ? checkFunctionContent(subArg) : false)
|
||||
);
|
||||
}
|
||||
// @TODO: improve here the check to get the last instance of the invalidExpression
|
||||
// to provide a better location for the error message
|
||||
// i.e. STATS round(round(round( a + sum(b) )))
|
||||
// should return the location of the + node, just before the agg one
|
||||
const invalidExpressions = statsArg.filter((arg) => !checkFunctionContent(arg));
|
||||
|
||||
if (invalidExpressions.length) {
|
||||
messages.push(
|
||||
...invalidExpressions.map((fn) => ({
|
||||
location: fn.location,
|
||||
text: i18n.translate(
|
||||
'kbn-esql-validation-autocomplete.esql.validation.noCombinationOfAggAndNonAggValues',
|
||||
{
|
||||
defaultMessage:
|
||||
'Cannot combine aggregation and non-aggregation values in [{commandName}], found [{expression}]',
|
||||
values: {
|
||||
expression: fn.text,
|
||||
commandName,
|
||||
},
|
||||
}
|
||||
),
|
||||
type: 'error' as const,
|
||||
code: 'statsNoCombinationOfAggAndNonAggValues',
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
};
|
||||
export const commandDefinitions: CommandDefinition[] = [
|
||||
{
|
||||
name: 'row',
|
||||
|
@ -118,120 +233,29 @@ export const commandDefinitions: CommandDefinition[] = [
|
|||
},
|
||||
options: [byOption],
|
||||
modes: [],
|
||||
validate: (command: ESQLCommand) => {
|
||||
const messages: ESQLMessage[] = [];
|
||||
if (!command.args.length) {
|
||||
messages.push({
|
||||
location: command.location,
|
||||
text: i18n.translate(
|
||||
'kbn-esql-validation-autocomplete.esql.validation.statsNoArguments',
|
||||
{
|
||||
defaultMessage: 'At least one aggregation or grouping expression required in [STATS]',
|
||||
}
|
||||
),
|
||||
type: 'error',
|
||||
code: 'statsNoArguments',
|
||||
});
|
||||
}
|
||||
|
||||
// now that all functions are supported, there's a specific check to perform
|
||||
// unfortunately the logic here is a bit complex as it needs to dig deeper into the args
|
||||
// until an agg function is detected
|
||||
// in the long run this might be integrated into the validation function
|
||||
const statsArg = command.args
|
||||
.flatMap((arg) => (isAssignment(arg) ? arg.args[1] : arg))
|
||||
.filter(isFunctionItem);
|
||||
|
||||
if (statsArg.length) {
|
||||
function isAggFunction(arg: ESQLAstItem): arg is ESQLFunction {
|
||||
return isFunctionItem(arg) && getFunctionDefinition(arg.name)?.type === 'agg';
|
||||
}
|
||||
function isOtherFunction(arg: ESQLAstItem): arg is ESQLFunction {
|
||||
return isFunctionItem(arg) && getFunctionDefinition(arg.name)?.type !== 'agg';
|
||||
}
|
||||
|
||||
function checkAggExistence(arg: ESQLFunction): boolean {
|
||||
// TODO the grouping function check may not
|
||||
// hold true for all future cases
|
||||
if (isAggFunction(arg)) {
|
||||
return true;
|
||||
}
|
||||
if (isOtherFunction(arg)) {
|
||||
return (arg as ESQLFunction).args.filter(isFunctionItem).some(checkAggExistence);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// first check: is there an agg function somewhere?
|
||||
const noAggsExpressions = statsArg.filter((arg) => !checkAggExistence(arg));
|
||||
|
||||
if (noAggsExpressions.length) {
|
||||
messages.push(
|
||||
...noAggsExpressions.map((fn) => ({
|
||||
location: fn.location,
|
||||
text: i18n.translate(
|
||||
'kbn-esql-validation-autocomplete.esql.validation.statsNoAggFunction',
|
||||
{
|
||||
defaultMessage:
|
||||
'At least one aggregation function required in [STATS], found [{expression}]',
|
||||
values: {
|
||||
expression: fn.text,
|
||||
},
|
||||
}
|
||||
),
|
||||
type: 'error' as const,
|
||||
code: 'statsNoAggFunction',
|
||||
}))
|
||||
);
|
||||
} else {
|
||||
function isConstantOrAggFn(arg: ESQLAstItem): boolean {
|
||||
return isLiteralItem(arg) || isAggFunction(arg);
|
||||
}
|
||||
// now check that:
|
||||
// * the agg function is at root level
|
||||
// * or if it's a builtin function, then all operands are agg functions or literals
|
||||
// * or if it's a eval function then all arguments are agg functions or literals
|
||||
function checkFunctionContent(arg: ESQLFunction) {
|
||||
// TODO the grouping function check may not
|
||||
// hold true for all future cases
|
||||
if (isAggFunction(arg)) {
|
||||
return true;
|
||||
}
|
||||
return (arg as ESQLFunction).args.every(
|
||||
(subArg): boolean =>
|
||||
isConstantOrAggFn(subArg) ||
|
||||
(isOtherFunction(subArg) ? checkFunctionContent(subArg) : false)
|
||||
);
|
||||
}
|
||||
// @TODO: improve here the check to get the last instance of the invalidExpression
|
||||
// to provide a better location for the error message
|
||||
// i.e. STATS round(round(round( a + sum(b) )))
|
||||
// should return the location of the + node, just before the agg one
|
||||
const invalidExpressions = statsArg.filter((arg) => !checkFunctionContent(arg));
|
||||
|
||||
if (invalidExpressions.length) {
|
||||
messages.push(
|
||||
...invalidExpressions.map((fn) => ({
|
||||
location: fn.location,
|
||||
text: i18n.translate(
|
||||
'kbn-esql-validation-autocomplete.esql.validation.noCombinationOfAggAndNonAggValues',
|
||||
{
|
||||
defaultMessage:
|
||||
'Cannot combine aggregation and non-aggregation values in [STATS], found [{expression}]',
|
||||
values: {
|
||||
expression: fn.text,
|
||||
},
|
||||
}
|
||||
),
|
||||
type: 'error' as const,
|
||||
code: 'statsNoCombinationOfAggAndNonAggValues',
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
},
|
||||
validate: statsValidator,
|
||||
},
|
||||
{
|
||||
name: 'inlinestats',
|
||||
hidden: true,
|
||||
description: i18n.translate(
|
||||
'kbn-esql-validation-autocomplete.esql.definitions.inlineStatsDoc',
|
||||
{
|
||||
defaultMessage:
|
||||
'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.',
|
||||
}
|
||||
),
|
||||
examples: ['… | EVAL bar = a * b | INLINESTATS m = MAX(bar) BY b'],
|
||||
signature: {
|
||||
multipleParams: true,
|
||||
params: [{ name: 'expression', type: 'function', optional: true }],
|
||||
},
|
||||
options: [byOption],
|
||||
modes: [],
|
||||
// Reusing the same validation logic as stats command
|
||||
validate: statsValidator,
|
||||
},
|
||||
|
||||
{
|
||||
name: 'eval',
|
||||
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.evalDoc', {
|
||||
|
|
|
@ -80,7 +80,7 @@ const absDefinition: FunctionDefinition = {
|
|||
returnType: 'unsigned_long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -139,7 +139,7 @@ const acosDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=.9\n| EVAL acos=ACOS(a)'],
|
||||
|
@ -196,7 +196,7 @@ const asinDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=.9\n| EVAL asin=ASIN(a)'],
|
||||
|
@ -253,7 +253,7 @@ const atanDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=12.9\n| EVAL atan=ATAN(a)'],
|
||||
|
@ -510,7 +510,7 @@ const atan2Definition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW y=12.9, x=.6\n| EVAL atan2=ATAN2(y, x)'],
|
||||
|
@ -567,7 +567,7 @@ const cbrtDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW d = 1000.0\n| EVAL c = cbrt(d)'],
|
||||
|
@ -623,7 +623,7 @@ const ceilDefinition: FunctionDefinition = {
|
|||
returnType: 'unsigned_long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=1.8\n| EVAL a=CEIL(a)'],
|
||||
|
@ -672,7 +672,7 @@ const cidrMatchDefinition: FunctionDefinition = {
|
|||
minParams: 2,
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -938,7 +938,7 @@ const coalesceDefinition: FunctionDefinition = {
|
|||
minParams: 1,
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=null, b="b"\n| EVAL COALESCE(a, b)'],
|
||||
|
@ -1018,7 +1018,7 @@ const concatDefinition: FunctionDefinition = {
|
|||
minParams: 2,
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -1076,7 +1076,7 @@ const cosDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=1.8 \n| EVAL cos=COS(a)'],
|
||||
|
@ -1132,7 +1132,7 @@ const coshDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=1.8 \n| EVAL cosh=COSH(a)'],
|
||||
|
@ -1250,7 +1250,7 @@ const dateDiffDefinition: FunctionDefinition = {
|
|||
returnType: 'integer',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -1330,7 +1330,7 @@ const dateExtractDefinition: FunctionDefinition = {
|
|||
returnType: 'long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -1379,7 +1379,7 @@ const dateFormatDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -1458,7 +1458,7 @@ const dateParseDefinition: FunctionDefinition = {
|
|||
returnType: 'date',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW date_string = "2022-05-06"\n| EVAL date = DATE_PARSE("yyyy-MM-dd", date_string)'],
|
||||
|
@ -1504,7 +1504,7 @@ const dateTruncDefinition: FunctionDefinition = {
|
|||
returnType: 'date',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -1528,7 +1528,7 @@ const eDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW E()'],
|
||||
|
@ -1605,7 +1605,7 @@ const endsWithDefinition: FunctionDefinition = {
|
|||
returnType: 'boolean',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['FROM employees\n| KEEP last_name\n| EVAL ln_E = ENDS_WITH(last_name, "d")'],
|
||||
|
@ -1661,7 +1661,7 @@ const expDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW d = 5.0\n| EVAL s = EXP(d)'],
|
||||
|
@ -1717,7 +1717,7 @@ const floorDefinition: FunctionDefinition = {
|
|||
returnType: 'unsigned_long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=1.8\n| EVAL a=FLOOR(a)'],
|
||||
|
@ -1753,7 +1753,7 @@ const fromBase64Definition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['row a = "ZWxhc3RpYw==" \n| eval d = from_base64(a)'],
|
||||
|
@ -1953,7 +1953,7 @@ const greatestDefinition: FunctionDefinition = {
|
|||
minParams: 1,
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a = 10, b = 20\n| EVAL g = GREATEST(a, b)'],
|
||||
|
@ -1989,7 +1989,7 @@ const ipPrefixDefinition: FunctionDefinition = {
|
|||
returnType: 'ip',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -2191,7 +2191,7 @@ const leastDefinition: FunctionDefinition = {
|
|||
minParams: 1,
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a = 10, b = 20\n| EVAL l = LEAST(a, b)'],
|
||||
|
@ -2238,7 +2238,7 @@ const leftDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -2276,7 +2276,7 @@ const lengthDefinition: FunctionDefinition = {
|
|||
returnType: 'integer',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['FROM employees\n| KEEP first_name, last_name\n| EVAL fn_length = LENGTH(first_name)'],
|
||||
|
@ -2433,7 +2433,7 @@ const locateDefinition: FunctionDefinition = {
|
|||
returnType: 'integer',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['row a = "hello"\n| eval a_ll = locate(a, "ll")'],
|
||||
|
@ -2730,14 +2730,14 @@ const logDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: (fnDef: ESQLFunction) => {
|
||||
const messages = [];
|
||||
// do not really care here about the base and field
|
||||
// just need to check both values are not negative
|
||||
for (const arg of fnDef.args) {
|
||||
if (isLiteralItem(arg) && Number(arg.value) < 0) {
|
||||
if (isLiteralItem(arg) && typeof arg.value === 'number' && arg.value < 0) {
|
||||
messages.push({
|
||||
type: 'warning' as const,
|
||||
code: 'logOfNegativeValue',
|
||||
|
@ -2813,14 +2813,14 @@ const log10Definition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: (fnDef: ESQLFunction) => {
|
||||
const messages = [];
|
||||
// do not really care here about the base and field
|
||||
// just need to check both values are not negative
|
||||
for (const arg of fnDef.args) {
|
||||
if (isLiteralItem(arg) && Number(arg.value) < 0) {
|
||||
if (isLiteralItem(arg) && typeof arg.value === 'number' && arg.value < 0) {
|
||||
messages.push({
|
||||
type: 'warning' as const,
|
||||
code: 'logOfNegativeValue',
|
||||
|
@ -2872,7 +2872,7 @@ const ltrimDefinition: FunctionDefinition = {
|
|||
returnType: 'text',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -3085,7 +3085,7 @@ const mvAppendDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [],
|
||||
|
@ -3142,7 +3142,7 @@ const mvAvgDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=[3, 5, 1, 6]\n| EVAL avg_a = MV_AVG(a)'],
|
||||
|
@ -3219,7 +3219,7 @@ const mvConcatDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -3379,7 +3379,7 @@ const mvCountDefinition: FunctionDefinition = {
|
|||
returnType: 'integer',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=["foo", "zoo", "bar"]\n| EVAL count_a = MV_COUNT(a)'],
|
||||
|
@ -3525,7 +3525,7 @@ const mvDedupeDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=["foo", "foo", "bar", "foo"]\n| EVAL dedupe_a = MV_DEDUPE(a)'],
|
||||
|
@ -3682,7 +3682,7 @@ const mvFirstDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a="foo;bar;baz"\n| EVAL first_a = MV_FIRST(SPLIT(a, ";"))'],
|
||||
|
@ -3839,7 +3839,7 @@ const mvLastDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a="foo;bar;baz"\n| EVAL last_a = MV_LAST(SPLIT(a, ";"))'],
|
||||
|
@ -3956,7 +3956,7 @@ const mvMaxDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -4016,7 +4016,7 @@ const mvMedianDefinition: FunctionDefinition = {
|
|||
returnType: 'unsigned_long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -4136,7 +4136,7 @@ const mvMinDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -4453,7 +4453,7 @@ const mvSliceDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -4616,9 +4616,10 @@ const mvSortDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
|
||||
examples: ['ROW a = [4, 2, -3, 2]\n| EVAL sa = mv_sort(a), sd = mv_sort(a, "DESC")'],
|
||||
};
|
||||
|
||||
|
@ -4673,7 +4674,7 @@ const mvSumDefinition: FunctionDefinition = {
|
|||
returnType: 'unsigned_long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=[3, 5, 6]\n| EVAL sum_a = MV_SUM(a)'],
|
||||
|
@ -4910,7 +4911,7 @@ const mvZipDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -4932,7 +4933,7 @@ const nowDefinition: FunctionDefinition = {
|
|||
returnType: 'date',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW current_date = NOW()', 'FROM sample_data\n| WHERE @timestamp > NOW() - 1 hour'],
|
||||
|
@ -4952,7 +4953,7 @@ const piDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW PI()'],
|
||||
|
@ -5208,7 +5209,7 @@ const powDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -5258,7 +5259,7 @@ const repeatDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a = "Hello!"\n| EVAL triple_a = REPEAT(a, 3);'],
|
||||
|
@ -5435,7 +5436,7 @@ const replaceDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW str = "Hello World"\n| EVAL str = REPLACE(str, "World", "Universe")\n| KEEP str'],
|
||||
|
@ -5482,7 +5483,7 @@ const rightDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -5586,7 +5587,7 @@ const roundDefinition: FunctionDefinition = {
|
|||
returnType: 'unsigned_long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -5624,7 +5625,7 @@ const rtrimDefinition: FunctionDefinition = {
|
|||
returnType: 'text',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -5683,7 +5684,7 @@ const signumDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW d = 100.0\n| EVAL s = SIGNUM(d)'],
|
||||
|
@ -5739,7 +5740,7 @@ const sinDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=1.8 \n| EVAL sin=SIN(a)'],
|
||||
|
@ -5795,7 +5796,7 @@ const sinhDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=1.8 \n| EVAL sinh=SINH(a)'],
|
||||
|
@ -5871,7 +5872,7 @@ const splitDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW words="foo;bar;baz;qux;quux;corge"\n| EVAL word = SPLIT(words, ";")'],
|
||||
|
@ -5928,7 +5929,7 @@ const sqrtDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW d = 100.0\n| EVAL s = SQRT(d)'],
|
||||
|
@ -6065,7 +6066,7 @@ const stContainsDefinition: FunctionDefinition = {
|
|||
returnType: 'boolean',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -6204,7 +6205,7 @@ const stDisjointDefinition: FunctionDefinition = {
|
|||
returnType: 'boolean',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -6253,7 +6254,7 @@ const stDistanceDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -6392,7 +6393,7 @@ const stIntersectsDefinition: FunctionDefinition = {
|
|||
returnType: 'boolean',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -6531,7 +6532,7 @@ const stWithinDefinition: FunctionDefinition = {
|
|||
returnType: 'boolean',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -6570,7 +6571,7 @@ const stXDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -6609,7 +6610,7 @@ const stYDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -6688,7 +6689,7 @@ const startsWithDefinition: FunctionDefinition = {
|
|||
returnType: 'boolean',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['FROM employees\n| KEEP last_name\n| EVAL ln_S = STARTS_WITH(last_name, "B")'],
|
||||
|
@ -6745,7 +6746,7 @@ const substringDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -6805,7 +6806,7 @@ const tanDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=1.8 \n| EVAL tan=TAN(a)'],
|
||||
|
@ -6861,7 +6862,7 @@ const tanhDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=1.8 \n| EVAL tanh=TANH(a)'],
|
||||
|
@ -6881,7 +6882,7 @@ const tauDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW TAU()'],
|
||||
|
@ -6917,7 +6918,7 @@ const toBase64Definition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['row a = "elastic" \n| eval e = to_base64(a)'],
|
||||
|
@ -7004,7 +7005,7 @@ const toBooleanDefinition: FunctionDefinition = {
|
|||
returnType: 'boolean',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW str = ["true", "TRuE", "false", "", "yes", "1"]\n| EVAL bool = TO_BOOLEAN(str)'],
|
||||
|
@ -7054,7 +7055,7 @@ const toCartesianpointDefinition: FunctionDefinition = {
|
|||
returnType: 'cartesian_point',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -7116,7 +7117,7 @@ const toCartesianshapeDefinition: FunctionDefinition = {
|
|||
returnType: 'cartesian_shape',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -7205,7 +7206,7 @@ const toDatetimeDefinition: FunctionDefinition = {
|
|||
returnType: 'date',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -7264,7 +7265,7 @@ const toDegreesDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW rad = [1.57, 3.14, 4.71]\n| EVAL deg = TO_DEGREES(rad)'],
|
||||
|
@ -7391,7 +7392,7 @@ const toDoubleDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -7440,7 +7441,7 @@ const toGeopointDefinition: FunctionDefinition = {
|
|||
returnType: 'geo_point',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW wkt = "POINT(42.97109630194 14.7552534413725)"\n| EVAL pt = TO_GEOPOINT(wkt)'],
|
||||
|
@ -7497,7 +7498,7 @@ const toGeoshapeDefinition: FunctionDefinition = {
|
|||
returnType: 'geo_shape',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -7606,7 +7607,7 @@ const toIntegerDefinition: FunctionDefinition = {
|
|||
returnType: 'integer',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW long = [5013792, 2147483647, 501379200000]\n| EVAL int = TO_INTEGER(long)'],
|
||||
|
@ -7652,7 +7653,7 @@ const toIpDefinition: FunctionDefinition = {
|
|||
returnType: 'ip',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -7771,7 +7772,7 @@ const toLongDefinition: FunctionDefinition = {
|
|||
returnType: 'long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -7809,7 +7810,7 @@ const toLowerDefinition: FunctionDefinition = {
|
|||
returnType: 'text',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW message = "Some Text"\n| EVAL message_lower = TO_LOWER(message)'],
|
||||
|
@ -7865,7 +7866,7 @@ const toRadiansDefinition: FunctionDefinition = {
|
|||
returnType: 'double',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW deg = [90.0, 180.0, 270.0]\n| EVAL rad = TO_RADIANS(deg)'],
|
||||
|
@ -8021,7 +8022,7 @@ const toStringDefinition: FunctionDefinition = {
|
|||
returnType: 'keyword',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW a=10\n| EVAL j = TO_STRING(a)', 'ROW a=[10, 9, 8]\n| EVAL j = TO_STRING(a)'],
|
||||
|
@ -8121,7 +8122,7 @@ const toUnsignedLongDefinition: FunctionDefinition = {
|
|||
returnType: 'unsigned_long',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -8159,7 +8160,7 @@ const toUpperDefinition: FunctionDefinition = {
|
|||
returnType: 'text',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW message = "Some Text"\n| EVAL message_upper = TO_UPPER(message)'],
|
||||
|
@ -8205,7 +8206,7 @@ const toVersionDefinition: FunctionDefinition = {
|
|||
returnType: 'version',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: ['ROW v = TO_VERSION("1.2.3")'],
|
||||
|
@ -8241,7 +8242,7 @@ const trimDefinition: FunctionDefinition = {
|
|||
returnType: 'text',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
@ -8274,7 +8275,7 @@ const caseDefinition: FunctionDefinition = {
|
|||
returnType: 'any',
|
||||
},
|
||||
],
|
||||
supportedCommands: ['stats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'],
|
||||
supportedOptions: ['by'],
|
||||
validate: undefined,
|
||||
examples: [
|
||||
|
|
|
@ -147,6 +147,10 @@ export interface CommandBaseDefinition {
|
|||
name: string;
|
||||
alias?: string;
|
||||
description: string;
|
||||
/**
|
||||
* Whether to show or hide in autocomplete suggestion list
|
||||
*/
|
||||
hidden?: boolean;
|
||||
signature: {
|
||||
multipleParams: boolean;
|
||||
// innerType here is useful to drill down the type in case of "column"
|
||||
|
|
|
@ -156,9 +156,9 @@ export function collectVariables(
|
|||
): Map<string, ESQLVariable[]> {
|
||||
const variables = new Map<string, ESQLVariable[]>();
|
||||
for (const command of commands) {
|
||||
if (['row', 'eval', 'stats', 'metrics'].includes(command.name)) {
|
||||
if (['row', 'eval', 'stats', 'inlinestats', 'metrics'].includes(command.name)) {
|
||||
collectVariablesFromList(command.args, fields, queryString, variables);
|
||||
if (command.name === 'stats') {
|
||||
if (command.name === 'stats' || command.name === 'inlinestats') {
|
||||
const commandOptionsWithAssignment = command.args.filter(
|
||||
(arg) => isOptionItem(arg) && arg.name === 'by'
|
||||
) as ESQLCommandOption[];
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* 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 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as helpers from '../helpers';
|
||||
|
||||
export const validationStatsCommandTestSuite = (setup: helpers.Setup) => {
|
||||
describe('validation', () => {
|
||||
describe('command', () => {
|
||||
describe('INLINESTATS <aggregates> [ BY <grouping> ]', () => {
|
||||
test('no errors on correct usage', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS by textField', []);
|
||||
await expectErrors(
|
||||
`FROM index
|
||||
| EVAL doubleField * 3.281
|
||||
| INLINESTATS avg_doubleField = AVG(\`doubleField * 3.281\`)`,
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
`FROM index | INLINESTATS AVG(doubleField) by round(doubleField) + 1 | EVAL \`round(doubleField) + 1\` / 2`,
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
test('errors on invalid command start', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS ', [
|
||||
'At least one aggregation or grouping expression required in [INLINESTATS]',
|
||||
]);
|
||||
});
|
||||
|
||||
describe('... <aggregates> ...', () => {
|
||||
test('no errors on correct usage', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS avg(doubleField) by 1', []);
|
||||
await expectErrors('from a_index | INLINESTATS count(`doubleField`)', []);
|
||||
await expectErrors('from a_index | INLINESTATS count(*)', []);
|
||||
await expectErrors('from a_index | INLINESTATS count()', []);
|
||||
await expectErrors('from a_index | INLINESTATS var0 = count(*)', []);
|
||||
await expectErrors('from a_index | INLINESTATS var0 = count()', []);
|
||||
await expectErrors('from a_index | INLINESTATS var0 = avg(doubleField), count(*)', []);
|
||||
await expectErrors(`from a_index | INLINESTATS sum(case(false, 0, 1))`, []);
|
||||
await expectErrors(`from a_index | INLINESTATS var0 = sum( case(false, 0, 1))`, []);
|
||||
|
||||
// "or" must accept "null"
|
||||
await expectErrors('from a_index | INLINESTATS count(textField == "a" or null)', []);
|
||||
});
|
||||
|
||||
test('sub-command can reference aggregated field', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
for (const subCommand of ['keep', 'drop', 'eval']) {
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS count(`doubleField`) | ' +
|
||||
subCommand +
|
||||
' `count(``doubleField``)` ',
|
||||
[]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('errors on agg and non-agg mix', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS sum( doubleField ) + abs( doubleField ) ',
|
||||
[
|
||||
'Cannot combine aggregation and non-aggregation values in [INLINESTATS], found [sum(doubleField)+abs(doubleField)]',
|
||||
]
|
||||
);
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS abs( doubleField + sum( doubleField )) ',
|
||||
[
|
||||
'Cannot combine aggregation and non-aggregation values in [INLINESTATS], found [abs(doubleField+sum(doubleField))]',
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('errors on each aggregation field, which does not contain at least one agg function', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS doubleField + 1', [
|
||||
'At least one aggregation function required in [INLINESTATS], found [doubleField+1]',
|
||||
]);
|
||||
await expectErrors('from a_index | INLINESTATS doubleField + 1, textField', [
|
||||
'At least one aggregation function required in [INLINESTATS], found [doubleField+1]',
|
||||
'Expected an aggregate function or group but got [textField] of type [FieldAttribute]',
|
||||
]);
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS doubleField + 1, doubleField + 2, count()',
|
||||
[
|
||||
'At least one aggregation function required in [INLINESTATS], found [doubleField+1]',
|
||||
'At least one aggregation function required in [INLINESTATS], found [doubleField+2]',
|
||||
]
|
||||
);
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS doubleField + 1, doubleField + count(), count()',
|
||||
['At least one aggregation function required in [INLINESTATS], found [doubleField+1]']
|
||||
);
|
||||
await expectErrors('from a_index | INLINESTATS 5 + doubleField + 1', [
|
||||
'At least one aggregation function required in [INLINESTATS], found [5+doubleField+1]',
|
||||
]);
|
||||
await expectErrors('from a_index | INLINESTATS doubleField + 1 by ipField', [
|
||||
'At least one aggregation function required in [INLINESTATS], found [doubleField+1]',
|
||||
]);
|
||||
});
|
||||
|
||||
test('errors when input is not an aggregate function', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS doubleField ', [
|
||||
'Expected an aggregate function or group but got [doubleField] of type [FieldAttribute]',
|
||||
]);
|
||||
});
|
||||
|
||||
test('various errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS doubleField=', [
|
||||
"SyntaxError: mismatched input '<EOF>' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}",
|
||||
]);
|
||||
await expectErrors('from a_index | INLINESTATS doubleField=5 by ', [
|
||||
"SyntaxError: mismatched input '<EOF>' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}",
|
||||
]);
|
||||
await expectErrors('from a_index | INLINESTATS avg(doubleField) by wrongField', [
|
||||
'Unknown column [wrongField]',
|
||||
]);
|
||||
await expectErrors('from a_index | INLINESTATS avg(doubleField) by wrongField + 1', [
|
||||
'Unknown column [wrongField]',
|
||||
]);
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS avg(doubleField) by var0 = wrongField + 1',
|
||||
['Unknown column [wrongField]']
|
||||
);
|
||||
await expectErrors('from a_index | INLINESTATS var0 = avg(fn(number)), count(*)', [
|
||||
'Unknown function [fn]',
|
||||
]);
|
||||
});
|
||||
|
||||
test('semantic errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS count(round(*))', [
|
||||
'Using wildcards (*) in round is not allowed',
|
||||
]);
|
||||
await expectErrors('from a_index | INLINESTATS count(count(*))', [
|
||||
`Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [count(*)] of type [long]`,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('... BY <grouping>', () => {
|
||||
test('no errors on correct usage', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS avg(doubleField), percentile(doubleField, 50) by ipField',
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS avg(doubleField), percentile(doubleField, 50) BY ipField',
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS avg(doubleField), percentile(doubleField, 50) + 1 by ipField',
|
||||
[]
|
||||
);
|
||||
for (const op of ['+', '-', '*', '/', '%']) {
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS avg(doubleField) ${op} percentile(doubleField, 50) BY ipField`,
|
||||
[]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('cannot specify <grouping> without <aggregates>', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS by ', [
|
||||
"SyntaxError: mismatched input '<EOF>' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}",
|
||||
]);
|
||||
});
|
||||
|
||||
test('syntax errors in <aggregates>', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS count(* + 1) BY ipField', [
|
||||
"SyntaxError: no viable alternative at input 'count(* +'",
|
||||
]);
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS count(* + round(doubleField)) BY ipField',
|
||||
["SyntaxError: no viable alternative at input 'count(* +'"]
|
||||
);
|
||||
});
|
||||
|
||||
test('semantic errors in <aggregates>', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from a_index | INLINESTATS count(round(*)) BY ipField', [
|
||||
'Using wildcards (*) in round is not allowed',
|
||||
]);
|
||||
await expectErrors('from a_index | INLINESTATS count(count(*)) BY ipField', [
|
||||
`Aggregate function's parameters must be an attribute, literal or a non-aggregation function; found [count(*)] of type [long]`,
|
||||
]);
|
||||
});
|
||||
|
||||
test('various errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS avg(doubleField) by percentile(doubleField)',
|
||||
['INLINESTATS BY does not support function percentile']
|
||||
);
|
||||
await expectErrors(
|
||||
'from a_index | INLINESTATS avg(doubleField) by textField, percentile(doubleField) by ipField',
|
||||
[
|
||||
"SyntaxError: mismatched input 'by' expecting <EOF>",
|
||||
'INLINESTATS BY does not support function percentile',
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
describe('constant-only parameters', () => {
|
||||
test('no errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors(
|
||||
'from index | INLINESTATS by bucket(dateField, 1 + 30 / 10, "", "")',
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
'from index | INLINESTATS by bucket(dateField, 1 + 30 / 10, concat("", ""), "")',
|
||||
['Argument of [bucket] must be [date], found value [concat("","")] type [keyword]']
|
||||
);
|
||||
});
|
||||
|
||||
test('errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors('from index | INLINESTATS by bucket(dateField, pi(), "", "")', [
|
||||
'Argument of [bucket] must be [integer], found value [pi()] type [double]',
|
||||
]);
|
||||
|
||||
await expectErrors(
|
||||
'from index | INLINESTATS by bucket(dateField, abs(doubleField), "", "")',
|
||||
['Argument of [bucket] must be a constant, received [abs(doubleField)]']
|
||||
);
|
||||
await expectErrors(
|
||||
'from index | INLINESTATS by bucket(dateField, abs(length(doubleField)), "", "")',
|
||||
['Argument of [bucket] must be a constant, received [abs(length(doubleField))]']
|
||||
);
|
||||
await expectErrors(
|
||||
'from index | INLINESTATS by bucket(dateField, doubleField, textField, textField)',
|
||||
[
|
||||
'Argument of [bucket] must be a constant, received [doubleField]',
|
||||
'Argument of [bucket] must be a constant, received [textField]',
|
||||
'Argument of [bucket] must be a constant, received [textField]',
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('nesting', () => {
|
||||
const NESTING_LEVELS = 4;
|
||||
const NESTED_DEPTHS = Array(NESTING_LEVELS)
|
||||
.fill(0)
|
||||
.map((_, i) => i + 1);
|
||||
|
||||
for (const nesting of NESTED_DEPTHS) {
|
||||
describe(`depth = ${nesting}`, () => {
|
||||
describe('builtin', () => {
|
||||
const builtinWrapping = Array(nesting).fill('+1').join('');
|
||||
|
||||
test('no errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS 5 + avg(doubleField) ${builtinWrapping}`,
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS 5 ${builtinWrapping} + avg(doubleField)`,
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
test('errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS 5 ${builtinWrapping} + doubleField`,
|
||||
[
|
||||
`At least one aggregation function required in [INLINESTATS], found [5${builtinWrapping}+doubleField]`,
|
||||
]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS 5 + doubleField ${builtinWrapping}`,
|
||||
[
|
||||
`At least one aggregation function required in [INLINESTATS], found [5+doubleField${builtinWrapping}]`,
|
||||
]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS 5 + doubleField ${builtinWrapping}, var0 = sum(doubleField)`,
|
||||
[
|
||||
`At least one aggregation function required in [INLINESTATS], found [5+doubleField${builtinWrapping}]`,
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EVAL', () => {
|
||||
const evalWrapping = Array(nesting).fill('round(').join('');
|
||||
const closingWrapping = Array(nesting).fill(')').join('');
|
||||
|
||||
test('no errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS ${evalWrapping} sum(doubleField) ${closingWrapping}`,
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS ${evalWrapping} sum(doubleField) ${closingWrapping} + ${evalWrapping} sum(doubleField) ${closingWrapping}`,
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS ${evalWrapping} sum(doubleField + doubleField) ${closingWrapping}`,
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS ${evalWrapping} sum(doubleField + round(doubleField)) ${closingWrapping}`,
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS ${evalWrapping} sum(doubleField + round(doubleField)) ${closingWrapping} + ${evalWrapping} sum(doubleField + round(doubleField)) ${closingWrapping}`,
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS sum(${evalWrapping} doubleField ${closingWrapping} )`,
|
||||
[]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS sum(${evalWrapping} doubleField ${closingWrapping} ) + sum(${evalWrapping} doubleField ${closingWrapping} )`,
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
test('errors', async () => {
|
||||
const { expectErrors } = await setup();
|
||||
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS ${evalWrapping} doubleField + sum(doubleField) ${closingWrapping}`,
|
||||
[
|
||||
`Cannot combine aggregation and non-aggregation values in [INLINESTATS], found [${evalWrapping}doubleField+sum(doubleField)${closingWrapping}]`,
|
||||
]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS ${evalWrapping} doubleField + sum(doubleField) ${closingWrapping}, var0 = sum(doubleField)`,
|
||||
[
|
||||
`Cannot combine aggregation and non-aggregation values in [INLINESTATS], found [${evalWrapping}doubleField+sum(doubleField)${closingWrapping}]`,
|
||||
]
|
||||
);
|
||||
await expectErrors(
|
||||
`from a_index | INLINESTATS var0 = ${evalWrapping} doubleField + sum(doubleField) ${closingWrapping}, var1 = sum(doubleField)`,
|
||||
[
|
||||
`Cannot combine aggregation and non-aggregation values in [INLINESTATS], found [${evalWrapping}doubleField+sum(doubleField)${closingWrapping}]`,
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as helpers from './helpers';
|
||||
import { validationStatsCommandTestSuite } from './test_suites/validation.command.stats';
|
||||
|
||||
validationStatsCommandTestSuite(helpers.setup);
|
|
@ -464,7 +464,7 @@ function validateFunction(
|
|||
allMatchingArgDefinitionsAreConstantOnly || forceConstantOnly,
|
||||
// use the nesting flag for now just for stats and metrics
|
||||
// TODO: revisit this part later on to make it more generic
|
||||
parentCommand === 'stats' || parentCommand === 'metrics'
|
||||
['stats', 'inlinestats', 'metrics'].includes(parentCommand)
|
||||
? isNested || !isAssignment(astFunction)
|
||||
: false
|
||||
);
|
||||
|
@ -1010,7 +1010,7 @@ function validateCommand(command: ESQLCommand, references: ReferenceMaps): ESQLM
|
|||
);
|
||||
}
|
||||
if (isColumnItem(arg)) {
|
||||
if (command.name === 'stats') {
|
||||
if (command.name === 'stats' || command.name === 'inlinestats') {
|
||||
messages.push(errors.unknownAggFunction(arg));
|
||||
} else {
|
||||
messages.push(...validateColumnForCommand(arg, command.name, references));
|
||||
|
|
|
@ -60,6 +60,7 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({
|
|||
'metadata',
|
||||
'mv_expand',
|
||||
'stats',
|
||||
'inlinestats',
|
||||
'dissect',
|
||||
'grok',
|
||||
'project',
|
||||
|
|
|
@ -5164,10 +5164,7 @@
|
|||
"kbn-esql-validation-autocomplete.esql.validation.expectedConstantValue": "L'argument de [{fn}] doit être une constante, reçu [{given}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.metadataBracketsDeprecation": "Les crochets \"[]\" doivent être supprimés de la déclaration FROM METADATA",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.missingFunction": "Fonction inconnue [{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.noCombinationOfAggAndNonAggValues": "Impossible de combiner les valeurs agrégées et non agrégées dans [STATS], [{expression}] trouvé",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.noNestedArgumentSupport": "Les paramètres de la fonction agrégée doivent être un attribut, un littéral ou une fonction non agrégée ; trouvé [{name}] de type [{argType}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.statsNoAggFunction": "Au moins une fonction d'agrégation requise dans [STATS], [{expression}] trouvé",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.statsNoArguments": "[STATS] doit contenir au moins une expression d'agrégation ou de regroupement",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.typeOverwrite": "La colonne [{field}] de type {fieldType} a été écrasée par un nouveau type : {newType}",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknowAggregateFunction": "Attendait une fonction ou un groupe agrégé mais a obtenu [{value}] de type [{type}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownColumn": "Colonne inconnue[{name}]",
|
||||
|
|
|
@ -5145,10 +5145,7 @@
|
|||
"kbn-esql-validation-autocomplete.esql.validation.expectedConstantValue": "[{fn}]の引数は定数でなければなりません。[{given}]が渡されました",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.metadataBracketsDeprecation": "FROM METADATA宣言から角括弧[]を削除する必要があります",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.missingFunction": "不明な関数[{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.noCombinationOfAggAndNonAggValues": "[STATS]では集計値と非集計値を結合できません。[{expression}]が見つかりました",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.noNestedArgumentSupport": "集計関数のパラメーターは属性、リテラル、または非集計関数でなければなりません。タイプ[{argType}]の[{name}]が見つかりました",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.statsNoAggFunction": "[STATS]では1つ以上の集計関数が必要です。[{expression}]が見つかりました",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.statsNoArguments": "[STATS]では1つ以上の集計またはグループ式が必要です",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.typeOverwrite": "{fieldType}型の列[{field}]が新しい型の{newType}として上書きされました",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknowAggregateFunction": "集計関数またはグループが想定されていますが、[{type}]型の[{value}]が渡されました",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownColumn": "不明な列[{name}]",
|
||||
|
|
|
@ -5170,10 +5170,7 @@
|
|||
"kbn-esql-validation-autocomplete.esql.validation.expectedConstantValue": "[{fn}] 的参数必须为常数,收到的是 [{given}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.metadataBracketsDeprecation": "需要从 FROM METADATA 声明中移除方括号“[]”",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.missingFunction": "未知函数 [{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.noCombinationOfAggAndNonAggValues": "无法在 [STATS] 中组合聚合与非聚合值,找到了 [{expression}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.noNestedArgumentSupport": "聚合函数的参数必须为属性、文本或非聚合函数;找到了 [{argType}] 类型的 [{name}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.statsNoAggFunction": "[STATS] 中至少需要一个聚合函数,找到了 [{expression}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.statsNoArguments": "[STATS] 中至少需要一个聚合或分组表达式",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.typeOverwrite": "类型为 {fieldType} 的列 [{field}] 已重写为新类型:{newType}",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknowAggregateFunction": "应为聚合函数或组,但收到的是 [{type}] 类型的 [{value}]",
|
||||
"kbn-esql-validation-autocomplete.esql.validation.unknownColumn": "未知列 [{name}]",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue