2023-12-10 22:04:52 +00:00
|
|
|
import { type AuthorStatsRow, db, type EventStatsRow } from '@/db.ts';
|
2023-12-10 19:53:51 +00:00
|
|
|
import { Event, findReplyTag } from '@/deps.ts';
|
2023-12-08 00:43:24 +00:00
|
|
|
|
2023-12-10 22:04:52 +00:00
|
|
|
type AuthorStat = keyof Omit<AuthorStatsRow, 'pubkey'>;
|
2023-12-10 17:43:41 +00:00
|
|
|
type EventStat = keyof Omit<EventStatsRow, 'event_id'>;
|
2023-12-08 00:43:24 +00:00
|
|
|
|
2023-12-10 22:04:52 +00:00
|
|
|
type AuthorStatDiff = ['author_stats', pubkey: string, stat: AuthorStat, diff: number];
|
2023-12-10 19:53:51 +00:00
|
|
|
type EventStatDiff = ['event_stats', eventId: string, stat: EventStat, diff: number];
|
2023-12-10 22:04:52 +00:00
|
|
|
type StatDiff = AuthorStatDiff | EventStatDiff;
|
2023-12-10 19:53:51 +00:00
|
|
|
|
2023-12-08 00:43:24 +00:00
|
|
|
/** Store stats for the event in LMDB. */
|
2023-12-10 21:33:01 +00:00
|
|
|
async function updateStats(event: Event) {
|
2023-12-10 19:53:51 +00:00
|
|
|
const statDiffs = getStatsDiff(event);
|
|
|
|
if (!statDiffs.length) return;
|
|
|
|
|
2023-12-10 22:04:52 +00:00
|
|
|
const pubkeyDiffs = statDiffs.filter(([table]) => table === 'author_stats') as AuthorStatDiff[];
|
2023-12-10 19:53:51 +00:00
|
|
|
const eventDiffs = statDiffs.filter(([table]) => table === 'event_stats') as EventStatDiff[];
|
|
|
|
|
2023-12-10 21:33:01 +00:00
|
|
|
await Promise.all([
|
2023-12-10 22:04:52 +00:00
|
|
|
pubkeyDiffs.length ? authorStatsQuery(pubkeyDiffs).execute() : undefined,
|
2023-12-10 21:33:01 +00:00
|
|
|
eventDiffs.length ? eventStatsQuery(eventDiffs).execute() : undefined,
|
|
|
|
]);
|
2023-12-10 17:10:11 +00:00
|
|
|
}
|
|
|
|
|
2023-12-10 19:53:51 +00:00
|
|
|
/** Calculate stats changes ahead of time so we can build an efficient query. */
|
|
|
|
function getStatsDiff(event: Event): StatDiff[] {
|
|
|
|
const statDiffs: StatDiff[] = [];
|
|
|
|
|
|
|
|
const firstE = event.tags.find(([name]) => name === 'e')?.[1];
|
2023-12-10 19:58:35 +00:00
|
|
|
const inReplyToId = findReplyTag(event as Event<1>)?.[1];
|
2023-12-10 17:43:41 +00:00
|
|
|
|
2023-12-08 00:43:24 +00:00
|
|
|
switch (event.kind) {
|
2023-12-10 17:10:11 +00:00
|
|
|
case 1:
|
2023-12-10 22:04:52 +00:00
|
|
|
statDiffs.push(['author_stats', event.pubkey, 'notes_count', 1]);
|
2023-12-10 19:58:35 +00:00
|
|
|
if (inReplyToId) {
|
|
|
|
statDiffs.push(['event_stats', inReplyToId, 'replies_count', 1]);
|
2023-12-10 19:53:51 +00:00
|
|
|
}
|
|
|
|
break;
|
2023-12-08 00:43:24 +00:00
|
|
|
case 6:
|
2023-12-10 19:53:51 +00:00
|
|
|
if (firstE) {
|
|
|
|
statDiffs.push(['event_stats', firstE, 'reposts_count', 1]);
|
|
|
|
}
|
|
|
|
break;
|
2023-12-08 00:43:24 +00:00
|
|
|
case 7:
|
2023-12-10 19:53:51 +00:00
|
|
|
if (firstE) {
|
|
|
|
statDiffs.push(['event_stats', firstE, 'reactions_count', 1]);
|
|
|
|
}
|
2023-12-08 00:43:24 +00:00
|
|
|
}
|
2023-12-10 19:53:51 +00:00
|
|
|
|
|
|
|
return statDiffs;
|
2023-12-08 00:43:24 +00:00
|
|
|
}
|
|
|
|
|
2023-12-10 22:04:52 +00:00
|
|
|
function authorStatsQuery(diffs: AuthorStatDiff[]) {
|
|
|
|
const values: AuthorStatsRow[] = diffs.map(([_, pubkey, stat, diff]) => {
|
|
|
|
const row: AuthorStatsRow = {
|
2023-12-10 19:12:35 +00:00
|
|
|
pubkey,
|
|
|
|
followers_count: 0,
|
|
|
|
following_count: 0,
|
|
|
|
notes_count: 0,
|
|
|
|
};
|
|
|
|
row[stat] = diff;
|
|
|
|
return row;
|
|
|
|
});
|
2023-12-10 17:10:11 +00:00
|
|
|
|
2023-12-10 22:04:52 +00:00
|
|
|
return db.insertInto('author_stats')
|
2023-12-10 19:12:35 +00:00
|
|
|
.values(values)
|
2023-12-10 17:10:11 +00:00
|
|
|
.onConflict((oc) =>
|
|
|
|
oc
|
|
|
|
.column('pubkey')
|
|
|
|
.doUpdateSet((eb) => ({
|
2023-12-10 19:53:51 +00:00
|
|
|
followers_count: eb('followers_count', '+', eb.ref('excluded.followers_count')),
|
|
|
|
following_count: eb('following_count', '+', eb.ref('excluded.following_count')),
|
|
|
|
notes_count: eb('notes_count', '+', eb.ref('excluded.notes_count')),
|
2023-12-10 17:10:11 +00:00
|
|
|
}))
|
|
|
|
);
|
2023-12-08 00:43:24 +00:00
|
|
|
}
|
|
|
|
|
2023-12-10 19:53:51 +00:00
|
|
|
function eventStatsQuery(diffs: EventStatDiff[]) {
|
|
|
|
const values: EventStatsRow[] = diffs.map(([_, event_id, stat, diff]) => {
|
2023-12-10 19:12:35 +00:00
|
|
|
const row: EventStatsRow = {
|
|
|
|
event_id,
|
|
|
|
replies_count: 0,
|
|
|
|
reposts_count: 0,
|
|
|
|
reactions_count: 0,
|
|
|
|
};
|
|
|
|
row[stat] = diff;
|
|
|
|
return row;
|
|
|
|
});
|
2023-12-10 17:43:41 +00:00
|
|
|
|
|
|
|
return db.insertInto('event_stats')
|
2023-12-10 19:12:35 +00:00
|
|
|
.values(values)
|
2023-12-10 17:43:41 +00:00
|
|
|
.onConflict((oc) =>
|
|
|
|
oc
|
|
|
|
.column('event_id')
|
|
|
|
.doUpdateSet((eb) => ({
|
2023-12-10 19:53:51 +00:00
|
|
|
replies_count: eb('replies_count', '+', eb.ref('excluded.replies_count')),
|
|
|
|
reposts_count: eb('reposts_count', '+', eb.ref('excluded.reposts_count')),
|
|
|
|
reactions_count: eb('reactions_count', '+', eb.ref('excluded.reactions_count')),
|
2023-12-10 17:43:41 +00:00
|
|
|
}))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-12-10 17:10:11 +00:00
|
|
|
export { updateStats };
|