mirror of https://github.com/grafana/grafana
Co-authored-by: Kevin Yu <kevinwcyu@users.noreply.github.com> Co-authored-by: Nathan Vērzemnieks <njvrzm@users.noreply.github.com>release-11.4.0
parent
80691e4297
commit
b12308499b
@ -0,0 +1,8 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
export const commentOnlyQuery = { |
||||
query: `-- comment ending with whitespace `, |
||||
tokens: [ |
||||
[{ offset: 0, type: 'comment.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,134 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
export const multiLineFullQuery = { |
||||
query: `SELECT
|
||||
length(\`@message\`) as msg_length,
|
||||
COUNT(*) as count,
|
||||
MIN(\`@message\`) as sample_message
|
||||
FROM \`LogGroupA\`
|
||||
WHERE \`startTime\` >= date_sub(current_timestamp(), 1)
|
||||
GROUP BY length(\`@message\`)
|
||||
HAVING count > 10
|
||||
ORDER BY msg_length DESC
|
||||
/* |
||||
a |
||||
comment |
||||
over |
||||
multiple |
||||
lines |
||||
*/ |
||||
LIMIT 10`,
|
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 2, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 19, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 20, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 21, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 23, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 24, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 34, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 35, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 2, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 10, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 11, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 13, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 14, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 19, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 20, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 2, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 16, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 17, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 18, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 20, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 21, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 35, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 16, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 17, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 18, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 20, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 21, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 29, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 30, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 47, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 49, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 50, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 51, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 52, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 53, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 15, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 16, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 26, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 27, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 12, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 13, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 14, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 15, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 17, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 19, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 20, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 24, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'comment.quote.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 2, type: 'comment.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[{ offset: 0, type: 'comment.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }], |
||||
[{ offset: 0, type: 'comment.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }], |
||||
[{ offset: 0, type: 'comment.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }], |
||||
[{ offset: 0, type: 'comment.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }], |
||||
[{ offset: 0, type: 'comment.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }], |
||||
[{ offset: 0, type: 'comment.quote.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,148 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
export const multiLineFullQueryWithCaseClause = { |
||||
query: `SELECT id,
|
||||
CASE id
|
||||
WHEN 100 THEN 'big'
|
||||
WHEN id > 300 THEN 'biggest'
|
||||
ELSE 'small'
|
||||
END as size
|
||||
FROM LogGroupA
|
||||
WHERE
|
||||
CASE 1 = 1
|
||||
WHEN 100 THEN 'long'
|
||||
WHEN 200 THEN 'longest'
|
||||
ELSE 'short'
|
||||
END = 'short'
|
||||
ORDER BY message_count DESC`,
|
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 10, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 13, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 14, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 15, type: 'string.escape.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 18, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 19, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 10, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 13, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 14, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 18, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 19, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 20, type: 'string.escape.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 27, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 28, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'string.escape.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 11, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 12, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 3, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 11, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 14, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 10, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 13, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 14, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 15, type: 'string.escape.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 19, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 20, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'number.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 13, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 14, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 15, type: 'string.escape.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 22, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 23, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'string.escape.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 11, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 12, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 3, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 4, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'string.escape.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 12, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 13, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 5, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 22, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 23, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,13 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
export const partialQueryWithFunction = { |
||||
query: `SELECT length()`, |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'predefined.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 13, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,24 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
export const partialQueryWithSubquery = { |
||||
query: 'SELECT requestId FROM LogGroupA WHERE requestId IN ()', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 16, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 17, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 21, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 22, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 31, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 32, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 37, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 38, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 47, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 48, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 50, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 51, type: 'delimiter.parenthesis.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,85 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
export const singleLineFullQuery = { |
||||
query: |
||||
"SELECT A.transaction_id AS txn_id_a, A.user_id, A.instance_id AS inst_id_a, B.instance_id AS inst_id_b FROM `LogGroupA` AS A INNER JOIN `LogGroupB` AS B ON A.userId = B.userId WHERE B.Status = 'ERROR' -- comment at the end", |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 6, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 7, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 8, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 9, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 23, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 24, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 26, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 27, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 35, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 36, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 37, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 38, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 39, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 46, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 47, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 48, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 49, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 50, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 61, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 62, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 64, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 65, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 74, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 75, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 76, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 77, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 78, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 89, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 90, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 92, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 93, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 102, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 103, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 107, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 108, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 119, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 120, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 122, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 123, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 124, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 125, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 130, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 131, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 135, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 136, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 147, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 148, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 150, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 151, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 152, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 153, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 155, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 156, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 157, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 158, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 164, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 165, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 166, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 167, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 168, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 169, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 175, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 176, type: 'keyword.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 181, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 182, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 183, type: 'delimiter.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 184, type: 'identifier.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 190, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 191, type: 'operator.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 192, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 193, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 194, type: 'string.escape.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 199, type: 'string.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 200, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
{ offset: 201, type: 'comment.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }, |
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,8 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
export const whitespaceQuery = { |
||||
query: ' ', |
||||
tokens: [ |
||||
[{ offset: 0, type: 'white.cloudwatch-logs-sql', language: 'cloudwatch-logs-sql' }], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,294 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID } from '../../language/cloudwatch-ppl/language'; |
||||
import { PPLTokenTypes } from '../../language/cloudwatch-ppl/tokenTypes'; |
||||
|
||||
export const multiLineNewCommandQuery = { |
||||
query: `fields ingestionTime, level
|
||||
| `,
|
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 8, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 21, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 22, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 23, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
export const multiLineFullQuery = { |
||||
query: `fields ingestionTime, level
|
||||
| WHERE like(\`@message\`, "%Exception%") AND not like(server, "test")
|
||||
| FIELDS + \`@ingestionTime\`, timestamp, table
|
||||
| stats avg(timestamp) as exceptionCount by span(\`@timestamp\`, 1h)
|
||||
| EVENTSTATS avg(timestamp) as exceptionCount by span(\`@timestamp\`, 1h)
|
||||
| sort - DisconnectReason, + timestamp, server |
||||
| sort - AUTO(DisconnectReason) |
||||
| DEDUP 5 timestamp, ingestionTime, \`@query\` keepempty = true consecutive = false
|
||||
| DEDUP timestamp, ingestionTime, \`@query\` |
||||
| TOP 100 ingestionTime, timestamp by server, region |
||||
| HEAD 10 from 1500 |
||||
| RARE server, ingestionTime by region, user |
||||
| EVAL total_revenue = price * quantity, discount_price = price >= 0.9, revenue_category = IF(price > 100, 'high', 'low') |
||||
| parse email ".+@(?<host>.+)"'`,
|
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 7, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 20, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 21, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 22, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "WHERE"
|
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 8, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "like"
|
||||
{ offset: 12, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 13, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "`@message`"
|
||||
{ offset: 23, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 24, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 25, type: PPLTokenTypes.String, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "%Exception"
|
||||
{ offset: 38, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")"
|
||||
{ offset: 39, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 40, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "and"
|
||||
{ offset: 43, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 44, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "not"
|
||||
{ offset: 47, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 48, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "like"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "fields"
|
||||
{ offset: 8, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 9, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "+"
|
||||
{ offset: 10, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 11, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "@ingestionTime"
|
||||
{ offset: 27, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 28, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " ",
|
||||
{ offset: 29, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp",
|
||||
{ offset: 38, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 39, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 40, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "table"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "stats"
|
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 8, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "avg"
|
||||
{ offset: 11, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 12, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp",
|
||||
{ offset: 21, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")",
|
||||
{ offset: 22, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 23, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "as"
|
||||
{ offset: 25, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 26, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "exceptionCount"
|
||||
{ offset: 40, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 41, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "by"
|
||||
{ offset: 43, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 44, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "span"
|
||||
{ offset: 48, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 49, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "@timestmap"
|
||||
{ offset: 61, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 62, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 63, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "1"
|
||||
{ offset: 64, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, //"h"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "eventstats"
|
||||
{ offset: 12, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 13, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "avg"
|
||||
{ offset: 16, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 17, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp",
|
||||
{ offset: 26, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")",
|
||||
{ offset: 27, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 28, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "as"
|
||||
{ offset: 30, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 31, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "exceptionCount"
|
||||
{ offset: 45, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 46, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "by"
|
||||
{ offset: 48, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 49, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "span"
|
||||
{ offset: 53, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 54, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "@timestmap"
|
||||
{ offset: 66, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 67, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 68, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "1"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "sort"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "-"
|
||||
{ offset: 8, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 9, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "DisconnectReason"
|
||||
{ offset: 25, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 26, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 27, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "+"
|
||||
{ offset: 28, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 29, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 38, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 39, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 40, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "server"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "sort"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "-"
|
||||
{ offset: 8, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 9, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "AUTO"
|
||||
{ offset: 13, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 14, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "DisconnectReason"
|
||||
{ offset: 30, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "dedup"
|
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 8, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "5"
|
||||
{ offset: 9, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 10, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 19, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 20, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 21, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 34, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 35, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 36, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "`@query`"
|
||||
{ offset: 44, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 45, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "keepempty"
|
||||
{ offset: 54, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 55, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 56, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 57, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "true"
|
||||
{ offset: 61, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 62, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "consecutive"
|
||||
{ offset: 73, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 74, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 75, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 76, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "false"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "dedup"
|
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 8, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 17, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 18, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 19, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 32, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 33, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 34, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "`@query`"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "top"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "100"
|
||||
{ offset: 9, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 10, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 23, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 24, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 25, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 34, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 35, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "by"
|
||||
{ offset: 37, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 38, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "server"
|
||||
{ offset: 44, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 45, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 46, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "region"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "head"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "10"
|
||||
{ offset: 9, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 10, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "from"
|
||||
{ offset: 14, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 15, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "1500"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "rare"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "server"
|
||||
{ offset: 13, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 14, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 15, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 28, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, //
|
||||
{ offset: 29, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "by"
|
||||
{ offset: 31, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 32, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "region"
|
||||
{ offset: 38, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 39, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 40, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "user"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "eval"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "total_revenue"
|
||||
{ offset: 20, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 21, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 22, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 23, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "price"
|
||||
{ offset: 28, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 29, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "*"
|
||||
{ offset: 30, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 31, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "quantity"
|
||||
{ offset: 39, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 40, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 41, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "discount_price"
|
||||
{ offset: 55, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 56, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 57, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 58, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "price"
|
||||
{ offset: 63, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 64, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ">="
|
||||
{ offset: 66, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 67, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "0.9"
|
||||
{ offset: 70, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 71, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 72, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "revenue_category"
|
||||
{ offset: 88, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 89, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 90, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 91, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "IF"
|
||||
{ offset: 93, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 94, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "price"
|
||||
{ offset: 99, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 100, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ">"
|
||||
{ offset: 101, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 102, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "100"
|
||||
], |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 1, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 2, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "parse"
|
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 8, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "email"
|
||||
{ offset: 13, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 14, type: PPLTokenTypes.String, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // '".+@(?<host>.+)"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,18 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID } from '../../language/cloudwatch-ppl/language'; |
||||
import { PPLTokenTypes } from '../../language/cloudwatch-ppl/tokenTypes'; |
||||
|
||||
export const newCommandQuery = { |
||||
query: `fields timestamp | `, |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 7, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 16, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 17, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
{ offset: 18, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, |
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
@ -0,0 +1,420 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID } from '../../language/cloudwatch-ppl/language'; |
||||
import { PPLTokenTypes } from '../../language/cloudwatch-ppl/tokenTypes'; |
||||
|
||||
export const emptyQuery = { |
||||
query: '', |
||||
tokens: [], |
||||
}; |
||||
|
||||
export const whitespaceOnlyQuery = { |
||||
query: ' ', |
||||
tokens: [ |
||||
[{ offset: 0, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const whereQuery = { |
||||
query: 'WHERE like(`@message`, "%Exception%") AND not like(server, "test") in ()', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "WHERE"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "like"
|
||||
{ offset: 10, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 11, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "`@message`"
|
||||
{ offset: 21, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 22, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 23, type: PPLTokenTypes.String, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "%Exception"
|
||||
{ offset: 36, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")"
|
||||
{ offset: 37, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 38, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "and"
|
||||
{ offset: 41, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 42, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "not"
|
||||
{ offset: 45, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 46, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "like"
|
||||
{ offset: 50, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 51, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "server"
|
||||
{ offset: 57, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 58, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 59, type: PPLTokenTypes.String, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "'test'"
|
||||
{ offset: 55, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")"
|
||||
{ offset: 66, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 67, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "in"
|
||||
{ offset: 69, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 70, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
export const fieldsQuery = { |
||||
query: 'FIELDS + `@ingestionTime`, timestamp, table', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "fields"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "+"
|
||||
{ offset: 8, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 9, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "@ingestionTime"
|
||||
{ offset: 25, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 26, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " ",
|
||||
{ offset: 27, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp",
|
||||
{ offset: 36, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 37, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 38, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "table"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const statsQuery = { |
||||
query: 'stats avg(timestamp) as exceptionCount by span(`@timestamp`, 1h)', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "stats"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "avg"
|
||||
{ offset: 9, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 10, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp",
|
||||
{ offset: 19, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")",
|
||||
{ offset: 20, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 21, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "as"
|
||||
{ offset: 23, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 24, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "exceptionCount"
|
||||
{ offset: 38, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 39, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "by"
|
||||
{ offset: 41, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 42, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "span"
|
||||
{ offset: 46, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 47, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "@timestmap"
|
||||
{ offset: 59, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 60, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 61, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "1h"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const eventStatsQuery = { |
||||
query: 'EVENTSTATS avg(timestamp) as exceptionCount by span(`@timestamp`, 1h)', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "eventstats"
|
||||
{ offset: 10, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 11, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "avg"
|
||||
{ offset: 14, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 15, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp",
|
||||
{ offset: 24, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")",
|
||||
{ offset: 25, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 26, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "as"
|
||||
{ offset: 28, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 29, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "exceptionCount"
|
||||
{ offset: 43, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 44, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "by"
|
||||
{ offset: 46, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 47, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "span"
|
||||
{ offset: 51, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 52, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "@timestmap"
|
||||
{ offset: 64, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 65, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 66, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "1h"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const sortQuery = { |
||||
query: 'sort - DisconnectReason, + timestamp, server', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "sort"
|
||||
{ offset: 4, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 5, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "-"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "DisconnectReason"
|
||||
{ offset: 23, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 24, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 25, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "+"
|
||||
{ offset: 26, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 27, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 36, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 37, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 38, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "server"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
export const sortQueryWithFunctions = { |
||||
query: 'sort - AUTO(DisconnectReason)', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "sort"
|
||||
{ offset: 4, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 5, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "-"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "AUTO"
|
||||
{ offset: 11, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 12, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "DisconnectReason"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const dedupQueryWithOptionalArgs = { |
||||
query: 'DEDUP 5 timestamp, ingestionTime, `@query` keepempty = true consecutive = false', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "dedup"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "5"
|
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 8, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 17, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 18, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 19, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 32, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 33, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 34, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "`@query`"
|
||||
{ offset: 42, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 43, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "keepempty"
|
||||
{ offset: 52, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 53, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 54, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 55, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "true"
|
||||
{ offset: 59, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 60, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "consecutive"
|
||||
{ offset: 71, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 72, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 73, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 74, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "false"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const dedupQueryWithoutOptionalArgs = { |
||||
query: 'DEDUP timestamp, ingestionTime, `@query`', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "dedup"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 15, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 16, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 17, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 30, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 31, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 32, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "`@query`"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const topQuery = { |
||||
query: 'TOP 100 ingestionTime, timestamp by server, region', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "top"
|
||||
{ offset: 3, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 4, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "100"
|
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 8, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 21, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 22, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 23, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 32, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 33, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "by"
|
||||
{ offset: 35, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 36, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "server"
|
||||
{ offset: 42, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 43, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 44, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "region"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const headQuery = { |
||||
query: 'HEAD 10 from 1500', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "head"
|
||||
{ offset: 4, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 5, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "10"
|
||||
{ offset: 7, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 8, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "from"
|
||||
{ offset: 12, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 13, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "1500"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
export const rareQuery = { |
||||
query: 'RARE server, ingestionTime by region, user', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "rare"
|
||||
{ offset: 4, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 5, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "server"
|
||||
{ offset: 11, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 12, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 13, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 26, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 27, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "by"
|
||||
{ offset: 29, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 30, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "region"
|
||||
{ offset: 36, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 37, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 38, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "user"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const evalQuery = { |
||||
query: |
||||
'EVAL total_revenue = price * quantity, discount_price = price >= 0.9, revenue_category = IF(price BETWEEN 100 AND 200, "high", "low")', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "eval"
|
||||
{ offset: 4, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 5, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "total_revenue"
|
||||
{ offset: 18, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 19, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 20, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 21, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "price"
|
||||
{ offset: 26, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 27, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "*"
|
||||
{ offset: 28, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 29, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "quantity"
|
||||
{ offset: 37, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 38, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 39, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "discount_price"
|
||||
{ offset: 53, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 54, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 55, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 56, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "price"
|
||||
{ offset: 61, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 62, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ">="
|
||||
{ offset: 64, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 65, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "0.9"
|
||||
{ offset: 68, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 69, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 70, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "revenue_category"
|
||||
{ offset: 86, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 87, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 88, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 89, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "IF"
|
||||
{ offset: 91, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 92, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "price"
|
||||
{ offset: 97, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 98, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "between"
|
||||
{ offset: 105, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 106, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "100"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const parseQuery = { |
||||
query: 'parse email ".+@(?<host>.+)"', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "parse"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "email"
|
||||
{ offset: 11, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 12, type: PPLTokenTypes.String, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // '".+@(?<host>.+)"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
export const queryWithArithmeticOps = { |
||||
query: 'where price * discount >= 200', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "where"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "price"
|
||||
{ offset: 11, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 12, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "*"
|
||||
{ offset: 13, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 14, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "discount"
|
||||
{ offset: 22, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 23, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ">="
|
||||
{ offset: 25, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 26, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "200"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
export const queryWithLogicalExpression = { |
||||
query: 'where orders = "shipped" OR NOT /returned/ AND price > 20', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "where"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "orders"
|
||||
{ offset: 12, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 13, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "="
|
||||
{ offset: 14, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 15, type: PPLTokenTypes.String, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "'shipped'"
|
||||
{ offset: 24, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 25, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "OR"
|
||||
{ offset: 27, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 28, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "NOT"
|
||||
{ offset: 31, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 32, type: PPLTokenTypes.Regexp, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "/returned/"
|
||||
{ offset: 42, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 43, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "AND"
|
||||
{ offset: 46, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 47, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "price"
|
||||
{ offset: 52, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 53, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ">"
|
||||
{ offset: 54, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 55, type: PPLTokenTypes.Number, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "20"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
export const queryWithFieldList = { |
||||
query: 'fields ingestionTime, timestamp, `@server`, bytesReceived', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "fields"
|
||||
{ offset: 6, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 7, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "ingestionTime"
|
||||
{ offset: 20, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 21, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 22, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "timestamp"
|
||||
{ offset: 31, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 32, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 33, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "`@server`"
|
||||
{ offset: 42, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 43, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 44, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "bytesReceived"
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
||||
|
||||
export const queryWithFunctionCalls = { |
||||
query: 'where like(dstAddr, ) where logType = "Tracing"| where cos(`duration`), right(`duration`)', |
||||
tokens: [ |
||||
[ |
||||
{ offset: 0, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "where"
|
||||
{ offset: 5, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 6, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "like"
|
||||
{ offset: 10, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 11, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "dstAddr"
|
||||
{ offset: 18, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 19, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 20, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")"
|
||||
{ offset: 21, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 22, type: PPLTokenTypes.Keyword, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // where
|
||||
{ offset: 27, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 28, type: PPLTokenTypes.Identifier, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // logType
|
||||
{ offset: 35, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 36, type: PPLTokenTypes.Operator, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // =
|
||||
{ offset: 37, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 38, type: PPLTokenTypes.String, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "Tracing"
|
||||
{ offset: 47, type: PPLTokenTypes.Pipe, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "|"
|
||||
{ offset: 48, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ""
|
||||
{ offset: 49, type: PPLTokenTypes.Command, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "where"
|
||||
{ offset: 54, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 55, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "cos"
|
||||
{ offset: 58, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
{ offset: 59, type: PPLTokenTypes.Backtick, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "`duration`"
|
||||
{ offset: 69, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ")"
|
||||
{ offset: 70, type: PPLTokenTypes.Delimiter, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // ","
|
||||
{ offset: 71, type: PPLTokenTypes.Whitespace, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // " "
|
||||
{ offset: 72, type: PPLTokenTypes.Function, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "right"
|
||||
{ offset: 77, type: PPLTokenTypes.Parenthesis, language: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID }, // "("
|
||||
], |
||||
] as monacoTypes.Token[][], |
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,94 @@ |
||||
// import { Grammar } from 'prismjs';
|
||||
|
||||
import { Grammar } from 'prismjs'; |
||||
|
||||
import { FUNCTIONS, KEYWORDS, QUERY_COMMANDS } from '../../language/cloudwatch-logs/syntax'; |
||||
import * as sql from '../../language/cloudwatch-logs-sql/language'; |
||||
import * as ppl from '../../language/cloudwatch-ppl/language'; |
||||
|
||||
export const baseTokenizer = (languageSpecificFeatures: Grammar): Grammar => ({ |
||||
comment: { |
||||
pattern: /^#.*/, |
||||
greedy: true, |
||||
}, |
||||
backticks: { |
||||
pattern: /`.*?`/, |
||||
alias: 'string', |
||||
greedy: true, |
||||
}, |
||||
quote: { |
||||
pattern: /[\"'].*?[\"']/, |
||||
alias: 'string', |
||||
greedy: true, |
||||
}, |
||||
regex: { |
||||
pattern: /\/.*?\/(?=\||\s*$|,)/, |
||||
greedy: true, |
||||
}, |
||||
...languageSpecificFeatures, |
||||
|
||||
'field-name': { |
||||
pattern: /(@?[_a-zA-Z]+[_.0-9a-zA-Z]*)|(`((\\`)|([^`]))*?`)/, |
||||
greedy: true, |
||||
}, |
||||
number: /\b-?\d+((\.\d*)?([eE][+-]?\d+)?)?\b/, |
||||
'command-separator': { |
||||
pattern: /\|/, |
||||
alias: 'punctuation', |
||||
}, |
||||
'comparison-operator': { |
||||
pattern: /([<>]=?)|(!?=)/, |
||||
}, |
||||
punctuation: /[{}()`,.]/, |
||||
whitespace: /\s+/, |
||||
}); |
||||
|
||||
export const cwliTokenizer: Grammar = { |
||||
...baseTokenizer({ |
||||
'query-command': { |
||||
pattern: new RegExp(`\\b(?:${QUERY_COMMANDS.map((command) => command.label).join('|')})\\b`, 'i'), |
||||
alias: 'function', |
||||
}, |
||||
function: { |
||||
pattern: new RegExp(`\\b(?:${FUNCTIONS.map((f) => f.label).join('|')})\\b`, 'i'), |
||||
}, |
||||
keyword: { |
||||
pattern: new RegExp(`(\\s+)(${KEYWORDS.join('|')})(?=\\s+)`, 'i'), |
||||
lookbehind: true, |
||||
}, |
||||
}), |
||||
}; |
||||
|
||||
export const pplTokenizer: Grammar = { |
||||
...baseTokenizer({ |
||||
'query-command': { |
||||
pattern: new RegExp(`\\b(?:${ppl.PPL_COMMANDS.join('|')})\\b`, 'i'), |
||||
alias: 'function', |
||||
}, |
||||
function: { |
||||
pattern: new RegExp(`\\b(?:${ppl.ALL_FUNCTIONS.join('|')})\\b`, 'i'), |
||||
}, |
||||
keyword: { |
||||
pattern: new RegExp(`(\\s+)(${ppl.ALL_KEYWORDS.join('|')})(?=\\s+)`, 'i'), |
||||
lookbehind: true, |
||||
}, |
||||
operator: { |
||||
pattern: new RegExp(`\\b(?:${ppl.PPL_OPERATORS.map((operator) => `\\${operator}`).join('|')})\\b`, 'i'), |
||||
}, |
||||
}), |
||||
}; |
||||
|
||||
export const sqlTokenizer = { |
||||
...baseTokenizer({ |
||||
function: { |
||||
pattern: new RegExp(`\\b(?:${sql.ALL_FUNCTIONS.join('|')})\\b(?!\\.)`, 'i'), |
||||
}, |
||||
keyword: { |
||||
pattern: new RegExp(`\\b(?:${sql.ALL_KEYWORDS.join('|')})\\b(?=\\s)`, 'i'), |
||||
lookbehind: true, |
||||
}, |
||||
operator: { |
||||
pattern: new RegExp(`\\b(?:${sql.ALL_OPERATORS.map((operator) => `\\${operator}`).join('|')})\\b`, 'i'), |
||||
}, |
||||
}), |
||||
}; |
@ -1,37 +1,102 @@ |
||||
import { css } from '@emotion/css'; |
||||
import { memo } from 'react'; |
||||
import { memo, useCallback, useEffect, useState } from 'react'; |
||||
import { useEffectOnce } from 'react-use'; |
||||
|
||||
import { QueryEditorProps } from '@grafana/data'; |
||||
import { InlineFormLabel } from '@grafana/ui'; |
||||
import { QueryEditorProps, SelectableValue } from '@grafana/data'; |
||||
import { InlineSelect } from '@grafana/experimental'; |
||||
|
||||
import { CloudWatchDatasource } from '../../../datasource'; |
||||
import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery } from '../../../types'; |
||||
import { DEFAULT_CWLI_QUERY_STRING, DEFAULT_PPL_QUERY_STRING, DEFAULT_SQL_QUERY_STRING } from '../../../defaultQueries'; |
||||
import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery, LogsQueryLanguage } from '../../../types'; |
||||
|
||||
import { CloudWatchLink } from './CloudWatchLink'; |
||||
import CloudWatchLogsQueryField from './LogsQueryField'; |
||||
import { CloudWatchLogsQueryField } from './LogsQueryField'; |
||||
|
||||
type Props = QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData> & { |
||||
query: CloudWatchLogsQuery; |
||||
extraHeaderElementLeft?: React.Dispatch<JSX.Element | undefined>; |
||||
}; |
||||
|
||||
const labelClass = css` |
||||
margin-left: 3px; |
||||
flex-grow: 0; |
||||
`;
|
||||
const logsQueryLanguageOptions: Array<SelectableValue<LogsQueryLanguage>> = [ |
||||
{ label: 'Logs Insights QL', value: LogsQueryLanguage.CWLI }, |
||||
{ label: 'OpenSearch SQL', value: LogsQueryLanguage.SQL }, |
||||
{ label: 'OpenSearch PPL', value: LogsQueryLanguage.PPL }, |
||||
]; |
||||
|
||||
export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor(props: Props) { |
||||
const { query, data, datasource } = props; |
||||
const { query, data, datasource, onChange, extraHeaderElementLeft } = props; |
||||
|
||||
const [isQueryNew, setIsQueryNew] = useState(true); |
||||
|
||||
const onQueryLanguageChange = useCallback( |
||||
(language: LogsQueryLanguage | undefined) => { |
||||
if (isQueryNew) { |
||||
onChange({ |
||||
...query, |
||||
expression: getDefaultQueryString(language), |
||||
queryLanguage: language ?? LogsQueryLanguage.CWLI, |
||||
}); |
||||
} else { |
||||
onChange({ ...query, queryLanguage: language ?? LogsQueryLanguage.CWLI }); |
||||
} |
||||
}, |
||||
[isQueryNew, onChange, query] |
||||
); |
||||
|
||||
// if the query has already been saved from before, we shouldn't replace it with a default one
|
||||
useEffectOnce(() => { |
||||
if (query.expression) { |
||||
setIsQueryNew(false); |
||||
} |
||||
}); |
||||
|
||||
useEffect(() => { |
||||
// if it's a new query, we should replace it with a default one
|
||||
if (isQueryNew && !query.expression) { |
||||
onChange({ ...query, expression: getDefaultQueryString(query.queryLanguage) }); |
||||
} |
||||
}, [onChange, query, isQueryNew]); |
||||
|
||||
useEffect(() => { |
||||
extraHeaderElementLeft?.( |
||||
<InlineSelect |
||||
label="Query language" |
||||
value={query.queryLanguage || LogsQueryLanguage.CWLI} |
||||
options={logsQueryLanguageOptions} |
||||
onChange={({ value }) => { |
||||
onQueryLanguageChange(value); |
||||
}} |
||||
/> |
||||
); |
||||
|
||||
return () => { |
||||
extraHeaderElementLeft?.(undefined); |
||||
}; |
||||
}, [extraHeaderElementLeft, onChange, onQueryLanguageChange, query]); |
||||
|
||||
const onQueryStringChange = (query: CloudWatchQuery) => { |
||||
onChange(query); |
||||
setIsQueryNew(false); |
||||
}; |
||||
|
||||
return ( |
||||
<CloudWatchLogsQueryField |
||||
{...props} |
||||
ExtraFieldElement={ |
||||
<InlineFormLabel className={`gf-form-label--btn ${labelClass}`} width="auto" tooltip="Link to Graph in AWS"> |
||||
<CloudWatchLink query={query} panelData={data} datasource={datasource} /> |
||||
</InlineFormLabel> |
||||
} |
||||
onChange={onQueryStringChange} |
||||
ExtraFieldElement={<CloudWatchLink query={query} panelData={data} datasource={datasource} />} |
||||
/> |
||||
); |
||||
}); |
||||
|
||||
export default CloudWatchLogsQueryEditor; |
||||
|
||||
const getDefaultQueryString = (language: LogsQueryLanguage | undefined) => { |
||||
switch (language) { |
||||
case LogsQueryLanguage.SQL: |
||||
return DEFAULT_SQL_QUERY_STRING; |
||||
case LogsQueryLanguage.PPL: |
||||
return DEFAULT_PPL_QUERY_STRING; |
||||
case LogsQueryLanguage.CWLI: |
||||
default: |
||||
return DEFAULT_CWLI_QUERY_STRING; |
||||
} |
||||
}; |
||||
|
@ -0,0 +1,93 @@ |
||||
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api'; |
||||
import { useCallback, useRef } from 'react'; |
||||
|
||||
import { CodeEditor, Monaco } from '@grafana/ui'; |
||||
|
||||
import { CloudWatchDatasource } from '../../../../datasource'; |
||||
import language from '../../../../language/logs/definition'; |
||||
import { TRIGGER_SUGGEST } from '../../../../language/monarch/commands'; |
||||
import { registerLanguage, reRegisterCompletionProvider } from '../../../../language/monarch/register'; |
||||
import { CloudWatchLogsQuery } from '../../../../types'; |
||||
import { getStatsGroups } from '../../../../utils/query/getStatsGroups'; |
||||
|
||||
import { codeEditorCommonProps } from './PPLQueryEditor'; |
||||
|
||||
interface CodeEditorProps { |
||||
query: CloudWatchLogsQuery; |
||||
datasource: CloudWatchDatasource; |
||||
onChange: (query: CloudWatchLogsQuery) => void; |
||||
} |
||||
export const LogsQLCodeEditor = (props: CodeEditorProps) => { |
||||
const { query, datasource, onChange } = props; |
||||
|
||||
const monacoRef = useRef<Monaco>(); |
||||
const disposalRef = useRef<monacoType.IDisposable>(); |
||||
|
||||
const onFocus = useCallback(async () => { |
||||
disposalRef.current = await reRegisterCompletionProvider( |
||||
monacoRef.current!, |
||||
language, |
||||
datasource.logsCompletionItemProviderFunc({ |
||||
region: query.region, |
||||
logGroups: query.logGroups, |
||||
}), |
||||
disposalRef.current |
||||
); |
||||
}, [datasource, query.logGroups, query.region]); |
||||
|
||||
const onChangeQuery = useCallback( |
||||
(value: string) => { |
||||
const nextQuery = { |
||||
...query, |
||||
expression: value, |
||||
statsGroups: getStatsGroups(value), |
||||
}; |
||||
onChange(nextQuery); |
||||
}, |
||||
[onChange, query] |
||||
); |
||||
const onEditorMount = useCallback( |
||||
(editor: monacoType.editor.IStandaloneCodeEditor, monaco: Monaco) => { |
||||
editor.onDidFocusEditorText(() => editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {})); |
||||
editor.onDidChangeModelContent(() => { |
||||
const model = editor.getModel(); |
||||
if (model?.getValue().trim() === '') { |
||||
editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {}); |
||||
} |
||||
}); |
||||
editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => { |
||||
const text = editor.getValue(); |
||||
onChangeQuery(text); |
||||
}); |
||||
}, |
||||
[onChangeQuery] |
||||
); |
||||
const onBeforeEditorMount = async (monaco: Monaco) => { |
||||
monacoRef.current = monaco; |
||||
disposalRef.current = await registerLanguage( |
||||
monaco, |
||||
language, |
||||
datasource.logsCompletionItemProviderFunc({ |
||||
region: query.region, |
||||
logGroups: query.logGroups, |
||||
}) |
||||
); |
||||
}; |
||||
return ( |
||||
<CodeEditor |
||||
{...codeEditorCommonProps} |
||||
language={language.id} |
||||
value={query.expression ?? ''} |
||||
onBlur={(value: string) => { |
||||
if (value !== query.expression) { |
||||
onChangeQuery(value); |
||||
} |
||||
disposalRef.current?.dispose(); |
||||
}} |
||||
onFocus={onFocus} |
||||
onBeforeEditorMount={onBeforeEditorMount} |
||||
onEditorDidMount={onEditorMount} |
||||
onEditorWillUnmount={() => disposalRef.current?.dispose()} |
||||
/> |
||||
); |
||||
}; |
@ -0,0 +1,115 @@ |
||||
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api'; |
||||
import { useCallback, useRef } from 'react'; |
||||
|
||||
import { CodeEditor, Monaco } from '@grafana/ui'; |
||||
import { CodeEditorProps } from '@grafana/ui/src/components/Monaco/types'; |
||||
|
||||
import { CloudWatchDatasource } from '../../../../datasource'; |
||||
import language from '../../../../language/cloudwatch-ppl/definition'; |
||||
import { TRIGGER_SUGGEST } from '../../../../language/monarch/commands'; |
||||
import { registerLanguage, reRegisterCompletionProvider } from '../../../../language/monarch/register'; |
||||
import { CloudWatchLogsQuery } from '../../../../types'; |
||||
import { getStatsGroups } from '../../../../utils/query/getStatsGroups'; |
||||
|
||||
export const codeEditorCommonProps: Partial<CodeEditorProps> = { |
||||
height: '150px', |
||||
width: '100%', |
||||
showMiniMap: false, |
||||
monacoOptions: { |
||||
// without this setting, the auto-resize functionality causes an infinite loop, don't remove it!
|
||||
scrollBeyondLastLine: false, |
||||
|
||||
// These additional options are style focused and are a subset of those in the query editor in Prometheus
|
||||
fontSize: 14, |
||||
lineNumbers: 'off', |
||||
renderLineHighlight: 'none', |
||||
scrollbar: { |
||||
vertical: 'hidden', |
||||
horizontal: 'hidden', |
||||
}, |
||||
suggestFontSize: 12, |
||||
wordWrap: 'on', |
||||
padding: { |
||||
top: 6, |
||||
}, |
||||
}, |
||||
}; |
||||
interface LogsCodeEditorProps { |
||||
query: CloudWatchLogsQuery; |
||||
datasource: CloudWatchDatasource; |
||||
onChange: (query: CloudWatchLogsQuery) => void; |
||||
} |
||||
export const PPLQueryEditor = (props: LogsCodeEditorProps) => { |
||||
const { query, datasource, onChange } = props; |
||||
|
||||
const monacoRef = useRef<Monaco>(); |
||||
const disposalRef = useRef<monacoType.IDisposable>(); |
||||
|
||||
const onFocus = useCallback(async () => { |
||||
disposalRef.current = await reRegisterCompletionProvider( |
||||
monacoRef.current!, |
||||
language, |
||||
datasource.pplCompletionItemProviderFunc({ |
||||
region: query.region, |
||||
logGroups: query.logGroups, |
||||
}), |
||||
disposalRef.current |
||||
); |
||||
}, [datasource, query.logGroups, query.region]); |
||||
|
||||
const onChangeQuery = useCallback( |
||||
(value: string) => { |
||||
const nextQuery = { |
||||
...query, |
||||
expression: value, |
||||
statsGroups: getStatsGroups(value), |
||||
}; |
||||
onChange(nextQuery); |
||||
}, |
||||
[onChange, query] |
||||
); |
||||
const onEditorMount = useCallback( |
||||
(editor: monacoType.editor.IStandaloneCodeEditor, monaco: Monaco) => { |
||||
editor.onDidFocusEditorText(() => editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {})); |
||||
editor.onDidChangeModelContent(() => { |
||||
const model = editor.getModel(); |
||||
if (model?.getValue().trim() === '') { |
||||
editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {}); |
||||
} |
||||
}); |
||||
editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => { |
||||
const text = editor.getValue(); |
||||
onChangeQuery(text); |
||||
}); |
||||
}, |
||||
[onChangeQuery] |
||||
); |
||||
const onBeforeEditorMount = async (monaco: Monaco) => { |
||||
monacoRef.current = monaco; |
||||
disposalRef.current = await registerLanguage( |
||||
monaco, |
||||
language, |
||||
datasource.pplCompletionItemProviderFunc({ |
||||
region: query.region, |
||||
logGroups: query.logGroups, |
||||
}) |
||||
); |
||||
}; |
||||
return ( |
||||
<CodeEditor |
||||
{...codeEditorCommonProps} |
||||
language={language.id} |
||||
value={query.expression ?? ''} |
||||
onBlur={(value: string) => { |
||||
if (value !== query.expression) { |
||||
onChangeQuery(value); |
||||
} |
||||
disposalRef.current?.dispose(); |
||||
}} |
||||
onFocus={onFocus} |
||||
onBeforeEditorMount={onBeforeEditorMount} |
||||
onEditorDidMount={onEditorMount} |
||||
onEditorWillUnmount={() => disposalRef.current?.dispose()} |
||||
/> |
||||
); |
||||
}; |
@ -0,0 +1,93 @@ |
||||
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api'; |
||||
import { useCallback, useRef } from 'react'; |
||||
|
||||
import { CodeEditor, Monaco } from '@grafana/ui'; |
||||
|
||||
import { CloudWatchDatasource } from '../../../../datasource'; |
||||
import language from '../../../../language/cloudwatch-logs-sql/definition'; |
||||
import { TRIGGER_SUGGEST } from '../../../../language/monarch/commands'; |
||||
import { registerLanguage, reRegisterCompletionProvider } from '../../../../language/monarch/register'; |
||||
import { CloudWatchLogsQuery } from '../../../../types'; |
||||
import { getStatsGroups } from '../../../../utils/query/getStatsGroups'; |
||||
|
||||
import { codeEditorCommonProps } from './PPLQueryEditor'; |
||||
|
||||
interface SQLCodeEditorProps { |
||||
query: CloudWatchLogsQuery; |
||||
datasource: CloudWatchDatasource; |
||||
onChange: (query: CloudWatchLogsQuery) => void; |
||||
} |
||||
export const SQLQueryEditor = (props: SQLCodeEditorProps) => { |
||||
const { query, datasource, onChange } = props; |
||||
|
||||
const monacoRef = useRef<Monaco>(); |
||||
const disposalRef = useRef<monacoType.IDisposable>(); |
||||
|
||||
const onFocus = useCallback(async () => { |
||||
disposalRef.current = await reRegisterCompletionProvider( |
||||
monacoRef.current!, |
||||
language, |
||||
datasource.logsSqlCompletionItemProviderFunc({ |
||||
region: query.region, |
||||
logGroups: query.logGroups, |
||||
}), |
||||
disposalRef.current |
||||
); |
||||
}, [datasource, query.logGroups, query.region]); |
||||
|
||||
const onChangeQuery = useCallback( |
||||
(value: string) => { |
||||
const nextQuery = { |
||||
...query, |
||||
expression: value, |
||||
statsGroups: getStatsGroups(value), |
||||
}; |
||||
onChange(nextQuery); |
||||
}, |
||||
[onChange, query] |
||||
); |
||||
const onEditorMount = useCallback( |
||||
(editor: monacoType.editor.IStandaloneCodeEditor, monaco: Monaco) => { |
||||
editor.onDidFocusEditorText(() => editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {})); |
||||
editor.onDidChangeModelContent(() => { |
||||
const model = editor.getModel(); |
||||
if (model?.getValue().trim() === '') { |
||||
editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {}); |
||||
} |
||||
}); |
||||
editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => { |
||||
const text = editor.getValue(); |
||||
onChangeQuery(text); |
||||
}); |
||||
}, |
||||
[onChangeQuery] |
||||
); |
||||
const onBeforeEditorMount = async (monaco: Monaco) => { |
||||
monacoRef.current = monaco; |
||||
disposalRef.current = await registerLanguage( |
||||
monaco, |
||||
language, |
||||
datasource.logsSqlCompletionItemProviderFunc({ |
||||
region: query.region, |
||||
logGroups: query.logGroups, |
||||
}) |
||||
); |
||||
}; |
||||
return ( |
||||
<CodeEditor |
||||
{...codeEditorCommonProps} |
||||
language={language.id} |
||||
value={query.expression ?? ''} |
||||
onBlur={(value: string) => { |
||||
if (value !== query.expression) { |
||||
onChangeQuery(value); |
||||
} |
||||
disposalRef.current?.dispose(); |
||||
}} |
||||
onFocus={onFocus} |
||||
onBeforeEditorMount={onBeforeEditorMount} |
||||
onEditorDidMount={onEditorMount} |
||||
onEditorWillUnmount={() => disposalRef.current?.dispose()} |
||||
/> |
||||
); |
||||
}; |
@ -0,0 +1,319 @@ |
||||
import { CustomVariableModel } from '@grafana/data'; |
||||
import { Monaco, monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { setupMockedTemplateService, logGroupNamesVariable } from '../../../__mocks__/CloudWatchDataSource'; |
||||
import { multiLineFullQuery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/multiLineFullQuery'; |
||||
import { multiLineFullQueryWithCaseClause } from '../../../__mocks__/cloudwatch-logs-sql-test-data/multiLineFullQueryWithCaseClause'; |
||||
import { partialQueryWithSubquery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/partialQueryWithSubquery'; |
||||
import { singleLineFullQuery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/singleLineFullQuery'; |
||||
import { whitespaceQuery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/whitespaceQuery'; |
||||
import MonacoMock from '../../../__mocks__/monarch/Monaco'; |
||||
import TextModel from '../../../__mocks__/monarch/TextModel'; |
||||
import { ResourcesAPI } from '../../../resources/ResourcesAPI'; |
||||
import { ResourceResponse } from '../../../resources/types'; |
||||
import { LogGroup, LogGroupField } from '../../../types'; |
||||
import cloudWatchLogsLanguageDefinition from '../definition'; |
||||
import { |
||||
SELECT, |
||||
ALL, |
||||
DISTINCT, |
||||
ALL_FUNCTIONS, |
||||
FROM, |
||||
BY, |
||||
WHERE, |
||||
GROUP, |
||||
ORDER, |
||||
LIMIT, |
||||
INNER, |
||||
LEFT, |
||||
OUTER, |
||||
JOIN, |
||||
ON, |
||||
HAVING, |
||||
PREDICATE_OPERATORS, |
||||
LOGICAL_OPERATORS, |
||||
ASC, |
||||
DESC, |
||||
CASE, |
||||
WHEN, |
||||
THEN, |
||||
ELSE, |
||||
END, |
||||
} from '../language'; |
||||
|
||||
import { LogsSQLCompletionItemProvider } from './CompletionItemProvider'; |
||||
|
||||
jest.mock('monaco-editor/esm/vs/editor/editor.api', () => ({ |
||||
Token: jest.fn((offset, type, language) => ({ offset, type, language })), |
||||
})); |
||||
|
||||
const getSuggestions = async ( |
||||
value: string, |
||||
position: monacoTypes.IPosition, |
||||
variables: CustomVariableModel[] = [], |
||||
logGroups: LogGroup[] = [], |
||||
fields: Array<ResourceResponse<LogGroupField>> = [] |
||||
) => { |
||||
const setup = new LogsSQLCompletionItemProvider( |
||||
{ |
||||
getActualRegion: () => 'us-east-2', |
||||
} as ResourcesAPI, |
||||
setupMockedTemplateService(variables), |
||||
{ region: 'default', logGroups } |
||||
); |
||||
|
||||
setup.resources.getLogGroupFields = jest.fn().mockResolvedValue(fields); |
||||
const monaco = MonacoMock as Monaco; |
||||
const provider = setup.getCompletionProvider(monaco, cloudWatchLogsLanguageDefinition); |
||||
const { suggestions } = await provider.provideCompletionItems( |
||||
TextModel(value) as monacoTypes.editor.ITextModel, |
||||
position |
||||
); |
||||
return suggestions; |
||||
}; |
||||
|
||||
describe('LogsSQLCompletionItemProvider', () => { |
||||
describe('getSuggestions', () => { |
||||
it('returns select keyword for an empty query', async () => { |
||||
const suggestions = await getSuggestions(whitespaceQuery.query, { lineNumber: 1, column: 0 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([SELECT])); |
||||
}); |
||||
|
||||
it('returns `ALL`, `DISTINCT`, `CASE`, keywords and all functions after select keyword', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 7 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([ALL, DISTINCT, CASE, ...ALL_FUNCTIONS])); |
||||
}); |
||||
|
||||
it('returns `CASE` keyword and all functions for a select expression', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 37 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([CASE, ...ALL_FUNCTIONS])); |
||||
}); |
||||
|
||||
it('returns `FROM`, `CASE` keywords and all functions after a select expression', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 103 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual( |
||||
expect.arrayContaining([FROM, `${FROM} \`logGroups(logGroupIdentifier: [...])\``, CASE, ...ALL_FUNCTIONS]) |
||||
); |
||||
}); |
||||
|
||||
it('returns logGroups suggestion after from keyword', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 108 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(['`logGroups(logGroupIdentifier: [...])`'])); |
||||
}); |
||||
|
||||
it('returns where, having, limit, group by, order by, and join suggestions after from arguments', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 125 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual( |
||||
expect.arrayContaining([ |
||||
WHERE, |
||||
HAVING, |
||||
LIMIT, |
||||
`${GROUP} ${BY}`, |
||||
`${ORDER} ${BY}`, |
||||
`${INNER} ${JOIN} <log group> ${ON} <field>`, |
||||
`${LEFT} ${OUTER} ${JOIN} <log group> ${ON} <field>`, |
||||
]) |
||||
); |
||||
}); |
||||
|
||||
it('returns `CASE` keyword and all functions for a where key', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 182 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([CASE, ...ALL_FUNCTIONS])); |
||||
}); |
||||
|
||||
it('returns predicate operators after a where key', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 191 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(PREDICATE_OPERATORS)); |
||||
}); |
||||
|
||||
it('returns all functions after a where comparison operator', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 193 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns logical operators, group by, order by, and limit keywords after a where value', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 201 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual( |
||||
expect.arrayContaining([...LOGICAL_OPERATORS, LIMIT, `${GROUP} ${BY}`, `${ORDER} ${BY}`]) |
||||
); |
||||
}); |
||||
|
||||
it('returns all functions for a having key', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQuery.query, { lineNumber: 8, column: 7 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns predicate operators after a having key', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQuery.query, { lineNumber: 8, column: 13 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(PREDICATE_OPERATORS)); |
||||
}); |
||||
|
||||
it('returns all functions after a having comparison operator', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQuery.query, { lineNumber: 8, column: 15 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns logical operators, order by, and limit keywords after a having value', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQuery.query, { lineNumber: 8, column: 18 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([...LOGICAL_OPERATORS, LIMIT, `${ORDER} ${BY}`])); |
||||
}); |
||||
|
||||
it('returns all functions for an on key', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 156 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns predicate operators after an on key', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 165 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(PREDICATE_OPERATORS)); |
||||
}); |
||||
|
||||
it('returns all functions after an on comparison operator', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 167 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns logical operators, group by, order by, and limit keywords after an on value', async () => { |
||||
const suggestions = await getSuggestions(singleLineFullQuery.query, { lineNumber: 1, column: 176 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual( |
||||
expect.arrayContaining([...LOGICAL_OPERATORS, LIMIT, `${GROUP} ${BY}`, `${ORDER} ${BY}`]) |
||||
); |
||||
}); |
||||
|
||||
it('returns `WHEN` keyword and all functions for a case key', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 9, column: 5 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([WHEN, ...ALL_FUNCTIONS])); |
||||
}); |
||||
|
||||
it('returns `WHEN` keyword and predicate operators after a case key', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 9, column: 7 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([WHEN, ...PREDICATE_OPERATORS])); |
||||
}); |
||||
|
||||
it('returns all functions after a case comparison operator', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 9, column: 9 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns `WHEN` keyword after a case value', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 9, column: 11 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([WHEN])); |
||||
}); |
||||
|
||||
it('returns all functions for a when key', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 5 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns `THEN` keyword and predicate operators after a when key', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 8 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([THEN, ...PREDICATE_OPERATORS])); |
||||
}); |
||||
|
||||
it('returns all functions after a when comparison operator', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 10 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns `THEN` keyword after a when value', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 14 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([THEN])); |
||||
}); |
||||
|
||||
it('returns all functions after a then keyword', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 19 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns `WHEN`, `ELSE`, and `END` keywords after a then expression', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 29 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([WHEN, `${ELSE} ... ${END}`])); |
||||
}); |
||||
|
||||
it('returns all functions after an else keyword', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQueryWithCaseClause.query, { lineNumber: 5, column: 5 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns all functions after group by keywords', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQuery.query, { lineNumber: 7, column: 9 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(ALL_FUNCTIONS)); |
||||
}); |
||||
|
||||
it('returns having, limit, order by suggestions after group by', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQuery.query, { lineNumber: 7, column: 27 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([HAVING, LIMIT, `${ORDER} ${BY}`])); |
||||
}); |
||||
|
||||
it('returns order directions and limit keywords after order by keywords', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQuery.query, { lineNumber: 9, column: 9 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([LIMIT, ASC, DESC])); |
||||
}); |
||||
|
||||
it('returns limit keyword after order by direction', async () => { |
||||
const suggestions = await getSuggestions(multiLineFullQuery.query, { lineNumber: 9, column: 26 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([LIMIT])); |
||||
}); |
||||
|
||||
it('returns `SELECT` keyword and all functions at the start of a subquery', async () => { |
||||
const suggestions = await getSuggestions(partialQueryWithSubquery.query, { lineNumber: 1, column: 53 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([SELECT, ...ALL_FUNCTIONS])); |
||||
}); |
||||
|
||||
it('returns template variables appended to list of suggestions', async () => { |
||||
const suggestions = await getSuggestions(whitespaceQuery.query, { lineNumber: 1, column: 0 }, [ |
||||
logGroupNamesVariable, |
||||
]); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
const expectedTemplateVariableLabel = `$${logGroupNamesVariable.name}`; |
||||
const expectedLabels = [SELECT, expectedTemplateVariableLabel]; |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(expectedLabels)); |
||||
}); |
||||
|
||||
it('fetches fields when logGroups are set', async () => { |
||||
const suggestions = await getSuggestions( |
||||
singleLineFullQuery.query, |
||||
{ lineNumber: 1, column: 37 }, |
||||
[], |
||||
[{ arn: 'foo', name: 'bar' }], |
||||
[{ value: { name: '@field' } }] |
||||
); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(['@field'])); |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,314 @@ |
||||
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime'; |
||||
import type { Monaco, monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { ResourcesAPI } from '../../../resources/ResourcesAPI'; |
||||
import { LogGroup } from '../../../types'; |
||||
import { CompletionItemProvider } from '../../monarch/CompletionItemProvider'; |
||||
import { LinkedToken } from '../../monarch/LinkedToken'; |
||||
import { TRIGGER_SUGGEST } from '../../monarch/commands'; |
||||
import { SuggestionKind, CompletionItemPriority, StatementPosition } from '../../monarch/types'; |
||||
import { |
||||
ASC, |
||||
BY, |
||||
PREDICATE_OPERATORS, |
||||
DESC, |
||||
FROM, |
||||
ALL_FUNCTIONS, |
||||
ALL, |
||||
DISTINCT, |
||||
GROUP, |
||||
LIMIT, |
||||
INNER, |
||||
LEFT, |
||||
OUTER, |
||||
ON, |
||||
JOIN, |
||||
LOGICAL_OPERATORS, |
||||
ORDER, |
||||
SELECT, |
||||
WHERE, |
||||
HAVING, |
||||
CASE, |
||||
WHEN, |
||||
THEN, |
||||
ELSE, |
||||
END, |
||||
} from '../language'; |
||||
|
||||
import { getStatementPosition } from './statementPosition'; |
||||
import { getSuggestionKinds } from './suggestionKind'; |
||||
import { SQLTokenTypes } from './types'; |
||||
|
||||
type CompletionItem = monacoTypes.languages.CompletionItem; |
||||
|
||||
export type queryContext = { |
||||
logGroups?: LogGroup[]; |
||||
region: string; |
||||
}; |
||||
|
||||
export function LogsSQLCompletionItemProviderFunc( |
||||
resources: ResourcesAPI, |
||||
templateSrv: TemplateSrv = getTemplateSrv() |
||||
) { |
||||
return (queryContext: queryContext) => { |
||||
return new LogsSQLCompletionItemProvider(resources, templateSrv, queryContext); |
||||
}; |
||||
} |
||||
|
||||
export class LogsSQLCompletionItemProvider extends CompletionItemProvider { |
||||
region: string; |
||||
queryContext: queryContext; |
||||
|
||||
constructor(resources: ResourcesAPI, templateSrv: TemplateSrv = getTemplateSrv(), queryContext: queryContext) { |
||||
super(resources, templateSrv); |
||||
this.region = resources.getActualRegion() ?? ''; |
||||
this.getStatementPosition = getStatementPosition; |
||||
this.getSuggestionKinds = getSuggestionKinds; |
||||
this.tokenTypes = SQLTokenTypes; |
||||
this.queryContext = queryContext; |
||||
} |
||||
|
||||
async getSuggestions( |
||||
monaco: Monaco, |
||||
currentToken: LinkedToken | null, |
||||
suggestionKinds: SuggestionKind[], |
||||
statementPosition: StatementPosition, |
||||
position: monacoTypes.IPosition |
||||
): Promise<CompletionItem[]> { |
||||
let suggestions: CompletionItem[] = []; |
||||
const invalidRangeToken = currentToken?.isWhiteSpace() || currentToken?.isParenthesis(); |
||||
const range = |
||||
invalidRangeToken || !currentToken?.range ? monaco.Range.fromPositions(position) : currentToken?.range; |
||||
|
||||
const toCompletionItem = (value: string, rest: Partial<CompletionItem> = {}) => { |
||||
const item: CompletionItem = { |
||||
label: value, |
||||
insertText: value, |
||||
kind: monaco.languages.CompletionItemKind.Field, |
||||
range, |
||||
sortText: CompletionItemPriority.Medium, |
||||
...rest, |
||||
}; |
||||
return item; |
||||
}; |
||||
|
||||
function addSuggestion(value: string, rest: Partial<CompletionItem> = {}) { |
||||
suggestions = [...suggestions, toCompletionItem(value, rest)]; |
||||
} |
||||
|
||||
for (const suggestion of suggestionKinds) { |
||||
switch (suggestion) { |
||||
case SuggestionKind.SelectKeyword: |
||||
addSuggestion(SELECT, { |
||||
insertText: `${SELECT} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.AfterSelectKeyword: |
||||
addSuggestion(ALL, { |
||||
insertText: `${ALL} `, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
command: TRIGGER_SUGGEST, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
}); |
||||
addSuggestion(DISTINCT, { |
||||
insertText: `${DISTINCT} `, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
command: TRIGGER_SUGGEST, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.FunctionsWithArguments: |
||||
ALL_FUNCTIONS.map((s) => |
||||
addSuggestion(s, { |
||||
insertText: `${s}($0)`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
command: TRIGGER_SUGGEST, |
||||
kind: monaco.languages.CompletionItemKind.Function, |
||||
}) |
||||
); |
||||
break; |
||||
|
||||
case SuggestionKind.FromKeyword: |
||||
addSuggestion(FROM, { |
||||
insertText: `${FROM} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
sortText: CompletionItemPriority.MediumHigh, |
||||
}); |
||||
addSuggestion(`${FROM} \`logGroups(logGroupIdentifier: [...])\``, { |
||||
insertText: `${FROM} \`logGroups(logGroupIdentifier: [$0])\``, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
sortText: CompletionItemPriority.MediumHigh, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.AfterFromKeyword: |
||||
addSuggestion('`logGroups(logGroupIdentifier: [...])`', { |
||||
insertText: '`logGroups(logGroupIdentifier: [$0])`', |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Function, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.LogicalOperators: |
||||
LOGICAL_OPERATORS.map((o) => |
||||
addSuggestion(`${o}`, { |
||||
insertText: `${o} `, |
||||
command: TRIGGER_SUGGEST, |
||||
sortText: CompletionItemPriority.MediumHigh, |
||||
}) |
||||
); |
||||
break; |
||||
|
||||
case SuggestionKind.WhereKeyword: |
||||
addSuggestion(`${WHERE}`, { |
||||
insertText: `${WHERE} `, |
||||
command: TRIGGER_SUGGEST, |
||||
sortText: CompletionItemPriority.High, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.HavingKeywords: |
||||
addSuggestion(`${HAVING}`, { |
||||
insertText: `${HAVING} `, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.ComparisonOperators: |
||||
PREDICATE_OPERATORS.map((o) => addSuggestion(`${o}`, { insertText: `${o} `, command: TRIGGER_SUGGEST })); |
||||
break; |
||||
|
||||
case SuggestionKind.CaseKeyword: |
||||
addSuggestion(CASE, { |
||||
insertText: `${CASE} `, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.WhenKeyword: |
||||
addSuggestion(WHEN, { |
||||
insertText: `${WHEN} `, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.ThenKeyword: |
||||
addSuggestion(THEN, { |
||||
insertText: `${THEN} `, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.AfterThenExpression: |
||||
addSuggestion(`${ELSE} ... ${END}`, { |
||||
insertText: `${ELSE} $0 ${END}`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.GroupByKeywords: |
||||
addSuggestion(`${GROUP} ${BY}`, { |
||||
insertText: `${GROUP} ${BY} `, |
||||
command: TRIGGER_SUGGEST, |
||||
sortText: CompletionItemPriority.MediumHigh, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.OrderByKeywords: |
||||
addSuggestion(`${ORDER} ${BY}`, { |
||||
insertText: `${ORDER} ${BY} `, |
||||
command: TRIGGER_SUGGEST, |
||||
sortText: CompletionItemPriority.Medium, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.JoinKeywords: |
||||
addSuggestion(`${INNER} ${JOIN} <log group> ${ON} <field>`, { |
||||
insertText: `${INNER} ${JOIN} $1 ${ON} $2`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
sortText: CompletionItemPriority.MediumLow, |
||||
}); |
||||
addSuggestion(`${LEFT} ${OUTER} ${JOIN} <log group> ${ON} <field>`, { |
||||
insertText: `${LEFT} ${OUTER} ${JOIN} $1 ${ON} $2`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
sortText: CompletionItemPriority.MediumLow, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.LimitKeyword: |
||||
addSuggestion(LIMIT, { insertText: `${LIMIT} ` }); |
||||
break; |
||||
|
||||
case SuggestionKind.SortOrderDirectionKeyword: |
||||
[ASC, DESC].map((s) => |
||||
addSuggestion(s, { |
||||
insertText: `${s} `, |
||||
command: TRIGGER_SUGGEST, |
||||
}) |
||||
); |
||||
break; |
||||
|
||||
case SuggestionKind.Field: |
||||
const fields = await this.fetchFields(this.queryContext.logGroups || [], this.queryContext.region); |
||||
fields.forEach((field) => { |
||||
if (field !== '') { |
||||
addSuggestion(field, { |
||||
label: field, |
||||
insertText: `\`${field}\``, |
||||
kind: monaco.languages.CompletionItemKind.Field, |
||||
}); |
||||
} |
||||
}); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
this.templateSrv.getVariables().map((v) => { |
||||
const variable = `$${v.name}`; |
||||
addSuggestion(variable, { |
||||
range, |
||||
label: variable, |
||||
insertText: variable, |
||||
kind: monaco.languages.CompletionItemKind.Variable, |
||||
sortText: CompletionItemPriority.Low, |
||||
}); |
||||
}); |
||||
|
||||
return suggestions; |
||||
} |
||||
|
||||
private fetchFields = async (logGroups: LogGroup[], region: string): Promise<string[]> => { |
||||
if (logGroups.length === 0) { |
||||
return []; |
||||
} |
||||
|
||||
const results = await Promise.all( |
||||
logGroups.map((logGroup) => |
||||
this.resources |
||||
.getLogGroupFields({ logGroupName: logGroup.name, arn: logGroup.arn, region }) |
||||
.then((fields) => fields.filter((f) => f).map((f) => f.value.name ?? '')) |
||||
) |
||||
); |
||||
// Deduplicate fields
|
||||
return [...new Set(results.flat())]; |
||||
}; |
||||
} |
@ -0,0 +1,264 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { commentOnlyQuery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/commentOnlyQuery'; |
||||
import { multiLineFullQuery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/multiLineFullQuery'; |
||||
import { multiLineFullQueryWithCaseClause } from '../../../__mocks__/cloudwatch-logs-sql-test-data/multiLineFullQueryWithCaseClause'; |
||||
import { partialQueryWithFunction } from '../../../__mocks__/cloudwatch-logs-sql-test-data/partialQueryWithFunction'; |
||||
import { partialQueryWithSubquery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/partialQueryWithSubquery'; |
||||
import { singleLineFullQuery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/singleLineFullQuery'; |
||||
import { whitespaceQuery } from '../../../__mocks__/cloudwatch-logs-sql-test-data/whitespaceQuery'; |
||||
import MonacoMock from '../../../__mocks__/monarch/Monaco'; |
||||
import TextModel from '../../../__mocks__/monarch/TextModel'; |
||||
import { linkedTokenBuilder } from '../../monarch/linkedTokenBuilder'; |
||||
import { StatementPosition } from '../../monarch/types'; |
||||
import cloudWatchLogsSqlLanguageDefinition from '../definition'; |
||||
|
||||
import { getStatementPosition } from './statementPosition'; |
||||
import { SQLTokenTypes } from './types'; |
||||
|
||||
describe('statementPosition', () => { |
||||
function assertPosition(query: string, position: monacoTypes.IPosition, expected: StatementPosition) { |
||||
const testModel = TextModel(query); |
||||
const current = linkedTokenBuilder( |
||||
MonacoMock, |
||||
cloudWatchLogsSqlLanguageDefinition, |
||||
testModel as monacoTypes.editor.ITextModel, |
||||
position, |
||||
SQLTokenTypes |
||||
); |
||||
const statementPosition = getStatementPosition(current); |
||||
expect(StatementPosition[statementPosition]).toBe(StatementPosition[expected]); |
||||
} |
||||
|
||||
test.each([ |
||||
[commentOnlyQuery.query, { lineNumber: 1, column: 0 }], |
||||
[singleLineFullQuery.query, { lineNumber: 1, column: 202 }], |
||||
[multiLineFullQuery.query, { lineNumber: 10, column: 0 }], |
||||
[multiLineFullQuery.query, { lineNumber: 11, column: 0 }], |
||||
[multiLineFullQuery.query, { lineNumber: 12, column: 0 }], |
||||
[multiLineFullQuery.query, { lineNumber: 13, column: 0 }], |
||||
[multiLineFullQuery.query, { lineNumber: 14, column: 0 }], |
||||
[multiLineFullQuery.query, { lineNumber: 15, column: 0 }], |
||||
[multiLineFullQuery.query, { lineNumber: 16, column: 0 }], |
||||
])('should be comment', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.Comment); |
||||
}); |
||||
test.each([ |
||||
[singleLineFullQuery.query, { lineNumber: 1, column: 0 }], |
||||
[multiLineFullQuery.query, { lineNumber: 1, column: 0 }], |
||||
[whitespaceQuery.query, { lineNumber: 1, column: 0 }], |
||||
])('should be select keyword', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.SelectKeyword); |
||||
}); |
||||
test.each([ |
||||
[singleLineFullQuery.query, { lineNumber: 1, column: 7 }], |
||||
[multiLineFullQuery.query, { lineNumber: 1, column: 7 }], |
||||
])('should be after select keyword', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterSelectKeyword); |
||||
}); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 37 }]])( |
||||
'should be select expression', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.SelectExpression); |
||||
} |
||||
); |
||||
test.each([ |
||||
[singleLineFullQuery.query, { lineNumber: 1, column: 103 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 6, column: 4 }], |
||||
])('should be after select expression', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterSelectExpression); |
||||
}); |
||||
test.each([[partialQueryWithSubquery.query, { lineNumber: 1, column: 52 }]])( |
||||
'should be subquery', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.Subquery); |
||||
} |
||||
); |
||||
test.each([[partialQueryWithFunction.query, { lineNumber: 1, column: 14 }]])( |
||||
'should be predefined function argument', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.PredefinedFunctionArgument); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 108 }]])( |
||||
'should be after from keyword', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterFromKeyword); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 125 }]])( |
||||
'should be after from arguments', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterFromArguments); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 182 }]])( |
||||
'should be where key', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.WhereKey); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 191 }]])( |
||||
'should be where comparison operator', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.WhereComparisonOperator); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 193 }]])( |
||||
'should be where value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.WhereValue); |
||||
} |
||||
); |
||||
test.each([ |
||||
[singleLineFullQuery.query, { lineNumber: 1, column: 201 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 13, column: 4 }], |
||||
])('should be after where value', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterWhereValue); |
||||
}); |
||||
test.each([[multiLineFullQuery.query, { lineNumber: 8, column: 7 }]])( |
||||
'should be having key', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.HavingKey); |
||||
} |
||||
); |
||||
test.each([[multiLineFullQuery.query, { lineNumber: 8, column: 13 }]])( |
||||
'should be having comparison operator', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.HavingComparisonOperator); |
||||
} |
||||
); |
||||
test.each([[multiLineFullQuery.query, { lineNumber: 8, column: 15 }]])( |
||||
'should be having value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.HavingValue); |
||||
} |
||||
); |
||||
test.each([[multiLineFullQuery.query, { lineNumber: 8, column: 18 }]])( |
||||
'should be after having value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterHavingValue); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 156 }]])( |
||||
'should be on key', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.OnKey); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 165 }]])( |
||||
'should be on comparison operator', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.OnComparisonOperator); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 167 }]])( |
||||
'should be on value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.OnValue); |
||||
} |
||||
); |
||||
test.each([[singleLineFullQuery.query, { lineNumber: 1, column: 176 }]])( |
||||
'should be after on value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterOnValue); |
||||
} |
||||
); |
||||
test.each([ |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 2, column: 5 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 9, column: 5 }], |
||||
])('should be case key', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.CaseKey); |
||||
}); |
||||
test.each([ |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 2, column: 8 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 9, column: 7 }], |
||||
])('should be case comparison operator', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.CaseComparisonOperator); |
||||
}); |
||||
test.each([[multiLineFullQueryWithCaseClause.query, { lineNumber: 9, column: 9 }]])( |
||||
'should be case value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.CaseValue); |
||||
} |
||||
); |
||||
test.each([[multiLineFullQueryWithCaseClause.query, { lineNumber: 9, column: 11 }]])( |
||||
'should be after case value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterCaseValue); |
||||
} |
||||
); |
||||
test.each([ |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 3, column: 5 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 5 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 10, column: 5 }], |
||||
])('should be when key', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.WhenKey); |
||||
}); |
||||
test.each([ |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 3, column: 9 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 8 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 10, column: 9 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 11, column: 9 }], |
||||
])('should be when comparison operator', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.WhenComparisonOperator); |
||||
}); |
||||
test.each([[multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 10 }]])( |
||||
'should be when value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.WhenValue); |
||||
} |
||||
); |
||||
test.each([[multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 14 }]])( |
||||
'should be after when value', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterWhenValue); |
||||
} |
||||
); |
||||
test.each([ |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 3, column: 14 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 19 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 10, column: 14 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 11, column: 14 }], |
||||
])('should be then expression', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.ThenExpression); |
||||
}); |
||||
test.each([ |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 3, column: 20 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 4, column: 29 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 10, column: 21 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 11, column: 24 }], |
||||
])('should be after then expression', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterThenExpression); |
||||
}); |
||||
test.each([ |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 5, column: 5 }], |
||||
[multiLineFullQueryWithCaseClause.query, { lineNumber: 12, column: 5 }], |
||||
])('should be after else keyword', (query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterElseKeyword); |
||||
}); |
||||
test.each([[multiLineFullQuery.query, { lineNumber: 7, column: 9 }]])( |
||||
'should be after group by keywords', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterGroupByKeywords); |
||||
} |
||||
); |
||||
test.each([[multiLineFullQuery.query, { lineNumber: 7, column: 27 }]])( |
||||
'should be after group by', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterGroupBy); |
||||
} |
||||
); |
||||
test.each([[multiLineFullQuery.query, { lineNumber: 9, column: 9 }]])( |
||||
'should be after order by keywords', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterOrderByKeywords); |
||||
} |
||||
); |
||||
test.each([[multiLineFullQuery.query, { lineNumber: 9, column: 26 }]])( |
||||
'should be after order by direction', |
||||
(query: string, position: monacoTypes.IPosition) => { |
||||
assertPosition(query, position, StatementPosition.AfterOrderByDirection); |
||||
} |
||||
); |
||||
}); |
@ -0,0 +1,375 @@ |
||||
import { LinkedToken } from '../../monarch/LinkedToken'; |
||||
import { StatementPosition } from '../../monarch/types'; |
||||
import { |
||||
ALL, |
||||
DISTINCT, |
||||
AS, |
||||
ASC, |
||||
BY, |
||||
DESC, |
||||
FROM, |
||||
GROUP, |
||||
ORDER, |
||||
SELECT, |
||||
WHERE, |
||||
HAVING, |
||||
ON, |
||||
LOGICAL_OPERATORS, |
||||
PREDICATE_OPERATORS, |
||||
NULL, |
||||
TRUE, |
||||
FALSE, |
||||
IN, |
||||
CASE, |
||||
WHEN, |
||||
THEN, |
||||
ELSE, |
||||
END, |
||||
} from '../language'; |
||||
|
||||
import { SQLTokenTypes } from './types'; |
||||
|
||||
export function getStatementPosition(currentToken: LinkedToken | null): StatementPosition { |
||||
const previousNonWhiteSpace = currentToken?.getPreviousNonWhiteSpaceToken(); |
||||
const previousKeyword = currentToken?.getPreviousKeyword(); |
||||
|
||||
const normalizedPreviousNonWhiteSpaceValue = previousNonWhiteSpace?.value?.toUpperCase() || ''; |
||||
const normalizedPreviousKeywordValue = previousKeyword?.value?.toUpperCase() || ''; |
||||
|
||||
let previousNonAliasKeywordValue = previousKeyword; |
||||
let normalizedPreviousNonAliasKeywordValue = normalizedPreviousKeywordValue; |
||||
while (normalizedPreviousNonAliasKeywordValue === AS) { |
||||
previousNonAliasKeywordValue = previousNonAliasKeywordValue?.getPreviousKeyword(); |
||||
normalizedPreviousNonAliasKeywordValue = previousNonAliasKeywordValue?.value.toUpperCase() || ''; |
||||
} |
||||
|
||||
const isPreviousSelectKeywordGroup = |
||||
normalizedPreviousNonAliasKeywordValue === SELECT || |
||||
([ALL, DISTINCT].includes(normalizedPreviousNonAliasKeywordValue) && |
||||
previousNonAliasKeywordValue?.getPreviousKeyword()?.value.toUpperCase() === SELECT); |
||||
|
||||
if (currentToken?.is(SQLTokenTypes.Comment) || currentToken?.is('comment.quote.cloudwatch-logs-sql')) { |
||||
return StatementPosition.Comment; |
||||
} |
||||
|
||||
if ( |
||||
currentToken === null || |
||||
(currentToken.previous === null && currentToken.isIdentifier()) || |
||||
(currentToken.previous === null && currentToken.isWhiteSpace()) || |
||||
(currentToken.previous === null && currentToken.isKeyword() && currentToken.value.toUpperCase() === SELECT) |
||||
) { |
||||
return StatementPosition.SelectKeyword; |
||||
} |
||||
|
||||
if ( |
||||
(currentToken.isWhiteSpace() || currentToken.is(SQLTokenTypes.Parenthesis, ')')) && |
||||
normalizedPreviousNonWhiteSpaceValue === SELECT |
||||
) { |
||||
return StatementPosition.AfterSelectKeyword; |
||||
} |
||||
|
||||
if ( |
||||
isPreviousSelectKeywordGroup && |
||||
(currentToken.is(SQLTokenTypes.Delimiter, ',') || |
||||
(currentToken.isWhiteSpace() && previousNonWhiteSpace?.is(SQLTokenTypes.Delimiter, ',')) || |
||||
(currentToken.isWhiteSpace() && previousNonWhiteSpace?.isKeyword()) || |
||||
(currentToken.is(SQLTokenTypes.Parenthesis, ')') && |
||||
(previousNonWhiteSpace?.isKeyword() || previousNonWhiteSpace?.is(SQLTokenTypes.Delimiter, ',')))) |
||||
) { |
||||
return StatementPosition.SelectExpression; |
||||
} |
||||
|
||||
if ( |
||||
isPreviousSelectKeywordGroup && |
||||
(currentToken.isWhiteSpace() || currentToken.is(SQLTokenTypes.Parenthesis, ')')) && |
||||
(previousNonWhiteSpace?.isIdentifier() || |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Parenthesis, ')') || |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Parenthesis, '()') || |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Operator, '*')) |
||||
) { |
||||
return StatementPosition.AfterSelectExpression; |
||||
} |
||||
|
||||
if ( |
||||
currentToken.is(SQLTokenTypes.Parenthesis, '()') && |
||||
normalizedPreviousNonAliasKeywordValue === WHERE && |
||||
normalizedPreviousNonWhiteSpaceValue === IN |
||||
) { |
||||
return StatementPosition.Subquery; |
||||
} |
||||
|
||||
if ( |
||||
((currentToken.is(SQLTokenTypes.Parenthesis, '()') || currentToken.is(SQLTokenTypes.Parenthesis, '())')) && |
||||
previousNonWhiteSpace?.isFunction()) || |
||||
(currentToken.is(SQLTokenTypes.Delimiter, ',') && |
||||
currentToken.getPreviousOfType(SQLTokenTypes.Parenthesis, '(')?.getPreviousNonWhiteSpaceToken()?.isFunction()) || |
||||
(currentToken.isWhiteSpace() && |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Delimiter, ',') && |
||||
currentToken.getPreviousOfType(SQLTokenTypes.Parenthesis, '(')?.getPreviousNonWhiteSpaceToken()?.isFunction()) || |
||||
(currentToken.is(SQLTokenTypes.Parenthesis, ')') && |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Delimiter, ',') && |
||||
currentToken.getPreviousOfType(SQLTokenTypes.Parenthesis, '(')?.getPreviousNonWhiteSpaceToken()?.isFunction()) |
||||
) { |
||||
return StatementPosition.PredefinedFunctionArgument; |
||||
} |
||||
|
||||
if ( |
||||
(currentToken.isWhiteSpace() || currentToken.is(SQLTokenTypes.Parenthesis, ')')) && |
||||
normalizedPreviousNonWhiteSpaceValue === FROM |
||||
) { |
||||
return StatementPosition.AfterFromKeyword; |
||||
} |
||||
|
||||
if ( |
||||
normalizedPreviousNonAliasKeywordValue === FROM && |
||||
(previousNonWhiteSpace?.isIdentifier() || |
||||
previousNonWhiteSpace?.isDoubleQuotedString() || |
||||
previousNonWhiteSpace?.isVariable() || |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Parenthesis, ')')) |
||||
) { |
||||
return StatementPosition.AfterFromArguments; |
||||
} |
||||
|
||||
if ( |
||||
(LOGICAL_OPERATORS.includes(normalizedPreviousNonWhiteSpaceValue) && |
||||
[WHERE, HAVING, ON, CASE, WHEN].includes(normalizedPreviousKeywordValue)) || |
||||
((currentToken.isWhiteSpace() || currentToken.is(SQLTokenTypes.Parenthesis, ')')) && |
||||
[WHERE, HAVING, ON, CASE, WHEN].includes(normalizedPreviousNonWhiteSpaceValue)) |
||||
) { |
||||
switch (normalizedPreviousKeywordValue) { |
||||
case WHERE: |
||||
return StatementPosition.WhereKey; |
||||
case HAVING: |
||||
return StatementPosition.HavingKey; |
||||
case ON: |
||||
return StatementPosition.OnKey; |
||||
case CASE: |
||||
return StatementPosition.CaseKey; |
||||
case WHEN: |
||||
return StatementPosition.WhenKey; |
||||
} |
||||
} |
||||
|
||||
if ( |
||||
(LOGICAL_OPERATORS.includes(normalizedPreviousNonWhiteSpaceValue) && |
||||
[NULL, TRUE, FALSE].includes(normalizedPreviousKeywordValue)) || |
||||
((currentToken.isWhiteSpace() || currentToken.is(SQLTokenTypes.Parenthesis, ')')) && |
||||
[NULL, TRUE, FALSE].includes(normalizedPreviousNonWhiteSpaceValue)) |
||||
) { |
||||
let nearestPreviousKeyword = previousKeyword; |
||||
let normalizedNearestPreviousKeywordValue = normalizedPreviousKeywordValue; |
||||
while (![WHERE, HAVING, ON, CASE, WHEN].includes(normalizedNearestPreviousKeywordValue)) { |
||||
nearestPreviousKeyword = nearestPreviousKeyword?.getPreviousKeyword(); |
||||
normalizedNearestPreviousKeywordValue = nearestPreviousKeyword?.value.toUpperCase() || ''; |
||||
} |
||||
|
||||
switch (normalizedNearestPreviousKeywordValue) { |
||||
case WHERE: |
||||
return StatementPosition.WhereKey; |
||||
case HAVING: |
||||
return StatementPosition.HavingKey; |
||||
case ON: |
||||
return StatementPosition.OnKey; |
||||
case CASE: |
||||
return StatementPosition.CaseKey; |
||||
case WHEN: |
||||
return StatementPosition.WhenKey; |
||||
} |
||||
} |
||||
|
||||
if ( |
||||
[WHERE, HAVING, ON, CASE, WHEN].includes(normalizedPreviousKeywordValue) && |
||||
PREDICATE_OPERATORS.includes(normalizedPreviousNonWhiteSpaceValue) |
||||
) { |
||||
switch (normalizedPreviousKeywordValue) { |
||||
case WHERE: |
||||
return StatementPosition.WhereValue; |
||||
case HAVING: |
||||
return StatementPosition.HavingValue; |
||||
case ON: |
||||
return StatementPosition.OnValue; |
||||
case CASE: |
||||
return StatementPosition.CaseValue; |
||||
case WHEN: |
||||
return StatementPosition.WhenValue; |
||||
} |
||||
} |
||||
|
||||
if ( |
||||
[NULL, TRUE, FALSE].includes(normalizedPreviousKeywordValue) && |
||||
PREDICATE_OPERATORS.includes(normalizedPreviousNonWhiteSpaceValue) |
||||
) { |
||||
let nearestPreviousKeyword = previousKeyword; |
||||
let normalizedNearestPreviousKeywordValue = normalizedPreviousKeywordValue; |
||||
while (![WHERE, HAVING, ON, CASE, WHEN].includes(normalizedNearestPreviousKeywordValue)) { |
||||
nearestPreviousKeyword = nearestPreviousKeyword?.getPreviousKeyword(); |
||||
normalizedNearestPreviousKeywordValue = nearestPreviousKeyword?.value.toUpperCase() || ''; |
||||
} |
||||
|
||||
switch (normalizedNearestPreviousKeywordValue) { |
||||
case WHERE: |
||||
return StatementPosition.WhereValue; |
||||
case HAVING: |
||||
return StatementPosition.HavingValue; |
||||
case ON: |
||||
return StatementPosition.OnValue; |
||||
case CASE: |
||||
return StatementPosition.CaseValue; |
||||
case WHEN: |
||||
return StatementPosition.WhenValue; |
||||
} |
||||
} |
||||
|
||||
if ( |
||||
[WHERE, HAVING, ON, CASE, WHEN].includes(normalizedPreviousKeywordValue) && |
||||
(previousNonWhiteSpace?.isIdentifier() || |
||||
previousNonWhiteSpace?.isDoubleQuotedString() || |
||||
previousNonWhiteSpace?.isFunction() || |
||||
previousNonWhiteSpace?.isNumber() || |
||||
previousNonWhiteSpace?.isString() || |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Parenthesis, ')') || |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Parenthesis, '()')) |
||||
) { |
||||
const previousTokens = currentToken.getPreviousUntil(SQLTokenTypes.Keyword, [], normalizedPreviousKeywordValue); |
||||
const numPredicateOperators = |
||||
previousTokens?.filter((token) => PREDICATE_OPERATORS.includes(token.value.toUpperCase())).length || 0; |
||||
const numLogicalOperators = |
||||
previousTokens?.filter((token) => LOGICAL_OPERATORS.includes(token.value.toUpperCase())).length || 0; |
||||
|
||||
if (numPredicateOperators - numLogicalOperators === 0) { |
||||
switch (normalizedPreviousKeywordValue) { |
||||
case WHERE: |
||||
return StatementPosition.WhereComparisonOperator; |
||||
case HAVING: |
||||
return StatementPosition.HavingComparisonOperator; |
||||
case ON: |
||||
return StatementPosition.OnComparisonOperator; |
||||
case CASE: |
||||
return StatementPosition.CaseComparisonOperator; |
||||
case WHEN: |
||||
return StatementPosition.WhenComparisonOperator; |
||||
} |
||||
} else { |
||||
switch (normalizedPreviousKeywordValue) { |
||||
case WHERE: |
||||
return StatementPosition.AfterWhereValue; |
||||
case HAVING: |
||||
return StatementPosition.AfterHavingValue; |
||||
case ON: |
||||
return StatementPosition.AfterOnValue; |
||||
case CASE: |
||||
return StatementPosition.AfterCaseValue; |
||||
case WHEN: |
||||
return StatementPosition.AfterWhenValue; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if ( |
||||
[NULL, TRUE, FALSE].includes(normalizedPreviousKeywordValue) && |
||||
PREDICATE_OPERATORS.includes(previousKeyword?.getPreviousNonWhiteSpaceToken()?.value.toUpperCase() || '') |
||||
) { |
||||
let nearestPreviousKeyword = previousKeyword?.getPreviousKeyword(); |
||||
let normalizedNearestPreviousKeywordValue = nearestPreviousKeyword?.value.toUpperCase() || ''; |
||||
while (![WHERE, HAVING, ON, CASE, WHEN].includes(normalizedNearestPreviousKeywordValue)) { |
||||
nearestPreviousKeyword = nearestPreviousKeyword?.getPreviousKeyword(); |
||||
normalizedNearestPreviousKeywordValue = nearestPreviousKeyword?.value.toUpperCase() || ''; |
||||
} |
||||
|
||||
const previousTokens = currentToken.getPreviousUntil( |
||||
SQLTokenTypes.Keyword, |
||||
[], |
||||
normalizedNearestPreviousKeywordValue |
||||
); |
||||
const numPredicateOperators = |
||||
previousTokens?.filter((token) => PREDICATE_OPERATORS.includes(token.value.toUpperCase())).length || 0; |
||||
const numLogicalOperators = |
||||
previousTokens?.filter((token) => LOGICAL_OPERATORS.includes(token.value.toUpperCase())).length || 0; |
||||
|
||||
if (numPredicateOperators - numLogicalOperators === 0) { |
||||
switch (normalizedNearestPreviousKeywordValue) { |
||||
case WHERE: |
||||
return StatementPosition.WhereComparisonOperator; |
||||
case HAVING: |
||||
return StatementPosition.HavingComparisonOperator; |
||||
case ON: |
||||
return StatementPosition.OnComparisonOperator; |
||||
case CASE: |
||||
return StatementPosition.CaseComparisonOperator; |
||||
case WHEN: |
||||
return StatementPosition.WhenComparisonOperator; |
||||
} |
||||
} else { |
||||
switch (normalizedNearestPreviousKeywordValue) { |
||||
case WHERE: |
||||
return StatementPosition.AfterWhereValue; |
||||
case HAVING: |
||||
return StatementPosition.AfterHavingValue; |
||||
case ON: |
||||
return StatementPosition.AfterOnValue; |
||||
case CASE: |
||||
return StatementPosition.AfterCaseValue; |
||||
case WHEN: |
||||
return StatementPosition.AfterWhenValue; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (currentToken.isWhiteSpace() && normalizedPreviousNonWhiteSpaceValue === THEN) { |
||||
return StatementPosition.ThenExpression; |
||||
} |
||||
|
||||
if ( |
||||
currentToken.isWhiteSpace() && |
||||
normalizedPreviousKeywordValue === THEN && |
||||
normalizedPreviousNonWhiteSpaceValue !== THEN |
||||
) { |
||||
return StatementPosition.AfterThenExpression; |
||||
} |
||||
|
||||
if (currentToken.isWhiteSpace() && normalizedPreviousNonWhiteSpaceValue === ELSE) { |
||||
return StatementPosition.AfterElseKeyword; |
||||
} |
||||
|
||||
if (normalizedPreviousNonWhiteSpaceValue === END && currentToken.isWhiteSpace()) { |
||||
let nearestCaseKeyword = previousKeyword; |
||||
while (CASE !== nearestCaseKeyword?.value.toUpperCase()) { |
||||
nearestCaseKeyword = nearestCaseKeyword?.getPreviousKeyword(); |
||||
} |
||||
const nearestKeywordBeforeCaseKeywordValue = nearestCaseKeyword.getPreviousKeyword()?.value.toUpperCase() || ''; |
||||
switch (nearestKeywordBeforeCaseKeywordValue) { |
||||
case SELECT: |
||||
return StatementPosition.AfterSelectExpression; |
||||
case WHERE: |
||||
return StatementPosition.AfterWhereValue; |
||||
} |
||||
} |
||||
|
||||
if ( |
||||
normalizedPreviousKeywordValue === BY && |
||||
previousKeyword?.getPreviousKeyword()?.value.toUpperCase() === GROUP && |
||||
(previousNonWhiteSpace?.value.toUpperCase() === BY || previousNonWhiteSpace?.is(SQLTokenTypes.Delimiter, ',')) |
||||
) { |
||||
return StatementPosition.AfterGroupByKeywords; |
||||
} |
||||
|
||||
if ( |
||||
normalizedPreviousKeywordValue === BY && |
||||
previousKeyword?.getPreviousKeyword()?.value.toUpperCase() === GROUP && |
||||
(previousNonWhiteSpace?.isIdentifier() || |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Parenthesis, ')') || |
||||
previousNonWhiteSpace?.is(SQLTokenTypes.Parenthesis, '()')) |
||||
) { |
||||
return StatementPosition.AfterGroupBy; |
||||
} |
||||
|
||||
if (normalizedPreviousKeywordValue === BY && previousKeyword?.getPreviousKeyword()?.value.toUpperCase() === ORDER) { |
||||
return StatementPosition.AfterOrderByKeywords; |
||||
} |
||||
|
||||
if ([DESC, ASC].includes(normalizedPreviousKeywordValue)) { |
||||
return StatementPosition.AfterOrderByDirection; |
||||
} |
||||
|
||||
return StatementPosition.Unknown; |
||||
} |
@ -0,0 +1,119 @@ |
||||
import { StatementPosition, SuggestionKind } from '../../monarch/types'; |
||||
|
||||
export function getSuggestionKinds(statementPosition: StatementPosition): SuggestionKind[] { |
||||
switch (statementPosition) { |
||||
case StatementPosition.SelectKeyword: |
||||
return [SuggestionKind.SelectKeyword]; |
||||
case StatementPosition.AfterSelectKeyword: |
||||
return [ |
||||
SuggestionKind.AfterSelectKeyword, |
||||
SuggestionKind.FunctionsWithArguments, |
||||
SuggestionKind.Field, |
||||
SuggestionKind.CaseKeyword, |
||||
]; |
||||
case StatementPosition.SelectExpression: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field, SuggestionKind.CaseKeyword]; |
||||
case StatementPosition.AfterSelectExpression: |
||||
return [ |
||||
SuggestionKind.FromKeyword, |
||||
SuggestionKind.FunctionsWithArguments, |
||||
SuggestionKind.Field, |
||||
SuggestionKind.CaseKeyword, |
||||
]; |
||||
|
||||
case StatementPosition.FromKeyword: |
||||
return [SuggestionKind.FromKeyword, SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.AfterFromKeyword: |
||||
return [SuggestionKind.AfterFromKeyword]; |
||||
case StatementPosition.AfterFromArguments: |
||||
return [ |
||||
SuggestionKind.WhereKeyword, |
||||
SuggestionKind.GroupByKeywords, |
||||
SuggestionKind.OrderByKeywords, |
||||
SuggestionKind.LimitKeyword, |
||||
SuggestionKind.JoinKeywords, |
||||
SuggestionKind.HavingKeywords, |
||||
]; |
||||
|
||||
case StatementPosition.WhereKey: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field, SuggestionKind.CaseKeyword]; |
||||
case StatementPosition.WhereComparisonOperator: |
||||
return [SuggestionKind.ComparisonOperators]; |
||||
case StatementPosition.WhereValue: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.AfterWhereValue: |
||||
return [ |
||||
SuggestionKind.LogicalOperators, |
||||
SuggestionKind.GroupByKeywords, |
||||
SuggestionKind.OrderByKeywords, |
||||
SuggestionKind.LimitKeyword, |
||||
]; |
||||
|
||||
case StatementPosition.HavingKey: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.HavingComparisonOperator: |
||||
return [SuggestionKind.ComparisonOperators]; |
||||
case StatementPosition.HavingValue: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.AfterHavingValue: |
||||
return [SuggestionKind.LogicalOperators, SuggestionKind.OrderByKeywords, SuggestionKind.LimitKeyword]; |
||||
|
||||
case StatementPosition.OnKey: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.OnComparisonOperator: |
||||
return [SuggestionKind.ComparisonOperators]; |
||||
case StatementPosition.OnValue: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.AfterOnValue: |
||||
return [ |
||||
SuggestionKind.LogicalOperators, |
||||
SuggestionKind.GroupByKeywords, |
||||
SuggestionKind.OrderByKeywords, |
||||
SuggestionKind.LimitKeyword, |
||||
]; |
||||
|
||||
case StatementPosition.CaseKey: |
||||
return [SuggestionKind.WhenKeyword, SuggestionKind.Field, SuggestionKind.FunctionsWithArguments]; |
||||
case StatementPosition.CaseComparisonOperator: |
||||
return [SuggestionKind.ComparisonOperators, SuggestionKind.WhenKeyword]; |
||||
case StatementPosition.CaseValue: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.AfterCaseValue: |
||||
return [SuggestionKind.WhenKeyword]; |
||||
|
||||
case StatementPosition.WhenKey: |
||||
return [SuggestionKind.Field, SuggestionKind.FunctionsWithArguments]; |
||||
case StatementPosition.WhenComparisonOperator: |
||||
return [SuggestionKind.ComparisonOperators, SuggestionKind.ThenKeyword]; |
||||
case StatementPosition.WhenValue: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.AfterWhenValue: |
||||
return [SuggestionKind.ThenKeyword]; |
||||
|
||||
case StatementPosition.ThenExpression: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
case StatementPosition.AfterThenExpression: |
||||
return [SuggestionKind.WhenKeyword, SuggestionKind.AfterThenExpression]; |
||||
|
||||
case StatementPosition.AfterElseKeyword: |
||||
return [SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
|
||||
case StatementPosition.AfterGroupByKeywords: |
||||
return [SuggestionKind.Field, SuggestionKind.FunctionsWithArguments]; |
||||
case StatementPosition.AfterGroupBy: |
||||
return [SuggestionKind.OrderByKeywords, SuggestionKind.LimitKeyword, SuggestionKind.HavingKeywords]; |
||||
|
||||
case StatementPosition.AfterOrderByKeywords: |
||||
return [SuggestionKind.SortOrderDirectionKeyword, SuggestionKind.LimitKeyword, SuggestionKind.Field]; |
||||
case StatementPosition.AfterOrderByDirection: |
||||
return [SuggestionKind.LimitKeyword]; |
||||
|
||||
case StatementPosition.PredefinedFunctionArgument: |
||||
return [SuggestionKind.Field]; |
||||
|
||||
case StatementPosition.Subquery: |
||||
return [SuggestionKind.SelectKeyword, SuggestionKind.FunctionsWithArguments, SuggestionKind.Field]; |
||||
} |
||||
|
||||
return []; |
||||
} |
@ -0,0 +1,18 @@ |
||||
import { TokenTypes } from '../../monarch/types'; |
||||
import { CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID } from '../definition'; |
||||
|
||||
export const SQLTokenTypes: TokenTypes = { |
||||
Parenthesis: `delimiter.parenthesis.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Whitespace: `white.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Keyword: `keyword.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Delimiter: `delimiter.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Operator: `operator.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Identifier: `identifier.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Type: `type.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Function: `predefined.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Number: `number.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
String: `string.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Variable: `variable.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Comment: `comment.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
Regexp: `regexp.${CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID}`, |
||||
}; |
@ -0,0 +1,12 @@ |
||||
import { LanguageDefinition } from '../monarch/register'; |
||||
|
||||
export const CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID = 'cloudwatch-logs-sql'; |
||||
|
||||
const cloudWatchLogsSqlLanguageDefinition: LanguageDefinition = { |
||||
id: CLOUDWATCH_LOGS_SQL_LANGUAGE_DEFINITION_ID, |
||||
extensions: [], |
||||
aliases: [], |
||||
mimetypes: [], |
||||
loader: () => import('./language'), |
||||
}; |
||||
export default cloudWatchLogsSqlLanguageDefinition; |
@ -0,0 +1,596 @@ |
||||
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api'; |
||||
|
||||
interface CloudWatchLanguage extends monacoType.languages.IMonarchLanguage { |
||||
keywords: string[]; |
||||
operators: string[]; |
||||
builtinFunctions: string[]; |
||||
} |
||||
|
||||
/* KEYWORDS */ |
||||
export const ALL = 'ALL'; |
||||
export const AND = 'AND'; |
||||
export const ANY = 'ANY'; |
||||
export const AS = 'AS'; |
||||
export const ASC = 'ASC'; |
||||
export const BETWEEN = 'BETWEEN'; |
||||
export const BY = 'BY'; |
||||
export const CASE = 'CASE'; |
||||
export const CUBE = 'CUBE'; |
||||
export const DESC = 'DESC'; |
||||
export const DISTINCT = 'DISTINCT'; |
||||
export const ELSE = 'ELSE'; |
||||
export const END = 'END'; |
||||
export const ESCAPE = 'ESCAPE'; |
||||
export const EXISTS = 'EXISTS'; |
||||
export const FALSE = 'FALSE'; |
||||
export const FILTER = 'FILTER'; |
||||
export const FIRST = 'FIRST'; |
||||
export const FROM = 'FROM'; |
||||
export const GROUP = 'GROUP'; |
||||
export const GROUPING = 'GROUPING'; |
||||
export const HAVING = 'HAVING'; |
||||
export const ILIKE = 'ILIKE'; |
||||
export const IN = 'IN'; |
||||
export const INNER = 'INNER'; |
||||
export const IS = 'IS'; |
||||
export const JOIN = 'JOIN'; |
||||
export const LAST = 'LAST'; |
||||
export const LEFT = 'LEFT'; |
||||
export const LIKE = 'LIKE'; |
||||
export const LIMIT = 'LIMIT'; |
||||
export const NOT = 'NOT'; |
||||
export const NULL = 'NULL'; |
||||
export const ON = 'ON'; |
||||
export const OR = 'OR'; |
||||
export const ORDER = 'ORDER'; |
||||
export const OUTER = 'OUTER'; |
||||
export const ROLLUP = 'ROLLUP'; |
||||
export const SELECT = 'SELECT'; |
||||
export const SETS = 'SETS'; |
||||
export const SOME = 'SOME'; |
||||
export const THEN = 'THEN'; |
||||
export const TRUE = 'TRUE'; |
||||
export const USING = 'USING'; |
||||
export const WHEN = 'WHEN'; |
||||
export const WHERE = 'WHERE'; |
||||
export const WITH = 'WITH'; |
||||
|
||||
export const KEYWORDS = [ |
||||
ALL, |
||||
AND, |
||||
ANY, |
||||
AS, |
||||
ASC, |
||||
BETWEEN, |
||||
BY, |
||||
CASE, |
||||
CUBE, |
||||
DESC, |
||||
DISTINCT, |
||||
ELSE, |
||||
END, |
||||
ESCAPE, |
||||
EXISTS, |
||||
FALSE, |
||||
FILTER, |
||||
FIRST, |
||||
FROM, |
||||
GROUP, |
||||
GROUPING, |
||||
HAVING, |
||||
ILIKE, |
||||
IN, |
||||
INNER, |
||||
IS, |
||||
JOIN, |
||||
LAST, |
||||
LEFT, |
||||
LIKE, |
||||
LIMIT, |
||||
NOT, |
||||
NULL, |
||||
ON, |
||||
OR, |
||||
ORDER, |
||||
OUTER, |
||||
ROLLUP, |
||||
SELECT, |
||||
SETS, |
||||
SOME, |
||||
THEN, |
||||
TRUE, |
||||
USING, |
||||
WHEN, |
||||
WHERE, |
||||
WITH, |
||||
]; |
||||
export const AFTER_SELECT_KEYWORDS = [ALL, DISTINCT]; |
||||
|
||||
export const ALL_KEYWORDS = [...KEYWORDS, ...AFTER_SELECT_KEYWORDS]; |
||||
|
||||
/* FUNCTIONS */ |
||||
export const AGGREGATE_FUNCTIONS = [ |
||||
'any', |
||||
'any_value', |
||||
'approx_count_distinct', |
||||
'approx_percentile', |
||||
'array_agg', |
||||
'avg', |
||||
'bit_and', |
||||
'bit_or', |
||||
'bit_xor', |
||||
'bitmap_construct_agg', |
||||
'bitmap_or_agg', |
||||
'bool_and', |
||||
'bool_or', |
||||
'collect_list', |
||||
'collect_set', |
||||
'count', |
||||
'count_if', |
||||
'count_min_sketch', |
||||
'covar_pop', |
||||
'covar_samp', |
||||
'every', |
||||
'first', |
||||
'first_value', |
||||
'grouping', |
||||
'grouping_id', |
||||
'histogram_numeric', |
||||
'hll_sketch_agg', |
||||
'hll_union_agg', |
||||
'kurtosis', |
||||
'last', |
||||
'last_value', |
||||
'max', |
||||
'max_by', |
||||
'mean', |
||||
'median', |
||||
'min', |
||||
'min_by', |
||||
'mode', |
||||
'percentile', |
||||
'percentile_approx', |
||||
'regr_avgx', |
||||
'regr_avgy', |
||||
'regr_count', |
||||
'regr_intercept', |
||||
'regr_r2', |
||||
'regr_slope', |
||||
'regr_sxx', |
||||
'regr_sxy', |
||||
'regr_syy', |
||||
'skewness', |
||||
'some', |
||||
'std', |
||||
'stddev', |
||||
'stddev_pop', |
||||
'stddev_samp', |
||||
'sum', |
||||
'try_avg', |
||||
'try_sum', |
||||
'var_pop', |
||||
'var_samp', |
||||
'variance', |
||||
]; |
||||
export const ARRAY_FUNCTIONS = [ |
||||
'array', |
||||
'array_append', |
||||
'array_compact', |
||||
'array_contains', |
||||
'array_distinct', |
||||
'array_except', |
||||
'array_insert', |
||||
'array_intersect', |
||||
'array_join', |
||||
'array_max', |
||||
'array_min', |
||||
'array_position', |
||||
'array_prepend', |
||||
'array_remove', |
||||
'array_repeat', |
||||
'array_union', |
||||
'arrays_overlap', |
||||
'arrays_zip', |
||||
'flatten', |
||||
'get', |
||||
'sequence', |
||||
'shuffle', |
||||
'slice', |
||||
'sort_array', |
||||
]; |
||||
export const CONDITIONAL_FUNCTIONS = ['coalesce', 'if', 'ifnull', 'nanvl', 'nullif', 'nvl', 'nvl2']; |
||||
export const CONVERSION_FUNCTIONS = [ |
||||
'bigint', |
||||
'binary', |
||||
'boolean', |
||||
'cast', |
||||
'date', |
||||
'decimal', |
||||
'double', |
||||
'float', |
||||
'int', |
||||
'smallint', |
||||
'string', |
||||
'timestamp', |
||||
'tinyint', |
||||
]; |
||||
export const DATE_AND_TIMESTAMP_FUNCTIONS = [ |
||||
'add_months', |
||||
'convert_timezone', |
||||
'curdate', |
||||
'current_date', |
||||
'current_timestamp', |
||||
'current_timezone', |
||||
'date_add', |
||||
'date_diff', |
||||
'date_format', |
||||
'date_from_unix_date', |
||||
'date_part', |
||||
'date_sub', |
||||
'date_trunc', |
||||
'dateadd', |
||||
'datediff', |
||||
'datepart', |
||||
'day', |
||||
'dayofmonth', |
||||
'dayofweek', |
||||
'dayofyear', |
||||
'extract', |
||||
'from_unixtime', |
||||
'from_utc_timestamp', |
||||
'hour', |
||||
'last_day', |
||||
'localtimestamp', |
||||
'localtimestamp', |
||||
'make_date', |
||||
'make_dt_interval', |
||||
'make_interval', |
||||
'make_timestamp', |
||||
'make_timestamp_ltz', |
||||
'make_timestamp_ntz', |
||||
'make_ym_interval', |
||||
'minute', |
||||
'month', |
||||
'months_between', |
||||
'next_day', |
||||
'now', |
||||
'quarter', |
||||
'second', |
||||
'session_window', |
||||
'timestamp_micros', |
||||
'timestamp_millis', |
||||
'timestamp_seconds', |
||||
'to_date', |
||||
'to_timestamp', |
||||
'to_timestamp_ltz', |
||||
'to_timestamp_ntz', |
||||
'to_unix_timestamp', |
||||
'to_utc_timestamp', |
||||
'trunc', |
||||
'try_to_timestamp', |
||||
'unix_date', |
||||
'unix_micros', |
||||
'unix_millis', |
||||
'unix_seconds', |
||||
'unix_timestamp', |
||||
'weekday', |
||||
'weekofyear', |
||||
'window', |
||||
'window_time', |
||||
'year', |
||||
]; |
||||
export const JSON_FUNCTIONS = [ |
||||
'from_json', |
||||
'get_json_object', |
||||
'json_array_length', |
||||
'json_object_keys', |
||||
'json_tuple', |
||||
'schema_of_json', |
||||
'to_json', |
||||
]; |
||||
export const MATHEMATICAL_FUNCTIONS = [ |
||||
'abs', |
||||
'acos', |
||||
'acosh', |
||||
'asin', |
||||
'asinh', |
||||
'atan', |
||||
'atan2', |
||||
'atanh', |
||||
'bin', |
||||
'bround', |
||||
'cbrt', |
||||
'ceil', |
||||
'ceiling', |
||||
'conv', |
||||
'cos', |
||||
'cosh', |
||||
'cot', |
||||
'csc', |
||||
'degrees', |
||||
'e', |
||||
'exp', |
||||
'expm1', |
||||
'factorial', |
||||
'floor', |
||||
'greatest', |
||||
'hex', |
||||
'hypot', |
||||
'least', |
||||
'ln', |
||||
'log', |
||||
'log10', |
||||
'log1p', |
||||
'log2', |
||||
'negative', |
||||
'pi', |
||||
'pmod', |
||||
'positive', |
||||
'pow', |
||||
'power', |
||||
'radians', |
||||
'rand', |
||||
'randn', |
||||
'random', |
||||
'rint', |
||||
'round', |
||||
'sec', |
||||
'shiftleft', |
||||
'sign', |
||||
'signum', |
||||
'sin', |
||||
'sinh', |
||||
'sqrt', |
||||
'tan', |
||||
'tanh', |
||||
'try_add', |
||||
'try_divide', |
||||
'try_multiply', |
||||
'try_subtract', |
||||
'unhex', |
||||
'width_bucket', |
||||
]; |
||||
export const PREDICATE_FUNCTIONS = ['isnan', 'isnotnull', 'isnull', 'regexp', 'regexp_like', 'rlike']; |
||||
export const STRING_FUNCTIONS = [ |
||||
'ascii', |
||||
'base64', |
||||
'bit_length', |
||||
'btrim', |
||||
'char', |
||||
'char_length', |
||||
'character_length', |
||||
'chr', |
||||
'concat_ws', |
||||
'contains', |
||||
'decode', |
||||
'elt', |
||||
'encode', |
||||
'endswith', |
||||
'find_in_set', |
||||
'format_number', |
||||
'format_string', |
||||
'initcap', |
||||
'instr', |
||||
'lcase', |
||||
'left', |
||||
'len', |
||||
'length', |
||||
'levenshtein', |
||||
'locate', |
||||
'lower', |
||||
'lpad', |
||||
'ltrim', |
||||
'luhn_check', |
||||
'mask', |
||||
'octet_length', |
||||
'overlay', |
||||
'position', |
||||
'printf', |
||||
'regexp_count', |
||||
'regexp_extract', |
||||
'regexp_extract_all', |
||||
'regexp_instr', |
||||
'regexp_replace', |
||||
'regexp_substr', |
||||
'repeat', |
||||
'replace', |
||||
'right', |
||||
'rpad', |
||||
'rtrim', |
||||
'sentences', |
||||
'soundex', |
||||
'space', |
||||
'split', |
||||
'split_part', |
||||
'startswith', |
||||
'substr', |
||||
'substring', |
||||
'substring_index', |
||||
'to_binary', |
||||
'to_char', |
||||
'to_number', |
||||
'to_varchar', |
||||
'translate', |
||||
'trim', |
||||
'try_to_binary', |
||||
'try_to_number', |
||||
'ucase', |
||||
'unbase64', |
||||
'upper', |
||||
]; |
||||
export const WINDOW_FUNCTIONS = [ |
||||
'cume_dist', |
||||
'dense_rank', |
||||
'lag', |
||||
'lead', |
||||
'nth_value', |
||||
'ntile', |
||||
'percent_rank', |
||||
'rank', |
||||
'row_number', |
||||
]; |
||||
|
||||
export const ALL_FUNCTIONS = [ |
||||
...AGGREGATE_FUNCTIONS, |
||||
...ARRAY_FUNCTIONS, |
||||
...CONDITIONAL_FUNCTIONS, |
||||
...CONVERSION_FUNCTIONS, |
||||
...DATE_AND_TIMESTAMP_FUNCTIONS, |
||||
...JSON_FUNCTIONS, |
||||
...MATHEMATICAL_FUNCTIONS, |
||||
...PREDICATE_FUNCTIONS, |
||||
...STRING_FUNCTIONS, |
||||
...WINDOW_FUNCTIONS, |
||||
]; |
||||
|
||||
/* OPERATORS */ |
||||
export const EQUAL = '='; |
||||
export const DOUBLE_EQUALS = '=='; |
||||
export const NULL_SAFE_EQUAL = '<=>'; |
||||
export const NOT_EQUAL = '!='; |
||||
export const GREATER_THAN = '>'; |
||||
export const GREATER_THAN_EQUAL = '>='; |
||||
export const LESS_THAN = '<'; |
||||
export const LESS_THAN_EQUAL = '<='; |
||||
|
||||
export const LOGICAL_OPERATORS = [OR, AND]; |
||||
export const MATH_OPERATORS = ['*', '/', '+', '-', '%', 'div', 'mod']; |
||||
export const PREDICATE_OPERATORS = [ |
||||
NOT, |
||||
IS, |
||||
EQUAL, |
||||
DOUBLE_EQUALS, |
||||
NULL_SAFE_EQUAL, |
||||
NOT_EQUAL, |
||||
GREATER_THAN, |
||||
GREATER_THAN_EQUAL, |
||||
LESS_THAN, |
||||
LESS_THAN_EQUAL, |
||||
LIKE, |
||||
ILIKE, |
||||
IN, |
||||
]; |
||||
|
||||
export const ALL_OPERATORS = [...MATH_OPERATORS, ...LOGICAL_OPERATORS, ...PREDICATE_OPERATORS]; |
||||
|
||||
export const language: CloudWatchLanguage = { |
||||
defaultToken: '', |
||||
ignoreCase: true, |
||||
brackets: [ |
||||
{ open: '[', close: ']', token: 'delimiter.square' }, |
||||
{ open: '(', close: ')', token: 'delimiter.parenthesis' }, |
||||
{ open: '{', close: '}', token: 'delimiter.curly' }, |
||||
], |
||||
keywords: ALL_KEYWORDS, |
||||
operators: ALL_OPERATORS, |
||||
builtinFunctions: ALL_FUNCTIONS, |
||||
tokenizer: { |
||||
root: [ |
||||
{ include: '@comments' }, |
||||
{ include: '@whitespace' }, |
||||
{ include: '@customParams' }, |
||||
{ include: '@numbers' }, |
||||
{ include: '@binaries' }, |
||||
{ include: '@strings' }, |
||||
{ include: '@strings' }, |
||||
{ include: '@complexIdentifiers' }, |
||||
[/[;,.]/, 'delimiter'], |
||||
[/[\(\)\[\]\{\}]/, '@brackets'], |
||||
[ |
||||
/[\w@#$]+/, |
||||
{ |
||||
cases: { |
||||
'@operators': 'operator', |
||||
'@builtinFunctions': 'predefined', |
||||
'@keywords': 'keyword', |
||||
'@default': 'identifier', |
||||
}, |
||||
}, |
||||
], |
||||
[/[<>=!%&+\-*/|~^]/, 'operator'], |
||||
], |
||||
whitespace: [[/[\s\t\r\n]+/, 'white']], |
||||
comments: [ |
||||
[/--+.*/, 'comment'], |
||||
[/\/\*/, { token: 'comment.quote', next: '@comment' }], |
||||
], |
||||
comment: [ |
||||
[/[^*/]+/, 'comment'], |
||||
[/\*\//, { token: 'comment.quote', next: '@pop' }], |
||||
[/./, 'comment'], |
||||
], |
||||
customParams: [ |
||||
[/\${[A-Za-z0-9._-]*}/, 'variable'], |
||||
[/\@\@{[A-Za-z0-9._-]*}/, 'variable'], |
||||
], |
||||
numbers: [ |
||||
[/0[xX][0-9a-fA-F]*/, 'number'], |
||||
[/[$][+-]*\d*(\.\d*)?/, 'number'], |
||||
[/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/, 'number'], |
||||
], |
||||
binaries: [ |
||||
[/X'/i, { token: 'binary', next: '@binarySingle' }], |
||||
[/X"/i, { token: 'binary', next: '@binaryDouble' }], |
||||
], |
||||
binarySingle: [ |
||||
[/\d+/, 'binary.escape'], |
||||
[/''/, 'binary'], |
||||
[/'/, { token: 'binary', next: '@pop' }], |
||||
], |
||||
binaryDouble: [ |
||||
[/\d+/, 'binary.escape'], |
||||
[/""/, 'binary'], |
||||
[/"/, { token: 'binary', next: '@pop' }], |
||||
], |
||||
strings: [ |
||||
[/'/, { token: 'string', next: '@stringSingle' }], |
||||
[/R'/i, { token: 'string', next: '@stringSingle' }], |
||||
[/"/, { token: 'string', next: '@stringDouble' }], |
||||
[/R"/i, { token: 'string', next: '@stringDouble' }], |
||||
], |
||||
stringSingle: [ |
||||
[/[^']+/, 'string.escape'], |
||||
[/''/, 'string'], |
||||
[/'/, { token: 'string', next: '@pop' }], |
||||
], |
||||
stringDouble: [ |
||||
[/[^"]+/, 'string.escape'], |
||||
[/""/, 'string'], |
||||
[/"/, { token: 'string', next: '@pop' }], |
||||
], |
||||
complexIdentifiers: [[/`/, { token: 'identifier', next: '@quotedIdentifier' }]], |
||||
quotedIdentifier: [ |
||||
[/[^`]+/, 'identifier'], |
||||
[/``/, 'identifier'], |
||||
[/`/, { token: 'identifier', next: '@pop' }], |
||||
], |
||||
}, |
||||
}; |
||||
|
||||
export const conf: monacoType.languages.LanguageConfiguration = { |
||||
comments: { |
||||
lineComment: '--', |
||||
blockComment: ['/*', '*/'], |
||||
}, |
||||
brackets: [ |
||||
['{', '}'], |
||||
['[', ']'], |
||||
['(', ')'], |
||||
], |
||||
autoClosingPairs: [ |
||||
{ open: '{', close: '}' }, |
||||
{ open: '[', close: ']' }, |
||||
{ open: '(', close: ')' }, |
||||
{ open: '"', close: '"' }, |
||||
{ open: "'", close: "'" }, |
||||
{ open: '`', close: '`' }, |
||||
], |
||||
surroundingPairs: [ |
||||
{ open: '{', close: '}' }, |
||||
{ open: '[', close: ']' }, |
||||
{ open: '(', close: ')' }, |
||||
{ open: '"', close: '"' }, |
||||
{ open: "'", close: "'" }, |
||||
{ open: '`', close: '`' }, |
||||
], |
||||
}; |
@ -0,0 +1,254 @@ |
||||
import { CustomVariableModel } from '@grafana/data'; |
||||
import { Monaco, monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { logGroupNamesVariable, setupMockedTemplateService } from '../../../__mocks__/CloudWatchDataSource'; |
||||
import { newCommandQuery } from '../../../__mocks__/cloudwatch-ppl-test-data/newCommandQuery'; |
||||
import { |
||||
dedupQueryWithOptionalArgs, |
||||
emptyQuery, |
||||
evalQuery, |
||||
fieldsQuery, |
||||
headQuery, |
||||
parseQuery, |
||||
queryWithArithmeticOps, |
||||
queryWithFunctionCalls, |
||||
queryWithFieldList, |
||||
sortQuery, |
||||
statsQuery, |
||||
topQuery, |
||||
whereQuery, |
||||
} from '../../../__mocks__/cloudwatch-ppl-test-data/singleLineQueries'; |
||||
import MonacoMock from '../../../__mocks__/monarch/Monaco'; |
||||
import TextModel from '../../../__mocks__/monarch/TextModel'; |
||||
import { ResourcesAPI } from '../../../resources/ResourcesAPI'; |
||||
import { ResourceResponse } from '../../../resources/types'; |
||||
import { LogGroup, LogGroupField } from '../../../types'; |
||||
import cloudWatchLogsPPLLanguageDefinition from '../definition'; |
||||
import { |
||||
BOOLEAN_LITERALS, |
||||
CONDITION_FUNCTIONS, |
||||
DEDUP_PARAMETERS, |
||||
EVAL_FUNCTIONS, |
||||
FIELD_OPERATORS, |
||||
NOT, |
||||
PPL_COMMANDS, |
||||
PPL_FUNCTIONS, |
||||
SORT_FIELD_FUNCTIONS, |
||||
SPAN, |
||||
STATS_PARAMETERS, |
||||
STATS_FUNCTIONS, |
||||
FROM, |
||||
} from '../language'; |
||||
|
||||
import { PPLCompletionItemProvider } from './PPLCompletionItemProvider'; |
||||
|
||||
jest.mock('monaco-editor/esm/vs/editor/editor.api', () => ({ |
||||
Token: jest.fn((offset, type, language) => ({ offset, type, language })), |
||||
})); |
||||
|
||||
const logFields = [{ value: { name: '@field' } }, { value: { name: '@message' } }]; |
||||
const logFieldNames = ['@field', '@message']; |
||||
const logGroups = [{ arn: 'foo', name: 'bar' }]; |
||||
|
||||
const getSuggestions = async ( |
||||
value: string, |
||||
position: monacoTypes.IPosition, |
||||
variables: CustomVariableModel[] = [], |
||||
logGroups: LogGroup[] = [], |
||||
fields: Array<ResourceResponse<LogGroupField>> = [] |
||||
) => { |
||||
const setup = new PPLCompletionItemProvider({} as ResourcesAPI, setupMockedTemplateService(variables), { |
||||
region: 'default', |
||||
logGroups, |
||||
}); |
||||
|
||||
setup.resources.getLogGroupFields = jest.fn().mockResolvedValue(fields); |
||||
const monaco = MonacoMock as Monaco; |
||||
const provider = setup.getCompletionProvider(monaco, cloudWatchLogsPPLLanguageDefinition); |
||||
const { suggestions } = await provider.provideCompletionItems( |
||||
TextModel(value) as monacoTypes.editor.ITextModel, |
||||
position |
||||
); |
||||
return suggestions; |
||||
}; |
||||
|
||||
describe('PPLCompletionItemProvider', () => { |
||||
describe('getSuggestions', () => { |
||||
it('should suggest commands for an empty query', async () => { |
||||
const suggestions = await getSuggestions(emptyQuery.query, { lineNumber: 1, column: 1 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(PPL_COMMANDS)); |
||||
}); |
||||
|
||||
it('should suggest commands for a query when a new command is started', async () => { |
||||
const suggestions = await getSuggestions(newCommandQuery.query, { lineNumber: 1, column: 20 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(PPL_COMMANDS)); |
||||
}); |
||||
|
||||
describe('SuggestionKind.ValueExpression', () => { |
||||
test.each([ |
||||
[queryWithFunctionCalls.query, { lineNumber: 1, column: 20 }], |
||||
[queryWithFunctionCalls.query, { lineNumber: 1, column: 59 }], |
||||
[queryWithFunctionCalls.query, { lineNumber: 1, column: 78 }], |
||||
[queryWithArithmeticOps.query, { lineNumber: 1, column: 14 }], |
||||
[whereQuery.query, { lineNumber: 1, column: 71 }], |
||||
])('should suggest functions and fields as argument for value expression', async (query, position) => { |
||||
const suggestions = await getSuggestions(query, position, [], logGroups, logFields); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([...EVAL_FUNCTIONS, ...logFieldNames])); |
||||
}); |
||||
}); |
||||
|
||||
describe('[SuggestioKind.Field]', () => { |
||||
test.each([ |
||||
[evalQuery.query, { lineNumber: 1, column: 5 }], |
||||
[fieldsQuery.query, { lineNumber: 1, column: 9 }], |
||||
[topQuery.query, { lineNumber: 1, column: 36 }], |
||||
[queryWithFieldList.query, { lineNumber: 1, column: 22 }], |
||||
[statsQuery.query, { lineNumber: 1, column: 10 }], |
||||
])('should suggest fields for SuggestionKind.Field', async (query, position) => { |
||||
const suggestions = await getSuggestions(query, position, [], logGroups, logFields); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(logFieldNames)); |
||||
}); |
||||
}); |
||||
|
||||
it('should suggest from clause after HEAD command', async () => { |
||||
const suggestions = await getSuggestions(headQuery.query, { lineNumber: 1, column: 5 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual([FROM]); |
||||
}); |
||||
|
||||
it('should suggest stats parameters after STATS command', async () => { |
||||
const suggestions = await getSuggestions(statsQuery.query, { lineNumber: 1, column: 6 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([...STATS_PARAMETERS, ...STATS_FUNCTIONS])); |
||||
expect(suggestionLabels).not.toContain('@field'); |
||||
}); |
||||
|
||||
it('should suggest fields, field operators and sort functions when in a sort field position', async () => { |
||||
const suggestions = await getSuggestions(sortQuery.query, { lineNumber: 1, column: 5 }, [], logGroups, logFields); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual( |
||||
expect.arrayContaining([...FIELD_OPERATORS, ...SORT_FIELD_FUNCTIONS, ...logFieldNames]) |
||||
); |
||||
}); |
||||
|
||||
it('should suggest field operators and fields after FIELDS command', async () => { |
||||
const suggestions = await getSuggestions( |
||||
fieldsQuery.query, |
||||
{ lineNumber: 1, column: 7 }, |
||||
[], |
||||
logGroups, |
||||
logFields |
||||
); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([...FIELD_OPERATORS, ...logFieldNames])); |
||||
}); |
||||
|
||||
it('should suggest boolean literals after boolean argument', async () => { |
||||
const suggestions = await getSuggestions(dedupQueryWithOptionalArgs.query, { lineNumber: 1, column: 53 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual( |
||||
expect.arrayContaining(BOOLEAN_LITERALS.map((booleanLiteral) => `= ${booleanLiteral}`)) |
||||
); |
||||
}); |
||||
|
||||
it('should suggest dedup parameters after DEDUP field names', async () => { |
||||
const suggestions = await getSuggestions(dedupQueryWithOptionalArgs.query, { lineNumber: 1, column: 43 }); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(DEDUP_PARAMETERS)); |
||||
}); |
||||
|
||||
it('should suggest fields and span function after STATS BY', async () => { |
||||
const suggestions = await getSuggestions( |
||||
statsQuery.query, |
||||
{ lineNumber: 1, column: 42 }, |
||||
[], |
||||
logGroups, |
||||
logFields |
||||
); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([SPAN, ...logFieldNames])); |
||||
}); |
||||
|
||||
it('should suggest fields and sort functions after SORT field operator', async () => { |
||||
const suggestions = await getSuggestions(sortQuery.query, { lineNumber: 1, column: 7 }, [], logGroups, logFields); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining([...SORT_FIELD_FUNCTIONS, ...logFieldNames])); |
||||
}); |
||||
|
||||
it('should suggest PPL functions, NOT, case and fields in Expression clauses', async () => { |
||||
const evalSuggestions = await getSuggestions( |
||||
evalQuery.query, |
||||
{ lineNumber: 1, column: 21 }, |
||||
[], |
||||
logGroups, |
||||
logFields |
||||
); |
||||
const evalSuggestionLabels = evalSuggestions.map((s) => s.label); |
||||
expect(evalSuggestionLabels).toEqual( |
||||
expect.arrayContaining([...PPL_FUNCTIONS, ...EVAL_FUNCTIONS, ...CONDITION_FUNCTIONS, NOT, '@field', '@message']) |
||||
); |
||||
|
||||
const parseSuggestions = await getSuggestions( |
||||
parseQuery.query, |
||||
{ lineNumber: 1, column: 6 }, |
||||
[], |
||||
logGroups, |
||||
logFields |
||||
); |
||||
const parseSuggestionLabels = parseSuggestions.map((s) => s.label); |
||||
expect(parseSuggestionLabels).toEqual( |
||||
expect.arrayContaining([...PPL_FUNCTIONS, ...EVAL_FUNCTIONS, ...CONDITION_FUNCTIONS, NOT, '@field', '@message']) |
||||
); |
||||
}); |
||||
|
||||
it('should suggest functions, fields and boolean functions in a logical expression', async () => { |
||||
const suggestions = await getSuggestions( |
||||
whereQuery.query, |
||||
{ lineNumber: 1, column: 6 }, |
||||
[], |
||||
logGroups, |
||||
logFields |
||||
); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual( |
||||
expect.arrayContaining([...CONDITION_FUNCTIONS, ...EVAL_FUNCTIONS, '@field', '@message']) |
||||
); |
||||
}); |
||||
|
||||
it('should suggest template variables appended to list of suggestions', async () => { |
||||
const suggestions = await getSuggestions( |
||||
sortQuery.query, |
||||
{ lineNumber: 1, column: 7 }, |
||||
[logGroupNamesVariable], |
||||
logGroups, |
||||
logFields |
||||
); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
const expectedTemplateVariableLabel = `$${logGroupNamesVariable.name}`; |
||||
const expectedLabels = [...SORT_FIELD_FUNCTIONS, ...logFieldNames, expectedTemplateVariableLabel]; |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(expectedLabels)); |
||||
}); |
||||
|
||||
it('fetches fields when logGroups are set', async () => { |
||||
const suggestions = await getSuggestions( |
||||
whereQuery.query, |
||||
{ lineNumber: 1, column: 6 }, |
||||
[], |
||||
logGroups, |
||||
logFields |
||||
); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).toEqual(expect.arrayContaining(logFieldNames)); |
||||
}); |
||||
|
||||
it('does not fetch fields when logGroups are not set', async () => { |
||||
const suggestions = await getSuggestions(whereQuery.query, { lineNumber: 1, column: 6 }, [], [], logFields); |
||||
const suggestionLabels = suggestions.map((s) => s.label); |
||||
expect(suggestionLabels).not.toContain('@field'); |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,284 @@ |
||||
import { getTemplateSrv, type TemplateSrv } from '@grafana/runtime'; |
||||
import { Monaco, monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { type ResourcesAPI } from '../../../resources/ResourcesAPI'; |
||||
import { LogGroup } from '../../../types'; |
||||
import { CompletionItemProvider } from '../../monarch/CompletionItemProvider'; |
||||
import { LinkedToken } from '../../monarch/LinkedToken'; |
||||
import { TRIGGER_SUGGEST } from '../../monarch/commands'; |
||||
import { CompletionItem, CompletionItemPriority, StatementPosition, SuggestionKind } from '../../monarch/types'; |
||||
import { |
||||
BOOLEAN_LITERALS, |
||||
CONDITION_FUNCTIONS, |
||||
DEDUP_PARAMETERS, |
||||
EVAL_FUNCTIONS, |
||||
FIELD_OPERATORS, |
||||
IN, |
||||
LOGICAL_EXPRESSION_OPERATORS, |
||||
NOT, |
||||
PPL_COMMANDS, |
||||
SORT_FIELD_FUNCTIONS, |
||||
SPAN, |
||||
STATS_PARAMETERS, |
||||
STATS_FUNCTIONS, |
||||
FROM, |
||||
} from '../language'; |
||||
import { PPLTokenTypes } from '../tokenTypes'; |
||||
|
||||
import { getStatementPosition } from './statementPosition'; |
||||
import { getSuggestionKinds } from './suggestionKinds'; |
||||
|
||||
export type queryContext = { |
||||
logGroups?: LogGroup[]; |
||||
region: string; |
||||
}; |
||||
|
||||
export function PPLCompletionItemProviderFunc(resources: ResourcesAPI, templateSrv: TemplateSrv = getTemplateSrv()) { |
||||
return (queryContext: queryContext) => { |
||||
return new PPLCompletionItemProvider(resources, templateSrv, queryContext); |
||||
}; |
||||
} |
||||
|
||||
export class PPLCompletionItemProvider extends CompletionItemProvider { |
||||
queryContext: queryContext; |
||||
constructor(resources: ResourcesAPI, templateSrv: TemplateSrv = getTemplateSrv(), queryContext: queryContext) { |
||||
super(resources, templateSrv); |
||||
this.getStatementPosition = getStatementPosition; |
||||
this.getSuggestionKinds = getSuggestionKinds; |
||||
this.tokenTypes = PPLTokenTypes; |
||||
this.queryContext = queryContext; |
||||
} |
||||
|
||||
async getSuggestions( |
||||
monaco: Monaco, |
||||
currentToken: LinkedToken | null, |
||||
suggestionKinds: SuggestionKind[], |
||||
_: StatementPosition, |
||||
position: monacoTypes.IPosition |
||||
): Promise<CompletionItem[]> { |
||||
const suggestions: CompletionItem[] = []; |
||||
const invalidRangeToken = |
||||
currentToken?.isWhiteSpace() || currentToken?.isParenthesis() || currentToken?.is(PPLTokenTypes.Backtick); // PPLTokenTypes.Backtick for field wrapping
|
||||
const range = |
||||
invalidRangeToken || !currentToken?.range ? monaco.Range.fromPositions(position) : currentToken?.range; |
||||
function toCompletionItem(value: string, rest: Partial<CompletionItem> = {}) { |
||||
const item: monacoTypes.languages.CompletionItem = { |
||||
label: value, |
||||
insertText: value, |
||||
kind: monaco.languages.CompletionItemKind.Field, |
||||
range, |
||||
sortText: CompletionItemPriority.Medium, |
||||
...rest, |
||||
}; |
||||
return item; |
||||
} |
||||
|
||||
function addSuggestion(value: string, rest: Partial<CompletionItem> = {}) { |
||||
suggestions.push(toCompletionItem(value, rest)); |
||||
} |
||||
|
||||
for (const kind of suggestionKinds) { |
||||
switch (kind) { |
||||
case SuggestionKind.Command: |
||||
PPL_COMMANDS.forEach((command) => { |
||||
addSuggestion(command, { |
||||
insertText: `${command} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Method, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.LogicalExpression: |
||||
// booleanExpression
|
||||
CONDITION_FUNCTIONS.forEach((funct) => { |
||||
addSuggestion(funct, { |
||||
insertText: `${funct}($0)`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Function, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
}); |
||||
addSuggestion(NOT, { |
||||
insertText: `${NOT} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Operator, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.ValueExpression: |
||||
EVAL_FUNCTIONS.forEach((funct) => { |
||||
addSuggestion(funct, { |
||||
insertText: `${funct}($0)`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Function, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
}); |
||||
await this.addFieldSuggestions(addSuggestion, monaco, range, currentToken); |
||||
break; |
||||
|
||||
case SuggestionKind.FieldOperators: |
||||
FIELD_OPERATORS.forEach((operator) => { |
||||
addSuggestion(operator, { |
||||
insertText: `${operator}$0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Operator, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.BooleanLiteral: |
||||
BOOLEAN_LITERALS.forEach((literal) => |
||||
addSuggestion(`= ${literal}`, { |
||||
insertText: `= ${literal} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Value, |
||||
command: TRIGGER_SUGGEST, |
||||
}) |
||||
); |
||||
break; |
||||
|
||||
case SuggestionKind.DedupParameter: |
||||
DEDUP_PARAMETERS.forEach((keyword) => |
||||
addSuggestion(keyword, { |
||||
insertText: `${keyword} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Property, |
||||
command: TRIGGER_SUGGEST, |
||||
}) |
||||
); |
||||
break; |
||||
|
||||
case SuggestionKind.StatsParameter: |
||||
STATS_PARAMETERS.forEach((keyword) => { |
||||
addSuggestion(keyword, { |
||||
insertText: `${keyword} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Property, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.StatsFunctions: |
||||
STATS_FUNCTIONS.forEach((f) => { |
||||
addSuggestion(f, { |
||||
insertText: `${f}($0)`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Function, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.LogicalOperators: |
||||
LOGICAL_EXPRESSION_OPERATORS.forEach((operator) => { |
||||
addSuggestion(operator, { |
||||
insertText: `${operator} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Operator, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.InKeyword: |
||||
addSuggestion(IN, { |
||||
insertText: `${IN} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.SpanClause: |
||||
addSuggestion(SPAN, { |
||||
insertText: `${SPAN}($0)`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Function, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.Field: |
||||
await this.addFieldSuggestions(addSuggestion, monaco, range, currentToken); |
||||
break; |
||||
|
||||
case SuggestionKind.FromKeyword: |
||||
addSuggestion(FROM, { |
||||
insertText: `${FROM} $0`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Keyword, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
break; |
||||
|
||||
case SuggestionKind.SortFunctions: |
||||
SORT_FIELD_FUNCTIONS.forEach((funct) => { |
||||
addSuggestion(funct, { |
||||
insertText: `${funct}($0)`, |
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, |
||||
kind: monaco.languages.CompletionItemKind.Function, |
||||
command: TRIGGER_SUGGEST, |
||||
}); |
||||
}); |
||||
break; |
||||
} |
||||
} |
||||
// always suggest template variables
|
||||
this.templateSrv.getVariables().map((v) => { |
||||
const variable = `$${v.name}`; |
||||
addSuggestion(variable, { |
||||
range, |
||||
label: variable, |
||||
insertText: variable, |
||||
kind: monaco.languages.CompletionItemKind.Variable, |
||||
sortText: CompletionItemPriority.Low, |
||||
}); |
||||
}); |
||||
|
||||
return suggestions; |
||||
} |
||||
|
||||
private async addFieldSuggestions( |
||||
addSuggestion: (value: string, rest?: Partial<CompletionItem>) => void, |
||||
monaco: typeof monacoTypes, |
||||
range: monacoTypes.IRange | monacoTypes.languages.CompletionItemRanges, |
||||
currentToken?: LinkedToken | null |
||||
): Promise<void> { |
||||
if (this.queryContext.logGroups && this.queryContext.logGroups.length > 0) { |
||||
try { |
||||
let fields = await this.fetchFields(this.queryContext.logGroups, this.queryContext.region); |
||||
fields.forEach((field) => { |
||||
if (field !== '') { |
||||
addSuggestion(field, { |
||||
range, |
||||
label: field, |
||||
insertText: currentToken?.is(PPLTokenTypes.Backtick) ? field : `\`${field}\``, |
||||
kind: monaco.languages.CompletionItemKind.Field, |
||||
sortText: CompletionItemPriority.High, |
||||
}); |
||||
} |
||||
}); |
||||
} catch { |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private async fetchFields(logGroups: LogGroup[], region: string): Promise<string[]> { |
||||
const results = await Promise.all( |
||||
logGroups.map((logGroup) => |
||||
this.resources |
||||
.getLogGroupFields({ logGroupName: logGroup.name, arn: logGroup.arn, region }) |
||||
.then((fields) => fields.filter((f) => f).map((f) => f.value.name ?? '')) |
||||
) |
||||
); |
||||
// Deduplicate fields
|
||||
return [...new Set(results.flat())]; |
||||
} |
||||
} |
@ -0,0 +1,553 @@ |
||||
import { monacoTypes } from '@grafana/ui'; |
||||
|
||||
import { multiLineFullQuery } from '../../../__mocks__/cloudwatch-ppl-test-data/multilineQueries'; |
||||
import { |
||||
dedupQueryWithOptionalArgs, |
||||
dedupQueryWithoutOptionalArgs, |
||||
evalQuery, |
||||
eventStatsQuery, |
||||
fieldsQuery, |
||||
headQuery, |
||||
parseQuery, |
||||
queryWithArithmeticOps, |
||||
queryWithFunctionCalls, |
||||
queryWithFieldList, |
||||
queryWithLogicalExpression, |
||||
rareQuery, |
||||
sortQuery, |
||||
sortQueryWithFunctions, |
||||
statsQuery, |
||||
topQuery, |
||||
whereQuery, |
||||
} from '../../../__mocks__/cloudwatch-ppl-test-data/singleLineQueries'; |
||||
import MonacoMock from '../../../__mocks__/monarch/Monaco'; |
||||
import TextModel from '../../../__mocks__/monarch/TextModel'; |
||||
import { linkedTokenBuilder } from '../../monarch/linkedTokenBuilder'; |
||||
import { StatementPosition } from '../../monarch/types'; |
||||
import cloudWatchLogsPPLLanguageDefinition from '../definition'; |
||||
import { PPLTokenTypes } from '../tokenTypes'; |
||||
|
||||
import { getStatementPosition } from './statementPosition'; |
||||
|
||||
function generateToken(query: string, position: monacoTypes.IPosition) { |
||||
const testModel = TextModel(query); |
||||
return linkedTokenBuilder( |
||||
MonacoMock, |
||||
cloudWatchLogsPPLLanguageDefinition, |
||||
testModel as monacoTypes.editor.ITextModel, |
||||
position, |
||||
PPLTokenTypes |
||||
); |
||||
} |
||||
|
||||
describe('getStatementPosition', () => { |
||||
it('should return StatementPosition.AfterArithmeticOperator if the position follows an arithmetic operator and not a fields or sort command', () => { |
||||
expect(getStatementPosition(generateToken(queryWithArithmeticOps.query, { lineNumber: 1, column: 14 }))).toEqual( |
||||
StatementPosition.AfterArithmeticOperator |
||||
); |
||||
expect( |
||||
getStatementPosition(generateToken(queryWithArithmeticOps.query, { lineNumber: 1, column: 26 })) |
||||
).not.toEqual(StatementPosition.AfterArithmeticOperator); |
||||
expect(getStatementPosition(generateToken(fieldsQuery.query, { lineNumber: 1, column: 9 }))).not.toEqual( |
||||
StatementPosition.AfterArithmeticOperator |
||||
); |
||||
expect(getStatementPosition(generateToken(sortQuery.query, { lineNumber: 1, column: 7 }))).not.toEqual( |
||||
StatementPosition.AfterArithmeticOperator |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.AfterBooleanAgument if the position follows a boolean argument', () => { |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithOptionalArgs.query, { lineNumber: 1, column: 53 })) |
||||
).toEqual(StatementPosition.AfterBooleanArgument); |
||||
}); |
||||
|
||||
it('should return StatementPosition.FieldList if the position follows a comma and field identifiers and is not sort or eval command', () => { |
||||
expect(getStatementPosition(generateToken(queryWithFieldList.query, { lineNumber: 1, column: 22 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(queryWithFieldList.query, { lineNumber: 1, column: 41 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(queryWithFieldList.query, { lineNumber: 1, column: 44 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(sortQuery.query, { lineNumber: 1, column: 53 }))).not.toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 53 }))).not.toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.AfterInKeyword if the position follows IN', () => { |
||||
expect(getStatementPosition(generateToken(whereQuery.query, { lineNumber: 1, column: 71 }))).toEqual( |
||||
StatementPosition.AfterINKeyword |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.StatementPosition.FunctionArg if the position is inside a condition function', () => { |
||||
expect(getStatementPosition(generateToken(queryWithFunctionCalls.query, { lineNumber: 1, column: 20 }))).toEqual( |
||||
StatementPosition.FunctionArg |
||||
); |
||||
expect(getStatementPosition(generateToken(queryWithFunctionCalls.query, { lineNumber: 1, column: 11 }))).toEqual( |
||||
StatementPosition.FunctionArg |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.StatementPosition.FunctionArg if the position is inside an evalFunction', () => { |
||||
expect(getStatementPosition(generateToken(queryWithFunctionCalls.query, { lineNumber: 1, column: 59 }))).toEqual( |
||||
StatementPosition.FunctionArg |
||||
); |
||||
expect(getStatementPosition(generateToken(queryWithFunctionCalls.query, { lineNumber: 1, column: 78 }))).toEqual( |
||||
StatementPosition.FunctionArg |
||||
); |
||||
}); |
||||
|
||||
describe('logical expression', () => { |
||||
it('should return StatementPosition.BeforeLogicalExpression if the position follows a logical expression operator and is not an eval command', () => { |
||||
expect( |
||||
getStatementPosition(generateToken(queryWithLogicalExpression.query, { lineNumber: 1, column: 28 })) |
||||
).toEqual(StatementPosition.BeforeLogicalExpression); |
||||
|
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 30 }))).not.toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.BeforeLogicalExpression after a logical expression operator', () => { |
||||
expect(getStatementPosition(generateToken(whereQuery.query, { lineNumber: 1, column: 42 }))).toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.BeforeLogicalExpression after a condition function', () => { |
||||
expect(getStatementPosition(generateToken(whereQuery.query, { lineNumber: 1, column: 38 }))).toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.BeforeLogicalExpression after a regex', () => { |
||||
expect( |
||||
getStatementPosition(generateToken(queryWithLogicalExpression.query, { lineNumber: 1, column: 43 })) |
||||
).toEqual(StatementPosition.BeforeLogicalExpression); |
||||
}); |
||||
it('should return StatementPosition.BeforeLogicalExpression after a NOT operator', () => { |
||||
expect(getStatementPosition(generateToken(whereQuery.query, { lineNumber: 1, column: 46 }))).toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
expect( |
||||
getStatementPosition(generateToken(queryWithLogicalExpression.query, { lineNumber: 1, column: 32 })) |
||||
).toEqual(StatementPosition.BeforeLogicalExpression); |
||||
}); |
||||
|
||||
it('should return Statementposition.FunctionArg after a BETWEEN keyword', () => { |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 106 }))).toEqual( |
||||
StatementPosition.FunctionArg |
||||
); |
||||
}); |
||||
}); |
||||
|
||||
describe('WHERE command', () => { |
||||
it('should return StatementPosition.BeforeLogicalExpression after where command', () => { |
||||
expect(getStatementPosition(generateToken(whereQuery.query, { lineNumber: 1, column: 6 }))).toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 2, column: 8 }))).toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
}); |
||||
}); |
||||
|
||||
describe('FIELDS command', () => { |
||||
it('should return StatementPosition.AfterFieldsCommand after fields command', () => { |
||||
expect(getStatementPosition(generateToken(fieldsQuery.query, { lineNumber: 1, column: 7 }))).toEqual( |
||||
StatementPosition.AfterFieldsCommand |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 3, column: 9 }))).toEqual( |
||||
StatementPosition.AfterFieldsCommand |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.FieldList after a + operator', () => { |
||||
expect(getStatementPosition(generateToken(fieldsQuery.query, { lineNumber: 1, column: 9 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.FieldList after a field', () => { |
||||
expect(getStatementPosition(generateToken(fieldsQuery.query, { lineNumber: 1, column: 27 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(fieldsQuery.query, { lineNumber: 1, column: 38 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 3, column: 29 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 3, column: 40 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
}); |
||||
|
||||
describe('STATS command', () => { |
||||
it('should return StatementPosition.AfterStatsCommand after stats command', () => { |
||||
expect(getStatementPosition(generateToken(statsQuery.query, { lineNumber: 1, column: 6 }))).toEqual( |
||||
StatementPosition.AfterStatsCommand |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 4, column: 8 }))).toEqual( |
||||
StatementPosition.AfterStatsCommand |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.AfterStatsBy after by keyword', () => { |
||||
expect(getStatementPosition(generateToken(statsQuery.query, { lineNumber: 1, column: 42 }))).toEqual( |
||||
StatementPosition.AfterStatsBy |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 4, column: 44 }))).toEqual( |
||||
StatementPosition.AfterStatsBy |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.FieldList in span function arguments', () => { |
||||
expect(getStatementPosition(generateToken(statsQuery.query, { lineNumber: 1, column: 47 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 4, column: 49 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.StatsFunctionArgument in span function arguments', () => { |
||||
expect(getStatementPosition(generateToken(statsQuery.query, { lineNumber: 1, column: 10 }))).toEqual( |
||||
StatementPosition.StatsFunctionArgument |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 4, column: 12 }))).toEqual( |
||||
StatementPosition.StatsFunctionArgument |
||||
); |
||||
}); |
||||
}); |
||||
|
||||
describe('EVENTSTATS command', () => { |
||||
it('should return StatementPosition.AfterStatsCommand after eventstats command', () => { |
||||
expect(getStatementPosition(generateToken(eventStatsQuery.query, { lineNumber: 1, column: 11 }))).toEqual( |
||||
StatementPosition.AfterStatsCommand |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 5, column: 13 }))).toEqual( |
||||
StatementPosition.AfterStatsCommand |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.AfterStatsBy after by keyword', () => { |
||||
expect(getStatementPosition(generateToken(eventStatsQuery.query, { lineNumber: 1, column: 47 }))).toEqual( |
||||
StatementPosition.AfterStatsBy |
||||
); |
||||
|
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 5, column: 49 }))).toEqual( |
||||
StatementPosition.AfterStatsBy |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.FieldList in span function arguments', () => { |
||||
expect(getStatementPosition(generateToken(eventStatsQuery.query, { lineNumber: 1, column: 52 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 5, column: 54 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.StatsFunctionArgument in span function arguments', () => { |
||||
expect(getStatementPosition(generateToken(eventStatsQuery.query, { lineNumber: 1, column: 15 }))).toEqual( |
||||
StatementPosition.StatsFunctionArgument |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 5, column: 17 }))).toEqual( |
||||
StatementPosition.StatsFunctionArgument |
||||
); |
||||
}); |
||||
}); |
||||
|
||||
describe('SORT command', () => { |
||||
it('should return StatementPosition.SortField as a sort clause', () => { |
||||
expect(getStatementPosition(generateToken(sortQuery.query, { lineNumber: 1, column: 5 }))).toEqual( |
||||
StatementPosition.SortField |
||||
); |
||||
expect(getStatementPosition(generateToken(sortQuery.query, { lineNumber: 1, column: 25 }))).toEqual( |
||||
StatementPosition.SortField |
||||
); |
||||
expect(getStatementPosition(generateToken(sortQueryWithFunctions.query, { lineNumber: 1, column: 5 }))).toEqual( |
||||
StatementPosition.SortField |
||||
); |
||||
expect(getStatementPosition(generateToken(sortQuery.query, { lineNumber: 1, column: 38 }))).toEqual( |
||||
StatementPosition.SortField |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 6, column: 7 }))).toEqual( |
||||
StatementPosition.SortField |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 6, column: 27 }))).toEqual( |
||||
StatementPosition.SortField |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 7, column: 7 }))).toEqual( |
||||
StatementPosition.SortField |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 6, column: 40 }))).toEqual( |
||||
StatementPosition.SortField |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.SortFieldExpression after a field operator in a sort command', () => { |
||||
expect(getStatementPosition(generateToken(sortQuery.query, { lineNumber: 1, column: 7 }))).toEqual( |
||||
StatementPosition.SortFieldExpression |
||||
); |
||||
expect(getStatementPosition(generateToken(sortQuery.query, { lineNumber: 1, column: 27 }))).toEqual( |
||||
StatementPosition.SortFieldExpression |
||||
); |
||||
expect(getStatementPosition(generateToken(sortQueryWithFunctions.query, { lineNumber: 1, column: 7 }))).toEqual( |
||||
StatementPosition.SortFieldExpression |
||||
); |
||||
expect(getStatementPosition(generateToken(sortQueryWithFunctions.query, { lineNumber: 1, column: 12 }))).toEqual( |
||||
StatementPosition.SortFieldExpression |
||||
); |
||||
// mulltiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 6, column: 9 }))).toEqual( |
||||
StatementPosition.SortFieldExpression |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 6, column: 29 }))).toEqual( |
||||
StatementPosition.SortFieldExpression |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 7, column: 9 }))).toEqual( |
||||
StatementPosition.SortFieldExpression |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 7, column: 14 }))).toEqual( |
||||
StatementPosition.SortFieldExpression |
||||
); |
||||
}); |
||||
}); |
||||
|
||||
describe('DEDUP command', () => { |
||||
it('should return StatementPosition.AfterDedupFieldNames after dedup command fields', () => { |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithOptionalArgs.query, { lineNumber: 1, column: 43 })) |
||||
).toEqual(StatementPosition.AfterDedupFieldNames); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 8, column: 45 }))).toEqual( |
||||
StatementPosition.AfterDedupFieldNames |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.FieldList after dedup command', () => { |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithOptionalArgs.query, { lineNumber: 1, column: 6 })) |
||||
).toEqual(StatementPosition.FieldList); |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithOptionalArgs.query, { lineNumber: 1, column: 8 })) |
||||
).toEqual(StatementPosition.FieldList); |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithOptionalArgs.query, { lineNumber: 1, column: 19 })) |
||||
).toEqual(StatementPosition.FieldList); |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithOptionalArgs.query, { lineNumber: 1, column: 34 })) |
||||
).toEqual(StatementPosition.FieldList); |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithoutOptionalArgs.query, { lineNumber: 1, column: 6 })) |
||||
).toEqual(StatementPosition.FieldList); |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithoutOptionalArgs.query, { lineNumber: 1, column: 17 })) |
||||
).toEqual(StatementPosition.FieldList); |
||||
expect( |
||||
getStatementPosition(generateToken(dedupQueryWithoutOptionalArgs.query, { lineNumber: 1, column: 32 })) |
||||
).toEqual(StatementPosition.FieldList); |
||||
|
||||
// multilin
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 8, column: 8 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 8, column: 10 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 8, column: 21 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 8, column: 36 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 9, column: 8 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 9, column: 19 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 9, column: 34 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
}); |
||||
describe('TOP command', () => { |
||||
it('should return StatementPosition.FieldList after top by keyword', () => { |
||||
expect(getStatementPosition(generateToken(topQuery.query, { lineNumber: 1, column: 36 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 10, column: 38 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.FieldList after fields in top command', () => { |
||||
expect(getStatementPosition(generateToken(topQuery.query, { lineNumber: 1, column: 4 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(topQuery.query, { lineNumber: 1, column: 8 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(topQuery.query, { lineNumber: 1, column: 23 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(topQuery.query, { lineNumber: 1, column: 44 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 10, column: 6 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 10, column: 10 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 10, column: 25 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 10, column: 46 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
}); |
||||
describe('HEAD command', () => { |
||||
it('should return StatementPosition.AfterHeadCommand after head', () => { |
||||
expect(getStatementPosition(generateToken(headQuery.query, { lineNumber: 1, column: 5 }))).toEqual( |
||||
StatementPosition.AfterHeadCommand |
||||
); |
||||
expect(getStatementPosition(generateToken(headQuery.query, { lineNumber: 1, column: 8 }))).toEqual( |
||||
StatementPosition.AfterHeadCommand |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 11, column: 7 }))).toEqual( |
||||
StatementPosition.AfterHeadCommand |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 11, column: 10 }))).toEqual( |
||||
StatementPosition.AfterHeadCommand |
||||
); |
||||
}); |
||||
}); |
||||
describe('RARE command', () => { |
||||
it('should return StatementPosition.FieldList after rare by', () => { |
||||
expect(getStatementPosition(generateToken(rareQuery.query, { lineNumber: 1, column: 30 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 12, column: 32 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.FieldList after rare fields', () => { |
||||
expect(getStatementPosition(generateToken(rareQuery.query, { lineNumber: 1, column: 5 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(rareQuery.query, { lineNumber: 1, column: 13 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(rareQuery.query, { lineNumber: 1, column: 38 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 12, column: 7 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 12, column: 15 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 12, column: 40 }))).toEqual( |
||||
StatementPosition.FieldList |
||||
); |
||||
}); |
||||
}); |
||||
describe('EVAL command', () => { |
||||
it('should return StatementPosition.Expression after eval = operator', () => { |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 21 }))).toEqual( |
||||
StatementPosition.Expression |
||||
); |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 56 }))).toEqual( |
||||
StatementPosition.Expression |
||||
); |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 89 }))).toEqual( |
||||
StatementPosition.Expression |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 13, column: 23 }))).toEqual( |
||||
StatementPosition.Expression |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 13, column: 58 }))).toEqual( |
||||
StatementPosition.Expression |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 13, column: 91 }))).toEqual( |
||||
StatementPosition.Expression |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.EvalClause after eval commas', () => { |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 5 }))).toEqual( |
||||
StatementPosition.EvalClause |
||||
); |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 39 }))).toEqual( |
||||
StatementPosition.EvalClause |
||||
); |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 70 }))).toEqual( |
||||
StatementPosition.EvalClause |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 13, column: 7 }))).toEqual( |
||||
StatementPosition.EvalClause |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 13, column: 41 }))).toEqual( |
||||
StatementPosition.EvalClause |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 13, column: 72 }))).toEqual( |
||||
StatementPosition.EvalClause |
||||
); |
||||
}); |
||||
|
||||
it('should return StatementPosition.BeforeLogicalExpression after a logical expression operator in eval', () => { |
||||
expect(getStatementPosition(generateToken(evalQuery.query, { lineNumber: 1, column: 65 }))).toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
// multiline
|
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 13, column: 67 }))).toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 13, column: 102 }))).toEqual( |
||||
StatementPosition.BeforeLogicalExpression |
||||
); |
||||
}); |
||||
}); |
||||
|
||||
describe('PARSE command', () => { |
||||
it('should return StatementPosition.Expression after PARSE command', () => { |
||||
expect(getStatementPosition(generateToken(parseQuery.query, { lineNumber: 1, column: 6 }))).toEqual( |
||||
StatementPosition.Expression |
||||
); |
||||
expect(getStatementPosition(generateToken(multiLineFullQuery.query, { lineNumber: 14, column: 8 }))).toEqual( |
||||
StatementPosition.Expression |
||||
); |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,220 @@ |
||||
import { LinkedToken } from '../../monarch/LinkedToken'; |
||||
import { StatementPosition } from '../../monarch/types'; |
||||
import { |
||||
ARITHMETIC_OPERATORS, |
||||
PARAMETERS_WITH_BOOLEAN_VALUES, |
||||
BY, |
||||
COMPARISON_OPERATORS, |
||||
CONDITION_FUNCTIONS, |
||||
DEDUP, |
||||
EVAL, |
||||
EVENTSTATS, |
||||
FIELD_OPERATORS, |
||||
FIELDS, |
||||
HEAD, |
||||
IN, |
||||
LOGICAL_EXPRESSION_OPERATORS, |
||||
NOT, |
||||
RARE, |
||||
SORT, |
||||
SORT_FIELD_FUNCTIONS, |
||||
SPAN, |
||||
STATS, |
||||
STATS_FUNCTIONS, |
||||
TOP, |
||||
WHERE, |
||||
PARSE, |
||||
BETWEEN, |
||||
EVAL_FUNCTIONS, |
||||
} from '../language'; |
||||
import { PPLTokenTypes } from '../tokenTypes'; |
||||
|
||||
// getStatementPosition returns the 'statement position' of the place where the cursor is currently positioned.
|
||||
// Statement positions are places that are syntactically and relevant for the evaluated language and are used to determine the suggestionKinds, i.e.
|
||||
// suggestions in the dropdown.
|
||||
// For example, in PPL, if the cursor is currently at the whitespace after the WHERE keyword, this function returns StatementPosition.BeforeLogicalExpression.
|
||||
// In getSuggestionKinds, this position will result in SuggestionKind.LogicalExpression.
|
||||
// Lastly, In PPLCompletionItemProvider appropriate suggestions of logical operators are added to the dropdown based on the suggestion kind.
|
||||
|
||||
export const getStatementPosition = (currentToken: LinkedToken | null): StatementPosition => { |
||||
const previousNonWhiteSpace = currentToken?.getPreviousNonWhiteSpaceToken(); |
||||
const nextNonWhiteSpace = currentToken?.getNextNonWhiteSpaceToken(); |
||||
|
||||
const normalizedPreviousNonWhiteSpace = previousNonWhiteSpace?.value?.toLowerCase(); |
||||
|
||||
if ( |
||||
currentToken === null || |
||||
(currentToken?.isWhiteSpace() && previousNonWhiteSpace === null && nextNonWhiteSpace === null) || |
||||
(previousNonWhiteSpace?.is(PPLTokenTypes.Pipe) && currentToken?.isWhiteSpace()) || |
||||
previousNonWhiteSpace?.is(PPLTokenTypes.Delimiter, '|') |
||||
) { |
||||
return StatementPosition.NewCommand; |
||||
} |
||||
|
||||
switch (normalizedPreviousNonWhiteSpace) { |
||||
case WHERE: |
||||
return StatementPosition.BeforeLogicalExpression; |
||||
case DEDUP: |
||||
return StatementPosition.FieldList; |
||||
case FIELDS: |
||||
return StatementPosition.AfterFieldsCommand; |
||||
case EVENTSTATS: |
||||
case STATS: |
||||
return StatementPosition.AfterStatsCommand; |
||||
case SORT: |
||||
return StatementPosition.SortField; |
||||
case PARSE: |
||||
return StatementPosition.Expression; |
||||
} |
||||
|
||||
if ( |
||||
currentToken?.isWhiteSpace() || |
||||
currentToken?.is(PPLTokenTypes.Backtick) || |
||||
currentToken?.is(PPLTokenTypes.Delimiter, ',') || |
||||
currentToken?.is(PPLTokenTypes.Parenthesis) // for STATS functions
|
||||
) { |
||||
const nearestFunction = currentToken?.getPreviousOfType(PPLTokenTypes.Function)?.value.toLowerCase(); |
||||
const nearestKeyword = currentToken?.getPreviousOfType(PPLTokenTypes.Keyword)?.value.toLowerCase(); |
||||
const nearestCommand = currentToken?.getPreviousOfType(PPLTokenTypes.Command)?.value.toLowerCase(); |
||||
|
||||
if (normalizedPreviousNonWhiteSpace) { |
||||
if ( |
||||
nearestCommand !== FIELDS && // FIELDS and SORT fields can be preceeded by a + or - which are not arithmetic ops
|
||||
nearestCommand !== SORT && |
||||
ARITHMETIC_OPERATORS.includes(normalizedPreviousNonWhiteSpace) |
||||
) { |
||||
return StatementPosition.AfterArithmeticOperator; |
||||
} |
||||
if (PARAMETERS_WITH_BOOLEAN_VALUES.includes(normalizedPreviousNonWhiteSpace)) { |
||||
return StatementPosition.AfterBooleanArgument; |
||||
} |
||||
} |
||||
|
||||
const isBeforeLogicalExpression = |
||||
(normalizedPreviousNonWhiteSpace && |
||||
(COMPARISON_OPERATORS.includes(normalizedPreviousNonWhiteSpace) || |
||||
LOGICAL_EXPRESSION_OPERATORS.includes(normalizedPreviousNonWhiteSpace))) || |
||||
previousNonWhiteSpace?.is(PPLTokenTypes.Regexp) || |
||||
normalizedPreviousNonWhiteSpace === NOT || // follows a comparison operator, logical operator, NOT or a regex
|
||||
(nearestFunction && CONDITION_FUNCTIONS.includes(nearestFunction) && normalizedPreviousNonWhiteSpace === ')'); // it's not a condition function argument
|
||||
|
||||
if ( |
||||
nearestCommand !== SORT && // sort command fields can be followed by a field operator, which is handled lower in the block
|
||||
nearestCommand !== EVAL && // eval fields can be followed by an eval clause, which is handled lower in the block
|
||||
nearestCommand !== STATS && // identifiers in STATS can be followed by a stats function, which is handled lower in the block
|
||||
(isListingFields(currentToken) || currentToken?.is(PPLTokenTypes.Backtick)) |
||||
) { |
||||
return StatementPosition.FieldList; |
||||
} |
||||
|
||||
if ( |
||||
nearestCommand !== EVAL && // eval can have StatementPosition.Expression after an equal operator
|
||||
isBeforeLogicalExpression |
||||
) { |
||||
return StatementPosition.BeforeLogicalExpression; |
||||
} |
||||
|
||||
if (nearestKeyword === IN) { |
||||
return StatementPosition.AfterINKeyword; |
||||
} |
||||
if (nearestKeyword === BETWEEN) { |
||||
return StatementPosition.FunctionArg; |
||||
} |
||||
|
||||
if ( |
||||
nearestFunction && |
||||
(currentToken?.is(PPLTokenTypes.Parenthesis) || currentToken?.getNextNonWhiteSpaceToken()?.value === ')') |
||||
) { |
||||
if ([...EVAL_FUNCTIONS, ...CONDITION_FUNCTIONS].includes(nearestFunction)) { |
||||
return StatementPosition.FunctionArg; |
||||
} |
||||
if (STATS_FUNCTIONS.includes(nearestFunction)) { |
||||
return StatementPosition.StatsFunctionArgument; |
||||
} |
||||
if (SORT_FIELD_FUNCTIONS.includes(nearestFunction)) { |
||||
return StatementPosition.SortFieldExpression; |
||||
} |
||||
} |
||||
|
||||
switch (nearestCommand) { |
||||
case SORT: { |
||||
if (previousNonWhiteSpace) { |
||||
if (previousNonWhiteSpace.is(PPLTokenTypes.Delimiter, ',')) { |
||||
return StatementPosition.SortField; |
||||
} else if (FIELD_OPERATORS.includes(previousNonWhiteSpace.value)) { |
||||
return StatementPosition.SortFieldExpression; |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
case DEDUP: { |
||||
// if current active command is DEDUP and there are identifiers (fieldNames) between currentToken and the dedup command
|
||||
const fieldNames = currentToken.getPreviousUntil(PPLTokenTypes.Number, [ |
||||
PPLTokenTypes.Delimiter, |
||||
PPLTokenTypes.Whitespace, |
||||
]); |
||||
if (fieldNames?.length && !havePipe(fieldNames)) { |
||||
return StatementPosition.AfterDedupFieldNames; |
||||
} |
||||
return StatementPosition.FieldList; |
||||
} |
||||
case FIELDS: { |
||||
return StatementPosition.FieldList; |
||||
} |
||||
case STATS: |
||||
case EVENTSTATS: { |
||||
if (nearestKeyword === BY && currentToken.isWhiteSpace()) { |
||||
return StatementPosition.AfterStatsBy; |
||||
} else if (nearestFunction === SPAN && currentToken?.is(PPLTokenTypes.Parenthesis)) { |
||||
return StatementPosition.FieldList; |
||||
} |
||||
return StatementPosition.AfterStatsCommand; |
||||
} |
||||
case RARE: { |
||||
return StatementPosition.FieldList; |
||||
} |
||||
case TOP: { |
||||
return StatementPosition.FieldList; |
||||
} |
||||
case HEAD: |
||||
return StatementPosition.AfterHeadCommand; |
||||
|
||||
case EVAL: |
||||
if (previousNonWhiteSpace?.value === '=') { |
||||
return StatementPosition.Expression; |
||||
} |
||||
if ( |
||||
currentToken?.isWhiteSpace() && |
||||
(normalizedPreviousNonWhiteSpace === EVAL || previousNonWhiteSpace?.is(PPLTokenTypes.Delimiter, ',')) |
||||
) { |
||||
return StatementPosition.EvalClause; |
||||
} |
||||
if (isBeforeLogicalExpression) { |
||||
return StatementPosition.BeforeLogicalExpression; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return StatementPosition.Unknown; |
||||
}; |
||||
|
||||
const havePipe = (fieldNames: LinkedToken[]) => { |
||||
return fieldNames?.some((word) => word.type === PPLTokenTypes.Pipe); |
||||
}; |
||||
const isListingFields = (currentToken: LinkedToken | null) => { |
||||
const tokensUntilFieldName = currentToken?.getPreviousUntil(PPLTokenTypes.Identifier, [PPLTokenTypes.Whitespace]); // tokens until exampleFieldName
|
||||
const tokensUntilEscapedFieldName = currentToken?.getPreviousUntil(PPLTokenTypes.Backtick, [ |
||||
// tokens until `@exampleFieldName`
|
||||
PPLTokenTypes.Whitespace, |
||||
]); |
||||
const isPreceededByAFieldName = |
||||
(tokensUntilFieldName?.length && tokensUntilFieldName.every((token) => token.is(PPLTokenTypes.Delimiter, ','))) || |
||||
(tokensUntilEscapedFieldName?.length && |
||||
tokensUntilEscapedFieldName.every((token) => token.is(PPLTokenTypes.Delimiter, ','))); |
||||
const isAfterComma = |
||||
currentToken?.isWhiteSpace() && currentToken?.getPreviousNonWhiteSpaceToken()?.is(PPLTokenTypes.Delimiter, ','); |
||||
const isFunctionArgument = currentToken?.getNextNonWhiteSpaceToken()?.value === ')'; // is not e.g. span(`@timestamp`, 5m)
|
||||
|
||||
return isAfterComma && isPreceededByAFieldName && !isFunctionArgument; |
||||
}; |
@ -0,0 +1,40 @@ |
||||
import { StatementPosition, SuggestionKind } from '../../monarch/types'; |
||||
|
||||
export function getSuggestionKinds(statementPosition: StatementPosition): SuggestionKind[] { |
||||
switch (statementPosition) { |
||||
case StatementPosition.NewCommand: |
||||
return [SuggestionKind.Command]; |
||||
case StatementPosition.AfterHeadCommand: |
||||
return [SuggestionKind.FromKeyword]; |
||||
case StatementPosition.AfterStatsCommand: |
||||
return [SuggestionKind.StatsParameter, SuggestionKind.StatsFunctions]; |
||||
case StatementPosition.SortField: |
||||
return [SuggestionKind.FieldOperators, SuggestionKind.Field, SuggestionKind.SortFunctions]; |
||||
case StatementPosition.EvalClause: |
||||
case StatementPosition.StatsFunctionArgument: |
||||
return [SuggestionKind.Field]; |
||||
case StatementPosition.AfterFieldsCommand: |
||||
return [SuggestionKind.FieldOperators, SuggestionKind.Field]; |
||||
case StatementPosition.FieldList: |
||||
return [SuggestionKind.Field]; |
||||
case StatementPosition.AfterBooleanArgument: |
||||
return [SuggestionKind.BooleanLiteral]; |
||||
case StatementPosition.AfterDedupFieldNames: |
||||
return [SuggestionKind.DedupParameter]; |
||||
case StatementPosition.AfterStatsBy: |
||||
return [SuggestionKind.Field, SuggestionKind.SpanClause]; |
||||
case StatementPosition.SortFieldExpression: |
||||
return [SuggestionKind.Field, SuggestionKind.SortFunctions]; |
||||
case StatementPosition.FunctionArg: |
||||
case StatementPosition.AfterArithmeticOperator: |
||||
case StatementPosition.AfterINKeyword: |
||||
return [SuggestionKind.ValueExpression]; |
||||
// logical expression can contain comparison expression, which can start with a value expression
|
||||
// so we always need to suggest valueExpression when SuggestionKind.LogicalExpression is present
|
||||
case StatementPosition.Expression: |
||||
case StatementPosition.BeforeLogicalExpression: |
||||
return [SuggestionKind.LogicalExpression, SuggestionKind.ValueExpression]; |
||||
} |
||||
|
||||
return []; |
||||
} |
@ -0,0 +1,12 @@ |
||||
import { LanguageDefinition } from '../monarch/register'; |
||||
|
||||
import { CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID } from './language'; |
||||
|
||||
const cloudWatchPPLLanguageDefinition: LanguageDefinition = { |
||||
id: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID, |
||||
extensions: [], |
||||
aliases: [], |
||||
mimetypes: [], |
||||
loader: () => import('./language'), |
||||
}; |
||||
export default cloudWatchPPLLanguageDefinition; |
@ -0,0 +1,246 @@ |
||||
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api'; |
||||
|
||||
// OpenSearch PPL syntax: https://github.com/opensearch-project/opensearch-spark/blob/0.5/ppl-spark-integration/src/main/antlr4/OpenSearchPPLParser.g4
|
||||
interface CloudWatchPPLLanguage extends monacoType.languages.IMonarchLanguage { |
||||
commands: string[]; |
||||
operators: string[]; |
||||
builtinFunctions: string[]; |
||||
} |
||||
|
||||
export const CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID = 'logs-ppl'; |
||||
|
||||
// COMMANDS
|
||||
export const WHERE = 'where'; |
||||
export const FIELDS = 'fields'; |
||||
export const DEDUP = 'dedup'; |
||||
export const STATS = 'stats'; |
||||
export const EVENTSTATS = 'eventstats'; |
||||
export const SORT = 'sort'; |
||||
export const EVAL = 'eval'; |
||||
export const HEAD = 'head'; |
||||
export const TOP = 'top'; |
||||
export const RARE = 'rare'; |
||||
export const PARSE = 'parse'; |
||||
|
||||
export const PPL_COMMANDS = [WHERE, FIELDS, STATS, EVENTSTATS, DEDUP, SORT, TOP, RARE, HEAD, EVAL, PARSE]; |
||||
|
||||
// KEYWORDS
|
||||
export const AS = 'as'; |
||||
export const BY = 'by'; |
||||
export const BETWEEN = 'between'; |
||||
export const FROM = 'from'; |
||||
|
||||
// PARAMETERS
|
||||
const KEEP_EMPTY = 'keepempty'; |
||||
const CONSECUTIVE = 'consecutive'; |
||||
const PARTITIONS = 'partitions'; |
||||
const ALLNUM = 'allnum'; |
||||
const DELIM = 'delim'; |
||||
const DEDUP_SPLITVALUES = 'dedup_splitvalues'; |
||||
|
||||
export const STATS_PARAMETERS = [PARTITIONS, ALLNUM, DELIM, DEDUP_SPLITVALUES]; |
||||
export const DEDUP_PARAMETERS = [KEEP_EMPTY, CONSECUTIVE]; |
||||
export const PARAMETERS_WITH_BOOLEAN_VALUES = [ALLNUM, DEDUP_SPLITVALUES, KEEP_EMPTY, CONSECUTIVE]; |
||||
export const BOOLEAN_LITERALS = ['true', 'false']; |
||||
export const IN = 'in'; |
||||
|
||||
export const ALL_KEYWORDS = [...STATS_PARAMETERS, ...DEDUP_PARAMETERS, ...BOOLEAN_LITERALS, AS, BY, IN, BETWEEN, FROM]; |
||||
|
||||
// FUNCTIONS
|
||||
export const MATH_FUNCTIONS = [ |
||||
'abs', |
||||
'acos', |
||||
'asin', |
||||
'atan', |
||||
'atan2', |
||||
'ceil', |
||||
'ceiling', |
||||
'conv', |
||||
'cos', |
||||
'cot', |
||||
'crc32', |
||||
'degrees', |
||||
'e', |
||||
'exp', |
||||
'floor', |
||||
'ln', |
||||
'log', |
||||
'log2', |
||||
'log10', |
||||
'mod', |
||||
'pi', |
||||
'pow', |
||||
'power', |
||||
'radians', |
||||
'rand', |
||||
'round', |
||||
'sign', |
||||
'sin', |
||||
'sqrt', |
||||
'cbrt', |
||||
]; |
||||
export const DATE_TIME_FUNCTIONS = [ |
||||
'datediff', |
||||
'day', |
||||
'dayofmonth', |
||||
'dayofweek', |
||||
'dayofyear', |
||||
'hour', |
||||
'minute', |
||||
'second', |
||||
'month', |
||||
'quarter', |
||||
'weekday', |
||||
'weekofyear', |
||||
'year', |
||||
'now', |
||||
'curdate', |
||||
'current_date', |
||||
]; |
||||
export const TEXT_FUNCTIONS = [ |
||||
'concat', |
||||
'concat_ws', |
||||
'length', |
||||
'lower', |
||||
'ltrim', |
||||
'reverse', |
||||
'rtrim', |
||||
'right', |
||||
'substring', |
||||
'substr', |
||||
'trim', |
||||
'upper', |
||||
]; |
||||
export const SPAN = 'span'; |
||||
export const POSITION = 'position'; |
||||
export const CONDITION_FUNCTIONS = ['like', 'isnull', 'isnotnull', 'exists', 'ifnull', 'nullif', 'if', 'ispresent']; |
||||
export const SORT_FIELD_FUNCTIONS = ['auto', 'str', 'ip', 'num']; |
||||
export const PPL_FUNCTIONS = [...MATH_FUNCTIONS, ...DATE_TIME_FUNCTIONS, ...TEXT_FUNCTIONS]; |
||||
export const EVAL_FUNCTIONS: string[] = [...PPL_FUNCTIONS, POSITION]; |
||||
export const STATS_FUNCTIONS = [ |
||||
'avg', |
||||
'count', |
||||
'sum', |
||||
'min', |
||||
'max', |
||||
'stddev_samp', |
||||
'stddev_pop', |
||||
'percentile', |
||||
'percentile_approx', |
||||
'distinct_count', |
||||
'dc', |
||||
]; |
||||
|
||||
export const ALL_FUNCTIONS = [ |
||||
...PPL_FUNCTIONS, |
||||
...STATS_FUNCTIONS, |
||||
...CONDITION_FUNCTIONS, |
||||
...SORT_FIELD_FUNCTIONS, |
||||
POSITION, |
||||
SPAN, |
||||
]; |
||||
|
||||
// OPERATORS
|
||||
export const PLUS = '+'; |
||||
export const MINUS = '-'; |
||||
export const NOT = 'not'; |
||||
|
||||
export const FIELD_OPERATORS = [PLUS, MINUS]; |
||||
export const ARITHMETIC_OPERATORS = [PLUS, MINUS, '*', '/', '%']; |
||||
export const COMPARISON_OPERATORS = ['>', '>=', '<', '!=', '<=', '=']; |
||||
export const LOGICAL_EXPRESSION_OPERATORS = ['and', 'or', 'xor', NOT]; |
||||
export const PPL_OPERATORS = [...ARITHMETIC_OPERATORS, ...LOGICAL_EXPRESSION_OPERATORS, ...COMPARISON_OPERATORS]; |
||||
|
||||
export const language: CloudWatchPPLLanguage = { |
||||
defaultToken: '', |
||||
id: CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID, |
||||
ignoreCase: true, |
||||
commands: PPL_COMMANDS, |
||||
operators: PPL_OPERATORS, |
||||
keywords: ALL_KEYWORDS, |
||||
builtinFunctions: ALL_FUNCTIONS, |
||||
brackets: [{ open: '(', close: ')', token: 'delimiter.parenthesis' }], |
||||
tokenizer: { |
||||
root: [ |
||||
{ include: '@comments' }, |
||||
{ include: '@regexes' }, |
||||
{ include: '@whitespace' }, |
||||
{ include: '@variables' }, |
||||
{ include: '@strings' }, |
||||
{ include: '@numbers' }, |
||||
|
||||
[/[,.:]/, 'delimiter'], |
||||
[/\|/, 'delimiter.pipe'], |
||||
[/[()\[\]]/, 'delimiter.parenthesis'], |
||||
|
||||
[ |
||||
/[\w@#$]+/, |
||||
{ |
||||
cases: { |
||||
'@commands': 'keyword.command', |
||||
'@keywords': 'keyword', |
||||
'@builtinFunctions': 'predefined', |
||||
'@operators': 'operator', |
||||
'@default': 'identifier', |
||||
}, |
||||
}, |
||||
], |
||||
[/[+\-*/^%=!<>]/, 'operator'], // handles the math operators
|
||||
[/[,.:]/, 'operator'], |
||||
], |
||||
// template variable syntax
|
||||
variables: [ |
||||
[/\${/, { token: 'variable', next: '@variable_bracket' }], |
||||
[/\$[a-zA-Z0-9-_]+/, 'variable'], |
||||
], |
||||
variable_bracket: [ |
||||
[/[a-zA-Z0-9-_:]+/, 'variable'], |
||||
[/}/, { token: 'variable', next: '@pop' }], |
||||
], |
||||
whitespace: [[/\s+/, 'white']], |
||||
comments: [ |
||||
[/^#.*/, 'comment'], |
||||
[/\s+#.*/, 'comment'], |
||||
], |
||||
numbers: [ |
||||
[/0[xX][0-9a-fA-F]*/, 'number'], |
||||
[/[$][+-]*\d*(\.\d*)?/, 'number'], |
||||
[/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/, 'number'], |
||||
], |
||||
strings: [ |
||||
[/'/, { token: 'string', next: '@string' }], |
||||
[/"/, { token: 'string', next: '@string_double' }], |
||||
[/`/, { token: 'string.backtick', next: '@string_backtick' }], |
||||
], |
||||
string: [ |
||||
[/[^']+/, 'string'], |
||||
[/''/, 'string'], |
||||
[/'/, { token: 'string', next: '@pop' }], |
||||
], |
||||
string_double: [ |
||||
[/[^\\"]+/, 'string'], |
||||
[/"/, 'string', '@pop'], |
||||
], |
||||
string_backtick: [ |
||||
[/[^\\`]+/, 'string.backtick'], |
||||
[/`/, 'string.backtick', '@pop'], |
||||
], |
||||
regexes: [[/\/.*?\/(?!\s*\d)/, 'regexp']], |
||||
}, |
||||
}; |
||||
|
||||
export const conf: monacoType.languages.LanguageConfiguration = { |
||||
brackets: [['(', ')']], |
||||
autoClosingPairs: [ |
||||
{ open: '(', close: ')' }, |
||||
{ open: '"', close: '"' }, |
||||
{ open: "'", close: "'" }, |
||||
{ open: '`', close: '`' }, |
||||
], |
||||
surroundingPairs: [ |
||||
{ open: '(', close: ')' }, |
||||
{ open: '"', close: '"' }, |
||||
{ open: "'", close: "'" }, |
||||
{ open: '`', close: '`' }, |
||||
], |
||||
}; |
@ -0,0 +1,28 @@ |
||||
import { TokenTypes } from '../monarch/types'; |
||||
|
||||
import { CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID } from './language'; |
||||
|
||||
interface IpplTokenTypes extends TokenTypes { |
||||
Pipe: string; |
||||
Backtick: string; |
||||
Command: string; |
||||
} |
||||
|
||||
export const PPLTokenTypes: IpplTokenTypes = { |
||||
Parenthesis: `delimiter.parenthesis.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Whitespace: `white.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Keyword: `keyword.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Command: `keyword.command.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Delimiter: `delimiter.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Pipe: `delimiter.pipe.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Operator: `operator.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Identifier: `identifier.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Type: `type.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Function: `predefined.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Number: `number.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
String: `string.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Variable: `variable.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Comment: `comment.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Regexp: `regexp.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
Backtick: `string.backtick.${CLOUDWATCH_PPL_LANGUAGE_DEFINITION_ID}`, |
||||
}; |
Loading…
Reference in new issue