Skip to content

Commit c64dc7b

Browse files
fix(tables): restore by orderKey, not position, under fractional flag
A saved position is the gappy column value, but under the flag insert reads position as a visual rank (OFFSET) — so position-based restore misplaces rows. - create-row redo now goes through the batch path carrying the saved orderKey (the single-insert API has no orderKey field); drop the now-unused single create mutation. - resolveBatchInsertOrderKeys appends under the flag instead of feeding gappy positions to resolveInsertOrderKey; positions remain the flag-off path.
1 parent cb42d4f commit c64dc7b

2 files changed

Lines changed: 18 additions & 6 deletions

File tree

apps/sim/hooks/use-table-undo.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
useAddTableColumn,
66
useBatchCreateTableRows,
77
useBatchUpdateTableRows,
8-
useCreateTableRow,
98
useDeleteColumn,
109
useDeleteTableRow,
1110
useDeleteTableRows,
@@ -56,7 +55,6 @@ export function useTableUndo({
5655
const canRedo = useTableUndoStore((s) => (s.stacks[tableId]?.redo.length ?? 0) > 0)
5756

5857
const updateRowMutation = useUpdateTableRow({ workspaceId, tableId })
59-
const createRowMutation = useCreateTableRow({ workspaceId, tableId })
6058
const batchCreateRowsMutation = useBatchCreateTableRows({ workspaceId, tableId })
6159
const batchUpdateRowsMutation = useBatchUpdateTableRows({ workspaceId, tableId })
6260
const deleteRowMutation = useDeleteTableRow({ workspaceId, tableId })
@@ -137,11 +135,18 @@ export function useTableUndo({
137135
if (direction === 'undo') {
138136
deleteRowMutation.mutate(action.rowId)
139137
} else {
140-
createRowMutation.mutate(
141-
{ data: action.data ?? {}, position: action.position },
138+
// Redo via the batch path so the saved orderKey restores exact placement.
139+
// The single-insert API has no orderKey field, and under the fractional-ordering
140+
// flag its `position` is read as a rank — a gappy saved position misplaces.
141+
batchCreateRowsMutation.mutate(
142+
{
143+
rows: [action.data ?? {}],
144+
positions: [action.position],
145+
orderKeys: action.orderKey ? [action.orderKey] : undefined,
146+
},
142147
{
143148
onSuccess: (response) => {
144-
const newRowId = extractCreatedRowId(response as Record<string, unknown>)
149+
const newRowId = response?.data?.rows?.[0]?.id
145150
if (newRowId && newRowId !== action.rowId) {
146151
patchUndoRowId(tableId, action.rowId, newRowId)
147152
}

apps/sim/lib/table/service.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,14 +1307,21 @@ async function resolveInsertByNeighbor(
13071307
* appends a contiguous run after the current max key. With explicit `positions`
13081308
* (undo restore), keys each row between its pre-shift position neighbors —
13091309
* correct because requested positions are distinct. Caller holds the lock.
1310+
*
1311+
* The explicit-`positions` path is meaningful only when `position` is
1312+
* authoritative (flag off): with the flag on, a saved `position` is a gappy
1313+
* column value, not a visual rank, so feeding it to {@link resolveInsertOrderKey}
1314+
* (which reads `position` as an `OFFSET` rank under the flag) would mint keys at
1315+
* the wrong ranks. Callers needing exact placement under the flag pass
1316+
* `orderKeys` (handled before this function); here we just append a run.
13101317
*/
13111318
async function resolveBatchInsertOrderKeys(
13121319
trx: DbTransaction,
13131320
tableId: string,
13141321
count: number,
13151322
positions?: number[]
13161323
): Promise<string[]> {
1317-
if (!positions || positions.length === 0) {
1324+
if (!positions || positions.length === 0 || isTablesFractionalOrderingEnabled) {
13181325
return nKeysBetween(await maxOrderKey(trx, tableId), null, count)
13191326
}
13201327
const keys: string[] = []

0 commit comments

Comments
 (0)