Skip to content

fix(tables): optimistic updates for column delete/update#4512

Merged
waleedlatif1 merged 2 commits intostagingfrom
waleedlatif1/tables-bugs-fix
May 8, 2026
Merged

fix(tables): optimistic updates for column delete/update#4512
waleedlatif1 merged 2 commits intostagingfrom
waleedlatif1/tables-bugs-fix

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

@waleedlatif1 waleedlatif1 commented May 8, 2026

Summary

  • Bug: Deleting a column on a 400-row table felt unresponsive — the column stayed visible until the server's JSONB rewrite returned, then briefly "flashed back" during the cache invalidation refetch. Concurrent type changes raced the in-flight delete's invalidation and got reverted.
  • Fix: Add `onMutate`/`onError` to `useDeleteColumn` and `useUpdateColumn`. `useDeleteColumn` cancels detail queries, removes the column from `schema.columns`, strips its width from `metadata.columnWidths`, and walks every cached row (single-page + infinite shapes via the existing `snapshotAndMutateRows` helper) to remove the field from `row.data`, with full snapshot rollback on error. `useUpdateColumn` does the equivalent for column edits.
  • Bug 1 (raw Zod toast on rename) is already addressed in staging via `extractValidationIssues` / `isValidationError` — no change needed there.
  • No server, contract, or DB-schema changes — fully UX-layer fix.

Test plan

  • `bun run test hooks/queries/tables.test.ts` (4 passing — `useDeleteColumn` optimistic write/rollback/invalidate + `useUpdateColumn` write/rollback)
  • `bun run check:api-validation` passes
  • `bun run type-check` passes
  • Manual: delete a column on a 400-row table — column disappears within one frame, no flash-back
  • Manual: with a 400-row delete in flight, change another column's type — type change lands cleanly

Add onMutate/onError to useDeleteColumn and useUpdateColumn so column
deletes feel instant on large tables (no flash-back during the JSONB
rewrite) and concurrent type changes don't race the in-flight delete's
invalidation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 8, 2026 2:53am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 8, 2026

PR Summary

Medium Risk
Moderate risk: changes React Query mutation behavior and cache shapes (schema, metadata, and row caches) with rollback logic; bugs here could leave UI caches inconsistent until refetch.

Overview
Improves table UX by making column delete and column update mutations optimistic.

useDeleteColumn now cancels in-flight schema queries, immediately removes the column from cached schema.columns, drops its entry from metadata.columnWidths, and strips the corresponding key from all cached row data (case-insensitive), snapshotting prior cache state for rollback on error.

useUpdateColumn now optimistically patches the cached column definition and, when renaming, rewrites the affected row-data key across cached rows; both mutations restore from snapshots on error and continue to invalidate schema/rows/table lists on settle. Adds Vitest coverage for optimistic write, rollback, invalidation, rename behavior, and case-insensitive row cleanup.

Reviewed by Cursor Bugbot for commit 39be514. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 8, 2026

Greptile Summary

This PR adds onMutate/onError optimistic-update lifecycles to useDeleteColumn and useUpdateColumn, eliminating the column-delete flash and the race condition where a concurrent type-change was reverted by an in-flight delete's cache invalidation.

  • useDeleteColumn.onMutate cancels the detail query, strips the column from schema.columns and metadata.columnWidths, then calls snapshotAndMutateRows (case-insensitive key lookup) to remove the column field from every cached row. onError restores both snapshots and shows a toast; onSettled invalidates detail, rows, and lists.
  • useUpdateColumn.onMutate applies the column patch optimistically to the schema; if the mutation is a rename, it additionally walks the row cache via snapshotAndMutateRows to rewrite the matching key to the new name so cells stay populated through the round-trip. onError rolls back both layers.
  • A new Vitest suite (tables.test.ts) covers optimistic write, rollback, onSettled invalidation, rename row-data migration, and case-insensitive key cleanup for both hooks.

Confidence Score: 5/5

Safe to merge — purely additive optimistic-update logic with no server, contract, or schema changes, and comprehensive test coverage for the new paths.

Both hooks follow the exact same rollback and invalidation pattern already proven by existing optimistic mutations in the file. The snapshotAndMutateRows helper is reused rather than reimplemented, case-insensitive key matching is correctly applied in both the schema filter and the row-data lookup, and onSettled ensures the cache is always reconciled with the server regardless of outcome. No data-loss or stale-state scenarios were identified.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/hooks/queries/tables.ts Adds onMutate/onError to useUpdateColumn and useDeleteColumn with correct schema, metadata, and row-cache optimistic updates; rollback and toast patterns mirror existing hooks.
apps/sim/hooks/queries/tables.test.ts New Vitest suite exercising optimistic write, rollback, onSettled invalidation, rename row-key migration, and case-insensitive cleanup for both hooks; mock setup is correct and isolated.

Sequence Diagram

sequenceDiagram
    participant UI
    participant useDeleteColumn / useUpdateColumn
    participant QueryCache
    participant Server

    UI->>useDeleteColumn / useUpdateColumn: mutate(columnName / {columnName, updates})
    useDeleteColumn / useUpdateColumn->>QueryCache: cancelQueries(detail)
    useDeleteColumn / useUpdateColumn->>QueryCache: setQueryData(detail) — remove/patch column+widths
    useDeleteColumn / useUpdateColumn->>QueryCache: cancelQueries(rowsRoot) [via snapshotAndMutateRows]
    useDeleteColumn / useUpdateColumn->>QueryCache: setQueryData(rows*) — strip/rename field in each row
    Note over QueryCache: optimistic state visible immediately
    useDeleteColumn / useUpdateColumn->>Server: DELETE/PATCH column
    alt success
        Server-->>useDeleteColumn / useUpdateColumn: 200 OK
        useDeleteColumn / useUpdateColumn->>QueryCache: invalidateQueries(detail + rowsRoot + lists)
        QueryCache-->>UI: refetch reconciles with server
    else error
        Server-->>useDeleteColumn / useUpdateColumn: error
        useDeleteColumn / useUpdateColumn->>QueryCache: setQueryData(detail, snapshot)
        useDeleteColumn / useUpdateColumn->>QueryCache: setQueryData(rows*, snapshots)
        useDeleteColumn / useUpdateColumn->>UI: toast.error(message)
        useDeleteColumn / useUpdateColumn->>QueryCache: invalidateQueries(detail + rowsRoot + lists)
    end
Loading

Reviews (4): Last reviewed commit: "fix(tables): toast on delete-column fail..." | Re-trigger Greptile

Comment thread apps/sim/hooks/queries/tables.ts Outdated
Comment thread apps/sim/hooks/queries/tables.ts
Comment thread apps/sim/hooks/queries/tables.ts Outdated
Comment thread apps/sim/hooks/queries/tables.ts
…anup, rename row-data keys

Address greptile review:
- useDeleteColumn now toasts on non-validation errors so users see when
  the column "snaps back" after a server/network failure
- Row data cleanup matches keys case-insensitively in both useDeleteColumn
  and useUpdateColumn so a column stored as "Age" is cleaned even when
  the request uses "age"
- useUpdateColumn now migrates row-data keys when updates.name is set,
  preventing blank cells during the server round-trip on a rename

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptileai

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 39be514. Configure here.

@waleedlatif1 waleedlatif1 merged commit 6a927c9 into staging May 8, 2026
14 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/tables-bugs-fix branch May 8, 2026 03:01
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile-apps please re-review

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