Skip to content

fix(editor): update/delete use full composite PK in WHERE clause#324

Open
thomaswasle wants to merge 5 commits into
TabularisDB:mainfrom
thomaswasle:bug/fix-pk-on-update-table-problem
Open

fix(editor): update/delete use full composite PK in WHERE clause#324
thomaswasle wants to merge 5 commits into
TabularisDB:mainfrom
thomaswasle:bug/fix-pk-on-update-table-problem

Conversation

@thomaswasle

Copy link
Copy Markdown
Contributor

Summary

  • Editing or deleting a row in a table with a composite primary key (e.g. PRIMARY KEY
    (profile_id, phone_type, key)) previously affected all rows sharing the partial key,
    because only the first PK column was sent to the backend
  • pkColumn: string | null replaced by pkColumns: string[] | null throughout the
    frontend; the row identity is now a pkMap: Record<string, unknown> object containing all
    PK column values
  • All Tauri commands (update_record, delete_record, save_blob_to_file,
    fetch_blob_as_data_url) and all three drivers (MySQL, SQLite, PostgreSQL) now receive
    pk_map: HashMap<String, Value> and build a compound WHERE col1 = ? AND col2 = ? AND col3
    = ? clause

Test plan

  • Open a table with a composite PK (e.g. two columns that together form the PK)
  • Edit a cell value in one row — confirm only that row is updated
  • Delete a row — confirm only that row is deleted
  • Verify single-PK tables still work correctly for edit and delete
  • Verify BLOB fetch/save works on a composite-PK table

@thomaswasle thomaswasle force-pushed the bug/fix-pk-on-update-table-problem branch from ef5ac7f to 8401c24 Compare June 15, 2026 20:05
@kilo-code-bot

kilo-code-bot Bot commented Jun 15, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Resolved Issues (click to expand)

CRITICAL

File Line Issue
src/components/ui/DataGrid.tsx 244 Incomplete composite PK when query result omits PK columns — FIXED

WARNING

File Line Issue
src/utils/dataGrid.ts 35 serializePkKey collision for single-column object-type PK values — FIXED
Files Reviewed (28 files)
  • src-tauri/src/commands.rs — Tauri commands updated to accept pk_map
  • src-tauri/src/drivers/driver_trait.rs — Trait signatures updated
  • src-tauri/src/drivers/mysql/mod.rs — Composite PK WHERE clause with build_mysql_pk_where
  • src-tauri/src/drivers/mysql/tests.rs — Tests for build_mysql_pk_where
  • src-tauri/src/drivers/postgres/binding.rsbuild_pk_map_predicate helper
  • src-tauri/src/drivers/postgres/mod.rs — Composite PK update/delete/BLOB ops
  • src-tauri/src/drivers/postgres/tests.rs — Tests for build_pk_map_predicate
  • src-tauri/src/drivers/sqlite/mod.rssqlite_push_pk_where helper
  • src-tauri/src/drivers/sqlite/tests.rs — Tests for sqlite_push_pk_where
  • src-tauri/src/plugins/driver.rs — RpcDriver updated for pk_map
  • src/components/notebook/SqlCellResult.tsx — Prop rename
  • src/components/ui/BlobInput.tsx — Prop rename pkCol/pkValpkMap
  • src/components/ui/DataGrid.tsx — Composite PK support, pkIndexMaps safety
  • src/components/ui/DataGridRow.tsx — Composite PK display and pending change logic
  • src/components/ui/FieldEditor.tsx — Prop rename
  • src/components/ui/ResultEntryContent.tsx — Prop rename
  • src/components/ui/RowEditorSidebar.tsxpkMap computation via useMemo
  • src/pages/Editor.tsx — Core editor composite PK handling
  • src/types/editor.tspkColumnpkColumns type change
  • src/utils/dataGrid.tsbuildPkMap and serializePkKey utilities
  • src/utils/editor.ts — Initial state uses pkColumns
  • src/utils/multiResult.ts — Initial state uses pkColumns
  • src/utils/tabCleaner.ts — Storage serialization uses pkColumns
  • tests/components/ui/MultiResultPanel.test.tsx — Test updates
  • tests/hooks/useEditor.test.ts — Test updates
  • tests/utils/dataGrid.test.ts — Tests for buildPkMap and serializePkKey
  • tests/utils/editor.test.ts — Test updates
  • tests/utils/multiResult.test.ts — Test updates
  • tests/utils/tabCleaner.test.ts — Test updates
  • tests/utils/tabFilters.test.ts — Test updates
Previous Review Summaries (4 snapshots, latest commit 27720e4)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 27720e4)

Status: No Issues Found | Recommendation: Merge

Resolved Issues (click to expand)

CRITICAL

File Line Issue
src/components/ui/DataGrid.tsx 244 Incomplete composite PK when query result omits PK columns — FIXED

WARNING

File Line Issue
src/utils/dataGrid.ts 35 serializePkKey collision for single-column object-type PK values — FIXED
Files Reviewed (1 file)
  • src/utils/dataGrid.ts — single-column PK special case removed; all PKs now use stable JSON.stringify serialization

Fix these issues in Kilo Cloud

Previous review (commit 464ab32)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
src/utils/dataGrid.ts 35 serializePkKey collision for single-column object-type PK values
Resolved Issues (click to expand)

CRITICAL

File Line Issue
src/components/ui/DataGrid.tsx 244 Incomplete composite PK when query result omits PK columns — FIXED
Files Reviewed (27 files)
  • src-tauri/src/commands.rs
  • src-tauri/src/drivers/driver_trait.rs
  • src-tauri/src/drivers/mysql/mod.rs
  • src-tauri/src/drivers/postgres/binding.rs
  • src-tauri/src/drivers/postgres/mod.rs
  • src-tauri/src/drivers/sqlite/mod.rs
  • src-tauri/src/plugins/driver.rs
  • src/components/notebook/SqlCellResult.tsx
  • src/components/ui/BlobInput.tsx
  • src/components/ui/DataGrid.tsx
  • src/components/ui/DataGridRow.tsx
  • src/components/ui/FieldEditor.tsx
  • src/components/ui/ResultEntryContent.tsx
  • src/components/ui/RowEditorSidebar.tsx
  • src/pages/Editor.tsx
  • src/types/editor.ts
  • src/utils/dataGrid.ts - 1 issue
  • src/utils/editor.ts
  • src/utils/multiResult.ts
  • src/utils/tabCleaner.ts
  • tests/components/ui/MultiResultPanel.test.tsx
  • tests/hooks/useEditor.test.ts
  • tests/utils/editor.test.ts
  • tests/utils/multiResult.test.ts
  • tests/utils/tabCleaner.test.ts
  • tests/utils/tabFilters.test.ts

Fix these issues in Kilo Cloud

Previous review (commit 1f7a266)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
src/components/ui/DataGrid.tsx 244 Incomplete composite PK when query result omits PK columns
Files Reviewed (21 files)
  • src-tauri/src/commands.rs
  • src-tauri/src/drivers/driver_trait.rs
  • src-tauri/src/drivers/mysql/mod.rs
  • src-tauri/src/drivers/postgres/binding.rs
  • src-tauri/src/drivers/postgres/mod.rs
  • src-tauri/src/drivers/sqlite/mod.rs
  • src-tauri/src/plugins/driver.rs
  • src/components/notebook/SqlCellResult.tsx
  • src/components/ui/BlobInput.tsx
  • src/components/ui/DataGrid.tsx - 1 issue
  • src/components/ui/DataGridRow.tsx
  • src/components/ui/FieldEditor.tsx
  • src/components/ui/ResultEntryContent.tsx
  • src/components/ui/RowEditorSidebar.tsx
  • src/pages/Editor.tsx
  • src/types/editor.ts
  • src/utils/dataGrid.ts
  • src/utils/editor.ts
  • src/utils/multiResult.ts
  • src/utils/tabCleaner.ts
  • tests/ (multiple test files)

Fix these issues in Kilo Cloud

Previous review (commit 8401c24)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (20 files)
  • src-tauri/src/commands.rs - Tauri command signatures updated to accept pk_map
  • src-tauri/src/drivers/driver_trait.rs - Trait methods updated for composite PK
  • src-tauri/src/drivers/mysql/mod.rs - MySQL driver uses compound WHERE clauses
  • src-tauri/src/drivers/postgres/binding.rs - New build_pk_map_predicate helper
  • src-tauri/src/drivers/postgres/mod.rs - Postgres driver uses compound WHERE clauses
  • src-tauri/src/drivers/sqlite/mod.rs - SQLite driver uses compound WHERE clauses
  • src-tauri/src/plugins/driver.rs - RPC driver payload updated
  • src/components/notebook/SqlCellResult.tsx - Prop rename pkColumnpkColumns
  • src/components/ui/BlobInput.tsx - Uses pkMap instead of pkCol/pkVal
  • src/components/ui/DataGrid.tsx - Composite PK support in grid operations
  • src/components/ui/DataGridRow.tsx - Composite PK support in row rendering
  • src/components/ui/FieldEditor.tsx - Prop rename for PK map
  • src/components/ui/ResultEntryContent.tsx - Prop rename
  • src/components/ui/RowEditorSidebar.tsx - Builds pkMap from composite columns
  • src/pages/Editor.tsx - Tab state and submission logic updated for composite PK
  • src/types/editor.ts - Type changes pkColumnpkColumns
  • src/utils/dataGrid.ts - New buildPkMap and serializePkKey utilities
  • src/utils/editor.ts - Initial state updated
  • src/utils/multiResult.ts - Initial state updated
  • src/utils/tabCleaner.ts - Storage serialization updated

Reviewed by kimi-k2.6-20260420 · Input: 122.5K · Output: 14.1K · Cached: 513.8K

@thomaswasle thomaswasle force-pushed the bug/fix-pk-on-update-table-problem branch from 8401c24 to 1f7a266 Compare June 15, 2026 20:21
Comment thread src/components/ui/DataGrid.tsx Outdated
if (!pkColumns || pkColumns.length === 0) return [];
return pkColumns
.map((col) => columns.indexOf(col))
.filter((idx) => idx >= 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CRITICAL: Incomplete composite PK when query result omits PK columns

pkIndexMaps filters out missing columns via .filter((idx) => idx >= 0), which can make the array shorter than pkColumns. When a table has a composite PK (e.g. ['id', 'tenant_id']) but the query only returns a subset of those columns, buildPkMap produces an incomplete map like { id: 1, tenant_id: undefined }. This incomplete map is passed to onPendingChange, stored in pendingChanges, and eventually sent to the backend for UPDATE/DELETE. The backend generates a WHERE clause with only the available columns, which can match multiple rows and cause data corruption.

Previously with single-column PKs, a missing PK column resulted in pkIndexMap === null, disabling all row editing. The composite PK implementation should preserve the same safety: if any PK column is missing from the query result columns, pkIndexMaps should be [] so that editing and deletion of existing rows is disabled.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@thomaswasle thomaswasle force-pushed the bug/fix-pk-on-update-table-problem branch from 1f7a266 to 464ab32 Compare June 15, 2026 20:38
Comment thread src/utils/dataGrid.ts Outdated
const entries = Object.entries(pkMap).sort(([a], [b]) =>
a.localeCompare(b),
);
if (entries.length === 1) return String(entries[0][1]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: serializePkKey collision for single-column object-type PK values

For single-column PKs this returns String(entries[0][1]). If the PK value is a JSON object (e.g. from a JSON/JSONB column), String({}) produces "[object Object]", so all rows with JSON PK values would share the same pending-changes key. The same collision risk exists for other values that stringify identically (e.g. 0 and "0").

Composite PKs already use JSON.stringify which handles objects correctly. Consider using JSON.stringify unconditionally so single- and multi-column PKs behave the same way.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@thomaswasle thomaswasle force-pushed the bug/fix-pk-on-update-table-problem branch from 464ab32 to 27720e4 Compare June 16, 2026 03:36
@debba debba self-assigned this Jun 18, 2026

@debba debba left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for taking this on,
it's a genuinely nasty bug and I'm glad someone finally chased it down. Sending only the first PK column meant composite-key tables were quietly updating or deleting every row that shared that partial value, which is about as bad as it gets for a data tool. The pk_map approach is the right one, and I appreciate that you carried it all the way through: all four Tauri commands, the trait, the three drivers, the RPC plugin path, and the whole frontend. I went looking for leftover pkCol/pkVal references and couldn't find any, so the migration is complete.

Two things in particular made me happy. Bailing out of edit mode entirely when a PK column is missing from the result set — instead of building a partial WHERE — is exactly the kind of defensive choice I'd want here. And slipping escape_identifier onto the identifiers that used to be interpolated raw is a nice bonus on top of the actual fix.

A few things I'd like sorted before we merge:

  • Tests. Right now everything in the test diff is just the pkColumnpkColumns rename — the new helpers have no coverage. serializePkKey and buildPkMap on the TS side, and build_mysql_pk_where / build_pk_map_predicate / sqlite_push_pk_where on the Rust side. I'd especially want serializePkKey tested for key ordering and the single vs. composite cases. We ask for tests alongside new utilities, so this is the main blocker for me.

  • The doc comment on serializePkKey says single-column PKs fall back to plain String(value) for backward compat, but the code always JSON.stringifys — so id=5 ends up as {"id":5}, not "5". It's harmless since these keys never leave memory, but the comment will trip up whoever reads it next, so I'd just fix the comment.

  • build_mysql_pk_where builds the predicate string and then all three callers throw it away (let (_, pairs)) and rebuild it by hand with push_bind. The join(" AND ") is dead work — I'd have it return just the sorted pairs. Postgres and SQLite are fine; it's only the MySQL helper that's out of step.

  • Minor, take it or leave it: RowEditorSidebar rebuilds pkMap with Object.fromEntries on every render, so BlobInput's fetch effect re-fires each time now (it used to lean on stable primitives). A useMemo would settle it.

The composite WHERE logic itself reads correctly to me, so really it's the tests and that comment standing between this and a merge. Nice work overall.

  Cover serializePkKey (key ordering, single vs composite) and buildPkMap
  on the TS side, and build_mysql_pk_where, sqlite_push_pk_where, and
  build_pk_map_predicate on the Rust side — including empty-map rejection,
  alphabetical sort invariant, identifier escaping, and placeholder
  indexing.
  The old comment claimed single-column PKs fall back to plain String(value);
  the function always uses JSON.stringify.
  All three callers discarded the WHERE string and rebuilt it via
  push/push_bind anyway, making the join(" AND ") dead work.
…tches

  Object.fromEntries on every render produced a new reference each time,
  causing BlobInput's fetch effect to re-fire. useMemo keeps the reference
  stable until pkColumns or rowData actually changes.
@thomaswasle

Copy link
Copy Markdown
Contributor Author

I tried to address your requested changes. But I am not shure why the kilo code review is failing.Can you have a look and help @debba ?

@debba

debba commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Hi @thomaswasle, it looks that kilo failed because of API error, so nothing related to the code .
I tried relaunch it.
Btw I will review ASAP the code.
Thanks a lot

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.

2 participants