* Splice a server-returned new row into the paginated row cache. Bumps the * `position` of any cached row at or past the new row's position, then inserts * the row into the overlapping page (or appends to the last page when the * position lies past everything fetched). * * Scoped to the default
( queryClient: ReturnType<typeof useQueryClient>, tableId: string, row: TableRow )
| 746 | * or column sort. Filtered/sorted queries are refetched by the caller. |
| 747 | */ |
| 748 | function reconcileCreatedRow( |
| 749 | queryClient: ReturnType<typeof useQueryClient>, |
| 750 | tableId: string, |
| 751 | row: TableRow |
| 752 | ) { |
| 753 | queryClient.setQueriesData<InfiniteData<TableRowsResponse, TableRowsPageParam>>( |
| 754 | { |
| 755 | queryKey: tableKeys.rowsRoot(tableId), |
| 756 | exact: false, |
| 757 | predicate: (query) => isDefaultOrderRowsQuery(query.queryKey), |
| 758 | }, |
| 759 | (old) => { |
| 760 | if (!old) return old |
| 761 | if (old.pages.some((p) => p.rows.some((r) => r.id === row.id))) return old |
| 762 | |
| 763 | // Use key-ordering only when the new row AND every cached row have an |
| 764 | // `orderKey` — then no neighbor bump is needed and order is exact. If any |
| 765 | // cached row is un-keyed (mid-backfill), fall back to the legacy `position` |
| 766 | // path so un-keyed rows aren't yanked to the front by an empty-string sort. |
| 767 | const byKey = |
| 768 | row.orderKey != null && old.pages.every((p) => p.rows.every((r) => r.orderKey != null)) |
| 769 | // Compare order keys bytewise to match the server's `COLLATE "C"` ordering |
| 770 | // and the `>=` checks in `fitsAfter` — `localeCompare` is locale-aware and |
| 771 | // would place the new row in a different slot than the server (e.g. an |
| 772 | // uppercase-prefixed key), leaving it visibly misordered until next reload. |
| 773 | const sortRows = (rows: TableRow[]) => |
| 774 | byKey |
| 775 | ? [...rows].sort((a, b) => |
| 776 | (a.orderKey as string) < (b.orderKey as string) |
| 777 | ? -1 |
| 778 | : (a.orderKey as string) > (b.orderKey as string) |
| 779 | ? 1 |
| 780 | : 0 |
| 781 | ) |
| 782 | : [...rows].sort((a, b) => a.position - b.position) |
| 783 | const fitsAfter = (last: TableRow | undefined) => |
| 784 | last === undefined || |
| 785 | (byKey |
| 786 | ? (last.orderKey as string) >= (row.orderKey as string) |
| 787 | : last.position >= row.position) |
| 788 | |
| 789 | const pages = byKey |
| 790 | ? old.pages |
| 791 | : old.pages.map((page) => |
| 792 | page.rows.some((r) => r.position >= row.position) |
| 793 | ? { |
| 794 | ...page, |
| 795 | rows: page.rows.map((r) => |
| 796 | r.position >= row.position ? { ...r, position: r.position + 1 } : r |
| 797 | ), |
| 798 | } |
| 799 | : page |
| 800 | ) |
| 801 | |
| 802 | let inserted = false |
| 803 | const nextPages = pages.map((page) => { |
| 804 | if (inserted) return page |
| 805 | if (!fitsAfter(page.rows[page.rows.length - 1])) return page |
no test coverage detected