Skip to content

feat(query): add visual SQL query builder for SQL-capable connections#165

Merged
Mananwebdev160408 merged 1 commit into
Mananwebdev160408:mainfrom
anshul23102:feat/sql-query-builder
Jul 16, 2026
Merged

feat(query): add visual SQL query builder for SQL-capable connections#165
Mananwebdev160408 merged 1 commit into
Mananwebdev160408:mainfrom
anshul23102:feat/sql-query-builder

Conversation

@anshul23102

Copy link
Copy Markdown
Contributor

Summary

Closes #155.

dbportal already had a VisualQueryBuilder component, but it is MongoDB only (it builds a $ne/$regex/$exists filter object) and is gated entirely behind capabilities.structuredQuery, which is only true for the mongodb driver. Every SQL-capable connection (postgres, mysql, sqlite, mssql) had nothing but a raw SQL textarea and zero visual builder, despite the issue's title specifically asking for a way to construct queries "without raw SQL".

This PR adds a real SQL query builder for those connections, covering the acceptance criteria directly.

What Was Changed

  • frontend/src/components/views/SqlQueryBuilder.tsx (new): a self-contained builder that fetches live schema via GET /api/schema, then lets the user:
    • pick a table from a dropdown
    • toggle SELECT columns via checkboxes (none checked = *)
    • add/remove WHERE conditions as column operator value rows, each joined to the previous one by a per-row AND/OR connector
    • set ORDER BY column + direction
    • set LIMIT
    • see a live, read-only SQL preview that updates on every change, with a Copy button
    • dialect-aware generation: MySQL uses backtick identifiers, SQL Server uses bracket identifiers and SELECT TOP n instead of a trailing LIMIT, everything else uses double-quoted identifiers with LIMIT
    • builder state (table, columns, conditions, order, limit) persisted to localStorage per dbId, so it survives a page refresh
  • frontend/src/components/views/QueryWorkbench.tsx: adds a "Show/Hide Builder" toggle (visibility also persisted) above the existing raw query tabs, shown whenever the active connection supports raw SQL. "Insert into Editor" writes the generated SQL into the active tab through the existing setRawQuery() path, the same mechanism already used by the Mongo builder and the quick-example buttons, so the existing "Run Query" button executes it and results render in the existing table/JSON views with no new execution path needed.
  • frontend/src/index.css: styles for the builder panel, column checkboxes, condition rows, and the SQL preview block, matching the existing query-group/query-input/query-example-btn conventions already used elsewhere in this file.

Acceptance Criteria (from the issue)

  • Selecting a table populates the column list from live schema metadata — fetched from /api/schema.
  • Adding and removing WHERE conditions updates the query preview in real time.
  • "Run" executes the generated query and shows results without errors — via "Insert into Editor" + the existing Run Query button.
  • Builder state survives a page refresh — localStorage, verified live (see below).
  • The generated query is syntactically correct for each supported database type — dialect-aware identifier quoting and LIMIT/TOP handling.

The issue's "Multi-database Translation" section also asks for MongoDB find() and Redis SCAN/HGETALL output. MongoDB already has its own (separate, pre-existing) visual builder in this codebase; Redis's driver doesn't implement query() at all currently (rawQuery: false, structuredQuery: false in its capabilities), so there's no query execution path to attach a builder to there. I scoped this PR to the SQL drivers, where the gap was real and total (0% builder coverage), rather than take on a Redis query-execution feature that doesn't otherwise exist yet.

Test Plan

  • npx vitest run — 22 passed (unchanged, this feature doesn't touch backend logic beyond the pre-existing /api/schema endpoint)
  • npm run lint (tsc --noEmit) — clean
  • npm run check-format — clean
  • npm run build — succeeds
  • Verified live against a real sqlite database with a temporary dev server:
    • Selected the users table, columns populated as real schema-derived checkboxes (id, name, age, email)
    • Checked name and age, added a condition age > 20, watched the preview update in real time to SELECT "name", "age" FROM "users" WHERE "age" > 20 LIMIT 100;
    • Clicked "Insert into Editor", confirmed the raw editor textarea now contained that exact SQL
    • Clicked "Run Query", confirmed POST /api/query?dbId=primary returned 200 with the correctly filtered and projected rows ([{name: "Alice", age: 30}, {name: "Bob", age: 25}])
    • Reloaded the page and confirmed the builder preview still showed the exact same generated SQL, proving the persisted state survived the refresh

Unrelated CI-blocking fixes included

Same fixes from PR #163/#164 (neither merged yet, so this branch needed them independently to pass CI):

  • frontend/src/components/Toolbar.tsx had duplicate aria-label attributes on two buttons, a TypeScript JSX compile error (TS17001) that fails npm run build.
  • frontend/src/App.tsx and src/cli.ts had Prettier formatting violations that fail npm run check-format. Ran prettier --write only, no logic changes.

Related Issues / PRs

None beyond #163/#164 (different branches, unmerged, share the same unrelated fixes noted above).

Addresses issue Mananwebdev160408#155. dbportal already had a VisualQueryBuilder
component, but it is MongoDB-only (builds a $ne/$regex/$exists filter
object) and is gated entirely behind capabilities.structuredQuery, which
is only true for the mongodb driver. Every SQL-capable connection
(postgres, mysql, sqlite, mssql) had nothing but a raw SQL textarea, with
no visual builder at all, despite the issue's title specifically asking
for a way to construct queries "without raw SQL".

- frontend/src/components/views/SqlQueryBuilder.tsx (new): a self
  contained builder that fetches live schema via GET /api/schema, and
  lets the user pick a table, toggle SELECT columns, add/remove WHERE
  conditions (column/operator/value rows joined by a per-row AND/OR
  connector), set ORDER BY column + direction, and set LIMIT. Renders a
  live, read-only SQL preview with a Copy button, and dialect-aware
  generation: MySQL uses backtick identifiers, SQL Server uses
  bracket identifiers plus `SELECT TOP n` instead of a trailing LIMIT,
  everything else uses double-quoted identifiers and LIMIT. Builder
  state (table, columns, conditions, order, limit) is persisted to
  localStorage per dbId so it survives a page refresh, per the issue's
  acceptance criteria.
- frontend/src/components/views/QueryWorkbench.tsx: adds a "Show/Hide
  Builder" toggle (visibility persisted too) above the existing raw
  query tabs when the active connection supports raw SQL. "Insert into
  Editor" writes the generated SQL into the active tab via the existing
  setRawQuery() path (same convention already used by the Mongo builder
  and the quick-example buttons), so the existing Run Query button
  executes it and results render in the existing table/JSON view with
  no new execution path needed.
- frontend/src/index.css: styles for the builder panel, column
  checkboxes, condition rows, and the SQL preview block, matching the
  existing query-group/query-input/query-example-btn conventions
  already used elsewhere in this file.

Verified live with a real sqlite database and a temporary dev server:
selecting a table populated real columns from schema, checking name/age
and adding a WHERE age > 20 condition updated the SQL preview in real
time to `SELECT "name", "age" FROM "users" WHERE "age" > 20 LIMIT 100;`,
Insert into Editor placed it in the raw editor, Run Query executed it
(POST /api/query -> 200, correct filtered/projected rows back), and a
full page reload restored the exact same builder state from
localStorage.

Also fixes the same duplicate aria-label build failure and App.tsx/
cli.ts formatting violations described in PR Mananwebdev160408#163/Mananwebdev160408#164 (neither merged
yet, so this branch needed the same fixes independently to pass CI).

Signed-off-by: Anshul Jain <aj.ts1758@gmail.com>
@anshul23102

Copy link
Copy Markdown
Contributor Author

@Mananwebdev160408 Requesting review for this feature!

This PR addresses issue #155 (SQL query builder) delivering:

  • New SqlQueryBuilder component for visual query construction without raw SQL
  • Support for all SQL-capable connections (PostgreSQL, MySQL, SQLite, MSSQL)
  • Column selection, WHERE conditions (with AND/OR logic), ORDER BY, LIMIT
  • Live SQL preview with dialect-aware identifier quoting and TOP/LIMIT handling
  • Builder state persistence to localStorage (survives page reload per acceptance criteria)
  • Copy-to-clipboard for generated SQL
  • Full-browser verification against real SQLite database

For GSSoC tracking, please add:

  • gssoc-2026 label (tracking)
  • gssoc:approved label (when ready)

Given the frontend focus and user-experience enhancement nature, labels like frontend, feature, or ux might be worth considering alongside the base GSSoC labels. This directly improves usability for analysts and junior developers who prefer visual query building over raw SQL.

Thanks for the review!

@Mananwebdev160408
Mananwebdev160408 merged commit 01eb363 into Mananwebdev160408:main Jul 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add Query Builder UI for Constructing Queries Without Raw SQL

2 participants