fix(parser): fixing select keyword parsing outside the SQL queries (#206)

* fix(parser): prevent 'select' keyword in config objects from being parsed as SQL query

* fix: fixing parsing with SELECT keywords outside sql queries

* chore: adding changeset
This commit is contained in:
Kacper 2026-03-29 11:15:57 +01:00 committed by GitHub
parent d9cb4d5fea
commit 03dfcd78b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 115 additions and 1 deletions

View file

@ -0,0 +1,5 @@
---
"sqlseal": patch
---
fixing issue with select keywords outside SQL queries

View file

@ -336,6 +336,58 @@ describe('parseWithDefaults', () => {
}) })
}) })
it('should not treat "select" as SQL keyword when it appears as part of a config property name', () => {
// Regression test for main-0e3: `selectedMode` in a GRID/CHART config object
// was incorrectly parsed as the start of a SQL SELECT query, causing a parse error.
expect(parseWithDefaults(`
TABLE data = file(test_data.csv)
GRID {
selectedMode: true,
selectAll: false
}
SELECT * FROM data`, DEFAULT_VIEWS, DEFAULTS)).toEqual({
flags: { explain: false, refresh: true },
query: 'SELECT * FROM data',
renderer: {
type: 'GRID',
options: `{
selectedMode: true,
selectAll: false
}`,
},
tables: [{ tableAlias: 'data', arguments: ['test_data.csv'], type: 'file' }]
})
})
it('should not treat "with" as SQL keyword when it appears as part of a config property name', () => {
// Same word-boundary fix covers "with" prefix: `withAnimation`, `without`, etc.
expect(parseWithDefaults(`
TABLE data = file(test_data.csv)
GRID {
withAnimation: true
}
SELECT * FROM data`, DEFAULT_VIEWS, DEFAULTS)).toEqual({
flags: { explain: false, refresh: true },
query: 'SELECT * FROM data',
renderer: {
type: 'GRID',
options: `{
withAnimation: true
}`,
},
tables: [{ tableAlias: 'data', arguments: ['test_data.csv'], type: 'file' }]
})
})
it('should still parse SELECT as keyword when used as a standalone SQL clause', () => {
expect(parseWithDefaults(`SELECT * FROM files`, DEFAULT_VIEWS, DEFAULTS)).toEqual({
flags: { explain: false, refresh: true },
query: 'SELECT * FROM files',
renderer: { type: 'GRID', name: 'GRID', options: '' },
tables: []
})
})
it('should properly handle chart', () => { it('should properly handle chart', () => {
expect(parseWithDefaults(` expect(parseWithDefaults(`
TABLE data = file(test_data.csv) TABLE data = file(test_data.csv)
@ -398,4 +450,61 @@ SELECT id, value FROM data`, DEFAULT_VIEWS, DEFAULTS)).toEqual({
}] }]
}) })
}) })
it('should not treat "select" as SQL keyword when it appears as a quoted config property key', () => {
// Test case for fix: quoted string "select" as a property key should not break the parser
expect(parseWithDefaults(`
GRID {
"select": 4
}
SELECT * FROM files`, DEFAULT_VIEWS, DEFAULTS)).toEqual({
flags: { explain: false, refresh: true },
query: 'SELECT * FROM files',
renderer: {
type: 'GRID',
options: `{
"select": 4
}`,
},
tables: []
})
})
it('should not treat "select" as SQL keyword when it appears as an unquoted config property key', () => {
// Bonus test: unquoted property key with colon immediately following
expect(parseWithDefaults(`
GRID {
select: 4
}
SELECT * FROM files`, DEFAULT_VIEWS, DEFAULTS)).toEqual({
flags: { explain: false, refresh: true },
query: 'SELECT * FROM files',
renderer: {
type: 'GRID',
options: `{
select: 4
}`,
},
tables: []
})
})
it('should handle "select" as property key with space before colon', () => {
// Edge case: space between quoted key and colon
expect(parseWithDefaults(`
GRID {
"select" : 4
}
SELECT * FROM files`, DEFAULT_VIEWS, DEFAULTS)).toEqual({
flags: { explain: false, refresh: true },
query: 'SELECT * FROM files',
renderer: {
type: 'GRID',
options: `{
"select" : 4
}`,
},
tables: []
})
})
}) })

View file

@ -53,7 +53,7 @@ export const SQLSealLangDefinition = (views: ViewDefinition[], flags: readonly F
anyObject = "{" (~selectKeyword any)* anyObject = "{" (~selectKeyword any)*
handlebarsTemplate = (~selectKeyword any)* handlebarsTemplate = (~selectKeyword any)*
javascriptTemplate = (~selectKeyword any)* javascriptTemplate = (~selectKeyword any)*
selectKeyword = caseInsensitive<"WITH"> | caseInsensitive<"SELECT"> selectKeyword = (caseInsensitive<"WITH"> | caseInsensitive<"SELECT">) &(space | nl | end)
tableKeyword = caseInsensitive<"TABLE"> tableKeyword = caseInsensitive<"TABLE">
nl = "\n" nl = "\n"
character = (alnum | "." | "-" | space | "_") character = (alnum | "." | "-" | space | "_")