Skip to content

Commit 59e9645

Browse files
authored
feat: Support Ts in subqueries (#128)
## Summary
1 parent b478255 commit 59e9645

6 files changed

Lines changed: 130 additions & 1 deletion

File tree

eslint.config.mjs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@ import eslintConfigPrettier from 'eslint-config-prettier';
66
import { requireLicenseHeader } from './lint-license-rule.mjs';
77

88
export default defineConfig([
9-
globalIgnores(['lib/', 'node_modules/', 'src/parser/antlr/', '*.js', '*.mjs']),
9+
globalIgnores([
10+
'lib/',
11+
'node_modules/',
12+
'src/parser/antlr/',
13+
'storybook-static/',
14+
'*.js',
15+
'*.mjs',
16+
]),
1017
eslint.configs.recommended,
1118
...tseslint.configs.recommended,
1219
{

src/parser/__tests__/from.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,5 +528,36 @@ describe('FROM', () => {
528528
},
529529
});
530530
});
531+
532+
it('can parse ts subquery as source', () => {
533+
const text = 'FROM (TS k8s)';
534+
const { ast, errors } = parse(text);
535+
536+
expect(errors.length).toBe(0);
537+
expect(ast[0].args[0]).toMatchObject({
538+
type: 'parens',
539+
child: {
540+
type: 'query',
541+
commands: [{ type: 'command', name: 'ts' }],
542+
},
543+
});
544+
});
545+
546+
it('can parse ts subquery with pipes', () => {
547+
const text = 'FROM (TS k8s | STATS max_bytes = max(bytes) BY cluster)';
548+
const { ast, errors } = parse(text);
549+
550+
expect(errors.length).toBe(0);
551+
expect(ast[0].args[0]).toMatchObject({
552+
type: 'parens',
553+
child: {
554+
type: 'query',
555+
commands: [
556+
{ type: 'command', name: 'ts' },
557+
{ type: 'command', name: 'stats' },
558+
],
559+
},
560+
});
561+
});
531562
});
532563
});

src/parser/__tests__/function.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,59 @@ describe('function AST nodes', () => {
584584
],
585585
});
586586
});
587+
588+
it('IN ts subquery', () => {
589+
const query = 'FROM a | WHERE a IN (TS b | KEEP c)';
590+
const { root, errors } = parse(query);
591+
const expression = Walker.findFunction(root, ({ name }) => name === 'in');
592+
593+
expect(errors.length).toBe(0);
594+
expect(expression?.args.length).toBe(2);
595+
expect(expression).toMatchObject({
596+
type: 'function',
597+
subtype: 'binary-expression',
598+
name: 'in',
599+
args: [
600+
{ type: 'column', name: 'a' },
601+
{
602+
type: 'parens',
603+
child: {
604+
type: 'query',
605+
commands: [
606+
{ type: 'command', name: 'ts' },
607+
{ type: 'command', name: 'keep' },
608+
],
609+
},
610+
},
611+
],
612+
});
613+
});
614+
615+
it('NOT IN ts subquery', () => {
616+
const query = 'FROM a | WHERE a NOT IN (TS b | KEEP c)';
617+
const { root, errors } = parse(query);
618+
const expression = Walker.findFunction(root, ({ name }) => name === 'not in');
619+
620+
expect(errors.length).toBe(0);
621+
expect(expression).toMatchObject({
622+
type: 'function',
623+
subtype: 'binary-expression',
624+
name: 'not in',
625+
args: [
626+
{ type: 'column', name: 'a' },
627+
{
628+
type: 'parens',
629+
child: {
630+
type: 'query',
631+
commands: [
632+
{ type: 'command', name: 'ts' },
633+
{ type: 'command', name: 'keep' },
634+
],
635+
},
636+
},
637+
],
638+
});
639+
});
587640
});
588641
});
589642
});

src/parser/core/cst_to_ast_converter.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@ export class CstToAstConverter {
660660
if (sourceCommandCtx) {
661661
const fromCommandCtx = sourceCommandCtx.fromCommand();
662662
const rowCommandCtx = sourceCommandCtx.rowCommand();
663+
const timeSeriesCommandCtx = sourceCommandCtx.timeSeriesCommand();
663664

664665
if (fromCommandCtx) {
665666
const fromCommand = this.fromFromCommand(fromCommandCtx);
@@ -669,6 +670,8 @@ export class CstToAstConverter {
669670
}
670671
} else if (rowCommandCtx) {
671672
commands.push(this.fromRowCommand(rowCommandCtx));
673+
} else if (timeSeriesCommandCtx) {
674+
commands.push(this.fromTimeseriesCommand(timeSeriesCommandCtx));
672675
}
673676
}
674677

src/pretty_print/__tests__/basic_pretty_printer.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,12 @@ describe('single line query', () => {
945945
expect(reprint('FROM a | WHERE b NOT IN (FROM c | KEEP d)').text).toBe(
946946
'FROM a | WHERE b NOT IN (FROM c | KEEP d)'
947947
);
948+
expect(reprint('FROM a | WHERE b IN (TS c | KEEP d)').text).toBe(
949+
'FROM a | WHERE b IN (TS c | KEEP d)'
950+
);
951+
expect(reprint('FROM a | WHERE b NOT IN (TS c | KEEP d)').text).toBe(
952+
'FROM a | WHERE b NOT IN (TS c | KEEP d)'
953+
);
948954
});
949955
});
950956
});
@@ -1171,4 +1177,12 @@ describe('subqueries (parens)', () => {
11711177

11721178
assertReprint(src, expected);
11731179
});
1180+
1181+
test('can print ts subquery in FROM', () => {
1182+
assertReprint('FROM (TS k8s | LIMIT 5)');
1183+
});
1184+
1185+
test('can print mixed FROM subqueries with ts source', () => {
1186+
assertReprint('FROM idx, (TS k8s | STATS max_bytes = MAX(bytes) BY cluster)');
1187+
});
11741188
});

src/pretty_print/__tests__/wrapping_pretty_printer.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,27 @@ describe('subqueries (parens)', () => {
15461546
| SORT max DESC`
15471547
);
15481548
});
1549+
1550+
test('can print IN subqueries with ts source', () => {
1551+
assertReprint(
1552+
'FROM main_index_with_a_long_name | WHERE main_field_with_a_long_name IN (TS sub_index_with_a_long_name | WHERE sub_field_with_a_long_name > 10 | KEEP sub_field_with_a_long_name)',
1553+
`FROM main_index_with_a_long_name
1554+
| WHERE
1555+
main_field_with_a_long_name IN
1556+
(TS sub_index_with_a_long_name
1557+
| WHERE sub_field_with_a_long_name > 10
1558+
| KEEP sub_field_with_a_long_name)`
1559+
);
1560+
});
1561+
1562+
test('can print ts subquery in FROM', () => {
1563+
assertReprint(
1564+
'FROM index1, (TS k8s_with_a_long_index_name | STATS max_bytes = MAX(bytes) BY cluster)',
1565+
`FROM
1566+
index1,
1567+
(TS k8s_with_a_long_index_name | STATS max_bytes = MAX(bytes) BY cluster)`
1568+
);
1569+
});
15491570
});
15501571

15511572
test.todo('Idempotence on multiple times pretty printing');

0 commit comments

Comments
 (0)