| 1 | #!/usr/bin/env node
|
|---|
| 2 | //
|
|---|
| 3 | // Backfill: reacties uit de afgeleide kolommen naar de tussentabel (shaer-9e9).
|
|---|
| 4 | //
|
|---|
| 5 | // "Heb ik hierop gereageerd" stond in Klonkt op twee plekken die door
|
|---|
| 6 | // verschillende routes werden gevuld: ap_timeline.liked/boosted (web-tijdlijn)
|
|---|
| 7 | // en ap_my_reactions (interact-pagina). Sinds fase 1 schrijft setReaction ze
|
|---|
| 8 | // allebei, maar alles van VOOR die wijziging staat nog maar in een van de twee.
|
|---|
| 9 | //
|
|---|
| 10 | // Dit script vult de tussentabel aan met wat alleen in de kolommen staat. Het
|
|---|
| 11 | // moet draaien VOORDAT de lezers naar de tussentabel wijzen (fase 2), anders
|
|---|
| 12 | // verdwijnen die reacties uit beeld -- stil, want een ontbrekende rij is geen
|
|---|
| 13 | // fout.
|
|---|
| 14 | //
|
|---|
| 15 | // node scripts/backfill-reactions.mjs --dry-run
|
|---|
| 16 | // node scripts/backfill-reactions.mjs
|
|---|
| 17 | //
|
|---|
| 18 | // Veilig om opnieuw te draaien: INSERT OR IGNORE plus de UNIQUE op
|
|---|
| 19 | // (site_slug, target_uri, kind) maakt het idempotent.
|
|---|
| 20 | //
|
|---|
| 21 | // Wat het NIET kan: de oorspronkelijke reactiedatum herstellen. Wanneer je
|
|---|
| 22 | // reageerde is nergens vastgelegd, dus de backfill-rijen krijgen de datum van
|
|---|
| 23 | // nu. Dat is geen verlies dat te repareren valt, wel iets om te weten als je
|
|---|
| 24 | // ooit op created_at gaat sorteren.
|
|---|
| 25 |
|
|---|
| 26 | import db from '../src/config/database.js';
|
|---|
| 27 |
|
|---|
| 28 | const dryRun = process.argv.includes('--dry-run');
|
|---|
| 29 |
|
|---|
| 30 | const scheef = (kind, kolom) => db.prepare(`
|
|---|
| 31 | SELECT t.slug, t.id FROM ap_timeline t
|
|---|
| 32 | WHERE t.${kolom} = 1
|
|---|
| 33 | AND NOT EXISTS (SELECT 1 FROM ap_my_reactions r
|
|---|
| 34 | WHERE r.site_slug = t.slug AND r.target_uri = t.id AND r.kind = ?)
|
|---|
| 35 | `).all(kind);
|
|---|
| 36 |
|
|---|
| 37 | const voor = {
|
|---|
| 38 | tussentabel: db.prepare('SELECT COUNT(*) AS n FROM ap_my_reactions').get().n,
|
|---|
| 39 | liked: db.prepare('SELECT COUNT(*) AS n FROM ap_timeline WHERE liked = 1').get().n,
|
|---|
| 40 | boosted: db.prepare('SELECT COUNT(*) AS n FROM ap_timeline WHERE boosted = 1').get().n,
|
|---|
| 41 | };
|
|---|
| 42 | const teDoen = { like: scheef('like', 'liked'), boost: scheef('boost', 'boosted') };
|
|---|
| 43 |
|
|---|
| 44 | console.log('vooraf :', JSON.stringify(voor));
|
|---|
| 45 | console.log('aan te vullen: like =', teDoen.like.length, ', boost =', teDoen.boost.length);
|
|---|
| 46 |
|
|---|
| 47 | if (dryRun) {
|
|---|
| 48 | for (const [kind, rijen] of Object.entries(teDoen)) {
|
|---|
| 49 | for (const r of rijen.slice(0, 10)) console.log(` [dry-run] ${kind} ${r.slug} ${r.id}`);
|
|---|
| 50 | if (rijen.length > 10) console.log(` ... en nog ${rijen.length - 10}`);
|
|---|
| 51 | }
|
|---|
| 52 | console.log('\n--dry-run: niets geschreven.');
|
|---|
| 53 | process.exit(0);
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | const ins = db.prepare('INSERT OR IGNORE INTO ap_my_reactions (site_slug, target_uri, kind) VALUES (?,?,?)');
|
|---|
| 57 | let toegevoegd = 0;
|
|---|
| 58 | db.transaction(() => {
|
|---|
| 59 | for (const [kind, rijen] of Object.entries(teDoen)) {
|
|---|
| 60 | for (const r of rijen) toegevoegd += ins.run(r.slug, r.id, kind).changes;
|
|---|
| 61 | }
|
|---|
| 62 | })();
|
|---|
| 63 |
|
|---|
| 64 | const na = {
|
|---|
| 65 | tussentabel: db.prepare('SELECT COUNT(*) AS n FROM ap_my_reactions').get().n,
|
|---|
| 66 | scheef: db.prepare(`
|
|---|
| 67 | SELECT COUNT(*) AS n FROM ap_timeline t
|
|---|
| 68 | WHERE (t.liked = 1 OR t.boosted = 1)
|
|---|
| 69 | AND NOT EXISTS (SELECT 1 FROM ap_my_reactions r
|
|---|
| 70 | WHERE r.site_slug = t.slug AND r.target_uri = t.id)`).get().n,
|
|---|
| 71 | };
|
|---|
| 72 |
|
|---|
| 73 | console.log('toegevoegd:', toegevoegd);
|
|---|
| 74 | console.log('achteraf :', JSON.stringify(na));
|
|---|
| 75 |
|
|---|
| 76 | // De controle die telt: is er nog een vlag zonder tegenhanger? Zo ja, dan is de
|
|---|
| 77 | // tussentabel nog niet veilig als bron en mag fase 2 niet.
|
|---|
| 78 | if (na.scheef !== 0) {
|
|---|
| 79 | console.error(`\nLET OP: nog ${na.scheef} rij(en) met een vlag zonder tegenhanger. Fase 2 mag NIET.`);
|
|---|
| 80 | process.exit(1);
|
|---|
| 81 | }
|
|---|
| 82 | if (toegevoegd !== teDoen.like.length + teDoen.boost.length) {
|
|---|
| 83 | console.error('\nLET OP: het aantal toegevoegde rijen wijkt af van de meting vooraf.');
|
|---|
| 84 | process.exit(1);
|
|---|
| 85 | }
|
|---|
| 86 | console.log('\nOK: elke vlag heeft nu een tegenhanger in de tussentabel.');
|
|---|