Skip to content

Release/260402#63

Merged
codeErrorSleep merged 15 commits into
mainfrom
release/260402
Apr 8, 2026
Merged

Release/260402#63
codeErrorSleep merged 15 commits into
mainfrom
release/260402

Conversation

@codeErrorSleep

@codeErrorSleep codeErrorSleep commented Apr 7, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added Oracle database driver support with full connection, querying, and data exploration capabilities
    • Added complex value viewer for expanded viewing of JSON and array data in table cells
    • Added column name autocomplete in WHERE and ORDER BY filter inputs
  • Improvements

    • Enhanced PostgreSQL array type display in query results
    • Improved sidebar navigation to auto-scroll to selected tables
    • Improved connection error messages for Oracle client setup issues
  • Documentation

    • Added comprehensive database driver development guide and automated scaffolding checklist
  • Chores

    • Version bumped to 0.3.2
    • Streamlined release process

codeErrorSleep and others added 15 commits April 2, 2026 14:56
Add unit tests for previously uncovered logic in the frontend layer:

- api.ts: isTauri(), normalizeImportDriver(), getImportDriverCapability(),
  invoke routing (Tauri path, mock mode, error fallback), and command name
  mapping for all API namespaces
- DataGrid/tableView/utils.ts: sortRows, collectSearchMatches, escapeSQL,
  quoteIdent, calculateAutoColumnWidths, and additional formatSQLValue cases
- connection-form/rules.ts: isMysqlFamilyDriver, isFileBasedDriver,
  allowsHostWithPort, requiresPasswordOnCreate, normalizeTextValue
- connection-form/validate.ts: happy paths, required field validation,
  password rules per driver and mode, host format checks
- sqlEditorDatabase.ts: normalizeDatabaseOptions and resolvePreferredDatabase
  edge cases (empty list, no fallback, all-undefined params)
- keyboard.ts: isModKey boolean combinations and null target guard
- Sidebar/connection-list/helpers.ts: sanitizeConnectionErrorMessage,
  getExportFilter, and getConnectionStatusLabel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PolarDB-X returns a vendor-specific error message containing
"Preparedoes not support" rather than the standard error code 1295,
causing queries to fail instead of falling back to simple protocol.

Extend is_prepared_protocol_unsupported_error() to match this variant
and add a regression test with the exact PolarDB-X error string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create src/lib/driver-registry.tsx as the single source of truth for
all driver attributes (ports, flags, icons, import capability). Update
api.ts, rules.ts, helpers.tsx, ConnectionList.tsx, and SavedQueriesList.tsx
to derive data from the registry instead of inline arrays/switch statements.
Adding a new driver now requires editing only one file.

Add driver-registry.unit.test.ts with 28 test cases covering all
helper functions and registry invariants.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add .claude/commands/new-db.md: /new-db slash command that scaffolds
  all boilerplate for a new database driver (Rust driver file, mod.rs
  registration, ssh.rs port, connection_input, Cargo.toml, frontend
  driver-registry, i18n, integration test skeleton)
- Add ADD_NEW_DB.md: precise reference checklist with exact file paths,
  line numbers, and common pitfalls for adding a new database driver
- Update CLAUDE.md: link to ADD_NEW_DB.md from the driver development
  section so Claude loads it automatically on each session

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement Oracle driver via the `oracle` crate (OCI-based), register it
in the driver enum and connection dispatcher, add SSH tunnel default port
(1521), wire up import transaction SQL (SELECT 1 FROM DUAL / COMMIT /
ROLLBACK), and register the driver config in the frontend registry.

Unit tests updated to reflect 9 supported drivers and Oracle-specific
capabilities (schema browsing, import support).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add driver integration tests (oracle_integration.rs), command integration
tests (oracle_command_integration.rs), and shared test context helper
(oracle_context.rs). Update test-integration.sh to support IT_DB=oracle
and include Oracle tests in the `all` target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PostgreSQL array columns (_INT2/4/8, _FLOAT4/8, _BOOL, _TEXT, _VARCHAR,
_BPCHAR, _NAME, _UUID, _NUMERIC, _JSON, _JSONB) were previously falling
through to the String fallback and rendering as "{1,2,3}" in the grid.
Now decoded as proper serde_json::Value::Array with correct element types
and NULL element support.

Also adds ComplexValueViewer dialog (JSON / Tree / Table tabs) for
inspecting complex cell values, fixes cell editing to show full JSON
instead of [object Object], and centralises all cell→string conversions
into a single cellValueToString() utility to eliminate duplicate logic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The cliff.zh.toml config file doesn't exist, so the Chinese changelog
step was not producing actual Chinese output. Simplify the workflow to
only generate English changelog.
- SQL editor Run button shows spinner and disables during query execution,
  preventing duplicate submissions (derives state from existing activeQueryId)
- Clicking a table in the sidebar now creates a placeholder tab immediately
  with a skeleton screen, replacing blank wait time with instant feedback
- Sidebar database/table tree nodes show a spinner while lazily loading
  children (tables or columns), tracked per-node via Set<string> state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sidebar tabs were capped at max-w-[200px] from the base TabsTrigger
component, leaving gaps when sidebar was wider than 400px. JSON viewer
tabs lacked flex-1, so they only took content width and left the right
side empty.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces Oracle database driver support to DbPaw, including a complete Rust driver implementation with SSH tunneling, new TypeScript-based driver registry system, UI enhancements for complex value viewing and table interactions, extensive documentation for adding new database drivers, and integration test coverage.

Changes

Cohort / File(s) Summary
Oracle Database Driver
src-tauri/src/db/drivers/oracle.rs, src-tauri/src/db/drivers/mod.rs, src-tauri/Cargo.toml, src-tauri/src/ssh.rs, src-tauri/src/commands/transfer.rs, src-tauri/src/connection_input/...
New Oracle driver with 13 DatabaseDriver trait methods, connection pooling via tokio::task::spawn_blocking, support for SSH tunneling, schema/table/view discovery via ALL_USERS/ALL_TABLES/ALL_VIEWS, paginated data retrieval with OFFSET ... FETCH NEXT, DDL extraction via DBMS_METADATA.GET_DDL, and DML/DDL execution. Added default port mapping (1521), error hint for missing Oracle Instant Client (DPI-1047), and transaction SQL mappings (SELECT 1 FROM DUAL). Enhanced MySQL driver array type detection for PolarDB-X.
Driver Registry System
src/lib/driver-registry.tsx, src/lib/driver-registry.unit.test.ts, src/lib/connection-form/rules.ts, src/services/api.ts
Centralized TypeScript driver registry replacing hardcoded driver lists. Exports 9-driver configuration (PostgreSQL, MySQL, MariaDB, TiDB, SQLite, DuckDB, ClickHouse, SQL Server, Oracle) with metadata (label, default port, capabilities, icon renderer). Provides helpers: getDefaultPort, isFileBasedDriver, isMysqlFamilyDriver, supportsSSLCA, supportsCreateDatabase, getConnectionIcon. Updated downstream consumers to import from registry instead of maintaining local driver sets.
Complex Value Viewer & Table UX
src/components/business/DataGrid/ComplexValueViewer.tsx, src/components/business/DataGrid/TableView.tsx, src/components/business/DataGrid/tableView/ColumnAutocompleteInput.tsx, src/components/business/DataGrid/tableView/columnAutocomplete.ts, src/components/business/DataGrid/tableView/utils.ts
New ComplexValueViewer modal component supporting JSON/Tree/Table representations of nested objects/arrays. Added column-name autocomplete in WHERE/ORDER BY inputs via ColumnAutocompleteInput. Enhanced TableView with isLoading skeleton state, cell hover-to-expand for complex values, and utilities (formatCellValue, cellValueToString, isComplexValue) for consistent formatting across editing/searching/export paths.
App Loading & Sidebar Reveal Logic
src/App.tsx, src/components/business/Sidebar/Sidebar.tsx, src/components/business/Sidebar/ConnectionList.tsx, src/components/business/Editor/SqlEditor.tsx
Added SidebarRevealRequest type with monotonically-increasing ID for synchronizing sidebar navigation across tab changes. Implemented placeholder table tab creation with isLoading: true state that transitions to full content on load success. Updated sidebar reveal to trigger on main-tab change, tab close, and keyboard shortcuts. Added isExecuting prop to SqlEditor to show Loader2 spinner while queries run.
Sidebar Icon & Connection Helpers Consolidation
src/components/business/Sidebar/connection-list/helpers.tsx, src/components/business/Sidebar/connection-list/helpers.unit.test.ts, src/components/business/Sidebar/SavedQueriesList.tsx
Removed local getConnectionIcon implementation from sidebar helpers. Centralized icon rendering via shared getConnectionIcon from driver-registry. Includes alias handling for postgresql/pgsql and fallback to generic Server icon. Added unit test coverage for sanitizeConnectionErrorMessage, getExportFilter, getConnectionStatusLabel.
Connection Form Validation & Rules
src/lib/connection-form/rules.ts, src/lib/connection-form/rules.unit.test.ts, src/lib/connection-form/validate.unit.test.ts
Re-exported isMysqlFamilyDriver and isFileBasedDriver from registry, removing local hardcoded driver lists. Expanded unit test coverage for driver categories (mysql-family, file-based), required field validation (host, username, password), numeric bounds checking, IPv6 bracket notation support, and conditional rules across "create"/"edit" modes.
Oracle Integration Tests
src-tauri/tests/oracle_integration.rs, src-tauri/tests/oracle_command_integration.rs, src-tauri/tests/common/oracle_context.rs
Added Oracle-specific integration test suites covering connection testing, schema/table/view discovery, DDL retrieval, data retrieval with pagination, SQL execution (SELECT/INSERT/DML), and error handling with [CONN_FAILED] tag validation. Includes test context helper reading Oracle connection details from environment variables (host, port, username, password, service name, schema) with IT_REUSE_LOCAL_DB requirement check.
PostgreSQL Array Type Support & Test Coverage
src-tauri/src/db/drivers/postgres.rs, src-tauri/tests/postgres_integration.rs
Extended PostgreSQL driver to decode array-typed columns (_BOOL, _INT2, _INT4, _INT8, _FLOAT4, _FLOAT8, _NUMERIC, _TEXT, _VARCHAR, _BPCHAR, _NAME, _UUID, _JSON, _JSONB) as JSON arrays with per-element null handling. Added integration test verifying array columns with fully-populated, null-element, and empty arrays are correctly serialized.
Test Infrastructure & Utilities
src/components/business/DataGrid/tableView/columnAutocomplete.unit.test.ts, src/components/business/DataGrid/tableView/utils.unit.test.ts, src/lib/sqlEditorDatabase.unit.test.ts, src/lib/keyboard.unit.test.ts, src/services/api.unit.test.ts, src/lockfile.unit.test.ts, src/types/bun-test.d.ts
Added comprehensive unit test suites for column autocomplete logic, cell value formatting, SQL editor database selection, keyboard utilities, and API layer (including Tauri delegation/fallback/mock mode). Updated lockfile assertions to validate structural integrity and package.json sync instead of hardcoded version pins. Extended Bun test type declarations for beforeEach/afterEach hooks and import.meta.dir.
Mock Data & API Mocking
src/services/mocks.ts, src/services/api.unit.test.ts
Extended mock connection/table datasets to include "PostgreSQL JSONB Test" and json_test/pg_arrays tables with complex/array-type columns. Added mockComplexTypeData and mockArrayTypeData exports. Updated mockGetTableData and mockExecuteQuery to route table-specific result sets. Added comprehensive API unit tests simulating Tauri invocation, mock mode, and fallback error handling.
Documentation: Driver Development
.claude/commands/new-db.md, ADD_NEW_DB.md, docs/table-selection-optimization.md, CLAUDE.md
Added /new-db command documentation specifying end-to-end scaffolding checklist for new database drivers (struct definition, trait implementation, module registration, SSH port mapping, connection input normalization, frontend registry, integration tests, i18n). Added comprehensive ADD_NEW_DB.md with detailed backend/frontend integration steps, file locations, and common pitfalls. Added table-selection-optimization.md describing cell-range drag-select feature with state management and styling. Updated CLAUDE.md pointer.
Version & CI/CD
package.json, src-tauri/tauri.conf.json, .github/workflows/release.yml, scripts/test-integration.sh
Bumped version from 0.3.1 to 0.3.2. Removed Chinese changelog generation step from release workflow; single-language RELEASE_BODY now used. Extended scripts/test-integration.sh to support IT_DB=oracle, adding oracle_integration and oracle_command_integration test targets.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant App as App.tsx
    participant Sidebar as ConnectionList
    participant Driver as OracleDriver
    participant DB as Oracle DB
    participant Grid as TableView

    User->>App: Click table in sidebar
    App->>App: Create placeholder tab (isLoading=true)
    App->>Sidebar: Trigger revealSidebarForTab()
    Sidebar->>Sidebar: Update selectedTableNode
    App->>Driver: execute_query(SELECT * FROM table OFFSET 0 FETCH NEXT 50)
    Driver->>DB: Connect via OCI
    DB-->>Driver: ResultSet
    Driver->>Driver: Convert rows to JSON
    Driver-->>App: QueryResult with data
    App->>App: setTabs(isLoading=false, data=result)
    App->>Grid: Pass table data + isLoading=false
    Grid-->>User: Render table with complex value hover buttons
    User->>Grid: Hover on nested JSON cell
    Grid->>Grid: Open ComplexValueViewer modal
    Grid-->>User: Show JSON/Tree/Table tabs
Loading
sequenceDiagram
    participant Client as Frontend
    participant Registry as driver-registry
    participant FormRules as connection-form/rules
    participant API as api.ts

    Client->>Registry: Import DRIVER_REGISTRY, getDefaultPort()
    Registry-->>Client: [postgres, mysql, oracle, ...]
    Client->>FormRules: Call isMysqlFamilyDriver(driver)
    FormRules->>Registry: Import helper
    Registry-->>FormRules: Boolean
    FormRules-->>Client: Validation result
    Client->>API: normalizeImportDriver(driver)
    API->>Registry: getDriverConfig(normalized)
    Registry-->>API: DriverConfig
    API-->>Client: importCapability (supported/read_only/unsupported)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Release/260330 #53: Modifies overlapping code paths in src-tauri/src/connection_input/mod.rs and scripts/test-integration.sh for connection handling and integration test orchestration.

Poem

🐰 A new database hops onto the stage,
With Oracle's stride and Instant Client sage,
Complex values shimmer in viewer's array,
Column suggestions guide queries' way,
From sidebar to grid, a seamless ballet!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Release/260402' is a branch/version identifier that does not clearly summarize the actual changes in the pull request, which include Oracle driver support, UI enhancements, documentation, and version bump to 0.3.2. Use a more descriptive title that captures the main change, such as 'Add Oracle database driver support and UI improvements' or 'Release v0.3.2 with Oracle driver and enhanced table selection'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/260402

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

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Release 0.3.2 - Oracle driver, PostgreSQL arrays, centralized driver registry, and enhanced data handling

✨ Enhancement 🧪 Tests 🐞 Bug fix 📝 Documentation

Grey Divider

Walkthroughs

Description
• **Oracle database driver implementation**: Complete Rust driver with connection management, schema
  browsing, DDL retrieval, paginated data fetching, filtering, sorting, and query execution with
  proper type conversion
• **PostgreSQL array type support**: Added support for 10 array types (_BOOL, _INT2, _INT4,
  _INT8, _FLOAT4, _FLOAT8, _NUMERIC, _TEXT, _JSON, _JSONB) with proper null handling and
  JSON serialization
• **Centralized driver registry**: New driver-registry module consolidating driver configurations,
  capabilities, and utility functions to eliminate code duplication across frontend components
• **Complex data type handling**: New utilities and components for formatting, displaying, and
  editing complex values (JSON, arrays) including ComplexValueViewer modal with multiple view modes
  (JSON, Tree, Table)
• **Column autocomplete for SQL filters**: New ColumnAutocompleteInput component providing
  intelligent column name suggestions for WHERE and ORDER BY clauses with keyboard navigation
• **Loading state indicators**: Added loading spinners for table data fetching, query execution, and
  database/table expansion operations with improved UX
• **MySQL error handling improvement**: Enhanced prepared statement protocol error detection with
  PolarDB-X support
• **Comprehensive test coverage**: Added 15+ new unit and integration test files covering Oracle
  driver, PostgreSQL arrays, API service, connection validation, and utility functions
• **Documentation**: Added database driver scaffolding guides in English and Chinese, plus table
  selection optimization proposal
• **Version bump**: Updated to version 0.3.2 with simplified release workflow (removed Chinese
  changelog generation)
Diagram
flowchart LR
  A["Oracle Driver<br/>Implementation"] -->|"Registers in"| B["Driver Registry"]
  C["PostgreSQL Array<br/>Support"] -->|"Uses"| B
  B -->|"Powers"| D["Connection List<br/>& Forms"]
  E["Complex Value<br/>Utilities"] -->|"Enables"| F["ComplexValueViewer<br/>Modal"]
  G["Column Autocomplete<br/>Input"] -->|"Enhances"| H["Table View<br/>Filters"]
  I["Loading States"] -->|"Improves"| H
  J["Comprehensive<br/>Tests"] -->|"Validates"| B
  J -->|"Validates"| E
  J -->|"Validates"| G
Loading

Grey Divider

File Changes

1. src-tauri/src/db/drivers/oracle.rs ✨ Enhancement +817/-0

Oracle database driver implementation with full feature support

• Implements complete Oracle database driver with 817 lines of code
• Provides connection management, table/schema browsing, and DDL retrieval
• Implements paginated data fetching with filtering and sorting support
• Includes query execution for both DML/DDL and SELECT statements with proper type conversion

src-tauri/src/db/drivers/oracle.rs


2. src-tauri/tests/oracle_integration.rs 🧪 Tests +254/-0

Oracle driver integration test suite

• Adds comprehensive integration tests for Oracle driver functionality
• Tests connection, schema listing, table operations, and data retrieval
• Validates pagination, DDL retrieval, and query execution
• Includes error handling and connection failure scenarios

src-tauri/tests/oracle_integration.rs


3. src-tauri/tests/oracle_command_integration.rs 🧪 Tests +276/-0

Oracle command integration tests

• Adds command-level integration tests for Oracle operations
• Tests connection validation, database listing, and table metadata
• Validates SELECT, INSERT, and pagination through command layer
• Includes error handling for invalid SQL and pagination

src-tauri/tests/oracle_command_integration.rs


View more (43)
4. src-tauri/tests/common/oracle_context.rs 🧪 Tests +39/-0

Oracle test context and environment configuration

• Provides test context helper for Oracle integration tests
• Reads Oracle connection parameters from environment variables
• Supports local database reuse mode for testing
• Defines default values for host, port, user, service, and schema

src-tauri/tests/common/oracle_context.rs


5. src-tauri/src/db/drivers/mod.rs ✨ Enhancement +23/-1

Oracle driver registration and error handling

• Adds oracle module to driver registry
• Registers OracleDriver in the connection factory
• Adds Oracle-specific error hint for missing Instant Client library
• Includes unit test for Oracle client library error detection

src-tauri/src/db/drivers/mod.rs


6. src-tauri/src/db/drivers/postgres.rs ✨ Enhancement +132/-0

PostgreSQL array type support in query results

• Adds support for PostgreSQL array types (_BOOL, _INT2, _INT4, _INT8, _FLOAT4, _FLOAT8,
 _NUMERIC, _TEXT, _JSON, _JSONB)
• Converts array columns to JSON arrays with proper null element handling
• Handles empty arrays and column-level NULL values correctly

src-tauri/src/db/drivers/postgres.rs


7. src-tauri/tests/postgres_integration.rs 🧪 Tests +147/-0

PostgreSQL array type integration test

• Adds comprehensive test for PostgreSQL array type handling
• Tests all array types including primitives, strings, booleans, and JSONB
• Validates null elements within arrays and empty arrays
• Verifies proper JSON serialization of array data

src-tauri/tests/postgres_integration.rs


8. src-tauri/src/db/drivers/mysql.rs 🐞 Bug fix +7/-1

MySQL prepared statement error handling enhancement

• Improves prepared statement protocol error detection
• Adds support for PolarDB-X error message pattern
• Fixes formatting inconsistency with extra blank line

src-tauri/src/db/drivers/mysql.rs


9. src-tauri/src/commands/transfer.rs ✨ Enhancement +5/-0

Oracle transaction SQL support for data import

• Adds Oracle transaction SQL configuration for import operations
• Defines Oracle-specific test query, commit, and rollback statements
• Includes unit test for Oracle transaction SQL configuration

src-tauri/src/commands/transfer.rs


10. src-tauri/src/ssh.rs ✨ Enhancement +1/-0

Oracle SSH tunnel port configuration

• Adds default SSH tunnel port 1521 for Oracle driver
• Enables SSH tunneling support for Oracle connections

src-tauri/src/ssh.rs


11. src/services/mocks.ts ✨ Enhancement +295/-6

Mock data expansion for complex and array types

• Adds PostgreSQL JSONB test connection to mock data
• Expands mock table data with complex JSON and array type examples
• Adds dedicated datasets for JSON and array type testing
• Implements mock query routing for json_test and pg_arrays tables

src/services/mocks.ts


12. src/components/business/DataGrid/tableView/utils.unit.test.ts 🧪 Tests +398/-0

DataGrid utility function unit tests

• Adds comprehensive unit tests for SQL formatting and escaping functions
• Tests identifier quoting for multiple database drivers
• Validates row sorting, search matching, and column width calculation
• Includes tests for complex value detection and cell formatting
• Adds PostgreSQL array column output validation tests

src/components/business/DataGrid/tableView/utils.unit.test.ts


13. src/lib/driver-registry.unit.test.ts 🧪 Tests +286/-0

Driver registry unit test suite

• Adds comprehensive test suite for driver registry
• Validates all 9 supported drivers including Oracle
• Tests registry invariants and driver capabilities
• Verifies schema browsing support for Oracle
• Tests connection icon resolution for all drivers

src/lib/driver-registry.unit.test.ts


14. src/lockfile.unit.test.ts 🧪 Tests +18/-105

Lockfile integrity test simplification

• Simplifies lockfile tests to verify package-lock.json integrity
• Validates metadata consistency between lockfile and package.json
• Removes overly specific version constraint tests
• Tests modern npm lockfile structure

src/lockfile.unit.test.ts


15. src/lib/connection-form/rules.unit.test.ts 🧪 Tests +65/-2

Connection form validation rules unit tests

• Adds tests for driver classification functions (isMysqlFamilyDriver, isFileBasedDriver)
• Tests host:port parsing and password requirement rules
• Adds tests for text value normalization
• Validates driver-specific connection form behavior

src/lib/connection-form/rules.unit.test.ts


16. src/services/api.unit.test.ts 🧪 Tests +273/-0

Comprehensive API service unit tests with mock setup

• Added comprehensive unit tests for API service functions (isTauri, normalizeImportDriver,
 getImportDriverCapability)
• Tests cover Tauri environment detection, driver name normalization, and import capability
 resolution
• Added tests for invoke routing logic (Tauri vs mock mode) and command mapping verification
• Includes mock setup for @tauri-apps/api/core and ./mocks modules

src/services/api.unit.test.ts


17. src/lib/connection-form/validate.unit.test.ts 🧪 Tests +99/-0

Connection form validation test coverage expansion

• Added happy path tests for valid connection forms (postgres and sqlite)
• Added required field validation tests (host, username, port, password)
• Added host format validation tests (whitespace, IPv6 bracket notation)
• Tests cover mode-specific behavior (create vs edit) and driver-specific rules (MySQL family)

src/lib/connection-form/validate.unit.test.ts


18. src/components/business/Sidebar/connection-list/helpers.unit.test.ts 🧪 Tests +92/-0

Connection list helper functions unit tests

• Added tests for sanitizeConnectionErrorMessage function (tag stripping, whitespace trimming)
• Added tests for getExportFilter function (CSV, JSON, SQL format filters)
• Added tests for getConnectionStatusLabel function (status state mapping and error message
 inclusion)

src/components/business/Sidebar/connection-list/helpers.unit.test.ts


19. src/components/business/DataGrid/tableView/utils.ts ✨ Enhancement +31/-2

Cell value formatting utilities for complex data types

• Replaced String(val) calls with formatCellValue(val) for consistent cell value formatting
• Added isComplexValue() helper to detect object/array values
• Added cellValueToString() for full-fidelity string conversion (used in editing/clipboard/export)
• Added formatCellValue() for display formatting with JSON serialization and truncation for large
 objects

src/components/business/DataGrid/tableView/utils.ts


20. src/components/business/DataGrid/tableView/columnAutocomplete.unit.test.ts 🧪 Tests +66/-0

Column autocomplete functionality unit tests

• Added tests for getAutocompleteToken function (token extraction, cursor positioning)
• Added tests for replaceAutocompleteToken function (token replacement logic)
• Added tests for getColumnAutocompleteOptions function (case-insensitive filtering and result
 capping)

src/components/business/DataGrid/tableView/columnAutocomplete.unit.test.ts


21. src/lib/sqlEditorDatabase.unit.test.ts 🧪 Tests +40/-0

Database normalization and resolution edge case tests

• Added tests for normalizeDatabaseOptions with empty input, blank filtering, and fallback
 deduplication
• Added tests for resolvePreferredDatabase covering edge cases (missing lists, empty values)
• Tests verify proper handling of undefined/empty states

src/lib/sqlEditorDatabase.unit.test.ts


22. src/services/api.ts ✨ Enhancement +8/-29

Driver registry centralization in API service

• Refactored Driver and ImportDriverCapability types to import from @/lib/driver-registry
• Updated getImportDriverCapability() to use DRIVER_REGISTRY lookup instead of hardcoded
 conditionals
• Simplified driver capability resolution logic

src/services/api.ts


23. src/components/business/DataGrid/tableView/columnAutocomplete.ts ✨ Enhancement +47/-0

Column autocomplete token and option utilities

• New module exporting column autocomplete utilities
• Implements getAutocompleteToken() for extracting identifier tokens before cursor
• Implements replaceAutocompleteToken() for token replacement in input strings
• Implements getColumnAutocompleteOptions() for filtering and capping autocomplete suggestions

src/components/business/DataGrid/tableView/columnAutocomplete.ts


24. src/lib/keyboard.unit.test.ts 🧪 Tests +29/-0

Keyboard utility functions unit tests

• Added tests for isModKey() function (metaKey/ctrlKey detection)
• Added tests for isEditableTarget() function (null target handling)
• Notes that DOM-dependent branches require integration/E2E tests

src/lib/keyboard.unit.test.ts


25. src/lib/connection-form/rules.ts ✨ Enhancement +5/-8

Driver classification functions centralization

• Removed local definitions of isMysqlFamilyDriver and isFileBasedDriver
• Now imports these functions from @/lib/driver-registry for centralized driver classification

src/lib/connection-form/rules.ts


26. src/types/bun-test.d.ts ⚙️ Configuration changes +6/-0

Bun test type definitions expansion

• Added beforeEach and afterEach type declarations for Bun test lifecycle hooks
• Added ImportMeta interface with dir property for test environment support

src/types/bun-test.d.ts


27. scripts/test-integration.sh ⚙️ Configuration changes +7/-1

Oracle database integration test support

• Added Oracle database integration test cases (oracle_integration and
 oracle_command_integration)
• Updated error message to include oracle in the list of valid IT_DB values
• Added Oracle tests to the all case for comprehensive test coverage

scripts/test-integration.sh


28. src/components/business/Sidebar/ConnectionList.tsx ✨ Enhancement +134/-135

Connection list refactoring with driver registry integration

• Imported driver registry functions (DRIVER_REGISTRY, getConnectionIcon, getDefaultPort,
 etc.)
• Replaced hardcoded driver arrays with registry-based lookups
• Refactored auto-scroll logic to use sidebarRevealRequest prop instead of interaction timers
• Added loading spinners for database and table expansion operations
• Replaced manual port/driver conditionals with getDefaultPort() and registry iteration
• Simplified driver-specific logic by delegating to registry helper functions

src/components/business/Sidebar/ConnectionList.tsx


29. .claude/commands/new-db.md 📝 Documentation +438/-0

Database driver scaffolding command documentation

• Comprehensive guide for scaffolding new database drivers in DbPaw
• Covers 9 implementation steps from Rust driver creation to integration tests
• Includes error prefix conventions, SSH tunnel setup, and frontend registry configuration
• Provides template code for driver struct, trait implementation, and test files

.claude/commands/new-db.md


30. ADD_NEW_DB.md 📝 Documentation +342/-0

Chinese database driver addition operational manual

• Chinese-language manual for adding new database drivers to DbPaw
• Details exact file paths, line numbers, and modification patterns
• Covers Rust backend setup, SSH configuration, frontend registry, and i18n
• Includes common pitfalls table and file modification checklist

ADD_NEW_DB.md


31. src/components/business/DataGrid/tableView/ColumnAutocompleteInput.tsx ✨ Enhancement +167/-0

Column autocomplete input component for SQL filters

• New component providing autocomplete input for WHERE and ORDER BY clauses
• Integrates column name suggestions with keyboard navigation (arrow keys, Enter)
• Displays filtered autocomplete options in a dropdown menu

src/components/business/DataGrid/tableView/ColumnAutocompleteInput.tsx


32. src/components/business/DataGrid/TableView.tsx ✨ Enhancement +77/-35

Table view enhancements with autocomplete and complex value viewer

• Added isLoading prop to display skeleton loaders while data is fetching
• Integrated ColumnAutocompleteInput for WHERE and ORDER BY filter inputs
• Added ComplexValueViewer modal for viewing/inspecting JSON/array cell values
• Replaced String() calls with cellValueToString() and formatCellValue() for better data
 handling
• Added hover button on complex value cells to open viewer modal
• Added column autocomplete options generation from table columns

src/components/business/DataGrid/TableView.tsx


33. docs/table-selection-optimization.md 📝 Documentation +365/-0

Table cell range selection optimization proposal

• Detailed analysis of current table selection issues (state clearing, lack of range selection, poor
 UX)
• Proposes Excel-like cell range drag selection implementation
• Provides step-by-step modification guide with code examples
• Includes CSS styling suggestions and optional keyboard shortcut enhancements

docs/table-selection-optimization.md


34. src/components/business/DataGrid/ComplexValueViewer.tsx ✨ Enhancement +281/-0

Complex value viewer modal component

• New modal component for viewing complex cell values (objects, arrays)
• Provides three view modes: JSON (formatted), Tree (hierarchical), Table (tabular)
• Includes copy-to-clipboard functionality for JSON representation
• Supports expandable tree nodes with depth-based indentation

src/components/business/DataGrid/ComplexValueViewer.tsx


35. src/components/business/Editor/SqlEditor.tsx ✨ Enhancement +9/-1

SQL editor query execution state indicator

• Added isExecuting prop to track query execution state
• Updated execute button to show loading spinner and disable during query execution
• Imported Loader2 icon for animated loading indicator

src/components/business/Editor/SqlEditor.tsx


36. src/App.tsx ✨ Enhancement +112/-48

App-level loading states and sidebar reveal coordination

• Added isLoading flag to TabItem interface for table loading state
• Added SidebarRevealRequest type for sidebar auto-scroll coordination
• Implemented getTableTargetFromTab() helper to extract table target from tab
• Added revealSidebarForTab() callback to trigger sidebar reveal on tab changes
• Modified table opening flow to create placeholder tab immediately with loading state
• Updated tab data loading to use state updates instead of creating new tabs
• Integrated sidebar reveal requests on tab navigation and closing
• Added isLoading prop to TableView component
• Added isExecuting prop to SqlEditor component

src/App.tsx


37. CLAUDE.md 📝 Documentation +2/-0

Documentation reference to driver scaffolding guide

• Added reference to ADD_NEW_DB.md for complete database driver scaffolding checklist
• Mentions /new-db skill for automated driver scaffolding

CLAUDE.md


38. src/lib/driver-registry.tsx ✨ Enhancement +198/-0

Centralized database driver registry and configuration

• New file creating a centralized driver registry for database connections
• Defines Driver type supporting 9 database systems (PostgreSQL, MySQL, MariaDB, TiDB, SQLite,
 DuckDB, ClickHouse, MSSQL, Oracle)
• Exports DriverConfig interface with connection properties and capabilities
• Provides utility functions to query driver configurations and render connection icons

src/lib/driver-registry.tsx


39. src/components/business/DataGrid/tableView/ColumnAutocompleteInput.tsx ✨ Enhancement +167/-0

Column autocomplete input component with suggestions

• New component implementing autocomplete input for column names with keyboard navigation
• Supports arrow keys for navigation, Tab/Enter to accept suggestions, Escape to close
• Manages cursor position and filtered suggestions using React hooks
• Displays suggestions in a popover with type information and hover highlighting

src/components/business/DataGrid/tableView/ColumnAutocompleteInput.tsx


40. src/components/business/Sidebar/Sidebar.tsx ✨ Enhancement +12/-4

Sidebar reveal request handling and layout improvements

• Added SidebarRevealRequest interface extending ActiveTableTarget with an id field
• Updated SidebarProps to include optional sidebarRevealRequest parameter
• Modified effect hook to trigger on sidebarRevealRequest instead of activeTableTarget
• Added max-w-none class to TabsTrigger elements for better layout control
• Passed sidebarRevealRequest to child components in both tree and tabs layouts

src/components/business/Sidebar/Sidebar.tsx


41. src/components/business/Sidebar/SavedQueriesList.tsx Refactoring +2/-56

Refactor to use centralized driver registry

• Removed duplicate getConnectionIcon function implementation
• Removed duplicate icon rendering logic and simple-icons imports
• Now imports getConnectionIcon from centralized @/lib/driver-registry module
• Simplified imports by removing unused icon components

src/components/business/Sidebar/SavedQueriesList.tsx


42. src/components/business/Sidebar/connection-list/helpers.tsx Refactoring +3/-59

Consolidate icon handling to driver registry

• Removed duplicate getConnectionIcon function implementation
• Removed all icon rendering logic and simple-icons imports
• Now re-exports getConnectionIcon from @/lib/driver-registry
• Kept only ConnectionStatusLike interface and status icon imports

src/components/business/Sidebar/connection-list/helpers.tsx


43. .github/workflows/release.yml ⚙️ Configuration changes +2/-14

Remove Chinese changelog generation from release workflow

• Removed Chinese changelog generation step using git-cliff-action
• Removed cliff.zh.toml configuration reference
• Simplified release body to use only English changelog
• Removed Chinese language suffix from release notes

.github/workflows/release.yml


44. package.json ⚙️ Configuration changes +1/-1

Bump package version to 0.3.2

• Updated version from 0.3.1 to 0.3.2

package.json


45. src-tauri/tauri.conf.json ⚙️ Configuration changes +1/-1

Bump Tauri app version to 0.3.2

• Updated version from 0.3.1 to 0.3.2

src-tauri/tauri.conf.json


46. src-tauri/Cargo.toml Dependencies +1/-0

Add Oracle database driver dependency

• Added oracle = "0.6" dependency to support Oracle database connections

src-tauri/Cargo.toml


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Apr 7, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2)   📘 Rule violations (1)   📎 Requirement gaps (0)   🎨 UX Issues (0)
🐞\ ≡ Correctness (2)
📘\ ≡ Correctness (1)

Grey Divider


Action required

1. test_connection() bypasses conn_failed_error() 📘
Description
OracleDriver::test_connection() converts Oracle connection/query errors to generic `[CONN_FAILED]
{e} strings, bypassing conn_failed_error()` and losing the standardized, user-friendly hints
required for connection failures. This can lead to inconsistent and less actionable error messages
in the UI.
Code

src-tauri/src/db/drivers/oracle.rs[R205-212]

+    async fn test_connection(&self) -> Result<(), String> {
+        self.run_blocking(|conn| {
+            conn.query("SELECT 1 FROM DUAL", &[] as &[&dyn oracle::sql_type::ToSql])
+                .map_err(|e| format!("[CONN_FAILED] {e}"))?
+                .next()
+                .ok_or("[CONN_FAILED] Empty response from DUAL")?
+                .map_err(|e| format!("[CONN_FAILED] {e}"))?;
+            Ok(())
Evidence
PR Compliance ID 3 requires user-facing connection failure paths to use conn_failed_error(). In
OracleDriver::test_connection(), errors are instead wrapped with format!("[CONN_FAILED] {e}"),
which bypasses conn_failed_error() and its hint logic.

CLAUDE.md
src-tauri/src/db/drivers/oracle.rs[205-212]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`OracleDriver::test_connection()` returns generic `[CONN_FAILED] {e}` strings for Oracle errors, bypassing `conn_failed_error()` which standardizes and enriches connection failure messages.

## Issue Context
Compliance requires connection failure paths to use `conn_failed_error()` so the UI can show consistent, user-friendly hints (e.g., Oracle Instant Client not installed, TLS/auth/network hints).

## Fix Focus Areas
- src-tauri/src/db/drivers/oracle.rs[205-212]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Oracle service name clobbered 🐞
Description
OracleDriver.connect reads ConnectionForm.database as the Oracle service name, but the
command-layer connection creation overwrites form.database with the request database parameter,
which (for Oracle) is coming from ALL_USERS schema names. This causes Oracle connections to
attempt //host:port/<SCHEMA> and fail in table browsing/export/metadata calls.
Code

src-tauri/src/db/drivers/oracle.rs[R142-154]

+        let service_name = effective_form
+            .database
+            .clone()
+            .map(|v| v.trim().to_string())
+            .filter(|v| !v.is_empty())
+            .unwrap_or_else(|| "ORCL".to_string());
+        let username = effective_form
+            .username
+            .clone()
+            .map(|v| v.trim().to_string())
+            .filter(|v| !v.is_empty())
+            .ok_or("[VALIDATION_ERROR] username cannot be empty")?;
+        let password = effective_form.password.clone().unwrap_or_default();
Evidence
Oracle treats database as the service name (used in the Easy Connect string). The Oracle driver’s
list_databases explicitly returns schema/user names, and the frontend passes those values as the
database argument in table selection/export/metadata. Separately, the backend replaces
form.database with the per-request database value before connecting, which overwrites the
service name and breaks Oracle connectivity.

src-tauri/src/db/drivers/oracle.rs[14-26]
src-tauri/src/db/drivers/oracle.rs[121-162]
src-tauri/src/db/drivers/oracle.rs[217-239]
src-tauri/src/commands/mod.rs[58-65]
src/components/business/Sidebar/ConnectionList.tsx[1202-1215]
src/components/business/DataGrid/TableView.tsx[378-433]
src-tauri/tests/common/oracle_context.rs[28-37]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Oracle uses `ConnectionForm.database` as the Easy Connect service name, but the backend currently overwrites `form.database` with the per-request `database` param. In the Oracle flow the UI uses the `database` param to represent a schema (from `ALL_USERS`), so this overwrite turns the service name into a schema name and breaks connections.

## Issue Context
- OracleDriver builds `//host:port/<service_name>` from `form.database`.
- `ensure_connection_with_db` unconditionally replaces `form.database` when a request provides a `database` value.
- For Oracle, `list_databases()` returns schemas/users, and the UI passes those values as the `database` request param.

## Fix Focus Areas
- src-tauri/src/commands/mod.rs[58-65]
- src-tauri/src/commands/mod.rs[97-105]
- src-tauri/src/db/drivers/oracle.rs[121-162]

## Suggested fix
1. In `ensure_connection_with_db` / `ensure_connection_with_db_from_app_state`, after loading the `form`, gate the `form.database = Some(db_name)` override by driver type.
  - For example: do **not** override `form.database` when `form.driver == "oracle"`.
  - (Optional) if you need the per-request value for Oracle, consider mapping it into `form.schema` instead (only when `form.schema` is empty), since schema is the Oracle-scoped concept.
2. (Optional but recommended) Add a regression test around `ensure_connection_with_db` to ensure an Oracle form’s `database` (service name) is preserved when a `database` request param is provided.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. WITH DML misrouted 🐞
Description
OracleDriver.execute_query treats any SQL whose first keyword is WITH as a read query and routes
it through conn.query() without committing. Oracle supports WITH-prefixed
INSERT/UPDATE/DELETE/MERGE, so those statements will either error as “not a query” or execute
without a commit.
Code

src-tauri/src/db/drivers/oracle.rs[R653-707]

+        let first_kw = first_sql_keyword(&sql_clean);
+        let is_read = matches!(
+            first_kw.as_deref(),
+            Some("select") | Some("with") | Some("show")
+        );
+
+        self.run_blocking(move |conn| {
+            if is_read {
+                let rows = conn
+                    .query(&sql_clean, &[] as &[&dyn oracle::sql_type::ToSql])
+                    .map_err(|e| format!("[QUERY_ERROR] {e}"))?;
+
+                // Collect column metadata before consuming rows
+                let col_info: Vec<(String, String)> = rows
+                    .column_info()
+                    .iter()
+                    .map(|c| (c.name().to_string(), format!("{}", c.oracle_type())))
+                    .collect();
+                let columns: Vec<QueryColumn> = col_info
+                    .iter()
+                    .map(|(name, ty)| QueryColumn {
+                        name: name.clone(),
+                        r#type: ty.clone(),
+                    })
+                    .collect();
+
+                let mut data = Vec::new();
+                for row_result in rows {
+                    let row = row_result.map_err(|e| format!("[QUERY_ERROR] {e}"))?;
+                    let mut map = serde_json::Map::new();
+                    for (i, (name, _)) in col_info.iter().enumerate() {
+                        map.insert(name.clone(), oracle_value_to_json(&row, i));
+                    }
+                    data.push(serde_json::Value::Object(map));
+                }
+
+                Ok(QueryResult {
+                    row_count: data.len() as i64,
+                    data,
+                    columns,
+                    time_taken_ms: start.elapsed().as_millis() as i64,
+                    success: true,
+                    error: None,
+                })
+            } else {
+                // DML or DDL — use Statement API to get affected-row count
+                let mut stmt = conn
+                    .statement(&sql_clean)
+                    .build()
+                    .map_err(|e| format!("[QUERY_ERROR] {e}"))?;
+                stmt.execute(&[] as &[&dyn oracle::sql_type::ToSql])
+                    .map_err(|e| format!("[QUERY_ERROR] {e}"))?;
+                let row_count = stmt.row_count().unwrap_or(0) as i64;
+                // Commit so the change is visible after the connection closes.
+                conn.commit().map_err(|e| format!("[QUERY_ERROR] commit failed: {e}"))?;
Evidence
The read/write decision is solely based on the first keyword and includes WITH in the read set;
only the non-read branch executes via Statement API and calls conn.commit(). A statement like
WITH cte AS (SELECT 1 FROM DUAL) INSERT INTO ... SELECT ... FROM cte is DML but will be treated as
read and not committed (or rejected by the query API).

src-tauri/src/db/drivers/oracle.rs[650-707]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`OracleDriver.execute_query` currently classifies all `WITH ...` statements as read-only and runs them via `conn.query()` without committing. Oracle allows `WITH` to prefix DML (INSERT/UPDATE/DELETE/MERGE), so this misclassification causes failures or uncommitted changes.

Concrete example that will be misclassified today:
```sql
WITH cte AS (SELECT 1 AS id, 'x' AS name FROM DUAL)
INSERT INTO MY_TABLE(id, name)
SELECT id, name FROM cte
```

## Issue Context
The current logic:
- `is_read` is true for `select | with | show`
- only the `else` branch calls `conn.commit()`

## Fix Focus Areas
- src-tauri/src/db/drivers/oracle.rs[650-707]

## Suggested fix approaches
Pick one:
1. **Safer fallback execution**
  - If `first_kw == Some("with")`, attempt to execute using the Statement API in a way that can handle both query and non-query:
    - Try building a statement and calling a query-style execution.
    - If that fails with a known “not a query / invalid statement type” Oracle error, retry with execute+commit.
  - Ensure you only fallback on specific, expected error codes/messages so you don’t mask real SQL errors.

2. **Parse second keyword for WITH**
  - When the first keyword is `WITH`, scan forward (token-based) for the first *non-CTE* keyword that determines the statement kind (`SELECT`, `INSERT`, `UPDATE`, `DELETE`, `MERGE`).
  - Treat `WITH ... SELECT` as read; treat `WITH ... INSERT/UPDATE/DELETE/MERGE` as write and commit.

Also add a unit/integration test covering a `WITH ... INSERT` statement to prevent regression.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review

Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: CI Success

Failed stage: Check all jobs succeeded [❌]

Failed test name: ""

Failure summary:

The action failed because the workflow step explicitly detected that the Smoke test job result was
failure (i.e., "failure" != "success"), printed Smoke tests failed, and exited with status code 1,
which caused the job to fail (Process completed with exit code 1).

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

28:  Metadata: read
29:  Models: read
30:  Packages: write
31:  Pages: write
32:  PullRequests: write
33:  RepositoryProjects: write
34:  SecurityEvents: write
35:  Statuses: write
36:  ##[endgroup]
37:  Secret source: Actions
38:  Prepare workflow directory
39:  Prepare all required actions
40:  Complete job name: CI Success
41:  ##[group]Run if [ "failure" != "success" ]; then
42:  �[36;1mif [ "failure" != "success" ]; then�[0m
43:  �[36;1m  echo "Smoke tests failed"�[0m
44:  �[36;1m  exit 1�[0m
45:  �[36;1mfi�[0m
46:  �[36;1mif [ "skipped" != "success" ]; then�[0m
47:  �[36;1m  echo "Integration tests failed"�[0m
48:  �[36;1m  exit 1�[0m
49:  �[36;1mfi�[0m
50:  �[36;1mecho "All CI checks passed!"�[0m
51:  shell: /usr/bin/bash -e {0}
52:  ##[endgroup]
53:  Smoke tests failed
54:  ##[error]Process completed with exit code 1.
55:  Cleaning up orphan processes

Comment on lines +205 to +212
async fn test_connection(&self) -> Result<(), String> {
self.run_blocking(|conn| {
conn.query("SELECT 1 FROM DUAL", &[] as &[&dyn oracle::sql_type::ToSql])
.map_err(|e| format!("[CONN_FAILED] {e}"))?
.next()
.ok_or("[CONN_FAILED] Empty response from DUAL")?
.map_err(|e| format!("[CONN_FAILED] {e}"))?;
Ok(())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. test_connection() bypasses conn_failed_error() 📘 Rule violation ≡ Correctness

OracleDriver::test_connection() converts Oracle connection/query errors to generic `[CONN_FAILED]
{e} strings, bypassing conn_failed_error()` and losing the standardized, user-friendly hints
required for connection failures. This can lead to inconsistent and less actionable error messages
in the UI.
Agent Prompt
## Issue description
`OracleDriver::test_connection()` returns generic `[CONN_FAILED] {e}` strings for Oracle errors, bypassing `conn_failed_error()` which standardizes and enriches connection failure messages.

## Issue Context
Compliance requires connection failure paths to use `conn_failed_error()` so the UI can show consistent, user-friendly hints (e.g., Oracle Instant Client not installed, TLS/auth/network hints).

## Fix Focus Areas
- src-tauri/src/db/drivers/oracle.rs[205-212]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +142 to +154
let service_name = effective_form
.database
.clone()
.map(|v| v.trim().to_string())
.filter(|v| !v.is_empty())
.unwrap_or_else(|| "ORCL".to_string());
let username = effective_form
.username
.clone()
.map(|v| v.trim().to_string())
.filter(|v| !v.is_empty())
.ok_or("[VALIDATION_ERROR] username cannot be empty")?;
let password = effective_form.password.clone().unwrap_or_default();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Oracle service name clobbered 🐞 Bug ≡ Correctness

OracleDriver.connect reads ConnectionForm.database as the Oracle service name, but the
command-layer connection creation overwrites form.database with the request database parameter,
which (for Oracle) is coming from ALL_USERS schema names. This causes Oracle connections to
attempt //host:port/<SCHEMA> and fail in table browsing/export/metadata calls.
Agent Prompt
## Issue description
Oracle uses `ConnectionForm.database` as the Easy Connect service name, but the backend currently overwrites `form.database` with the per-request `database` param. In the Oracle flow the UI uses the `database` param to represent a schema (from `ALL_USERS`), so this overwrite turns the service name into a schema name and breaks connections.

## Issue Context
- OracleDriver builds `//host:port/<service_name>` from `form.database`.
- `ensure_connection_with_db` unconditionally replaces `form.database` when a request provides a `database` value.
- For Oracle, `list_databases()` returns schemas/users, and the UI passes those values as the `database` request param.

## Fix Focus Areas
- src-tauri/src/commands/mod.rs[58-65]
- src-tauri/src/commands/mod.rs[97-105]
- src-tauri/src/db/drivers/oracle.rs[121-162]

## Suggested fix
1. In `ensure_connection_with_db` / `ensure_connection_with_db_from_app_state`, after loading the `form`, gate the `form.database = Some(db_name)` override by driver type.
   - For example: do **not** override `form.database` when `form.driver == "oracle"`.
   - (Optional) if you need the per-request value for Oracle, consider mapping it into `form.schema` instead (only when `form.schema` is empty), since schema is the Oracle-scoped concept.
2. (Optional but recommended) Add a regression test around `ensure_connection_with_db` to ensure an Oracle form’s `database` (service name) is preserved when a `database` request param is provided.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +653 to +707
let first_kw = first_sql_keyword(&sql_clean);
let is_read = matches!(
first_kw.as_deref(),
Some("select") | Some("with") | Some("show")
);

self.run_blocking(move |conn| {
if is_read {
let rows = conn
.query(&sql_clean, &[] as &[&dyn oracle::sql_type::ToSql])
.map_err(|e| format!("[QUERY_ERROR] {e}"))?;

// Collect column metadata before consuming rows
let col_info: Vec<(String, String)> = rows
.column_info()
.iter()
.map(|c| (c.name().to_string(), format!("{}", c.oracle_type())))
.collect();
let columns: Vec<QueryColumn> = col_info
.iter()
.map(|(name, ty)| QueryColumn {
name: name.clone(),
r#type: ty.clone(),
})
.collect();

let mut data = Vec::new();
for row_result in rows {
let row = row_result.map_err(|e| format!("[QUERY_ERROR] {e}"))?;
let mut map = serde_json::Map::new();
for (i, (name, _)) in col_info.iter().enumerate() {
map.insert(name.clone(), oracle_value_to_json(&row, i));
}
data.push(serde_json::Value::Object(map));
}

Ok(QueryResult {
row_count: data.len() as i64,
data,
columns,
time_taken_ms: start.elapsed().as_millis() as i64,
success: true,
error: None,
})
} else {
// DML or DDL — use Statement API to get affected-row count
let mut stmt = conn
.statement(&sql_clean)
.build()
.map_err(|e| format!("[QUERY_ERROR] {e}"))?;
stmt.execute(&[] as &[&dyn oracle::sql_type::ToSql])
.map_err(|e| format!("[QUERY_ERROR] {e}"))?;
let row_count = stmt.row_count().unwrap_or(0) as i64;
// Commit so the change is visible after the connection closes.
conn.commit().map_err(|e| format!("[QUERY_ERROR] commit failed: {e}"))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. With dml misrouted 🐞 Bug ≡ Correctness

OracleDriver.execute_query treats any SQL whose first keyword is WITH as a read query and routes
it through conn.query() without committing. Oracle supports WITH-prefixed
INSERT/UPDATE/DELETE/MERGE, so those statements will either error as “not a query” or execute
without a commit.
Agent Prompt
## Issue description
`OracleDriver.execute_query` currently classifies all `WITH ...` statements as read-only and runs them via `conn.query()` without committing. Oracle allows `WITH` to prefix DML (INSERT/UPDATE/DELETE/MERGE), so this misclassification causes failures or uncommitted changes.

Concrete example that will be misclassified today:
```sql
WITH cte AS (SELECT 1 AS id, 'x' AS name FROM DUAL)
INSERT INTO MY_TABLE(id, name)
SELECT id, name FROM cte
```

## Issue Context
The current logic:
- `is_read` is true for `select | with | show`
- only the `else` branch calls `conn.commit()`

## Fix Focus Areas
- src-tauri/src/db/drivers/oracle.rs[650-707]

## Suggested fix approaches
Pick one:
1. **Safer fallback execution**
   - If `first_kw == Some("with")`, attempt to execute using the Statement API in a way that can handle both query and non-query:
     - Try building a statement and calling a query-style execution.
     - If that fails with a known “not a query / invalid statement type” Oracle error, retry with execute+commit.
   - Ensure you only fallback on specific, expected error codes/messages so you don’t mask real SQL errors.

2. **Parse second keyword for WITH**
   - When the first keyword is `WITH`, scan forward (token-based) for the first *non-CTE* keyword that determines the statement kind (`SELECT`, `INSERT`, `UPDATE`, `DELETE`, `MERGE`).
   - Treat `WITH ... SELECT` as read; treat `WITH ... INSERT/UPDATE/DELETE/MERGE` as write and commit.

Also add a unit/integration test covering a `WITH ... INSERT` statement to prevent regression.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 19

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/business/Sidebar/ConnectionList.tsx (2)

883-890: ⚠️ Potential issue | 🟠 Major

Don't bail before hydrating the target connection tree.

If activeTableTarget points at a connection whose databases have not been loaded yet, targetDatabase is undefined and this exits without ever calling fetchAndSetDatabases()/connectConnection(). After a cold load or reconnect, the reveal never completes until the user manually expands that connection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/business/Sidebar/ConnectionList.tsx` around lines 883 - 890,
In ensureDatabaseTablesLoaded: don't return early when targetDatabase is
undefined; instead if targetConnection exists but its databases are not loaded
(targetDatabase === undefined and targetConnection is present), call the
existing fetchAndSetDatabases() and/or connectConnection() for that connectionId
to hydrate the connection tree, then re-resolve targetDatabase and proceed to
reveal the table; reference ensureDatabaseTablesLoaded, activeTableTarget,
connections, connectionId, databaseName, fetchAndSetDatabases, and
connectConnection when making the change.

872-882: ⚠️ Potential issue | 🟠 Major

Expand the database group before trying to reveal a table.

When showSavedQueriesInTree is enabled, the target node lives under ${connectionId}::databases. This effect only opens the connection and database keys, so the table row never mounts and the later autoscroll quietly gives up.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/business/Sidebar/ConnectionList.tsx` around lines 872 - 882,
The effect that expands nodes currently calls setExpandedConnections and
setExpandedDatabases but misses expanding the intermediate "databases" group
when showSavedQueriesInTree is true; update the logic (around
setExpandedConnections / setExpandedDatabases in ConnectionList.tsx) to also add
the composite parent key `${connectionId}::databases` to the expanded
connections set when showSavedQueriesInTree is enabled so the database group
mounts before attempting to reveal the table (use the same Set update pattern as
setExpandedConnections to add `${connectionId}::databases` alongside
connectionId and ensure dbKey is added to setExpandedDatabases).
🧹 Nitpick comments (8)
docs/table-selection-optimization.md (5)

238-240: Performance: Avoid inline arrow functions in JSX for frequently rendered cells.

The event handlers are defined as inline arrow functions, which creates new function instances on every render. In a large table with many cells, this can cause performance issues and unnecessary re-renders.

Consider using a memoized callback factory or event delegation pattern. For example:

// Outside the cell render, create a memoized handler factory
const createCellMouseDownHandler = useCallback(
  (rowIndex: number, colIndex: number, column: string) => 
    (e: React.MouseEvent) => handleCellMouseDown(e, rowIndex, colIndex, column),
  [handleCellMouseDown]
);

// Or use event delegation on the parent table/tbody

Alternatively, attach handlers to the parent <table> or <tbody> and use event.target to determine which cell was clicked.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/table-selection-optimization.md` around lines 238 - 240, Replace the
inline arrow handlers on each cell with memoized handler factories or an
event-delegation approach to avoid recreating functions on every render;
specifically, create useCallback factories like createCellMouseDownHandler,
createCellMouseEnterHandler and createCellClickHandler that accept
rowIndex/colIndex/column and return the actual event handler which calls the
existing handleCellMouseDown, handleCellMouseEnter and handleCellClick, or
alternatively move handlers to the table/tbody and implement event delegation
using event.target to resolve the cell indices—then update the JSX to reference
the stable handlers instead of inline arrows.

358-365: Consider documenting accessibility and performance implications.

The "Optional Enhancements" section mentions keyboard shortcuts, but the document would benefit from explicitly addressing:

  1. Accessibility: How will screen readers announce range selections? Should ARIA attributes like aria-selected be added to cells in the range?

  2. Performance: During drag selection, setSelectedRange will be called on every mouse move across cells. For large tables, consider throttling the state updates or using CSS-only visual feedback during drag with state update only on mouseup.

  3. Touch devices: The current proposal is mouse-only. Touch devices would need different interaction patterns (e.g., long-press to start selection).

  4. Testing: Consider adding a section about how to test the range selection functionality (unit tests for selection logic, E2E tests for user interactions).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/table-selection-optimization.md` around lines 358 - 365, The "Optional
Enhancements" section needs explicit guidance on accessibility, performance,
touch support, and testing: document adding ARIA attributes (e.g., use
aria-selected on table cells and describe how screen readers should announce
range selections), recommend performance strategies for setSelectedRange
(throttle/debounce updates or use CSS-only visual feedback during drag and
update state on mouseup), describe touch-specific patterns (long-press to begin
selection and touch-move handling), and add testing guidance (unit tests for
selection logic and E2E tests for drag/touch/keyboard interactions like
Shift+Click and Ctrl/Cmd+Click). Ensure the doc references the selection update
entry point setSelectedRange and the cell attribute aria-selected so
implementers can find where to apply these changes.

1-365: Suggestion: Use relative references instead of absolute line numbers.

Throughout the document, specific line numbers are referenced (e.g., "第 543-561 行", "第 2004-2083 行"). These will become stale as the codebase evolves, making the documentation less maintainable.

Consider using function names, code patterns, or section markers instead:

  • ✗ "位置: TableView.tsx 第 543-561 行"
  • ✓ "位置: TableView.tsx 中的 handleCellClick 函数"
  • ✓ "位置: TableView.tsx 中的单元格渲染逻辑 (<td> 元素)"

This makes the document more resilient to code changes and easier to maintain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/table-selection-optimization.md` around lines 1 - 365, The document uses
fragile absolute line-number references (e.g., "第 543-561 行"); update all such
occurrences to refer to stable code anchors instead — use function/handler names
and markup identifiers like handleCellClick, handleIndexMouseDown,
handleIndexMouseEnter, the cell rendering <td> block, the selected-range state
declarations (selectedRange, selectedRangeRef), the mouseup useEffect,
getSelectedRangeCopyText and the ContextMenuItem copy handler in TableView.tsx —
replace each "第 X-Y 行" note with a descriptive reference to the function/section
or JSX element so readers can locate the code even if lines shift.

285-309: Add bounds checking for array access.

Line 296 accesses columns[c] without verifying that c is within bounds. While the loop condition c <= endColIndex should ensure this, defensive programming would add a check to prevent potential runtime errors if selectedRange state becomes inconsistent.

Consider adding:

const col = columns[c];
if (!col) continue; // Skip if column index is out of bounds

Also, consider memoizing this function only when selectedRange changes significantly, not on every currentData change, to avoid unnecessary recomputations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/table-selection-optimization.md` around lines 285 - 309, In
getSelectedRangeCopyText, add defensive bounds checking before using columns[c]
(e.g., const col = columns[c]; if (!col) continue) to avoid runtime errors if
selectedRange is inconsistent, and reduce unnecessary recomputation by removing
currentData from the useCallback dependency array—keep [selectedRange, columns,
getCellDisplayValue] so the memo only updates when the selection, column set, or
cell-display logic changes rather than on every currentData mutation.

163-169: Empty function body may cause confusion.

The handleCellClick function is defined with an empty body and a comment explaining that "actual selection logic is in handleCellMouseDown." However, this function is still attached to onClick in the JSX (line 240). Consider either:

  1. Removing the onClick handler entirely if it's no longer needed, or
  2. Adding a clear comment explaining why the handler must remain (e.g., for accessibility or to prevent event bubbling)

Additionally, the function doesn't use its parameters rowIndex and col, which suggests they can be removed from the signature.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/table-selection-optimization.md` around lines 163 - 169, handleCellClick
currently has an empty body but remains bound to the onClick handler in the JSX;
either remove the onClick binding where handleCellClick is used, or keep the
handler and make its intent explicit: if it's required to consume the click
(e.g., to stop propagation/accessibility), replace the empty body with a clear
comment and minimal behavior (e.g., stopPropagation or blur) and remove unused
parameters (rowIndex, col) from the signature; update any references to
handleCellClick in the JSX accordingly (either delete the onClick prop or keep
it and ensure the handler documents/implements the necessary no-op behavior).
ADD_NEW_DB.md (2)

26-32: Line number references may become stale.

The documentation references specific line numbers (e.g., mod.rs:64-121 for the trait, lines 133-163 for connect()), but the actual locations differ in the current mod.rs (trait is around lines 79-128, connect() is around 140-175). Consider:

  • Using function/type names instead of line numbers where possible
  • Adding a note that line numbers are approximate and may shift
💡 Suggested change for Step 1
-必须实现 `DatabaseDriver` trait 的全部方法(定义见 `src-tauri/src/db/drivers/mod.rs:64-121`):
+必须实现 `DatabaseDriver` trait 的全部方法(定义见 `src-tauri/src/db/drivers/mod.rs` 中的 `pub trait DatabaseDriver`):
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ADD_NEW_DB.md` around lines 26 - 32, The docs currently point to exact line
numbers for the DatabaseDriver trait and connect(), which will become stale;
update the text to reference the actual symbol names (e.g., the DatabaseDriver
trait and the connect() function/impl) instead of file:line ranges and add a
short note that line numbers are approximate and may shift as the codebase
changes; ensure you mention the source file (mod.rs) by name and list the
required trait methods (test_connection, get_databases, get_table_names,
get_table_structure, get_table_info, get_table_data, execute_query,
cancel_query, get_schema_names, get_table_ddl, get_schema_overview, close) so
readers can locate them by name.

28-32: Add language specifiers to fenced code blocks.

Several code blocks are missing language specifiers, which affects syntax highlighting and lint compliance:

  • Lines 28-32: list of trait methods
  • Lines 262-266: file paths
  • Lines 278-280: file path
💡 Suggested fixes
-```
+```text
 test_connection, get_databases, get_table_names, get_table_structure,
-```
+```text
 src-tauri/tests/common/{driver}_context.rs    ← testcontainers 容器配置
-```
+```text
 src-tauri/tests/{driver}_stateful_command_integration.rs

Also applies to: 262-266, 278-280

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ADD_NEW_DB.md` around lines 28 - 32, Several fenced code blocks lack language
specifiers (e.g., the block containing "test_connection, get_databases,
get_table_names, get_table_structure, get_table_info, get_table_data,
execute_query, cancel_query, get_schema_names, get_table_ddl,
get_schema_overview, close" and the blocks listing file paths like
"src-tauri/tests/common/{driver}_context.rs    ← testcontainers 容器配置" and
"src-tauri/tests/{driver}_stateful_command_integration.rs"); update each opening
triple-backtick to include an appropriate language (for these snippets use
```text) so the blocks become fenced with ```text to restore syntax highlighting
and satisfy the linter.
src-tauri/src/db/drivers/mod.rs (1)

29-33: Consider adding Windows path hint for Oracle Instant Client.

The hint covers macOS (DYLD_LIBRARY_PATH) and Linux (LD_LIBRARY_PATH), but DbPaw is a cross-platform application. On Windows, users need to add the Oracle Instant Client directory to the PATH environment variable.

💡 Suggested enhancement
     let hint = if lower.contains("dpi-1047") || lower.contains("cannot locate a 64-bit oracle client") {
         "hint: Oracle Instant Client is not installed — download it from \
          https://www.oracle.com/database/technologies/instant-client/downloads.html \
          and add the directory containing libclntsh to your library path \
-         (macOS: DYLD_LIBRARY_PATH; Linux: LD_LIBRARY_PATH)"
+         (Windows: PATH; macOS: DYLD_LIBRARY_PATH; Linux: LD_LIBRARY_PATH)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/src/db/drivers/mod.rs` around lines 29 - 33, The hint text in
mod.rs (the block that builds the variable named hint when matching
lower.contains("dpi-1047") || lower.contains("cannot locate a 64-bit oracle
client")) only mentions macOS and Linux library vars; update that message to
also mention Windows users should add the Oracle Instant Client directory to
their PATH environment variable (e.g., "Windows: add the Instant Client
directory to PATH") so the hint covers all platforms and references the same
hint variable and matching condition.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/commands/new-db.md:
- Around line 417-425: Update the "Final Verification" checklist under the
"Final Verification" heading to include the repo's Rust verification steps: add
the commands `bun run lint:rust` (to run Rust linting via bun) and `cargo test
--lib` (to run Rust unit tests) in addition to the existing `cargo check
--manifest-path src-tauri/Cargo.toml`; ensure they appear in the same
three-check list so the final steps run in order: `bun run typecheck`, `bun run
lint`, `bun run lint:rust`, `cargo check --manifest-path src-tauri/Cargo.toml`,
and `cargo test --lib`.

In `@src-tauri/src/db/drivers/oracle.rs`:
- Around line 125-129: When SSH is enabled (check form.ssh_enabled) wrap
failures from crate::ssh::start_ssh_tunnel(form) into the driver's standard
connection failure error by mapping the returned Err to conn_failed_error(...)
instead of propagating raw SSH errors; replace the current ? propagation in the
block that sets effective_form.host/port and ssh_tunnel so that any Err from
start_ssh_tunnel is converted with conn_failed_error (include context like "SSH
tunnel setup failed") before returning, keeping effective_form and ssh_tunnel
assignment logic the same on success.
- Around line 549-553: The code uppercases schema/table names before quoting
(e.g., in the table_ref construction and other dictionary/query sites) which
breaks quoted mixed-case identifiers; update calls so quote_ident(...) and
escape_literal(...) receive the original schema and table variables (not
schema.to_uppercase() / table.to_uppercase()), e.g., change uses around
table_ref and the dictionary metadata query sites (the occurrences you saw near
the functions that build queries) to pass schema and table unchanged; leave any
explicit uppercasing only where unquoted comparisons to Oracle metadata require
it, but do not uppercase before calling quote_ident or escape_literal.

In `@src-tauri/src/db/drivers/postgres.rs`:
- Around line 1112-1125: The `_INT8` match arm currently maps array elements to
serde_json::Value::Number causing precision loss; update that arm (the match on
"_INT8" in postgres.rs) to mirror the scalar `INT8` handling by converting each
Some(i64) element to serde_json::Value::String(i64.to_string()) and leaving None
as Value::Null, preserving the outer Array and the existing
unwrap_or(serde_json::Value::Null) behavior so bigints in arrays retain full
precision for JS clients.

In `@src-tauri/tests/common/oracle_context.rs`:
- Line 15: The doc says ORACLE_PASSWORD is required but the code uses
env_or("ORACLE_PASSWORD", "") which supplies an empty default; change the code
so ORACLE_PASSWORD is truly required (remove the empty-string default and use
the required env lookup or fail-fast helper) instead of env_or with "" — update
the lookup around the env_or("ORACLE_PASSWORD", "") call in
tests/common/oracle_context.rs (the ORACLE_PASSWORD retrieval) to panic/error if
the variable is missing so docs and code match.

In `@src-tauri/tests/oracle_command_integration.rs`:
- Around line 17-20: The tests (prepare_test_table and callers using
oracle_form_from_test_context) are connecting to an external Oracle instance;
change them to use testcontainers so each integration test runs against an
isolated DB container: update prepare_test_table to accept a ConnectionForm
produced from a testcontainers-managed Oracle container, initialize that
container in the test setup (using the testcontainers crate, appropriate Oracle
image and wait strategy), and replace oracle_form_from_test_context() calls in
the tests with the container-derived form so all connections (e.g., in
OracleDriver::connect and subsequent test logic) target the testcontainer
instance; ensure container lifecycle is tied to the test scope to avoid leaking
external state.

In `@src-tauri/tests/oracle_integration.rs`:
- Around line 19-24: The test currently relies on
oracle_context::oracle_form_from_test_context() and an external ORACLE_SCHEMA
env var; instead provision an Oracle database via testcontainers inside the test
harness, replacing the external dependency with a container-backed instance:
create a test helper (or use existing testcontainers utilities) that starts an
Oracle container, waits until reachable, creates the required schema/user, and
returns a populated form struct (replace oracle_form_from_test_context usage) so
form.schema is set locally; ensure the helper injects the connection info into
the form and that the container is stopped/cleaned up at test teardown.
- Around line 8-13: unique_table_name() currently uses millisecond precision
which can collide when tests run in parallel; change it to append a
collision-proof suffix (e.g., a UUID v4 or a combination of
SystemTime::now().as_nanos() plus a short random hex) to the "DBPAW_ORA_IT_"
prefix to guarantee uniqueness; update the unique_table_name() function to
generate and return that stronger suffix (and keep callers/tests unchanged) so
setup/cleanup no longer flakes in parallel runs.

In `@src/App.tsx`:
- Around line 739-753: The placeholder tab created via setTabs (id: tabId,
fields: type "table", title, connection, database, connectionId, driver,
isLoading:true) lacks a table target so on load failure the code path that only
clears isLoading leaves an unusable tab; update the placeholder to include the
actual table identifier fields (e.g., tableName and schema) when creating it, or
alternatively remove/close the placeholder tab inside the failure/catch path
where isLoading is cleared so no target-less tab remains (adjust the same logic
used in the other occurrence around lines 810-812); ensure references to tabId,
isLoading, setTabs and setActiveTab are handled consistently.
- Around line 1155-1163: The current close-tab logic always activates
newTabs[newTabs.length - 1]; change it to pick the closed tab's neighbor
instead: inside the setTabs updater for setTabs and setActiveTab, determine the
index of the tab being closed (use the prev array to find the index of tabId
before filtering), then after computing newTabs choose the adjacent tab by
preferring the previous sibling (prev[index - 1]) if it exists, otherwise the
next sibling (newTabs[index] after removal); call revealSidebarForTab with that
neighbor id and return that id as the new active tab. Reference setTabs,
setActiveTab, tabId, newTabs, and revealSidebarForTab when making the change.

In `@src/components/business/DataGrid/ComplexValueViewer.tsx`:
- Around line 107-120: The component ComplexValueViewer is rendering hard-coded
user-facing strings (e.g., "JSON", "Tree", "Table", "Copy JSON", "Copied",
"key", "value", "array", "object") and must be routed through react-i18next;
import and call useTranslation inside the ComplexValueViewer component, replace
each literal label (menu/tab labels, button text, table headers, and type
labels) with t('namespace.key') lookups (choose or add descriptive keys like
complexViewer.json, complexViewer.tree, complexViewer.table,
complexViewer.copyJson, complexViewer.copied, complexViewer.key,
complexViewer.value, complexViewer.array, complexViewer.object), and ensure
every occurrence noted (including the table header block around keys, plus the
other ranges referenced: lines ~160-161 and ~183-225) is updated to use t(...)
so the strings follow app locale switching; also add corresponding keys to the
i18n locales files.

In `@src/components/business/DataGrid/TableView.tsx`:
- Around line 1863-1880: The placeholders and UI strings for the new
structured-data controls are hard-coded English and the viewer button lacks an
accessible name and keyboard-focus styling; update ColumnAutocompleteInput
usages (the instances named ColumnAutocompleteInput for WHERE and ORDER BY) to
pass localized strings via t('...') for placeholder text, ensure the viewer
title string is wrapped with t('...'), add an explicit aria-label to the viewer
button element, and add visible keyboard-focus styles (e.g., focus-visible:ring
or focus:outline classes) to the button so it shows on focus as well as hover;
apply the same i18n replacement for the other ColumnAutocompleteInput
occurrences mentioned around the 2100-2103 area.

In `@src/components/business/DataGrid/tableView/ColumnAutocompleteInput.tsx`:
- Around line 51-54: The useEffect that resets activeIndex on [hasSuggestions,
token?.text] misses clamping when the options list changes, causing
filteredOptions[activeIndex] to be undefined in acceptSuggestion; update the
effect (and the similar effect around the other occurrence) to
setActiveIndex(prev => Math.min(prev, Math.max(0, filteredOptions.length - 1)))
or setActiveIndex(0) when filteredOptions is empty so activeIndex is always
within [0, filteredOptions.length-1]; reference the useEffect that calls
setActiveIndex, the filteredOptions/options array, the activeIndex state, and
the acceptSuggestion function to ensure activeIndex is clamped whenever
options/filteredOptions change.

In `@src/components/business/DataGrid/tableView/utils.ts`:
- Around line 125-126: The search is using formatCellValue which returns an
abbreviated preview for large objects, causing false negatives; replace the call
to formatCellValue(value).toLowerCase() with the full serializer
cellValueToString(value).toLowerCase() so searches run against the complete
serialized cell value (ensure cellValueToString is imported/available where used
and keep the normalizedSearchKeyword comparison logic intact).

In `@src/components/business/Sidebar/Sidebar.tsx`:
- Around line 15-17: Export the existing SidebarRevealRequest type from
Sidebar.tsx (the interface extending ActiveTableTarget with id:number) and
update the other module that currently redefines it (the file where
SidebarRevealRequest was duplicated) to import that exported type instead; then
remove the duplicate local interface definition. Ensure the export uses the
exact symbol name SidebarRevealRequest and that the consumer file imports it and
uses the same type, leaving ActiveTableTarget references unchanged.

In `@src/lib/driver-registry.tsx`:
- Around line 167-168: getDriverConfig currently uses a non-null assertion and
will throw if given non-canonical IDs; update it to normalize and/or safely
handle mismatched IDs instead of crashing. Remove the "!" non-null assert in
getDriverConfig and either (a) introduce a normalization step (e.g.,
normalizeDriverId) that maps aliases like "postgresql" -> "postgres", "pgsql" ->
"postgres", "sqlite3" -> "sqlite", and case-folds values like "Oracle" before
lookup in DRIVER_REGISTRY, or (b) change getDriverConfig's return type to
DriverConfig | undefined and have callers handle missing configs gracefully;
reference getDriverConfig and DRIVER_REGISTRY when applying the normalization or
safe-return logic so runtime/imported values don't throw during render.

In `@src/lib/driver-registry.unit.test.ts`:
- Around line 110-205: Tests for helper functions omit the new "oracle" driver
causing blind spots; update the test cases for getDefaultPort,
isFileBasedDriver, isMysqlFamilyDriver, supportsSSLCA, and
supportsCreateDatabase to include assertions for "oracle" (e.g.,
expect(getDefaultPort("oracle")).toBe(<expected_port>),
expect(isFileBasedDriver("oracle")).toBe(false) or true as appropriate, and
corresponding expectations for isMysqlFamilyDriver, supportsSSLCA, and
supportsCreateDatabase) so the new driver is covered by these helper-unit tests.

In `@src/lib/keyboard.unit.test.ts`:
- Line 2: Replace the relative import in the unit test with the project path
alias: instead of importing isModKey and isEditableTarget from "./keyboard"
update the import to use "@/lib/keyboard" so the test imports isModKey and
isEditableTarget via the alias consistent with the frontend path policy.

In `@src/services/mocks.ts`:
- Around line 763-776: The current isArrayQuery/isComplexQuery logic matches any
substring "array"/"json" which misroutes queries; update those checks to detect
the actual table name (e.g., pg_arrays and json_test) using
word-boundary/table-name-aware matching on the normalized SQL (lower) instead of
plain substring checks, handling quoted/dotted identifiers; then keep the rest
of the selection that picks mockArrayTypeData, mockComplexTypeData or
mockQueryResult unchanged (refer to isArrayQuery, isComplexQuery,
mockArrayTypeData, mockComplexTypeData, mockQueryResult).

---

Outside diff comments:
In `@src/components/business/Sidebar/ConnectionList.tsx`:
- Around line 883-890: In ensureDatabaseTablesLoaded: don't return early when
targetDatabase is undefined; instead if targetConnection exists but its
databases are not loaded (targetDatabase === undefined and targetConnection is
present), call the existing fetchAndSetDatabases() and/or connectConnection()
for that connectionId to hydrate the connection tree, then re-resolve
targetDatabase and proceed to reveal the table; reference
ensureDatabaseTablesLoaded, activeTableTarget, connections, connectionId,
databaseName, fetchAndSetDatabases, and connectConnection when making the
change.
- Around line 872-882: The effect that expands nodes currently calls
setExpandedConnections and setExpandedDatabases but misses expanding the
intermediate "databases" group when showSavedQueriesInTree is true; update the
logic (around setExpandedConnections / setExpandedDatabases in
ConnectionList.tsx) to also add the composite parent key
`${connectionId}::databases` to the expanded connections set when
showSavedQueriesInTree is enabled so the database group mounts before attempting
to reveal the table (use the same Set update pattern as setExpandedConnections
to add `${connectionId}::databases` alongside connectionId and ensure dbKey is
added to setExpandedDatabases).

---

Nitpick comments:
In `@ADD_NEW_DB.md`:
- Around line 26-32: The docs currently point to exact line numbers for the
DatabaseDriver trait and connect(), which will become stale; update the text to
reference the actual symbol names (e.g., the DatabaseDriver trait and the
connect() function/impl) instead of file:line ranges and add a short note that
line numbers are approximate and may shift as the codebase changes; ensure you
mention the source file (mod.rs) by name and list the required trait methods
(test_connection, get_databases, get_table_names, get_table_structure,
get_table_info, get_table_data, execute_query, cancel_query, get_schema_names,
get_table_ddl, get_schema_overview, close) so readers can locate them by name.
- Around line 28-32: Several fenced code blocks lack language specifiers (e.g.,
the block containing "test_connection, get_databases, get_table_names,
get_table_structure, get_table_info, get_table_data, execute_query,
cancel_query, get_schema_names, get_table_ddl, get_schema_overview, close" and
the blocks listing file paths like "src-tauri/tests/common/{driver}_context.rs  
← testcontainers 容器配置" and
"src-tauri/tests/{driver}_stateful_command_integration.rs"); update each opening
triple-backtick to include an appropriate language (for these snippets use
```text) so the blocks become fenced with ```text to restore syntax highlighting
and satisfy the linter.

In `@docs/table-selection-optimization.md`:
- Around line 238-240: Replace the inline arrow handlers on each cell with
memoized handler factories or an event-delegation approach to avoid recreating
functions on every render; specifically, create useCallback factories like
createCellMouseDownHandler, createCellMouseEnterHandler and
createCellClickHandler that accept rowIndex/colIndex/column and return the
actual event handler which calls the existing handleCellMouseDown,
handleCellMouseEnter and handleCellClick, or alternatively move handlers to the
table/tbody and implement event delegation using event.target to resolve the
cell indices—then update the JSX to reference the stable handlers instead of
inline arrows.
- Around line 358-365: The "Optional Enhancements" section needs explicit
guidance on accessibility, performance, touch support, and testing: document
adding ARIA attributes (e.g., use aria-selected on table cells and describe how
screen readers should announce range selections), recommend performance
strategies for setSelectedRange (throttle/debounce updates or use CSS-only
visual feedback during drag and update state on mouseup), describe
touch-specific patterns (long-press to begin selection and touch-move handling),
and add testing guidance (unit tests for selection logic and E2E tests for
drag/touch/keyboard interactions like Shift+Click and Ctrl/Cmd+Click). Ensure
the doc references the selection update entry point setSelectedRange and the
cell attribute aria-selected so implementers can find where to apply these
changes.
- Around line 1-365: The document uses fragile absolute line-number references
(e.g., "第 543-561 行"); update all such occurrences to refer to stable code
anchors instead — use function/handler names and markup identifiers like
handleCellClick, handleIndexMouseDown, handleIndexMouseEnter, the cell rendering
<td> block, the selected-range state declarations (selectedRange,
selectedRangeRef), the mouseup useEffect, getSelectedRangeCopyText and the
ContextMenuItem copy handler in TableView.tsx — replace each "第 X-Y 行" note with
a descriptive reference to the function/section or JSX element so readers can
locate the code even if lines shift.
- Around line 285-309: In getSelectedRangeCopyText, add defensive bounds
checking before using columns[c] (e.g., const col = columns[c]; if (!col)
continue) to avoid runtime errors if selectedRange is inconsistent, and reduce
unnecessary recomputation by removing currentData from the useCallback
dependency array—keep [selectedRange, columns, getCellDisplayValue] so the memo
only updates when the selection, column set, or cell-display logic changes
rather than on every currentData mutation.
- Around line 163-169: handleCellClick currently has an empty body but remains
bound to the onClick handler in the JSX; either remove the onClick binding where
handleCellClick is used, or keep the handler and make its intent explicit: if
it's required to consume the click (e.g., to stop propagation/accessibility),
replace the empty body with a clear comment and minimal behavior (e.g.,
stopPropagation or blur) and remove unused parameters (rowIndex, col) from the
signature; update any references to handleCellClick in the JSX accordingly
(either delete the onClick prop or keep it and ensure the handler
documents/implements the necessary no-op behavior).

In `@src-tauri/src/db/drivers/mod.rs`:
- Around line 29-33: The hint text in mod.rs (the block that builds the variable
named hint when matching lower.contains("dpi-1047") || lower.contains("cannot
locate a 64-bit oracle client")) only mentions macOS and Linux library vars;
update that message to also mention Windows users should add the Oracle Instant
Client directory to their PATH environment variable (e.g., "Windows: add the
Instant Client directory to PATH") so the hint covers all platforms and
references the same hint variable and matching condition.
🪄 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

Run ID: 1f482542-3f97-4746-bf42-408311b6844f

📥 Commits

Reviewing files that changed from the base of the PR and between 6625771 and 4d895d9.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (45)
  • .claude/commands/new-db.md
  • .github/workflows/release.yml
  • ADD_NEW_DB.md
  • CLAUDE.md
  • docs/table-selection-optimization.md
  • package.json
  • scripts/test-integration.sh
  • src-tauri/Cargo.toml
  • src-tauri/src/commands/transfer.rs
  • src-tauri/src/db/drivers/mod.rs
  • src-tauri/src/db/drivers/mysql.rs
  • src-tauri/src/db/drivers/oracle.rs
  • src-tauri/src/db/drivers/postgres.rs
  • src-tauri/src/ssh.rs
  • src-tauri/tauri.conf.json
  • src-tauri/tests/common/oracle_context.rs
  • src-tauri/tests/oracle_command_integration.rs
  • src-tauri/tests/oracle_integration.rs
  • src-tauri/tests/postgres_integration.rs
  • src/App.tsx
  • src/components/business/DataGrid/ComplexValueViewer.tsx
  • src/components/business/DataGrid/TableView.tsx
  • src/components/business/DataGrid/tableView/ColumnAutocompleteInput.tsx
  • src/components/business/DataGrid/tableView/columnAutocomplete.ts
  • src/components/business/DataGrid/tableView/columnAutocomplete.unit.test.ts
  • src/components/business/DataGrid/tableView/utils.ts
  • src/components/business/DataGrid/tableView/utils.unit.test.ts
  • src/components/business/Editor/SqlEditor.tsx
  • src/components/business/Sidebar/ConnectionList.tsx
  • src/components/business/Sidebar/SavedQueriesList.tsx
  • src/components/business/Sidebar/Sidebar.tsx
  • src/components/business/Sidebar/connection-list/helpers.tsx
  • src/components/business/Sidebar/connection-list/helpers.unit.test.ts
  • src/lib/connection-form/rules.ts
  • src/lib/connection-form/rules.unit.test.ts
  • src/lib/connection-form/validate.unit.test.ts
  • src/lib/driver-registry.tsx
  • src/lib/driver-registry.unit.test.ts
  • src/lib/keyboard.unit.test.ts
  • src/lib/sqlEditorDatabase.unit.test.ts
  • src/lockfile.unit.test.ts
  • src/services/api.ts
  • src/services/api.unit.test.ts
  • src/services/mocks.ts
  • src/types/bun-test.d.ts

Comment on lines +417 to +425
## Final Verification

Run these three checks and fix any errors before declaring done:

```bash
bun run typecheck
bun run lint
cargo check --manifest-path src-tauri/Cargo.toml
```

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 | 🟡 Minor

Add the repo's Rust verification steps to the final checklist.

This currently stops at cargo check, but new drivers under src-tauri/src/**/*.rs are also expected to pass bun run lint:rust and cargo test --lib.

Suggested checklist update
 bun run typecheck
 bun run lint
+bun run lint:rust
 cargo check --manifest-path src-tauri/Cargo.toml
+cargo test --lib --manifest-path src-tauri/Cargo.toml

As per coding guidelines "Use cargo test --lib to run Rust unit tests defined with #[test] in source files" and "Run bun run lint:rust with cargo check to validate Rust code before committing".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/commands/new-db.md around lines 417 - 425, Update the "Final
Verification" checklist under the "Final Verification" heading to include the
repo's Rust verification steps: add the commands `bun run lint:rust` (to run
Rust linting via bun) and `cargo test --lib` (to run Rust unit tests) in
addition to the existing `cargo check --manifest-path src-tauri/Cargo.toml`;
ensure they appear in the same three-check list so the final steps run in order:
`bun run typecheck`, `bun run lint`, `bun run lint:rust`, `cargo check
--manifest-path src-tauri/Cargo.toml`, and `cargo test --lib`.

Comment on lines +125 to +129
if let Some(true) = form.ssh_enabled {
let tunnel = crate::ssh::start_ssh_tunnel(form)?;
effective_form.host = Some("127.0.0.1".to_string());
effective_form.port = Some(tunnel.local_port as i64);
ssh_tunnel = Some(tunnel);

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 | 🟡 Minor

Wrap SSH tunnel setup failures as connection failures too.

Right now SSH auth/network errors bypass the driver's normal connection-error path, so the Oracle connect flow returns a different class of message than a direct socket failure.

As per coding guidelines "Use conn_failed_error() to provide context-aware error messages for connection failures (TLS issues, auth failures, network problems)".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/src/db/drivers/oracle.rs` around lines 125 - 129, When SSH is
enabled (check form.ssh_enabled) wrap failures from
crate::ssh::start_ssh_tunnel(form) into the driver's standard connection failure
error by mapping the returned Err to conn_failed_error(...) instead of
propagating raw SSH errors; replace the current ? propagation in the block that
sets effective_form.host/port and ssh_tunnel so that any Err from
start_ssh_tunnel is converted with conn_failed_error (include context like "SSH
tunnel setup failed") before returning, keeping effective_form and ssh_tunnel
assignment logic the same on success.

Comment on lines +549 to +553
let table_ref = format!(
"{}.{}",
quote_ident(&schema.to_uppercase()),
quote_ident(&table.to_uppercase())
);

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

🧩 Analysis chain

🌐 Web query:

In Oracle Database, are quoted identifiers case-sensitive and stored with their exact case, such that uppercasing a quoted schema or table name changes which object is referenced?

💡 Result:

Yes.

  • Unquoted identifiers are case-insensitive in Oracle: Oracle folds them to uppercase when interpreting them (so hr.emp and HR.EMP refer to the same object). [1]
  • Double-quoted identifiers are case-sensitive and Oracle treats different casing as different names: e.g., employees, "employees", "Employees", and "EMPLOYEES" can be different objects in the same namespace. Therefore, changing the case inside the quotes (such as uppercasing "MyTable" to "MYTABLE") changes which object is referenced (or can cause “object does not exist” if only the original-cased object exists). [1]
  • Oracle’s docs also state that a quoted user-defined identifier is case-sensitive (with a separate exception about omitting quotes in some PL/SQL contexts when the name is otherwise a valid ordinary identifier). [2]

Sources: [1] Oracle SQL Reference (“Nonquoted identifiers … interpreted as uppercase. Quoted identifiers are case sensitive.”) [2] Oracle Database PL/SQL Language Reference (“A quoted user-defined identifier is case-sensitive …”).


🏁 Script executed:

# First, check the oracle.rs file structure and the specific lines mentioned
wc -l src-tauri/src/db/drivers/oracle.rs

Repository: codeErrorSleep/dbpaw

Length of output: 102


🏁 Script executed:

# Read the context around lines 549-553 and look for quote_ident usage
sed -n '530,570p' src-tauri/src/db/drivers/oracle.rs

Repository: codeErrorSleep/dbpaw

Length of output: 1476


🏁 Script executed:

# Search for other occurrences of to_uppercase() with quote_ident in oracle.rs
rg -n 'to_uppercase.*quote_ident|quote_ident.*to_uppercase' src-tauri/src/db/drivers/oracle.rs -A 2 -B 2

Repository: codeErrorSleep/dbpaw

Length of output: 249


🏁 Script executed:

# Look for dictionary filters pattern above line 549
sed -n '500,549p' src-tauri/src/db/drivers/oracle.rs | grep -n 'dictionary\|filter\|where\|to_uppercase\|quote_ident'

Repository: codeErrorSleep/dbpaw

Length of output: 284


🏁 Script executed:

# Find where quote_ident is defined
rg -n 'fn quote_ident|quote_ident =' src-tauri/src/db/drivers/oracle.rs -A 5

Repository: codeErrorSleep/dbpaw

Length of output: 594


🏁 Script executed:

# Look at the broader context of the dictionary filters (lines 1-50)
head -50 src-tauri/src/db/drivers/oracle.rs

Repository: codeErrorSleep/dbpaw

Length of output: 1561


🏁 Script executed:

# Search for all to_uppercase() calls in oracle.rs to see the full pattern
rg -n 'to_uppercase()' src-tauri/src/db/drivers/oracle.rs

Repository: codeErrorSleep/dbpaw

Length of output: 878


Do not uppercase schema and table names before quoting them for Oracle.

Oracle only folds unquoted identifiers to uppercase. When users create "CamelCaseTable" or "MixedSchema", uppercasing before quoting references a different object. For example, quote_ident(&"MyTable".to_uppercase()) produces "MYTABLE", not the originally created "MyTable".

This pattern exists across multiple methods: dictionary metadata queries (lines 305–306, 339–340, 399–400, 464–465, 511–512) and table data operations (lines 551–552). Pass the original schema and table names to quote_ident() and escape_literal() without modification.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/src/db/drivers/oracle.rs` around lines 549 - 553, The code
uppercases schema/table names before quoting (e.g., in the table_ref
construction and other dictionary/query sites) which breaks quoted mixed-case
identifiers; update calls so quote_ident(...) and escape_literal(...) receive
the original schema and table variables (not schema.to_uppercase() /
table.to_uppercase()), e.g., change uses around table_ref and the dictionary
metadata query sites (the occurrences you saw near the functions that build
queries) to pass schema and table unchanged; leave any explicit uppercasing only
where unquoted comparisons to Oracle metadata require it, but do not uppercase
before calling quote_ident or escape_literal.

Comment on lines +1112 to +1125
"_INT8" => row
.try_get::<Vec<Option<i64>>, _>(name)
.ok()
.map(|v| {
serde_json::Value::Array(
v.into_iter()
.map(|o| match o {
Some(n) => serde_json::Value::Number(n.into()),
None => serde_json::Value::Null,
})
.collect(),
)
})
.unwrap_or(serde_json::Value::Null),

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

Inconsistent precision handling for _INT8 (BIGINT[]) causes data loss.

Scalar INT8 (lines 989-998) is correctly converted to String to preserve precision for JavaScript clients (values > 2^53 - 1 lose precision as JSON numbers). However, _INT8 array elements are converted to Number, causing precision loss for large BIGINT values.

This should match the scalar behavior for consistency and correctness.

🔧 Proposed fix to preserve BIGINT precision in arrays
 "_INT8" => row
     .try_get::<Vec<Option<i64>>, _>(name)
     .ok()
     .map(|v| {
         serde_json::Value::Array(
             v.into_iter()
                 .map(|o| match o {
-                    Some(n) => serde_json::Value::Number(n.into()),
+                    Some(n) => serde_json::Value::String(n.to_string()),
                     None => serde_json::Value::Null,
                 })
                 .collect(),
         )
     })
     .unwrap_or(serde_json::Value::Null),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"_INT8" => row
.try_get::<Vec<Option<i64>>, _>(name)
.ok()
.map(|v| {
serde_json::Value::Array(
v.into_iter()
.map(|o| match o {
Some(n) => serde_json::Value::Number(n.into()),
None => serde_json::Value::Null,
})
.collect(),
)
})
.unwrap_or(serde_json::Value::Null),
"_INT8" => row
.try_get::<Vec<Option<i64>>, _>(name)
.ok()
.map(|v| {
serde_json::Value::Array(
v.into_iter()
.map(|o| match o {
Some(n) => serde_json::Value::String(n.to_string()),
None => serde_json::Value::Null,
})
.collect(),
)
})
.unwrap_or(serde_json::Value::Null),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/src/db/drivers/postgres.rs` around lines 1112 - 1125, The `_INT8`
match arm currently maps array elements to serde_json::Value::Number causing
precision loss; update that arm (the match on "_INT8" in postgres.rs) to mirror
the scalar `INT8` handling by converting each Some(i64) element to
serde_json::Value::String(i64.to_string()) and leaving None as Value::Null,
preserving the outer Array and the existing unwrap_or(serde_json::Value::Null)
behavior so bigints in arrays retain full precision for JS clients.

/// ORACLE_HOST – defaults to "localhost"
/// ORACLE_PORT – defaults to 1521
/// ORACLE_USER – defaults to "system"
/// ORACLE_PASSWORD – no default (required)

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 | 🟡 Minor

Documentation and code inconsistency for ORACLE_PASSWORD.

The doc comment at line 15 states ORACLE_PASSWORD has "no default (required)", but line 34 uses env_or("ORACLE_PASSWORD", "") which provides an empty string as the default. This inconsistency could lead to confusing test failures when connecting to Oracle instances that require a password.

🔧 Option A: Make password truly required (matches docs)
 fn oracle_form_from_local_env() -> ConnectionForm {
     ConnectionForm {
         driver: "oracle".to_string(),
         host: Some(shared::env_or("ORACLE_HOST", "localhost")),
         port: Some(shared::env_i64("ORACLE_PORT", 1521)),
         username: Some(shared::env_or("ORACLE_USER", "system")),
-        password: Some(shared::env_or("ORACLE_PASSWORD", "")),
+        password: Some(
+            std::env::var("ORACLE_PASSWORD")
+                .expect("ORACLE_PASSWORD environment variable is required")
+        ),
         database: Some(shared::env_or("ORACLE_SERVICE", "FREE")),
         schema: Some(shared::env_or("ORACLE_SCHEMA", "SYSTEM")),
         ..Default::default()
     }
 }
🔧 Option B: Update docs to reflect empty default
-///   ORACLE_PASSWORD   – no default (required)
+///   ORACLE_PASSWORD   – defaults to "" (empty string)

Also applies to: 34-34

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/tests/common/oracle_context.rs` at line 15, The doc says
ORACLE_PASSWORD is required but the code uses env_or("ORACLE_PASSWORD", "")
which supplies an empty default; change the code so ORACLE_PASSWORD is truly
required (remove the empty-string default and use the required env lookup or
fail-fast helper) instead of env_or with "" — update the lookup around the
env_or("ORACLE_PASSWORD", "") call in tests/common/oracle_context.rs (the
ORACLE_PASSWORD retrieval) to panic/error if the variable is missing so docs and
code match.

Comment on lines +15 to +17
interface SidebarRevealRequest extends ActiveTableTarget {
id: number;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if SidebarRevealRequest is constructed or typed elsewhere
rg -n "SidebarRevealRequest" --type=ts --type=tsx

Repository: codeErrorSleep/dbpaw

Length of output: 91


🏁 Script executed:

rg "SidebarRevealRequest" -t ts -t tsx

Repository: codeErrorSleep/dbpaw

Length of output: 91


🏁 Script executed:

rg "SidebarRevealRequest" --type-list | grep -i tsx

Repository: codeErrorSleep/dbpaw

Length of output: 453


🏁 Script executed:

rg "SidebarRevealRequest" --color=never

Repository: codeErrorSleep/dbpaw

Length of output: 483


🏁 Script executed:

cat -n src/App.tsx | head -100

Repository: codeErrorSleep/dbpaw

Length of output: 3559


🏁 Script executed:

sed -n '100,150p' src/App.tsx

Repository: codeErrorSleep/dbpaw

Length of output: 1340


SidebarRevealRequest is duplicated in two places and should be unified.

The type is defined both in src/App.tsx (line ~119) and in src/components/business/Sidebar/Sidebar.tsx (lines 15-17). App.tsx should import the type from Sidebar instead of redefining it locally. Export SidebarRevealRequest from Sidebar.tsx and remove the duplicate definition from App.tsx.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/business/Sidebar/Sidebar.tsx` around lines 15 - 17, Export the
existing SidebarRevealRequest type from Sidebar.tsx (the interface extending
ActiveTableTarget with id:number) and update the other module that currently
redefines it (the file where SidebarRevealRequest was duplicated) to import that
exported type instead; then remove the duplicate local interface definition.
Ensure the export uses the exact symbol name SidebarRevealRequest and that the
consumer file imports it and uses the same type, leaving ActiveTableTarget
references unchanged.

Comment on lines +167 to +168
export const getDriverConfig = (driver: Driver): DriverConfig =>
DRIVER_REGISTRY.find((d) => d.id === driver)!;

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

Don't let the central registry lookup crash on non-canonical driver IDs.

getDriverConfig() now sits underneath several UI helpers, but the ! assumes every runtime dbType is already canonical. A persisted/imported value like postgresql, pgsql, sqlite3, or mixed-case Oracle will now throw during render instead of being normalized or rejected gracefully.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/driver-registry.tsx` around lines 167 - 168, getDriverConfig
currently uses a non-null assertion and will throw if given non-canonical IDs;
update it to normalize and/or safely handle mismatched IDs instead of crashing.
Remove the "!" non-null assert in getDriverConfig and either (a) introduce a
normalization step (e.g., normalizeDriverId) that maps aliases like "postgresql"
-> "postgres", "pgsql" -> "postgres", "sqlite3" -> "sqlite", and case-folds
values like "Oracle" before lookup in DRIVER_REGISTRY, or (b) change
getDriverConfig's return type to DriverConfig | undefined and have callers
handle missing configs gracefully; reference getDriverConfig and DRIVER_REGISTRY
when applying the normalization or safe-return logic so runtime/imported values
don't throw during render.

Comment on lines +110 to +205
describe("getDefaultPort", () => {
test("returns correct ports for network drivers", () => {
expect(getDefaultPort("postgres")).toBe(5432);
expect(getDefaultPort("mysql")).toBe(3306);
expect(getDefaultPort("mariadb")).toBe(3306);
expect(getDefaultPort("tidb")).toBe(4000);
expect(getDefaultPort("clickhouse")).toBe(8123);
expect(getDefaultPort("mssql")).toBe(1433);
});

test("returns null for file-based drivers", () => {
expect(getDefaultPort("sqlite")).toBeNull();
expect(getDefaultPort("duckdb")).toBeNull();
});
});

// ─── isFileBasedDriver ────────────────────────────────────────────────────────

describe("isFileBasedDriver", () => {
test("returns true for file-based drivers", () => {
expect(isFileBasedDriver("sqlite")).toBe(true);
expect(isFileBasedDriver("duckdb")).toBe(true);
});

test("returns false for network drivers", () => {
const networkDrivers: Driver[] = [
"postgres",
"mysql",
"mariadb",
"tidb",
"clickhouse",
"mssql",
];
for (const d of networkDrivers) {
expect(isFileBasedDriver(d)).toBe(false);
}
});
});

// ─── isMysqlFamilyDriver ──────────────────────────────────────────────────────

describe("isMysqlFamilyDriver", () => {
test("returns true for MySQL-family drivers", () => {
expect(isMysqlFamilyDriver("mysql")).toBe(true);
expect(isMysqlFamilyDriver("mariadb")).toBe(true);
expect(isMysqlFamilyDriver("tidb")).toBe(true);
});

test("returns false for non-MySQL drivers", () => {
const others: Driver[] = [
"postgres",
"sqlite",
"duckdb",
"clickhouse",
"mssql",
];
for (const d of others) {
expect(isMysqlFamilyDriver(d)).toBe(false);
}
});
});

// ─── supportsSSLCA ────────────────────────────────────────────────────────────

describe("supportsSSLCA", () => {
test("returns true for drivers with SSL CA support", () => {
expect(supportsSSLCA("postgres")).toBe(true);
expect(supportsSSLCA("mysql")).toBe(true);
expect(supportsSSLCA("mariadb")).toBe(true);
expect(supportsSSLCA("tidb")).toBe(true);
});

test("returns false for drivers without SSL CA support", () => {
expect(supportsSSLCA("sqlite")).toBe(false);
expect(supportsSSLCA("duckdb")).toBe(false);
expect(supportsSSLCA("clickhouse")).toBe(false);
expect(supportsSSLCA("mssql")).toBe(false);
});
});

// ─── supportsCreateDatabase ───────────────────────────────────────────────────

describe("supportsCreateDatabase", () => {
test("returns true for drivers that can create databases", () => {
expect(supportsCreateDatabase("postgres")).toBe(true);
expect(supportsCreateDatabase("mysql")).toBe(true);
expect(supportsCreateDatabase("mariadb")).toBe(true);
expect(supportsCreateDatabase("tidb")).toBe(true);
expect(supportsCreateDatabase("clickhouse")).toBe(true);
expect(supportsCreateDatabase("mssql")).toBe(true);
});

test("returns false for file-based drivers", () => {
expect(supportsCreateDatabase("sqlite")).toBe(false);
expect(supportsCreateDatabase("duckdb")).toBe(false);
});

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 | 🟡 Minor

The helper coverage still skips Oracle.

This suite adds Oracle to the registry, but these helper sections never assert Oracle's default port or the basic capability helpers. A regression in the new driver's connection defaults would still ship green.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/driver-registry.unit.test.ts` around lines 110 - 205, Tests for
helper functions omit the new "oracle" driver causing blind spots; update the
test cases for getDefaultPort, isFileBasedDriver, isMysqlFamilyDriver,
supportsSSLCA, and supportsCreateDatabase to include assertions for "oracle"
(e.g., expect(getDefaultPort("oracle")).toBe(<expected_port>),
expect(isFileBasedDriver("oracle")).toBe(false) or true as appropriate, and
corresponding expectations for isMysqlFamilyDriver, supportsSSLCA, and
supportsCreateDatabase) so the new driver is covered by these helper-unit tests.

@@ -0,0 +1,29 @@
import { describe, expect, test } from "bun:test";
import { isModKey, isEditableTarget } from "./keyboard";

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 | 🟡 Minor

Use @/ alias instead of relative import

Please switch this import to the project alias to stay consistent with the frontend path policy.
As per coding guidelines, "Use path alias @/ to reference files from ./src/ directory".

Suggested change
-import { isModKey, isEditableTarget } from "./keyboard";
+import { isModKey, isEditableTarget } from "@/lib/keyboard";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { isModKey, isEditableTarget } from "./keyboard";
import { isModKey, isEditableTarget } from "@/lib/keyboard";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/keyboard.unit.test.ts` at line 2, Replace the relative import in the
unit test with the project path alias: instead of importing isModKey and
isEditableTarget from "./keyboard" update the import to use "@/lib/keyboard" so
the test imports isModKey and isEditableTarget via the alias consistent with the
frontend path policy.

Comment thread src/services/mocks.ts
Comment on lines +763 to 776
// Dedicated array-type dataset: SELECT * FROM pg_arrays
const isArrayQuery =
lower.includes("pg_arrays") ||
lower.includes("array");
// Dedicated complex-type dataset: SELECT * FROM json_test
const isComplexQuery =
!isArrayQuery &&
(lower.includes("json_test") ||
lower.includes("json") ||
lower.includes("jsonb") ||
lower.includes("complex"));
const result = {
...mockQueryResult,
...(isArrayQuery ? mockArrayTypeData : isComplexQuery ? mockComplexTypeData : mockQueryResult),
timeTakenMs: Math.floor(Math.random() * 100) + 20,

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 | 🟡 Minor

Match the special mock datasets on table name, not any array/json substring.

With this logic, unrelated queries like SELECT array_agg(...), SELECT json_agg(...), or even statements with those words in literals/comments get routed to the fixed pg_arrays/json_test fixtures. In mock mode that produces the wrong columns and row shape for otherwise normal query-editor flows.

More precise routing example
-    const isArrayQuery =
-      lower.includes("pg_arrays") ||
-      lower.includes("array");
+    const isArrayQuery = /\bfrom\s+(?:\w+\.)?pg_arrays\b/.test(lower);
@@
-      !isArrayQuery &&
-      (lower.includes("json_test") ||
-        lower.includes("json") ||
-        lower.includes("jsonb") ||
-        lower.includes("complex"));
+      !isArrayQuery && /\bfrom\s+(?:\w+\.)?json_test\b/.test(lower);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/mocks.ts` around lines 763 - 776, The current
isArrayQuery/isComplexQuery logic matches any substring "array"/"json" which
misroutes queries; update those checks to detect the actual table name (e.g.,
pg_arrays and json_test) using word-boundary/table-name-aware matching on the
normalized SQL (lower) instead of plain substring checks, handling quoted/dotted
identifiers; then keep the rest of the selection that picks mockArrayTypeData,
mockComplexTypeData or mockQueryResult unchanged (refer to isArrayQuery,
isComplexQuery, mockArrayTypeData, mockComplexTypeData, mockQueryResult).

@codeErrorSleep codeErrorSleep merged commit edaf268 into main Apr 8, 2026
13 of 19 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 10, 2026
@codeErrorSleep codeErrorSleep deleted the release/260402 branch April 12, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant