Changeset 952baf3 in Klonkt for src/config/database.js
- Timestamp:
- 08/07/2026 05:15:52 PM (5 weeks ago)
- Branches:
- main
- Children:
- ba76bf5
- Parents:
- f85b2c3 (diff), 0d5bd2c (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. - File:
-
- 1 edited
-
src/config/database.js (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/config/database.js
rf85b2c3 r952baf3 106 106 PRIMARY KEY (guardian_slug, id) 107 107 )`); 108 // Guardianship Fase 2 (shaer-jdb): een doorgestuurde follow-goedkeuring draagt 109 // een RICHTING. Bij een inkomende is de follower iemand anders en de ward het 110 // doel; bij een uitgaande is de ward zelf de follower en staat het doel in het 111 // Follow-object. Zonder deze twee kolommen werd een uitgaande opgeslagen als 112 // "deze ward wil deze ward volgen" en viel het doel weg -- dan valt er niets 113 // zinnigs te tonen, hoe je de wachtrij ook vult. 114 ensureColumn('ap_follow_reviews', 'direction', "TEXT DEFAULT 'incoming'"); 115 ensureColumn('ap_follow_reviews', 'target_uri', 'TEXT'); 116 ensureColumn('ap_follow_reviews', 'target_handle', 'TEXT'); 108 117 ensureColumn('sites', 'profile_photo', 'TEXT'); 109 118 ensureColumn('audio_tracks', 'cover_url', 'TEXT'); … … 469 478 UNIQUE(slug, actor_uri) 470 479 ); 480 -- Antwoorden van accounts die we volgen komen gewoon binnen, ondertekend 481 -- door de schrijver, maar horen niet in de Krant (belongsInTimeline) en 482 -- werden daarna nergens bewaard. Kwam er later een doorgestuurd antwoord OP 483 -- zo'n bericht, dan kenden we de ouder niet en wezen we het af (shaer-e9g). 484 -- Alleen de URI, geen inhoud: dit voedt uitsluitend de vraag "kennen wij dit 485 -- bericht?". Wordt na 30 dagen gesnoeid; doorsturen gebeurt kort na het 486 -- antwoord, dus langer bewaren levert niets op. 487 CREATE TABLE IF NOT EXISTS ap_seen_notes ( 488 uri TEXT PRIMARY KEY, 489 created_at DATETIME DEFAULT CURRENT_TIMESTAMP 490 ); 491 CREATE INDEX IF NOT EXISTS idx_ap_seen_notes_age ON ap_seen_notes(created_at); 471 492 CREATE TABLE IF NOT EXISTS ap_timeline ( 472 493 id TEXT NOT NULL, -- the remote note's AP id … … 714 735 ensureColumn('ap_outbox', 'to_actors', 'TEXT'); // JSON array of recipient actor URIs for direct notes 715 736 ensureColumn('ap_outbox', 'help_request', 'INTEGER'); // FEP-633c shaer:helpRequest (ward's call for help) 737 // Wie er op een hulpvraag af is, en wanneer hij is afgesloten (shaer-lgo). 738 // Los van ap_mentions, want dit is GEDEELDE staat: elke guardian van dit kind 739 // heeft er een kopie van, en die komt binnen als bericht van een ander. Een 740 // kolom op de mention zou alleen over onszelf gaan. 741 // 742 // OPGEPIKT mag stapelen: twee mensen die tegelijk reageren op een kind dat om 743 // hulp vraagt is geen probleem. Twee mensen die allebei niets doen omdat de 744 // ander het "geclaimd" had, wel. 745 // 746 // AFGEHANDELD kent geen terugdraai. Sluiten gebeurt met een stevige 747 // bevestiging, en leeft de vraag daarna nog, dan wordt hij opnieuw gesteld -- 748 // een nieuwe hulpvraag. Zo blijft het verslag eerlijk: er wordt niets 749 // herschreven, er wordt toegevoegd. 750 db.exec(`CREATE TABLE IF NOT EXISTS ap_help_state ( 751 note_uri TEXT NOT NULL, 752 guardian_uri TEXT NOT NULL, 753 kind TEXT NOT NULL, -- pickup | handled 754 guardian_handle TEXT, 755 created_at TEXT DEFAULT CURRENT_TIMESTAMP, 756 PRIMARY KEY (note_uri, guardian_uri, kind) 757 )`); 758 db.exec('CREATE INDEX IF NOT EXISTS idx_ap_help_state_note ON ap_help_state(note_uri)'); 716 759 ensureColumn('ap_mentions', 'help_request', 'INTEGER'); // inbound ward call-for-help (Guardian PWA message centre) 717 760 ensureColumn('ap_outbox', 'wave', 'INTEGER'); // FEP-633c shaer:wave (guardian -> ward nudge) … … 759 802 ensureColumn('ap_followers', 'handle', 'TEXT'); // @user@host 760 803 ensureColumn('ap_followers', 'icon', 'TEXT'); // avatar URL 804 feedStateTriggers(); 805 } 806 807 /** 808 * Wat er met een tijdlijn gebeurd is, op één plek (shaer-n05). 809 * 810 * De inbox-lezing voegt vier bronnen samen. De vraag "is er iets veranderd" werd 811 * eerst beantwoord met MAX(rowid) over die vier -- een TOEVALLIGE eigenschap van 812 * de tabellen, geen feit dat ergens is opgeschreven. Dat gaf precies de gebreken 813 * die je van zo'n afleiding verwacht: bewerkingen en verwijderingen bewogen hem 814 * niet, en hij kon achteruit lopen. Dezelfde fout als reacties uitlezen uit 815 * ap_timeline.liked (shaer-9e9). 816 * 817 * Nu één rij per bericht per tijdlijn, met een oplopende `rev` en `kind`. Dat 818 * beantwoordt drie vragen die anders drie eigen oplossingen zouden krijgen: 819 * is er iets veranderd sinds N, wát is er veranderd, en is dit bericht bewerkt. 820 * 821 * Bijgehouden door TRIGGERS en niet door de aanroepende code, om dezelfde reden 822 * dat er geen gebeurtenis-emitter is: een trigger zit in de database, dus geen 823 * enkel codepad kan hem vergeten. De prijs is onzichtbare logica -- wie alleen de 824 * JavaScript leest ziet niet waarom deze tabel vult. Vandaar dat ze hier staan, 825 * bij de tabel, en niet verspreid. 826 * 827 * Let op de `UPDATE OF`-kolomlijsten: die zijn niet decoratief. Een like schrijft 828 * ap_timeline.liked en een 🔁 schrijft .boosted; zonder die afbakening zou je 829 * eigen like het bericht als BEWERKT merken en elke wachtende client wekken. 830 */ 831 function feedStateTriggers() { 832 try { 833 db.exec(` 834 CREATE TABLE IF NOT EXISTS ap_feed_state ( 835 slug TEXT NOT NULL, 836 object_uri TEXT NOT NULL, 837 rev INTEGER NOT NULL, 838 kind TEXT NOT NULL, -- new | updated | deleted 839 at DATETIME DEFAULT CURRENT_TIMESTAMP, 840 PRIMARY KEY (slug, object_uri) 841 ); 842 CREATE INDEX IF NOT EXISTS idx_ap_feed_state_rev ON ap_feed_state(slug, rev); 843 -- Eén doorlopende teller voor de hele instance. Bewust niet MAX(rev) uit de 844 -- tabel zelf: verdwijnt de hoogste rij, dan zou die teruglopen en denkt een 845 -- client dat er niets gebeurd is. 846 CREATE TABLE IF NOT EXISTS ap_feed_rev (n INTEGER NOT NULL); 847 `); 848 if (!db.prepare('SELECT COUNT(*) AS n FROM ap_feed_rev').get().n) { 849 db.prepare('INSERT INTO ap_feed_rev (n) VALUES (0)').run(); 850 } 851 // slug + object_uri verschillen per bron; de rest is voor alle vier gelijk. 852 const zet = (naam, gebeurtenis, tabel, slug, uri, kind, extra = '') => ` 853 DROP TRIGGER IF EXISTS ${naam}; 854 CREATE TRIGGER ${naam} AFTER ${gebeurtenis} ON ${tabel} BEGIN 855 UPDATE ap_feed_rev SET n = n + 1; 856 INSERT INTO ap_feed_state (slug, object_uri, rev, kind) 857 ${extra || `VALUES (${slug}, ${uri}, (SELECT n FROM ap_feed_rev), '${kind}')`} 858 ON CONFLICT(slug, object_uri) DO UPDATE 859 SET rev = excluded.rev, kind = excluded.kind, at = CURRENT_TIMESTAMP; 860 END;`; 861 const joinPosts = (uri, kind) => ` 862 SELECT s.slug, ${uri}, (SELECT n FROM ap_feed_rev), '${kind}' 863 FROM posts p JOIN sites s ON s.id = p.site_id`; 864 db.exec([ 865 zet('trg_feed_tl_ins', 'INSERT', 'ap_timeline', 'NEW.slug', 'NEW.id', 'new'), 866 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'), 867 zet('trg_feed_tl_del', 'DELETE', 'ap_timeline', 'OLD.slug', 'OLD.id', 'deleted'), 868 zet('trg_feed_mn_ins', 'INSERT', 'ap_mentions', 'NEW.slug', 'NEW.object_uri', 'new'), 869 zet('trg_feed_mn_upd', 'UPDATE OF content, media_json, quote_json, embed_json', 'ap_mentions', 'NEW.slug', 'NEW.object_uri', 'updated'), 870 zet('trg_feed_mn_del', 'DELETE', 'ap_mentions', 'OLD.slug', 'OLD.object_uri', 'deleted'), 871 zet('trg_feed_ob_ins', 'INSERT', 'ap_outbox', 'NEW.site_slug', 'NEW.id', 'new'), 872 zet('trg_feed_ob_upd', 'UPDATE OF content, attachments', 'ap_outbox', 'NEW.site_slug', 'NEW.id', 'updated'), 873 zet('trg_feed_ob_del', 'DELETE', 'ap_outbox', 'OLD.site_slug', 'OLD.id', 'deleted'), 874 // ap_interactions draagt geen slug: die hangt aan de POST. Vandaar de join, 875 // en vandaar dat deze drie niet in de gewone vorm passen. 876 zet('trg_feed_ia_ins', 'INSERT', 'ap_interactions', '', '', '', `${joinPosts('NEW.object_uri', 'new')} WHERE p.id = NEW.post_id`), 877 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`), 878 zet('trg_feed_ia_del', 'DELETE', 'ap_interactions', '', '', '', `${joinPosts('OLD.object_uri', 'deleted')} WHERE p.id = OLD.post_id`), 879 ].join('\n')); 880 } catch (e) { 881 // Niet fataal: zonder deze tabel valt het wachten terug op "altijd de tijd 882 // volmaken", en dat is traag maar niet stuk. 883 console.error('❌ feed-state triggers:', e.message); 884 } 761 885 } 762 886
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)