Skip to content

feat(db-browser): add SQLite database browser example#692

Open
RosheshChaware wants to merge 3 commits into
Karanjot786:mainfrom
RosheshChaware:feat-db-browser
Open

feat(db-browser): add SQLite database browser example#692
RosheshChaware wants to merge 3 commits into
Karanjot786:mainfrom
RosheshChaware:feat-db-browser

Conversation

@RosheshChaware
Copy link
Copy Markdown

@RosheshChaware RosheshChaware commented Jun 4, 2026

Description

Added a new SQLite Database Browser example under examples/db-browser.

The example seeds an in-memory SQLite database using bun:sqlite, displays tables and columns in a Tree view, and shows table rows in a Table wrapped inside a ScrollView. Selecting a table updates the row view and row count dynamically.

Related Issue

Closes #ISSUE_NUMBER

Which package(s)?

  • examples/db-browser

Type of Change

  • ✨ Feature (type:feature)

Checklist

  • ⭐ You starred the repo.
  • Tests pass locally: bun vitest run
  • Build passes: bun run build
  • Typecheck passes: bun run typecheck
  • You read CONTRIBUTING.md.
  • Your PR title follows type: short description.
  • No new any types without an inline comment explaining why.
  • No unrelated refactors bundled into this PR.

GSSoC 2026 Participation

  • You are a GSSoC 2026 contributor.
  • Your GSSoC profile: https://gssoc.girlscript.org/profile/YOUR_PROFILE_ID

Screenshots / Recordings (UI changes)

Attached screenshot showing:

  • Tree of tables and columns on the left
  • Table rows on the right
  • Dynamic table switching using keyboard navigation

Notes for the Reviewer

  • All changes are confined to examples/db-browser.
  • Uses bun:sqlite with an in-memory seeded database.
  • Supports keyboard navigation, live table updates, row count display, and clean exit with q / Ctrl+C.
  • No changes were made under packages/.
Screenshot 2026-06-04 145953

Summary by CodeRabbit

  • New Features

    • Added an interactive SQLite database browser example with table browsing, keyboard navigation (including pane switching) and quick-exit shortcuts; the example includes runnable start/dev scripts.
  • Tests

    • Added a test suite validating startup rendering, table switching, navigation keys, pane toggling, and exit behavior.
  • Chores

    • Added TypeScript and test configurations for the example.

@github-actions github-actions Bot added area:examples Example apps. type:testing +10 pts. Tests. type:feature +10 pts. New feature. labels Jun 4, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f0a0503b-6177-4c80-ad47-2c1ddd3e0edf

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new TermUI example: a fullscreen SQLite database browser (DbBrowserApp) with schema tree, table viewer, keyboard navigation, startup/bootstrap entrypoint, configuration files, and a Vitest suite exercising navigation and exit behavior.

Changes

Database Browser Example App

Layer / File(s) Summary
Project Configuration
examples/db-browser/package.json, examples/db-browser/tsconfig.json, examples/db-browser/vitest.config.ts
Package manifest with Bun scripts, TypeScript config enabling @termuijs/jsx, and Vitest config for the example.
Schema tree and key translation helpers
examples/db-browser/src/index.tsx (imports, quoteSqliteIdentifier, buildDbTree, coreKeyToTreeKey, coreKeyToScrollKey)
Identifier quoting, buildDbTree() reads sqlite_master and PRAGMA metadata to build a tree of tables and columns; key translators map core KeyEvent names to Tree/ScrollView keys.
DbBrowserApp Widget
examples/db-browser/src/index.tsx (DbBrowserApp class, UI, load/focus/sync/keys)
DbBrowserApp composes header/tree/scroll/table/footer, selects initial table, _loadTable() queries rows and rebuilds Table, _updateFocus() toggles focused pane, _syncSelectedTable() reloads on selection change, and handleKey() handles quit/tab/delegation.
Application entry and bootstrap
examples/db-browser/src/index.tsx (main, import.meta.main)
main() creates the in-memory schema/data, mounts the app fullscreen, routes key events to request renders or close, closes DB on exit, and bootstraps via import.meta.main.
Vitest suite
examples/db-browser/src/index.test.tsx
Test helpers (makeKey, renderToText), in-memory SQLite fixture, and tests validating startup rendering, table navigation, pane toggling, exit behavior, and footer row count.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

🐰 A tiny rabbit taps the keys with cheer,
Rows and columns hop and gently appear.
Trees on the left, the table to the right,
Tab to leap, q to say goodnight.
Hop, hop — the DB hums in terminal light!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(db-browser): add SQLite database browser example' clearly and concisely describes the main change: adding a new SQLite database browser example.
Description check ✅ Passed The PR description covers the main requirements: description of changes, related issue reference, package specification, type of change checkbox, most checklist items, GSSoC participation, and review notes. However, the related issue reference shows a placeholder (Closes #ISSUE_NUMBER) rather than an actual issue number.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Thanks for your first PR to TermUI, @RosheshChaware.

Before your PR merges:

  1. Star the repo. Required. The star-check job blocks your merge otherwise.
  2. ✅ All checks green: build, test, typecheck.
  3. 🏷 PR title follows type: short description. Example: fix: handle empty list.
  4. 🔗 Link your closing issue in the description.

GSSoC 2026 points come from labels after merge:

  • gssoc:approved. +50 base points.
  • level:beginner / intermediate / advanced / critical. +20 / +35 / +55 / +80.
  • quality:clean / exceptional. x 1.2 / x 1.5.
  • type:*. Stackable bonus.

Your reviewer responds within 48 hours. Ping @Karanjot786 on Discord for urgent help.

🚀 Welcome to the cohort.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
examples/db-browser/src/index.tsx (1)

9-11: ⚡ Quick win

Make table loading deterministic with explicit ordering.

The initial selected table depends on query order; without ORDER BY, startup behavior can vary across schema evolution and make tests brittle.

Suggested fix
-    const tables = db.query<{ name: string }, []>(
-        "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"
-    ).all();
+    const tables = db.query<{ name: string }, []>(
+        "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name"
+    ).all();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/db-browser/src/index.tsx` around lines 9 - 11, The table list query
is non-deterministic because it lacks ordering; update the SQL used in the
tables constant (the db.query(...) call that builds tables) to include an
explicit ORDER BY (e.g., ORDER BY name ASC) so the initial selected table is
stable across runs and schema changes; modify the query string inside the tables
assignment (the db.query call) to add the ORDER BY clause.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/db-browser/src/index.tsx`:
- Around line 151-154: The code uses unsafe casts like (firstTableNode.data as {
type: string }) and (selected.data as { type: string; name?: string; table?:
string }); replace these with a proper discriminated union for node data (e.g.,
type NodeData = TableNodeData | OtherNodeData with a literal "type" field) and
add a type guard function (e.g., isTableNode(data): data is TableNodeData) that
checks data.type === 'table' before accessing .name/.table, then use
isTableNode(firstTableNode.data) and isTableNode(selected.data) to narrow types;
alternatively, if you intentionally know the shape at those call sites, add a
short inline comment justifying the cast (e.g., // safe: node.type === 'table'
ensured upstream) and keep the existing assertions.
- Around line 15-16: The SQL uses direct interpolation of table names (e.g.,
`PRAGMA table_info("${table.name}")` and `SELECT * FROM "${tableName}"`) which
fails for embedded double-quotes and is an injection risk; create a small helper
(e.g., quoteSqlIdentifier(name: string)) that escapes double quotes by replacing
" with "" and wraps the result in double quotes, then replace all places where
table.name or tableName are interpolated (the occurrences around the `PRAGMA
table_info(...)` call and the `SELECT * FROM ...` usages) to call this helper so
identifiers are safely quoted and reused everywhere.

In `@examples/db-browser/vitest.config.ts`:
- Line 3: The config currently uses a default export; change it to a named
export to follow TS rules: replace the `export default defineConfig(...)` with a
named export (for example `export const vitestConfig = defineConfig(...)`) and
update any consumers that import the config (change default imports to named
imports of `vitestConfig` or whatever name you choose). Ensure the symbol
`defineConfig` remains used and the new exported identifier is consistent across
imports.

---

Nitpick comments:
In `@examples/db-browser/src/index.tsx`:
- Around line 9-11: The table list query is non-deterministic because it lacks
ordering; update the SQL used in the tables constant (the db.query(...) call
that builds tables) to include an explicit ORDER BY (e.g., ORDER BY name ASC) so
the initial selected table is stable across runs and schema changes; modify the
query string inside the tables assignment (the db.query call) to add the ORDER
BY clause.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5dbe0581-f269-4c14-91f6-53c437ca24b2

📥 Commits

Reviewing files that changed from the base of the PR and between c36cc8c and 52748c3.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • examples/db-browser/package.json
  • examples/db-browser/src/index.test.tsx
  • examples/db-browser/src/index.tsx
  • examples/db-browser/tsconfig.json
  • examples/db-browser/vitest.config.ts

Comment thread examples/db-browser/src/index.tsx Outdated
Comment thread examples/db-browser/src/index.tsx Outdated
@@ -0,0 +1,13 @@
import { defineConfig } from 'vitest/config';

export default defineConfig({
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace default export with named export in config file.

Line 3 uses export default, which violates the repository TypeScript export rule. Use a named export instead (e.g., export const vitestConfig = defineConfig(...)), and update the consumer if needed.

As per coding guidelines: "**/*.{ts,tsx}: Use named exports only. Never export default."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/db-browser/vitest.config.ts` at line 3, The config currently uses a
default export; change it to a named export to follow TS rules: replace the
`export default defineConfig(...)` with a named export (for example `export
const vitestConfig = defineConfig(...)`) and update any consumers that import
the config (change default imports to named imports of `vitestConfig` or
whatever name you choose). Ensure the symbol `defineConfig` remains used and the
new exported identifier is consistent across imports.

@Karanjot786 Karanjot786 added gssoc:approved Approved PR. Earns +50 base points. quality:clean x 1.2 multiplier. Clean implementation. level:intermediate +35 pts. Moderate task. labels Jun 4, 2026
@Karanjot786
Copy link
Copy Markdown
Owner

Review: Unsafe type casts in db-browser example

In examples/db-browser/src/index.tsx around lines 151-154, the code uses as { type: string } casts.

Replace them with a type guard:

type TableNodeData = { type: 'table'; name: string };
type ColumnNodeData = { type: 'column'; name: string; table: string };
type NodeData = TableNodeData | ColumnNodeData;

function isTableNode(data: unknown): data is TableNodeData {
    return typeof data === 'object' && data !== null && (data as any).type === 'table';
}

Then use isTableNode(node.data) instead of the casts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:examples Example apps. gssoc:approved Approved PR. Earns +50 base points. level:intermediate +35 pts. Moderate task. quality:clean x 1.2 multiplier. Clean implementation. type:feature +10 pts. New feature. type:testing +10 pts. Tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants