Skip to content

Commit

Permalink
Update types
Browse files Browse the repository at this point in the history
  • Loading branch information
qn895 committed Nov 11, 2024
1 parent 55c368c commit f19e521
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 189 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,10 @@ const convertDateTime = (s: string) => (s === 'datetime' ? 'date' : s);
* @returns
*/
function getFunctionDefinition(ESFunctionDefinition: Record<string, any>): FunctionDefinition {
let supportedCommandsAndOptions =
let supportedCommandsAndOptions: Pick<
FunctionDefinition,
'supportedCommands' | 'supportedOptions'
> =
ESFunctionDefinition.type === 'eval'
? scalarSupportedCommandsAndOptions
: aggregationSupportedCommandsAndOptions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,149 +124,6 @@ describe('autocomplete', () => {
}
});

describe('where', () => {
const allEvalFns = getFunctionSignaturesByReturnType('where', 'any', {
scalar: true,
});
testSuggestions('from a | where /', [
...getFieldNamesByType('any').map((field) => `${field} `),
...allEvalFns,
]);
testSuggestions('from a | eval var0 = 1 | where /', [
...getFieldNamesByType('any').map((name) => `${name} `),
'var0',
...allEvalFns,
]);
testSuggestions('from a | where keywordField /', [
// all functions compatible with a keywordField type
...getFunctionSignaturesByReturnType(
'where',
'boolean',
{
builtin: true,
},
undefined,
['and', 'or', 'not']
),
]);

const expectedComparisonWithDateSuggestions = [
...getDateLiterals(),
...getFieldNamesByType(['date']),
// all functions compatible with a keywordField type
...getFunctionSignaturesByReturnType('where', ['date'], { scalar: true }),
];
testSuggestions('from a | where dateField == /', expectedComparisonWithDateSuggestions);

testSuggestions('from a | where dateField < /', expectedComparisonWithDateSuggestions);

testSuggestions('from a | where dateField >= /', expectedComparisonWithDateSuggestions);

const expectedComparisonWithTextFieldSuggestions = [
...getFieldNamesByType(['text', 'keyword', 'ip', 'version']),
...getFunctionSignaturesByReturnType('where', ['text', 'keyword', 'ip', 'version'], {
scalar: true,
}),
];
testSuggestions('from a | where textField >= /', expectedComparisonWithTextFieldSuggestions);
testSuggestions(
'from a | where textField >= textField/',
expectedComparisonWithTextFieldSuggestions
);
for (const op of ['and', 'or']) {
testSuggestions(`from a | where keywordField >= keywordField ${op} /`, [
...getFieldNamesByType('any'),
...getFunctionSignaturesByReturnType('where', 'any', { scalar: true }),
]);
testSuggestions(`from a | where keywordField >= keywordField ${op} doubleField /`, [
...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']),
]);
testSuggestions(`from a | where keywordField >= keywordField ${op} doubleField == /`, [
...getFieldNamesByType(ESQL_COMMON_NUMERIC_TYPES),
...getFunctionSignaturesByReturnType('where', ESQL_COMMON_NUMERIC_TYPES, {
scalar: true,
}),
]);
}
testSuggestions('from a | stats a=avg(doubleField) | where a /', [
...getFunctionSignaturesByReturnType('where', 'any', { builtin: true, skipAssign: true }, [
'double',
]),
]);
// Mind this test: suggestion is aware of previous commands when checking for fields
// in this case the doubleField has been wiped by the STATS command and suggest cannot find it's type
// @TODO: verify this is the correct behaviour in this case or if we want a "generic" suggestion anyway
testSuggestions(
'from a | stats a=avg(doubleField) | where doubleField /',
[],
undefined,
// make the fields suggest aware of the previous STATS, leave the other callbacks untouched
[[{ name: 'a', type: 'double' }], undefined, undefined]
);
// The editor automatically inject the final bracket, so it is not useful to test with just open bracket
testSuggestions(
'from a | where log10(/)',
[
...getFieldNamesByType(log10ParameterTypes),
...getFunctionSignaturesByReturnType(
'where',
log10ParameterTypes,
{ scalar: true },
undefined,
['log10']
),
],
'('
);
testSuggestions('from a | where log10(doubleField) /', [
...getFunctionSignaturesByReturnType('where', 'double', { builtin: true }, ['double']),
...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']),
]);
testSuggestions(
'from a | WHERE pow(doubleField, /)',
[
...getFieldNamesByType(powParameterTypes),
...getFunctionSignaturesByReturnType(
'where',
powParameterTypes,
{ scalar: true },
undefined,
['pow']
),
],
','
);

testSuggestions('from index | WHERE keywordField not /', ['LIKE $0', 'RLIKE $0', 'IN $0']);
testSuggestions('from index | WHERE keywordField NOT /', ['LIKE $0', 'RLIKE $0', 'IN $0']);
testSuggestions('from index | WHERE not /', [
...getFieldNamesByType('boolean'),
...getFunctionSignaturesByReturnType(['eval', 'where'], 'boolean', { scalar: true }),
]);
testSuggestions('from index | WHERE doubleField in /', ['( $0 )']);
testSuggestions('from index | WHERE doubleField not in /', ['( $0 )']);
testSuggestions(
'from index | WHERE doubleField not in (/)',
[
...getFieldNamesByType('double').filter((name) => name !== 'doubleField'),
...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }),
],
'('
);
testSuggestions('from index | WHERE doubleField in ( `any#Char$Field`, /)', [
...getFieldNamesByType('double').filter(
(name) => name !== '`any#Char$Field`' && name !== 'doubleField'
),
...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }),
]);
testSuggestions('from index | WHERE doubleField not in ( `any#Char$Field`, /)', [
...getFieldNamesByType('double').filter(
(name) => name !== '`any#Char$Field`' && name !== 'doubleField'
),
...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }),
]);
});

describe('grok', () => {
const constantPattern = '"%{WORD:firstWord}"';
const subExpressions = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ export interface ValidationErrors {
nestedAgg: string;
};
};
onlyWhereCommandSupported: {
message: string;
type: { fn: string };
};
}

export type ErrorTypes = keyof ValidationErrors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,13 @@ function removeInlineCasts(arg: ESQLAstItem): ESQLAstItem {

function validateIfHasUnsupportedCommandPrior(
fn: ESQLFunction,
parentAst: ESQLCommand[],
currentCommandIndex: number,
unsupportedCommands: string[]
parentAst: ESQLCommand[] = [],
unsupportedCommands: string[],
currentCommandIndex?: number
) {
if (currentCommandIndex === undefined) {
return NO_MESSAGE;
}
const unsupportedCommandsPrior = parentAst.filter(
(cmd, idx) => idx <= currentCommandIndex && unsupportedCommands.includes(cmd.name)
);
Expand All @@ -347,7 +350,7 @@ function validateIfHasUnsupportedCommandPrior(
return NO_MESSAGE;
}

function validateMatchFunction({
const validateMatchFunction: FunctionValidator = ({
fn,
parentCommand,
parentOption,
Expand All @@ -356,16 +359,7 @@ function validateMatchFunction({
isNested,
parentAst,
currentCommandIndex,
}: {
fn: ESQLFunction;
parentCommand: string;
parentOption?: string;
references: ReferenceMaps;
forceConstantOnly?: boolean;
isNested?: boolean;
parentAst?: ESQLCommand[];
currentCommandIndex?: number;
}): ESQLMessage[] {
}) => {
if (fn.name === 'match') {
if (parentCommand !== 'where') {
return [
Expand All @@ -376,20 +370,12 @@ function validateMatchFunction({
}),
];
}
return validateIfHasUnsupportedCommandPrior(fn, parentAst, currentCommandIndex, ['limit']);
return validateIfHasUnsupportedCommandPrior(fn, parentAst, ['limit'], currentCommandIndex);
}
return NO_MESSAGE;
}
function validateQSTRFunction({
fn,
parentCommand,
parentOption,
references,
forceConstantOnly = false,
isNested,
parentAst,
currentCommandIndex,
}: {
};

type FunctionValidator = (args: {
fn: ESQLFunction;
parentCommand: string;
parentOption?: string;
Expand All @@ -398,26 +384,42 @@ function validateQSTRFunction({
isNested?: boolean;
parentAst?: ESQLCommand[];
currentCommandIndex?: number;
}): ESQLMessage[] {
}) => ESQLMessage[];

const validateQSTRFunction: FunctionValidator = ({
fn,
parentCommand,
parentOption,
references,
forceConstantOnly = false,
isNested,
parentAst,
currentCommandIndex,
}) => {
if (fn.name === 'qstr') {
return validateIfHasUnsupportedCommandPrior(fn, parentAst, currentCommandIndex, [
'show',
'row',
'dissect',
'enrich',
'eval',
'grok',
'keep',
'mv_expand',
'rename',
'stats',
'limit',
]);
return validateIfHasUnsupportedCommandPrior(
fn,
parentAst,
[
'show',
'row',
'dissect',
'enrich',
'eval',
'grok',
'keep',
'mv_expand',
'rename',
'stats',
'limit',
],
currentCommandIndex
);
}
return NO_MESSAGE;
}
};

const textSearchFunctionsValidators = {
const textSearchFunctionsValidators: Record<string, FunctionValidator> = {
match: validateMatchFunction,
qstr: validateQSTRFunction,
};
Expand Down Expand Up @@ -450,7 +452,7 @@ function validateFunction({

const isFnSupported = isSupportedFunction(fn.name, parentCommand, parentOption);

if (textSearchFunctionsValidators[fn.name]) {
if (typeof textSearchFunctionsValidators[fn.name] === 'function') {
const validator = textSearchFunctionsValidators[fn.name];
messages.push(
...validator({
Expand Down Expand Up @@ -1151,7 +1153,7 @@ function validateCommand(
messages.push(
...validateOption(
arg,
commandDef.options.find(({ name }) => name === astFunction.name),
commandDef.options.find(({ name }) => name === arg.name),
command,
references
)
Expand All @@ -1171,7 +1173,7 @@ function validateCommand(
values: {
command: command.name.toUpperCase(),
type: 'date_period',
value: astFunction.name,
value: arg.name,
},
locations: arg.location,
})
Expand Down

0 comments on commit f19e521

Please sign in to comment.