feat(webui): Add support for building queries from guided SQL input boxes.#1304
Conversation
WalkthroughAdds a temporary React component for composing and submitting Presto SQL in guided mode, integrates it into SearchControls, and extends the SQL parser with a parser-construction helper, an exported buildSearchQuery function and BuildSearchQueryProps type; plus a minor syntax formatting tweak. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as BuildSqlTestingInputs
participant Builder as buildSearchQuery
participant Parser as buildParser / validate
participant Submit as handlePrestoQuerySubmit
User->>UI: Enter select/from/where/order/limit\nClick Run
UI->>Builder: buildSearchQuery(props)
Builder->>Parser: buildParser(sqlString).singleStatement()
alt valid SQL
Parser-->>Builder: success
Builder-->>UI: sqlString
UI->>Submit: handlePrestoQuerySubmit({ queryString: sqlString })
else parse error
Parser-->>Builder: throw SyntaxError
Builder-->>UI: throw Error(with constructed SQL + cause)
UI-->>User: surface/log error
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
components/webui/client/src/sql-parser/index.ts (1)
24-37: Avoid shadowing the built‑in SyntaxError. Rename to SqlSyntaxError.Shadowing can confuse consumers and stack traces.
Apply:
-class SyntaxError extends Error { +class SqlSyntaxError extends Error { } @@ - throw new SyntaxError(`line ${line}:${column}: ${msg}`); + throw new SqlSyntaxError(`line ${line}:${column}: ${msg}`);Also update all references/JSDoc/exports accordingly (see suggestions below).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (2)
components/webui/client/src/sql-parser/generated/SqlBaseParser.tsis excluded by!**/generated/**components/webui/client/src/sql-parser/generated/SqlBaseVisitor.tsis excluded by!**/generated/**
📒 Files selected for processing (5)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx(1 hunks)components/webui/client/src/pages/SearchPage/SearchControls/index.tsx(2 hunks)components/webui/client/src/sql-parser/SqlBase.g4(3 hunks)components/webui/client/src/sql-parser/index.ts(3 hunks)taskfiles/codegen.yaml(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}
⚙️ CodeRabbit configuration file
- Prefer
false == <expression>rather than!<expression>.
Files:
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsxcomponents/webui/client/src/pages/SearchPage/SearchControls/index.tsxcomponents/webui/client/src/sql-parser/index.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: haiqi96
PR: y-scope/clp#0
File: :0-0
Timestamp: 2025-07-29T14:04:13.769Z
Learning: User haiqi96 requested creating a GitHub issue to document a bug fix from PR #1136, which addressed MySQL compatibility issues with invalid SQL CAST operations in the WebUI component.
🧬 Code graph analysis (3)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (2)
components/webui/client/src/sql-parser/index.ts (2)
BuildSearchQueryProps(226-226)buildSearchQuery(221-221)components/webui/client/src/pages/SearchPage/SearchControls/Presto/presto-search-requests.ts (1)
handlePrestoQuerySubmit(104-104)
components/webui/client/src/pages/SearchPage/SearchControls/index.tsx (1)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (1)
BuildSqlTestingInputs(47-47)
components/webui/client/src/sql-parser/index.ts (4)
components/webui/client/src/sql-parser/generated/SqlBaseParser.ts (27)
SqlBaseParser(21-11173)SelectItemListContext(14582-14604)RelationListContext(14607-14629)BooleanExpressionContext(15294-15305)SortItemListContext(14304-14326)QuerySpecificationContext(14525-14579)selectItemList(4740-4782)selectItemList(11255-11257)selectItemList(14535-14537)relationList(4784-4826)relationList(11280-11282)relationList(14544-14546)booleanExpression(5841-6138)booleanExpression(11305-11307)booleanExpression(12871-12873)booleanExpression(12935-12937)booleanExpression(13514-13516)booleanExpression(14565-14567)booleanExpression(15016-15018)booleanExpression(15277-15279)booleanExpression(15314-15316)booleanExpression(15358-15360)booleanExpression(16945-16947)QueryNoWithContext(14237-14301)sortItemList(4339-4379)sortItemList(11330-11332)sortItemList(14254-14256)components/webui/client/src/sql-parser/generated/SqlBaseLexer.ts (1)
SqlBaseLexer(15-1482)components/webui/common/src/utility-types.ts (1)
Nullable(3-3)components/webui/client/src/sql-parser/generated/SqlBaseVisitor.ts (1)
SqlBaseVisitor(252-1832)
🪛 Biome (2.1.2)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx
[error] 30-30: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 32-32: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 34-34: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 36-36: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 38-38: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: musllinux_1_2-x86_64-dynamic-linked-bins
- GitHub Check: musllinux_1_2-x86_64-static-linked-bins
- GitHub Check: manylinux_2_28-x86_64-dynamic-linked-bins
- GitHub Check: ubuntu-jammy-static-linked-bins
- GitHub Check: manylinux_2_28-x86_64-static-linked-bins
- GitHub Check: ubuntu-jammy-dynamic-linked-bins
- GitHub Check: package-image
- GitHub Check: centos-stream-9-dynamic-linked-bins
- GitHub Check: ubuntu-jammy-lint
- GitHub Check: centos-stream-9-static-linked-bins
- GitHub Check: build-macos (macos-15, true)
- GitHub Check: lint-check (ubuntu-24.04)
- GitHub Check: build-macos (macos-15, false)
🔇 Additional comments (3)
taskfiles/codegen.yaml (1)
66-72: Visitor generated and referenced correctly — approved.
SqlBaseVisitor.ts exists at components/webui/client/src/sql-parser/generated/ and imports ParseTreeVisitor from 'antlr4'; SqlBaseParser.ts and SqlBaseLexer.ts import 'antlr4', and SqlBaseParser imports the visitor via "./SqlBaseVisitor.js". No changes required.components/webui/client/src/sql-parser/SqlBase.g4 (1)
33-51: Regenerate the ANTLR TypeScript parser and verify visitor behaviour + ORDER BY parsing
- Regenerate the parser (run ANTLR with -visitor) and confirm ANTLR reports no ambiguities/warnings.
- TypeScript target caveat: it emits a visitor interface only (no generated BaseVisitor with a visitChildren fallback). Implement/forward any required visitor methods or add a small BaseVisitor shim to preserve traversal behaviour.
- ORDER BY handling is fine for Presto/Trino — use a comma‑separated non‑left‑recursive list (expression (',' expression)*).
- Check: components/webui/client/src/sql-parser/SqlBase.g4 (lines 33–51; also verify 260–269 and 288–303).
components/webui/client/src/sql-parser/index.ts (1)
66-76: Confirmed: generated parser uses the 'antlr4' JS runtime — no change requiredcomponents/webui/client/src/sql-parser/generated/SqlBaseLexer.ts, SqlBaseParser.ts and SqlBaseVisitor.ts import from 'antlr4', and components/webui/client/package.json lists "antlr4": "^4.13.2".
davemarco
left a comment
There was a problem hiding this comment.
Great that it's works!
Overall i have a high level questions about this comment from the rabbit - #1304 (comment)
What is wrong with this approach, it seems more intuitive and simpler than the template approach? There is also no setting children directly.
Open to template approach, if you have good reason for it.
Also i think you should add more comments to parser code.
| {controls} | ||
| </form> | ||
| <> | ||
| <form onSubmit={handleSubmit}> |
There was a problem hiding this comment.
Move this to Guided Controls
There was a problem hiding this comment.
We cannot because the testing component uses form and a form cannot be nested in another form. Since it's temporarily, I guess it's ok.
There was a problem hiding this comment.
I think this is okay, since it still wont render without guided which is default false
There was a problem hiding this comment.
You may need to modify top of file per license
I guess both works for our use but template might be more structured? Ideally, we should be able to construct syntax trees directly using components, (e.g. I'm open to both. @junhaoliao |
Let's pull in some ANTLR experts for this discussion. @gibber9809 @LinZhihao-723 @kirkrodrigues From the solutions that were presented (templating vs string assembly), I believe the templating approach is easier to maintain. if we hardcode with string assembly method, we lost the AST abstraction. the code might become more complex if the query grammar grows (e.g., GROUP BY, HAVING, etc..) it does seem that building fragment ASTs for by the way, do you think this can be a better interface than buildSearchQuery(...)?: or can we mimic the interfaces in this library https://www.npmjs.com/package/node-sql-parser ? |
I'm not sure if I fully understand what Marco proposed, but I think the correct way to do it here is:
Q: Why parsing a complete SQL query string?
Q: Does it mean we need to maintain the format string carefully to concat subcomponents/clusters into a complete SQL query string?
|
|
@LinZhihao-723 I think good approach, but how do we send syntax error to user? I guess the errors would be for the full format string, and not the individual input, which may be fine? |
Yeah. Maybe we can do a preview of the generated query string in the UI. And reporting errors to that generated query string would make more sense. |
tbh, I don't really like Java-style builders -- they add many boilerplates to the code. I made a few changes using optional fields. Can you do a review again? |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
components/webui/client/src/sql-parser/index.ts (1)
13-14: Rename local SyntaxError to avoid shadowing the built‑in error.Shadowing the global SyntaxError hinders accurate type checks and tooling. Use a distinct name (e.g., SqlSyntaxError) and propagate the rename.
Apply:
-class SyntaxError extends Error { +class SqlSyntaxError extends Error { }
♻️ Duplicate comments (5)
components/webui/client/src/sql-parser/index.ts (3)
67-75: JSDoc should reference the SQL‑specific error type.- * @throws {SyntaxError} with line, column, and message details if a syntax error is found. + * @throws {SqlSyntaxError} with line, column, and message details if a syntax error is found.
125-129: Update exports to use the renamed error type.export { buildSearchQuery, - SyntaxError, + SqlSyntaxError, validate, };
85-97: Keep original SQL syntax error type when rethrowing; update JSDoc.Preserve SqlSyntaxError so callers can distinguish parse failures; fix the @throws tag accordingly.
- * @throws {SyntaxError} if any of the input is not valid. + * @throws {SqlSyntaxError} if any of the input is not valid. @@ try { validate(sqlString); } catch (err: unknown) { - throw new Error(`The constructed SQL is not valid: ${sqlString}`, {cause: err}); + if (err instanceof SqlSyntaxError) { + throw err; + } + throw new Error(`The constructed SQL is not valid: ${sqlString}`, {cause: err}); }components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (2)
59-69: Associate labels with inputs and constrain LIMIT to numeric.Fixes a11y violations and reduces invalid input.
- <label>select:</label> - <input name={"selectItemList"}/> - <label>from:</label> - <input name={"relationList"}/> - <label>where:</label> - <input name={"booleanExpression"}/> - <label>order:</label> - <input name={"sortItemList"}/> - <label>limit:</label> - <input name={"limitValue"}/> + <label> + select: + <input name="selectItemList" placeholder="col1, col2, t.*" /> + </label> + <label> + from: + <input name="relationList" placeholder="table1 t, table2" /> + </label> + <label> + where: + <input name="booleanExpression" placeholder="t.col = 1 AND ..." /> + </label> + <label> + order: + <input name="sortItemList" placeholder="col1 DESC, col2" /> + </label> + <label> + limit: + <input name="limitValue" type="number" inputMode="numeric" min="0" /> + </label>
46-57: Guard submit with try/catch and gate debug logs.Unhandled exceptions from parsing crash the UI; keep console noise out of production.
onSubmit={(ev: FormEvent<HTMLFormElement>) => { ev.preventDefault(); - const formData = new FormData(ev.target as HTMLFormElement); - const props: Static<typeof BuildSearchQueryPropsSchema> = Value.Parse( - BuildSearchQueryPropsSchema, - Object.fromEntries(formData), - ); - - const sqlString = buildSearchQuery(props); - console.log(`SQL: ${sqlString}`); - handlePrestoQuerySubmit({queryString: sqlString}); + try { + const formData = new FormData(ev.target as HTMLFormElement); + const props: Static<typeof BuildSearchQueryPropsSchema> = Value.Parse( + BuildSearchQueryPropsSchema, + Object.fromEntries(formData), + ); + const sqlString = buildSearchQuery(props); + if ("production" !== process.env.NODE_ENV) { + // eslint-disable-next-line no-console + console.log(`SQL: ${sqlString}`); + } + handlePrestoQuerySubmit({queryString: sqlString}); + } catch (err) { + // eslint-disable-next-line no-console + console.error(err); + alert("Invalid SQL fragments. Please check your inputs."); + } }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx(1 hunks)components/webui/client/src/sql-parser/index.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}
⚙️ CodeRabbit configuration file
- Prefer
false == <expression>rather than!<expression>.
Files:
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsxcomponents/webui/client/src/sql-parser/index.ts
🧬 Code graph analysis (2)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (2)
components/webui/client/src/sql-parser/index.ts (1)
buildSearchQuery(126-126)components/webui/client/src/pages/SearchPage/SearchControls/Presto/presto-search-requests.ts (1)
handlePrestoQuerySubmit(104-104)
components/webui/client/src/sql-parser/index.ts (2)
components/webui/client/src/sql-parser/generated/SqlBaseParser.ts (11)
SqlBaseParser(19-10938)booleanExpression(5617-5914)booleanExpression(12151-12153)booleanExpression(12199-12201)booleanExpression(12642-12644)booleanExpression(13413-13415)booleanExpression(13702-13704)booleanExpression(13883-13885)booleanExpression(13912-13914)booleanExpression(13940-13942)booleanExpression(15063-15065)components/webui/client/src/sql-parser/generated/SqlBaseLexer.ts (1)
SqlBaseLexer(15-1482)
🪛 Biome (2.1.2)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx
[error] 59-59: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 61-61: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 63-63: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 65-65: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 67-67: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: package-image
- GitHub Check: lint-check (ubuntu-24.04)
- GitHub Check: lint-check (macos-15)
🔇 Additional comments (2)
components/webui/client/src/sql-parser/index.ts (1)
55-66: LGTM: Parser factory separation is clean.Good encapsulation of lexer/parser setup with error listeners.
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (1)
16-27: LGTM: Schema transform for empty strings → undefined is solid.Keeps UI optional fields aligned with the builder’s types.
Also applies to: 28-36
Okay i think eventually we can change the error so its shows the full format string |
Or we can still add standaloneXXX back and validate individual components before formatting? |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
components/webui/client/src/sql-parser/index.ts (1)
13-26: Rename custom SyntaxError to SqlSyntaxError; update JSDoc and exports.Avoid colliding with the global SyntaxError — rename the class, the thrown instance, the @throws JSDoc, and the exported identifier.
Location: components/webui/client/src/sql-parser/index.ts — class: 13–26; JSDoc: 67–72; exports: 124–128
-class SyntaxError extends Error { +class SqlSyntaxError extends Error { } @@ - throw new SyntaxError(`line ${line}:${column}: ${msg}`); + throw new SqlSyntaxError(`line ${line}:${column}: ${msg}`);- * @throws {SyntaxError} with line, column, and message details if a syntax error is found. + * @throws {SqlSyntaxError} with line, column, and message details if a syntax error is found.-export { - buildSearchQuery, - SyntaxError, - validate, -}; +export {buildSearchQuery, validate, SqlSyntaxError};
♻️ Duplicate comments (6)
components/webui/client/src/sql-parser/index.ts (4)
115-119: Preserve the specific SQL error type when rethrowing.Let callers catch
SqlSyntaxErrorreliably; wrap only non‑syntax errors.- } catch (err: unknown) { - throw new Error(`The constructed SQL is not valid: ${sqlString}`, {cause: err}); - } + } catch (err: unknown) { + if (err instanceof SqlSyntaxError) throw err; + throw new Error(`The constructed SQL is not valid: ${sqlString}`, {cause: err}); + }
67-76: JSDoc must reference the renamed error type.Same as above; update the
@throwstag toSqlSyntaxError.
105-113: Prefer direct undefined checks overtypeofstring comparisons.Cleaner TS; no behaviour change.
- if ("undefined" !== typeof booleanExpression) { + if (undefined !== booleanExpression) { @@ - if ("undefined" !== typeof sortItemList) { + if (undefined !== sortItemList) { @@ - if ("undefined" !== typeof limitValue) { + if (undefined !== limitValue) {
104-113: Defensively reject empty strings for optional fragments (enforce API contract).If someone bypasses the UI schema,
""will emit broken clauses. Guard early.- if ("undefined" !== typeof booleanExpression) { - sqlString += ` WHERE ${booleanExpression}`; - } - if ("undefined" !== typeof sortItemList) { - sqlString += ` ORDER BY ${sortItemList}`; - } - if ("undefined" !== typeof limitValue) { - sqlString += ` LIMIT ${limitValue}`; - } + if (undefined !== booleanExpression) { + if ("" === booleanExpression) throw new Error("booleanExpression must be undefined or a valid fragment"); + sqlString += ` WHERE ${booleanExpression}`; + } + if (undefined !== sortItemList) { + if ("" === sortItemList) throw new Error("sortItemList must be undefined or a valid fragment"); + sqlString += ` ORDER BY ${sortItemList}`; + } + if (undefined !== limitValue) { + if ("" === limitValue) throw new Error("limitValue must be undefined or a valid fragment"); + sqlString += ` LIMIT ${limitValue}`; + }components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (2)
60-71: Associate labels with inputs and constrain LIMIT to numeric.Fixes a11y errors (Biome) and prevents non‑numeric limit.
- <label>select:</label> - <input name={"selectItemList"}/> - <label>from:</label> - <input name={"relationList"}/> - <label>where:</label> - <input name={"booleanExpression"}/> - <label>order:</label> - <input name={"sortItemList"}/> - <label>limit:</label> - <input name={"limitValue"}/> + <label> + select: + <input name="selectItemList" placeholder="col1, col2, t.*" required /> + </label> + <label> + from: + <input name="relationList" placeholder="table1 t, table2" required /> + </label> + <label> + where: + <input name="booleanExpression" placeholder="t.col = 1 AND ..." /> + </label> + <label> + order: + <input name="sortItemList" placeholder="col1 DESC, col2" /> + </label> + <label> + limit: + <input name="limitValue" type="number" inputMode="numeric" min="1" step="1" /> + </label>
47-58: Wrap parse/build in try/catch; don’t crash the UI on invalid input.Uncaught exceptions here will break the page.
- onSubmit={(ev: FormEvent<HTMLFormElement>) => { + onSubmit={(ev: FormEvent<HTMLFormElement>) => { ev.preventDefault(); - const formData = new FormData(ev.target as HTMLFormElement); - const props: Static<typeof BuildSearchQueryPropsSchema> = Value.Parse( - BuildSearchQueryPropsSchema, - Object.fromEntries(formData), - ); - - const sqlString = buildSearchQuery(props); - console.log(`SQL: ${sqlString}`); - handlePrestoQuerySubmit({queryString: sqlString}); + try { + const formData = new FormData(ev.target as HTMLFormElement); + const props = Value.Parse( + BuildSearchQueryPropsSchema, + Object.fromEntries(formData), + ); + const sqlString = buildSearchQuery(props); + if ("production" !== process.env.NODE_ENV) { + // eslint-disable-next-line no-console + console.log(`SQL: ${sqlString}`); + } + handlePrestoQuerySubmit({queryString: sqlString}); + } catch (err) { + // eslint-disable-next-line no-console + console.error(err); + alert("Invalid SQL fragments. Please check your inputs."); + } }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx(1 hunks)components/webui/client/src/sql-parser/index.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}
⚙️ CodeRabbit configuration file
- Prefer
false == <expression>rather than!<expression>.
Files:
components/webui/client/src/sql-parser/index.tscomponents/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx
🧠 Learnings (2)
📚 Learning: 2025-09-17T22:51:15.765Z
Learnt from: hoophalab
PR: y-scope/clp#1304
File: components/webui/client/src/sql-parser/index.ts:98-115
Timestamp: 2025-09-17T22:51:15.765Z
Learning: In the CLP webui codebase, when designing APIs that accept optional string parameters, developers should omit the value (pass undefined) rather than pass empty strings. The API contract should be clear that empty strings are not valid inputs - only undefined should be used to indicate omission of optional clauses.
Applied to files:
components/webui/client/src/sql-parser/index.ts
📚 Learning: 2025-06-09T17:48:56.024Z
Learnt from: junhaoliao
PR: y-scope/clp#988
File: components/log-viewer-webui/client/src/components/QueryBox/InputWithCaseSensitive/CaseSenstiveToggle.tsx:34-37
Timestamp: 2025-06-09T17:48:56.024Z
Learning: In the y-scope/clp project, prefer `false == <expression>` rather than `!<expression>` for boolean expressions in TypeScript/JavaScript files, as specified in the coding guidelines.
Applied to files:
components/webui/client/src/sql-parser/index.ts
🧬 Code graph analysis (2)
components/webui/client/src/sql-parser/index.ts (2)
components/webui/client/src/sql-parser/generated/SqlBaseParser.ts (1)
SqlBaseParser(19-10938)components/webui/client/src/sql-parser/generated/SqlBaseLexer.ts (1)
SqlBaseLexer(15-1482)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (2)
components/webui/client/src/sql-parser/index.ts (1)
buildSearchQuery(125-125)components/webui/client/src/pages/SearchPage/SearchControls/Presto/presto-search-requests.ts (1)
handlePrestoQuerySubmit(104-104)
🪛 Biome (2.1.2)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx
[error] 60-60: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 62-62: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 64-64: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 66-66: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 68-68: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: package-image
- GitHub Check: lint-check (macos-15)
- GitHub Check: lint-check (ubuntu-24.04)
🔇 Additional comments (2)
components/webui/client/src/sql-parser/index.ts (2)
49-66: Parser construction looks solid.Upper‑casing char stream + shared error listener for lexer/parser is correct and keeps case‑insensitive grammar behaviour.
77-84: Props shape LGTM (optional fragments viaundefined).Matches the agreed contract (omit optional fragments rather than pass empty strings).
Please confirm all call sites (including tests/Playgrounds) omit optional fields instead of sending
"".
davemarco
left a comment
There was a problem hiding this comment.
Some small comments. I am ready to approve after this
| {controls} | ||
| </form> | ||
| <> | ||
| <form onSubmit={handleSubmit}> |
There was a problem hiding this comment.
I think this is okay, since it still wont render without guided which is default false
| buildParser(sqlString).singleStatement(); | ||
| }; | ||
|
|
||
| interface BuildSearchQueryProps { |
There was a problem hiding this comment.
we could also maybe move the ascii types
There was a problem hiding this comment.
We usually keep function/component props interface in the original file?
if the errors look weird in testing, maybe we add this as a precheck in a later PR? |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (4)
47-58: Catch and surface parse/build errors; don’t crash the UI.Wrap Value.Parse/buildSearchQuery in try/catch, dev‑gate logs, and bail out on error. This prevents UX breakage on invalid fragments.
<form - onSubmit={(ev: FormEvent<HTMLFormElement>) => { + onSubmit={(ev: FormEvent<HTMLFormElement>) => { ev.preventDefault(); const formData = new FormData(ev.target as HTMLFormElement); - const props: Static<typeof BuildSearchQueryPropsSchema> = Value.Parse( - BuildSearchQueryPropsSchema, - Object.fromEntries(formData), - ); - - const sqlString = buildSearchQuery(props); - console.log(`SQL: ${sqlString}`); - handlePrestoQuerySubmit({queryString: sqlString}); + try { + const props = Value.Parse( + BuildSearchQueryPropsSchema, + Object.fromEntries(formData), + ); + const sqlString = buildSearchQuery(props); + if ("production" !== process.env.NODE_ENV) { + console.log(`SQL: ${sqlString}`); + } + handlePrestoQuerySubmit({queryString: sqlString}); + } catch (err) { + console.error(err); + alert("Invalid SQL fragments. Please check your inputs."); + } }} >
9-11: Type with the exported API type; drop Static to prevent drift.Keep UI strictly aligned with the parser’s public surface.
-import { - Static, - Type, -} from "@sinclair/typebox"; +import {Type} from "@sinclair/typebox"; import {Value} from "@sinclair/typebox/value"; -import {buildSearchQuery} from "../../../../sql-parser"; +import {buildSearchQuery, type BuildSearchQueryProps} from "../../../../sql-parser"; @@ - const props: Static<typeof BuildSearchQueryPropsSchema> = Value.Parse( + const props: BuildSearchQueryProps = Value.Parse( BuildSearchQueryPropsSchema, Object.fromEntries(formData), );Also applies to: 50-53, 3-7
60-71: Fix a11y label association; constrain limit as numeric; mark required fields.Resolves Biome errors and improves UX.
- <label>select:</label> - <input name={"selectItemList"}/> - <label>from:</label> - <input name={"relationList"}/> - <label>where:</label> - <input name={"booleanExpression"}/> - <label>order:</label> - <input name={"sortItemList"}/> - <label>limit:</label> - <input name={"limitValue"}/> + <label> + select: + <input name="selectItemList" placeholder="col1, col2, t.*" required /> + </label> + <label> + from: + <input name="relationList" placeholder="table1 t, table2" required /> + </label> + <label> + where: + <input name="booleanExpression" placeholder="t.col = 1 AND ..." /> + </label> + <label> + order: + <input name="sortItemList" placeholder="col1 DESC, col2" /> + </label> + <label> + limit: + <input name="limitValue" type="number" inputMode="numeric" min="0" step="1" /> + </label>
39-44: Tighten JSDoc phrasing and return tag./** - * Returns input boxes to test `buildSearchQuery`. + * Renders input boxes to test `buildSearchQuery`. * - * @return + * @returns JSX.Element */
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}
⚙️ CodeRabbit configuration file
- Prefer
false == <expression>rather than!<expression>.
Files:
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx
🧠 Learnings (1)
📚 Learning: 2024-11-21T15:51:33.203Z
Learnt from: junhaoliao
PR: y-scope/clp#596
File: components/log-viewer-webui/client/src/api/query.js:16-23
Timestamp: 2024-11-21T15:51:33.203Z
Learning: In `components/log-viewer-webui/client/src/api/query.js`, the `ExtractJsonResp` type definition is accurate as-is and does not require modification. When suggesting changes to type definitions, ensure they align with the server-side definitions, referencing the source code if necessary.
Applied to files:
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx
🧬 Code graph analysis (1)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (2)
components/webui/client/src/sql-parser/index.ts (1)
buildSearchQuery(125-125)components/webui/client/src/pages/SearchPage/SearchControls/Presto/presto-search-requests.ts (1)
handlePrestoQuerySubmit(104-104)
🪛 Biome (2.1.2)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx
[error] 60-60: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 62-62: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 64-64: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 66-66: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
[error] 68-68: A form label must be associated with an input.
Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.
(lint/a11y/noLabelWithoutControl)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: package-image
- GitHub Check: antlr-code-committed (macos-15)
🔇 Additional comments (1)
components/webui/client/src/pages/SearchPage/SearchControls/Presto/BuildSqlTestingInputs.tsx (1)
47-58: Await the submission if it’s async.If handlePrestoQuerySubmit returns a Promise, make the handler async and await it to surface network errors consistently.
- onSubmit={(ev: FormEvent<HTMLFormElement>) => { + onSubmit={async (ev: FormEvent<HTMLFormElement>) => { @@ - handlePrestoQuerySubmit({queryString: sqlString}); + await handlePrestoQuerySubmit({queryString: sqlString});
junhaoliao
left a comment
There was a problem hiding this comment.
deferring to @davemarco ’s review
Description
buildSqlQueryfunction to thesql-parserthat takes SQL query component strings as arguments and returns a valid SQL query.Checklist
breaking change.
Validation performed
Summary by CodeRabbit
New Features
Refactor