ditto/packages/utils/stats.test.ts
2025-02-17 15:32:18 -06:00

187 lines
6 KiB
TypeScript

import { assertEquals } from '@std/assert';
import { generateSecretKey, getPublicKey } from 'nostr-tools';
import { createTestDB, genEvent } from '@/test.ts';
import { countAuthorStats, getAuthorStats, getEventStats, getFollowDiff, updateStats } from './stats.ts';
Deno.test('updateStats with kind 1 increments notes count', async () => {
await using db = await createTestDB();
const sk = generateSecretKey();
const pubkey = getPublicKey(sk);
await updateStats(db, genEvent({ kind: 1 }, sk));
const stats = await getAuthorStats(db.kysely, pubkey);
assertEquals(stats!.notes_count, 1);
});
Deno.test('updateStats with kind 1 increments replies count', async () => {
await using db = await createTestDB();
const sk = generateSecretKey();
const note = genEvent({ kind: 1 }, sk);
await updateStats(db, note);
await db.store.event(note);
const reply = genEvent({ kind: 1, tags: [['e', note.id]] }, sk);
await updateStats(db, reply);
await db.store.event(reply);
const stats = await getEventStats(db.kysely, note.id);
assertEquals(stats!.replies_count, 1);
});
Deno.test('updateStats with kind 5 decrements notes count', async () => {
await using db = await createTestDB();
const sk = generateSecretKey();
const pubkey = getPublicKey(sk);
const create = genEvent({ kind: 1 }, sk);
const remove = genEvent({ kind: 5, tags: [['e', create.id]] }, sk);
await updateStats(db, create);
assertEquals((await getAuthorStats(db.kysely, pubkey))!.notes_count, 1);
await db.store.event(create);
await updateStats(db, remove);
assertEquals((await getAuthorStats(db.kysely, pubkey))!.notes_count, 0);
await db.store.event(remove);
});
Deno.test('updateStats with kind 3 increments followers count', async () => {
await using db = await createTestDB();
await updateStats(db, genEvent({ kind: 3, tags: [['p', 'alex']] }));
await updateStats(db, genEvent({ kind: 3, tags: [['p', 'alex']] }));
await updateStats(db, genEvent({ kind: 3, tags: [['p', 'alex']] }));
const stats = await getAuthorStats(db.kysely, 'alex');
assertEquals(stats!.followers_count, 3);
});
Deno.test('updateStats with kind 3 decrements followers count', async () => {
await using db = await createTestDB();
const sk = generateSecretKey();
const follow = genEvent({ kind: 3, tags: [['p', 'alex']], created_at: 0 }, sk);
const remove = genEvent({ kind: 3, tags: [], created_at: 1 }, sk);
await updateStats(db, follow);
assertEquals((await getAuthorStats(db.kysely, 'alex'))!.followers_count, 1);
await db.store.event(follow);
await updateStats(db, remove);
assertEquals((await getAuthorStats(db.kysely, 'alex'))!.followers_count, 0);
await db.store.event(remove);
});
Deno.test('getFollowDiff returns added and removed followers', () => {
const prev = genEvent({ tags: [['p', 'alex'], ['p', 'bob']] });
const next = genEvent({ tags: [['p', 'alex'], ['p', 'carol']] });
const { added, removed } = getFollowDiff(next.tags, prev.tags);
assertEquals(added, new Set(['carol']));
assertEquals(removed, new Set(['bob']));
});
Deno.test('updateStats with kind 6 increments reposts count', async () => {
await using db = await createTestDB();
const note = genEvent({ kind: 1 });
await updateStats(db, note);
await db.store.event(note);
const repost = genEvent({ kind: 6, tags: [['e', note.id]] });
await updateStats(db, repost);
await db.store.event(repost);
const stats = await getEventStats(db.kysely, note.id);
assertEquals(stats!.reposts_count, 1);
});
Deno.test('updateStats with kind 5 decrements reposts count', async () => {
await using db = await createTestDB();
const note = genEvent({ kind: 1 });
await updateStats(db, note);
await db.store.event(note);
const sk = generateSecretKey();
const repost = genEvent({ kind: 6, tags: [['e', note.id]] }, sk);
await updateStats(db, repost);
await db.store.event(repost);
await updateStats(db, genEvent({ kind: 5, tags: [['e', repost.id]] }, sk));
const stats = await getEventStats(db.kysely, note.id);
assertEquals(stats!.reposts_count, 0);
});
Deno.test('updateStats with kind 7 increments reactions count', async () => {
await using db = await createTestDB();
const note = genEvent({ kind: 1 });
await updateStats(db, note);
await db.store.event(note);
await updateStats(db, genEvent({ kind: 7, content: '+', tags: [['e', note.id]] }));
await updateStats(db, genEvent({ kind: 7, content: '😂', tags: [['e', note.id]] }));
const stats = await getEventStats(db.kysely, note.id);
assertEquals(stats!.reactions, JSON.stringify({ '+': 1, '😂': 1 }));
assertEquals(stats!.reactions_count, 2);
});
Deno.test('updateStats with kind 5 decrements reactions count', async () => {
await using db = await createTestDB();
const note = genEvent({ kind: 1 });
await updateStats(db, note);
await db.store.event(note);
const sk = generateSecretKey();
const reaction = genEvent({ kind: 7, content: '+', tags: [['e', note.id]] }, sk);
await updateStats(db, reaction);
await db.store.event(reaction);
await updateStats(db, genEvent({ kind: 5, tags: [['e', reaction.id]] }, sk));
const stats = await getEventStats(db.kysely, note.id);
assertEquals(stats!.reactions, JSON.stringify({}));
});
Deno.test('countAuthorStats counts author stats from the database', async () => {
await using db = await createTestDB();
const sk = generateSecretKey();
const pubkey = getPublicKey(sk);
await db.store.event(genEvent({ kind: 1, content: 'hello' }, sk));
await db.store.event(genEvent({ kind: 1, content: 'yolo' }, sk));
await db.store.event(genEvent({ kind: 3, tags: [['p', pubkey]] }));
await db.kysely.insertInto('author_stats').values({
pubkey,
search: 'Yolo Lolo',
notes_count: 0,
followers_count: 0,
following_count: 0,
}).onConflict((oc) => oc.column('pubkey').doUpdateSet({ 'search': 'baka' }))
.execute();
const stats = await countAuthorStats({ store: db.store, pubkey, kysely: db.kysely });
assertEquals(stats!.notes_count, 2);
assertEquals(stats!.followers_count, 1);
});