forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ES|QL] Incorrect command option location parsing (elastic#194115)
## Summary Closes elastic#192553 ### Checklist Delete any items that are not applicable to this PR. - [x] [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 ### For maintainers - [x] 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: kibanamachine <[email protected]> Co-authored-by: Elastic Machine <[email protected]> Co-authored-by: Stratoula Kalafateli <[email protected]>
- Loading branch information
1 parent
718444f
commit bc576fe
Showing
3 changed files
with
206 additions
and
11 deletions.
There are no files selected for viewing
163 changes: 163 additions & 0 deletions
163
packages/kbn-esql-ast/src/parser/__tests__/command_options.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the "Elastic License | ||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side | ||
* Public License v 1"; you may not use this file except in compliance with, at | ||
* your election, the "Elastic License 2.0", the "GNU Affero General Public | ||
* License v3.0 only", or the "Server Side Public License, v 1". | ||
*/ | ||
|
||
import { parse } from '..'; | ||
import { Walker } from '../../walker'; | ||
|
||
describe('command options', () => { | ||
describe('parses correctly location', () => { | ||
describe('FROM', () => { | ||
it('parses correctly METADATA option position', () => { | ||
const query = 'FROM a METADATA b'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'metadata' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'metadata', | ||
location: { | ||
min: 'FROM a '.length, | ||
max: 'FROM a METADATA b'.length - 1, | ||
}, | ||
}); | ||
}); | ||
|
||
it('parses correctly METADATA option position position with multiple arguments', () => { | ||
const query = | ||
'FROM kibana_e_commerce, index_pattern METADATA _id, _index | STATS b BY c | LIMIT 123'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'metadata' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'metadata', | ||
location: { | ||
min: 'FROM kibana_e_commerce, index_pattern '.length, | ||
max: 'FROM kibana_e_commerce, index_pattern METADATA _id, _index'.length - 1, | ||
}, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('ENRICH', () => { | ||
it('parses correctly ON option position in ENRICH command', () => { | ||
const query = 'FROM a | ENRICH b ON c'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'on' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'on', | ||
location: { | ||
min: 'FROM a | ENRICH b '.length, | ||
max: 'FROM a | ENRICH b ON c'.length - 1, | ||
}, | ||
}); | ||
}); | ||
|
||
it('parses correctly WITH option in ENRICH command', () => { | ||
const query = 'FROM a | ENRICH b ON c WITH d'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'with' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'with', | ||
location: { | ||
min: 'FROM a | ENRICH b ON c '.length, | ||
max: 'FROM a | ENRICH b ON c WITH d'.length - 1, | ||
}, | ||
}); | ||
}); | ||
|
||
it('parses correctly WITH option with multiple arguments in ENRICH command', () => { | ||
const query = 'FROM a | ENRICH b ON c WITH d, e,f | LIMIT 1000000'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'with' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'with', | ||
location: { | ||
min: 'FROM a | ENRICH b ON c '.length, | ||
max: 'FROM a | ENRICH b ON c WITH d, e,f'.length - 1, | ||
}, | ||
}); | ||
}); | ||
|
||
it('parses correctly WITH option position with assignment in ENRICH command', () => { | ||
const query = 'FROM a | ENRICH b ON c WITH d, e = policy,f = something | LIMIT 1000000'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'with' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'with', | ||
location: { | ||
min: 'FROM a | ENRICH b ON c '.length, | ||
max: 'FROM a | ENRICH b ON c WITH d, e = policy,f = something'.length - 1, | ||
}, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('STATS', () => { | ||
it('parses correctly BY option in STATS command', () => { | ||
const query = 'FROM a | STATS b BY c'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'by' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'by', | ||
location: { | ||
min: 'FROM a | STATS b '.length, | ||
max: 'FROM a | STATS b BY c'.length - 1, | ||
}, | ||
}); | ||
}); | ||
|
||
it('parses correctly BY option with multiple arguments in STATS command', () => { | ||
const query = 'FROM a | STATS b BY c, long.field.name | LIMIT 1000000'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'by' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'by', | ||
location: { | ||
min: 'FROM a | STATS b '.length, | ||
max: 'FROM a | STATS b BY c, long.field.name'.length - 1, | ||
}, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('RENAME', () => { | ||
it('parses correctly AS option position in RENAME command', () => { | ||
const query = 'FROM a | RENAME b AS c'; | ||
const { root } = parse(query); | ||
const option = Walker.match(root, { type: 'option', name: 'as' }); | ||
|
||
expect(option).toMatchObject({ | ||
type: 'option', | ||
name: 'as', | ||
location: { | ||
// The "AS" option is unusual as the it contains the argument before | ||
// it, the "a" argument. It should not be the case. The "AS" option | ||
// should not exist at all, should be replaced by a *rename expression* | ||
// in the future: https://github.com/elastic/kibana/issues/190360 | ||
min: 'FROM a | RENAME '.length, | ||
max: 'FROM a | RENAME b AS c'.length - 1, | ||
}, | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters