source: Klonkt/src/services/ap-cirkel.js@ 8151340

main
Last change on this file since 8151340 was 8151340, checked in by Robin <roboburr@…>, 4 days ago

Tijdstempels, leeskant: sorteren op tijd en niet op tekst (shaer-a937)

Deze database draagt twee spellingen door elkaar: '2026-08-06 09:02:01'
van CURRENT_TIMESTAMP en '2026-08-06T02:08:01.000Z' van toISOString().
SQLite vergelijkt tekst, en op positie 10 staat een T tegenover een
spatie -- dus binnen dezelfde dag wint de ISO-vorm altijd, hoe laat hij
ook is. Gemeten op dev: ap_timeline 80 ISO tegen 80 SQL, ap_mentions 26
tegen 38, ap_interactions 2 tegen 6. De menging is er dus echt.

De helper bestond al (STEMPEL in ap-timeline, gebouwd voor de
gesprekslezing) maar stond in een dienst, terwijl elke plek die sorteert
hem nodig heeft. Hij staat nu als isoSql in config/database.js -- daar
hoort hij, want het gaat over hoe deze OPSLAG met tijd omgaat, en elke
aanroeper importeert db toch al. STEMPEL is er nu een verwijzing naar,
zodat er niet twee kopieen van dezelfde regel bestaan.

Genormaliseerd waar de menging LEEFT: de tijdlijn zelf, de reacties
onder een post (de fout die de bead mat), de berichten en de Cirkel.
Plus de archief-export, die op dezelfde kolommen sorteert.

De terugval blijft de RAUWE waarde en niet leeg: isoSql levert ook de
cursor in de gesprekslezing, en een lege stempel zou een client zijn
plek kosten. Waar een onleesbare waarde dan landt is onbepaald, en dat
staat nu ook zo in het commentaar -- eerst schreef ik daar dat zoiets
onderaan hoort te eindigen, en dat deed de code niet.

Vier toetsen met gemengde data, ISO bewust VROEGER op de dag: precies de
stand waarin een ongenormaliseerde sortering omvalt. Tegenbewijs: maak
isoSql een doorgeefluik en alle vier vallen.

Volle suite 1248 groen.

  • Property mode set to 100644
File size: 2.1 KB
Line 
1/**
2 * ap-cirkel.js — de Cirkel (stap 10 van shaer-drc).
3 *
4 * De feed van uitgelichte accounts (auto_boost) plus zelf gebooste posts,
5 * en de twee lijstjes eromheen. Leest ap_timeline, ap_following en
6 * ap_my_reactions; schrijft niets. De enige snede tot nu toe zonder ook maar
7 * een werktuig uit de dienstlaag: alleen db.
8 */
9import db, { isoSql } from '../config/database.js';
10
11// ── Cirkel = posts from the accounts you auto-boost ("feature an artist") ──
12let _abCount, _cirkelPosts, _cirkelMembers;
13export function autoBoostCount(slug) {
14 try { if (!_abCount) _abCount = db.prepare('SELECT COUNT(*) AS n FROM ap_following WHERE slug = ? AND auto_boost = 1'); return _abCount.get(slug).n; } catch { return 0; }
15}
16export function getCirkelPosts(slug, limit, offset) {
17 try {
18 // Cirkel = posts from featured (auto_boost) accounts + posts you boosted
19 // (t.boosted), mixed by date. One row per note in ap_timeline → no duplicates.
20 if (!_cirkelPosts) _cirkelPosts = db.prepare(`
21 SELECT t.id, t.author_uri, t.author_name, t.author_handle, t.author_icon, t.author_url,
22 t.content, t.url, t.published, t.media_json, t.nsfw, t.cw,
23 (rb.target_uri IS NOT NULL) AS boosted
24 FROM ap_timeline t
25 LEFT JOIN ap_following f ON f.slug = t.slug AND f.actor_uri = t.author_uri
26 -- Uit de tussentabel, niet uit t.boosted: die kolom is een afgeleide. De
27 -- UNIQUE(site_slug, target_uri, kind) garandeert hoogstens één match, dus
28 -- deze join kan geen rijen verdubbelen.
29 LEFT JOIN ap_my_reactions rb ON rb.site_slug = t.slug AND rb.target_uri = t.id AND rb.kind = 'boost'
30 WHERE t.slug = ? AND (f.auto_boost = 1 OR rb.target_uri IS NOT NULL)
31 ORDER BY ${isoSql('COALESCE(t.published, t.created_at)')} DESC, t.rowid DESC
32 LIMIT ? OFFSET ?`);
33 return _cirkelPosts.all(slug, limit || 60, offset || 0);
34 } catch { return []; }
35}
36export function getCirkelMembers(slug) {
37 try { if (!_cirkelMembers) _cirkelMembers = db.prepare('SELECT name, url, icon FROM ap_following WHERE slug = ? AND auto_boost = 1 ORDER BY name'); return _cirkelMembers.all(slug); } catch { return []; }
38}
Note: See TracBrowser for help on using the repository browser.