fix: paginate getAllSyncedRows to fetch all products beyond the 1000 row Supabase cap

With 1005+ products, the old query returned only the top 1000 by updated_at.
Items edited long ago (like 51016DE) were silently missing from syncedData,
so the merge never applied their saved edits. Now paginate by product_id
until we exhaust the table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Vidal Wolf
2026-04-23 16:56:54 +02:00
co-authored by Claude Sonnet 4.6
parent be7009353a
commit e1cfaaedfa
2 changed files with 23 additions and 17 deletions
-3
View File
@@ -134,9 +134,6 @@ export default function App() {
console.log('Fetching synced data from Supabase...'); console.log('Fetching synced data from Supabase...');
const syncedData = await getAllSyncedRows(); const syncedData = await getAllSyncedRows();
// TEMP DIAG
const d = syncedData['51016DE'];
console.log('[DIAG v2] 51016DE:', d ? `status=${d.status} len=${d.data?.length} [103]=${JSON.stringify(d.data?.[103])}` : 'NOT FOUND');
// Extend headers with virtual columns if the Excel is shorter than the saved data. // Extend headers with virtual columns if the Excel is shorter than the saved data.
// COLUMNS hardcoded indices (PRODUCT_TYPE=103, ITEM_TO_LOGISTIC=104, etc.) are used // COLUMNS hardcoded indices (PRODUCT_TYPE=103, ITEM_TO_LOGISTIC=104, etc.) are used
+23 -14
View File
@@ -41,26 +41,35 @@ export interface SyncedRow {
} }
export async function getAllSyncedRows(): Promise<Record<string, SyncedRow>> { export async function getAllSyncedRows(): Promise<Record<string, SyncedRow>> {
const PAGE_SIZE = 1000;
const result: Record<string, SyncedRow> = {};
try { try {
const response = await safeFetch( let offset = 0;
`${SUPABASE_URL}/rest/v1/products?select=product_id,data,status&order=updated_at.desc&limit=1000`, // Paginate until Supabase returns fewer rows than PAGE_SIZE (no more pages).
{ cache: 'no-store' } // Supabase REST caps a single response at 1000 rows, so we must page.
); // Safety cap at 20 pages (20k products) to avoid infinite loops.
for (let page = 0; page < 20; page++) {
const response = await safeFetch(
`${SUPABASE_URL}/rest/v1/products?select=product_id,data,status&order=product_id.asc&limit=${PAGE_SIZE}&offset=${offset}`,
{ cache: 'no-store' }
);
if (!response.ok) { if (!response.ok) {
const errText = await response.text(); const errText = await response.text();
console.error('getAllSyncedRows failed:', response.status, errText); console.error('getAllSyncedRows failed:', response.status, errText);
return {}; return result;
} }
const rows = await response.json(); const rows = await response.json();
const result: Record<string, SyncedRow> = {}; for (const row of rows) {
for (const row of rows) { result[row.product_id] = { data: row.data, status: row.status };
result[row.product_id] = { data: row.data, status: row.status }; }
if (rows.length < PAGE_SIZE) break;
offset += PAGE_SIZE;
} }
return result; return result;
} catch (error) { } catch (error) {
console.error('Error fetching synced rows from Supabase:', error); console.error('Error fetching synced rows from Supabase:', error);
return {}; return result;
} }
} }