Changeset 44c9f3f in Klonkt for src/config/database.js


Ignore:
Timestamp:
08/07/2026 09:37:59 AM (5 weeks ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
31e63d1
Parents:
e5fc801 (diff), d14bf1c (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge feed-state: de merksteen als koppeltabel (shaer-n05)

Brengt d14bf1c binnen: feedCursor leest ap_feed_state in plaats van MAX(rowid)
over vier tabellen. main had e5fc801 (gate-melding in de Guardian PWA); die twee
raken elkaar alleen in feedCursor en de export-lijst.

Schone merge, geen conflict. Nagekeken op de gemergde boom: de oude
MAX(rowid)-cursor komt nul keer meer voor, de gate-melding en zijn test zijn
intact, en ap_seen_notes (shaer-e9g) staat er nog in beide bestanden. Suite
551/551 op de gemergde boom, gedraaid en niet alleen gelezen.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/config/database.js

    re5fc801 r44c9f3f  
    771771  ensureColumn('ap_followers', 'handle', 'TEXT');  // @user@host
    772772  ensureColumn('ap_followers', 'icon', 'TEXT');    // avatar URL
     773  feedStateTriggers();
     774}
     775
     776/**
     777 * Wat er met een tijdlijn gebeurd is, op één plek (shaer-n05).
     778 *
     779 * De inbox-lezing voegt vier bronnen samen. De vraag "is er iets veranderd" werd
     780 * eerst beantwoord met MAX(rowid) over die vier -- een TOEVALLIGE eigenschap van
     781 * de tabellen, geen feit dat ergens is opgeschreven. Dat gaf precies de gebreken
     782 * die je van zo'n afleiding verwacht: bewerkingen en verwijderingen bewogen hem
     783 * niet, en hij kon achteruit lopen. Dezelfde fout als reacties uitlezen uit
     784 * ap_timeline.liked (shaer-9e9).
     785 *
     786 * Nu één rij per bericht per tijdlijn, met een oplopende `rev` en `kind`. Dat
     787 * beantwoordt drie vragen die anders drie eigen oplossingen zouden krijgen:
     788 * is er iets veranderd sinds N, wát is er veranderd, en is dit bericht bewerkt.
     789 *
     790 * Bijgehouden door TRIGGERS en niet door de aanroepende code, om dezelfde reden
     791 * dat er geen gebeurtenis-emitter is: een trigger zit in de database, dus geen
     792 * enkel codepad kan hem vergeten. De prijs is onzichtbare logica -- wie alleen de
     793 * JavaScript leest ziet niet waarom deze tabel vult. Vandaar dat ze hier staan,
     794 * bij de tabel, en niet verspreid.
     795 *
     796 * Let op de `UPDATE OF`-kolomlijsten: die zijn niet decoratief. Een like schrijft
     797 * ap_timeline.liked en een 🔁 schrijft .boosted; zonder die afbakening zou je
     798 * eigen like het bericht als BEWERKT merken en elke wachtende client wekken.
     799 */
     800function feedStateTriggers() {
     801  try {
     802    db.exec(`
     803      CREATE TABLE IF NOT EXISTS ap_feed_state (
     804        slug TEXT NOT NULL,
     805        object_uri TEXT NOT NULL,
     806        rev INTEGER NOT NULL,
     807        kind TEXT NOT NULL,             -- new | updated | deleted
     808        at DATETIME DEFAULT CURRENT_TIMESTAMP,
     809        PRIMARY KEY (slug, object_uri)
     810      );
     811      CREATE INDEX IF NOT EXISTS idx_ap_feed_state_rev ON ap_feed_state(slug, rev);
     812      -- Eén doorlopende teller voor de hele instance. Bewust niet MAX(rev) uit de
     813      -- tabel zelf: verdwijnt de hoogste rij, dan zou die teruglopen en denkt een
     814      -- client dat er niets gebeurd is.
     815      CREATE TABLE IF NOT EXISTS ap_feed_rev (n INTEGER NOT NULL);
     816    `);
     817    if (!db.prepare('SELECT COUNT(*) AS n FROM ap_feed_rev').get().n) {
     818      db.prepare('INSERT INTO ap_feed_rev (n) VALUES (0)').run();
     819    }
     820    // slug + object_uri verschillen per bron; de rest is voor alle vier gelijk.
     821    const zet = (naam, gebeurtenis, tabel, slug, uri, kind, extra = '') => `
     822      DROP TRIGGER IF EXISTS ${naam};
     823      CREATE TRIGGER ${naam} AFTER ${gebeurtenis} ON ${tabel} BEGIN
     824        UPDATE ap_feed_rev SET n = n + 1;
     825        INSERT INTO ap_feed_state (slug, object_uri, rev, kind)
     826          ${extra || `VALUES (${slug}, ${uri}, (SELECT n FROM ap_feed_rev), '${kind}')`}
     827          ON CONFLICT(slug, object_uri) DO UPDATE
     828            SET rev = excluded.rev, kind = excluded.kind, at = CURRENT_TIMESTAMP;
     829      END;`;
     830    const joinPosts = (uri, kind) => `
     831          SELECT s.slug, ${uri}, (SELECT n FROM ap_feed_rev), '${kind}'
     832            FROM posts p JOIN sites s ON s.id = p.site_id`;
     833    db.exec([
     834      zet('trg_feed_tl_ins', 'INSERT', 'ap_timeline', 'NEW.slug', 'NEW.id', 'new'),
     835      zet('trg_feed_tl_upd', 'UPDATE OF content, media_json, nsfw, cw, url, poll_json, quote_json, embed_json', 'ap_timeline', 'NEW.slug', 'NEW.id', 'updated'),
     836      zet('trg_feed_tl_del', 'DELETE', 'ap_timeline', 'OLD.slug', 'OLD.id', 'deleted'),
     837      zet('trg_feed_mn_ins', 'INSERT', 'ap_mentions', 'NEW.slug', 'NEW.object_uri', 'new'),
     838      zet('trg_feed_mn_upd', 'UPDATE OF content, media_json, quote_json, embed_json', 'ap_mentions', 'NEW.slug', 'NEW.object_uri', 'updated'),
     839      zet('trg_feed_mn_del', 'DELETE', 'ap_mentions', 'OLD.slug', 'OLD.object_uri', 'deleted'),
     840      zet('trg_feed_ob_ins', 'INSERT', 'ap_outbox', 'NEW.site_slug', 'NEW.id', 'new'),
     841      zet('trg_feed_ob_upd', 'UPDATE OF content, attachments', 'ap_outbox', 'NEW.site_slug', 'NEW.id', 'updated'),
     842      zet('trg_feed_ob_del', 'DELETE', 'ap_outbox', 'OLD.site_slug', 'OLD.id', 'deleted'),
     843      // ap_interactions draagt geen slug: die hangt aan de POST. Vandaar de join,
     844      // en vandaar dat deze drie niet in de gewone vorm passen.
     845      zet('trg_feed_ia_ins', 'INSERT', 'ap_interactions', '', '', '', `${joinPosts('NEW.object_uri', 'new')} WHERE p.id = NEW.post_id`),
     846      zet('trg_feed_ia_upd', 'UPDATE OF content, media_json, quote_json, embed_json', 'ap_interactions', '', '', '', `${joinPosts('NEW.object_uri', 'updated')} WHERE p.id = NEW.post_id`),
     847      zet('trg_feed_ia_del', 'DELETE', 'ap_interactions', '', '', '', `${joinPosts('OLD.object_uri', 'deleted')} WHERE p.id = OLD.post_id`),
     848    ].join('\n'));
     849  } catch (e) {
     850    // Niet fataal: zonder deze tabel valt het wachten terug op "altijd de tijd
     851    // volmaken", en dat is traag maar niet stuk.
     852    console.error('❌ feed-state triggers:', e.message);
     853  }
    773854}
    774855
Note: See TracChangeset for help on using the changeset viewer.