← back to Filemaker Mcp

pull-fm-last1000.mjs

35 lines

// Pull the LAST N (newest) WALLPAPER records -> CSV. Read-only.
// Newest = highest internal record order, so we read the tail via offset.
import fs from 'fs';
const env = JSON.parse(fs.readFileSync('/tmp/fmenv.json', 'utf8'));
for (const [k, v] of Object.entries(env)) process.env[k] = v;
const fm = await import('./src/fm-client.js');

const DB = 'WALLPAPER', LAYOUT = 'Basic List of Fields';
const N = parseInt(process.argv[2] || '1000', 10);
const Q = String.fromCharCode(34);

// find total
const probe = await fm.listRecords(DB, LAYOUT, { limit: 1, offset: 1 });
const total = probe?.dataInfo?.totalRecordCount;
const start = Math.max(1, total - N + 1);
console.error(`total=${total} pulling offset ${start}..${total}`);

const rows = [];
let offset = start;
while (offset <= total) {
  const lim = Math.min(500, total - offset + 1);
  let res, tries = 0;
  while (true) { try { res = await fm.listRecords(DB, LAYOUT, { limit: lim, offset }); break; } catch (e) { if (++tries >= 4) throw e; await new Promise(r => setTimeout(r, 1500 * tries)); } }
  for (const r of (res.records || [])) {
    const f = r.fieldData || {};
    rows.push([f['combo sku'], f['Mfr Pattern'], f['JS Pattern'], f['Series'], f['Supplier'], f['Internal Description'], f['JPG Name'], r.recordId, f['Date Line Put Up:'], f['Net Price']]);
  }
  offset += lim;
}
const OUT = process.env.HOME + '/Desktop/FM_last' + N + '_' + new Date().toISOString().slice(0, 10).replace(/-/g, '') + '.csv';
const qq = x => Q + String(x ?? '').replace(/"/g, Q + Q).replace(/\r?\n/g, ' ') + Q;
fs.writeFileSync(OUT, 'combo_sku,mfr_pattern,js_pattern,series,supplier,internal_desc,jpg_name,record_id,date_put_up,net\n' + rows.map(r => r.map(qq).join(',')).join('\n') + '\n');
console.error('wrote', rows.length, '->', OUT);
console.log(JSON.stringify({ out: OUT, rows: rows.length, total }));