Skip to content

Commit 00db4ec

Browse files
fix(tables): scope optimistic insert splice to the default-order view
reconcileCreatedRow patched every rows query under rowsRoot, but its orderKey/position heuristic only matches the unfiltered, unsorted server order. Under a filter or column sort the splice could show wrong rows, wrong order, or an inflated totalCount, and without the prior rowsRoot refetch it persisted until the query went stale. - patch only the default-order rows queries (filter and sort both absent) - refetch the filtered/sorted variants on insert; active ones update now, inactive ones on next view. The default view stays optimistic (no flicker) - the find/write subtrees are excluded from the splice (different shape)
1 parent 9c011f6 commit 00db4ec

1 file changed

Lines changed: 41 additions & 3 deletions

File tree

apps/sim/hooks/queries/tables.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,17 @@ export function useCreateTableRow({ workspaceId, tableId }: RowMutationContext)
605605
// prior executions, so the stamped set is the full delta).
606606
const stampedCount = countNewlyInFlight({}, stamped.executions ?? {})
607607
if (stampedCount > 0) bumpRunState(queryClient, tableId, { [row.id]: stampedCount })
608+
609+
// `reconcileCreatedRow` only patches the default-order view. Filtered /
610+
// column-sorted rows queries can't be reconciled from that heuristic
611+
// (membership, sort position, and `totalCount` are query-specific), so
612+
// refetch them — active ones update now, inactive ones on next view. The
613+
// default view stays optimistic, so the common case never refetches.
614+
queryClient.invalidateQueries({
615+
queryKey: tableKeys.rowsRoot(tableId),
616+
exact: false,
617+
predicate: (query) => !isDefaultOrderRowsQuery(query.queryKey),
618+
})
608619
},
609620
onError: (error) => {
610621
if (isValidationError(error)) return
@@ -653,20 +664,47 @@ function patchCachedRows(
653664
)
654665
}
655666

667+
/**
668+
* A cached rows query whose ordering matches {@link reconcileCreatedRow}'s
669+
* orderKey/position heuristic: the default view with no active filter or sort.
670+
* Filtered or column-sorted variants encode a non-null `filter`/`sort` in their
671+
* params key — their membership, order, and `totalCount` are query-specific, so
672+
* an optimistic splice can't be trusted there (they're refetched instead). The
673+
* `find`/`write` subtrees aren't row-list data and never match.
674+
*/
675+
function isDefaultOrderRowsQuery(queryKey: readonly unknown[]): boolean {
676+
if (queryKey.includes('find') || queryKey.includes('write')) return false
677+
const last = queryKey[queryKey.length - 1]
678+
if (typeof last !== 'string') return false
679+
try {
680+
const params = JSON.parse(last) as { filter?: unknown; sort?: unknown }
681+
return params.filter == null && params.sort == null
682+
} catch {
683+
return false
684+
}
685+
}
686+
656687
/**
657688
* Splice a server-returned new row into the paginated row cache. Bumps the
658689
* `position` of any cached row at or past the new row's position, then inserts
659690
* the row into the overlapping page (or appends to the last page when the
660-
* position lies past everything fetched). `onSettled` invalidation reconciles
661-
* drift after the next refetch.
691+
* position lies past everything fetched).
692+
*
693+
* Scoped to the default-order rows queries only — the orderKey/position
694+
* heuristic matches the unfiltered, unsorted server order, not an active filter
695+
* or column sort. Filtered/sorted queries are refetched by the caller.
662696
*/
663697
function reconcileCreatedRow(
664698
queryClient: ReturnType<typeof useQueryClient>,
665699
tableId: string,
666700
row: TableRow
667701
) {
668702
queryClient.setQueriesData<InfiniteData<TableRowsResponse, number>>(
669-
{ queryKey: tableKeys.rowsRoot(tableId), exact: false },
703+
{
704+
queryKey: tableKeys.rowsRoot(tableId),
705+
exact: false,
706+
predicate: (query) => isDefaultOrderRowsQuery(query.queryKey),
707+
},
670708
(old) => {
671709
if (!old) return old
672710
if (old.pages.some((p) => p.rows.some((r) => r.id === row.id))) return old

0 commit comments

Comments
 (0)