stats: switch to a system based on diff tuples
This commit is contained in:
parent
a8944dd7ea
commit
7167553afe
64
src/stats.ts
64
src/stats.ts
|
@ -1,29 +1,59 @@
|
|||
import { db, type EventStatsRow, type PubkeyStatsRow } from '@/db.ts';
|
||||
import { Event } from '@/deps.ts';
|
||||
import { Event, findReplyTag } from '@/deps.ts';
|
||||
|
||||
type PubkeyStat = keyof Omit<PubkeyStatsRow, 'pubkey'>;
|
||||
type EventStat = keyof Omit<EventStatsRow, 'event_id'>;
|
||||
|
||||
type PubkeyStatDiff = ['pubkey_stats', pubkey: string, stat: PubkeyStat, diff: number];
|
||||
type EventStatDiff = ['event_stats', eventId: string, stat: EventStat, diff: number];
|
||||
type StatDiff = PubkeyStatDiff | EventStatDiff;
|
||||
|
||||
/** Store stats for the event in LMDB. */
|
||||
function updateStats(event: Event) {
|
||||
return updateStatsQuery(event)?.execute();
|
||||
const statDiffs = getStatsDiff(event);
|
||||
if (!statDiffs.length) return;
|
||||
|
||||
const pubkeyDiffs = statDiffs.filter(([table]) => table === 'pubkey_stats') as PubkeyStatDiff[];
|
||||
const eventDiffs = statDiffs.filter(([table]) => table === 'event_stats') as EventStatDiff[];
|
||||
|
||||
return db.transaction().execute(() => {
|
||||
return Promise.all([
|
||||
pubkeyStatsQuery(pubkeyDiffs).execute(),
|
||||
eventStatsQuery(eventDiffs).execute(),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
function updateStatsQuery(event: Event) {
|
||||
const firstE = findFirstTag(event, 'e');
|
||||
/** 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];
|
||||
const replyTag = findReplyTag(event as Event<1>);
|
||||
|
||||
switch (event.kind) {
|
||||
case 1:
|
||||
return incrementPubkeyStatsQuery([event.pubkey], 'notes_count', 1);
|
||||
statDiffs.push(['pubkey_stats', event.pubkey, 'notes_count', 1]);
|
||||
if (replyTag && replyTag[1]) {
|
||||
statDiffs.push(['event_stats', replyTag[1], 'replies_count', 1]);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
return firstE ? incrementEventStatsQuery([firstE], 'reposts_count', 1) : undefined;
|
||||
if (firstE) {
|
||||
statDiffs.push(['event_stats', firstE, 'reposts_count', 1]);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
return firstE ? incrementEventStatsQuery([firstE], 'reactions_count', 1) : undefined;
|
||||
if (firstE) {
|
||||
statDiffs.push(['event_stats', firstE, 'reactions_count', 1]);
|
||||
}
|
||||
}
|
||||
|
||||
function incrementPubkeyStatsQuery(pubkeys: string[], stat: PubkeyStat, diff: number) {
|
||||
const values: PubkeyStatsRow[] = pubkeys.map((pubkey) => {
|
||||
return statDiffs;
|
||||
}
|
||||
|
||||
function pubkeyStatsQuery(diffs: PubkeyStatDiff[]) {
|
||||
const values: PubkeyStatsRow[] = diffs.map(([_, pubkey, stat, diff]) => {
|
||||
const row: PubkeyStatsRow = {
|
||||
pubkey,
|
||||
followers_count: 0,
|
||||
|
@ -40,13 +70,15 @@ function incrementPubkeyStatsQuery(pubkeys: string[], stat: PubkeyStat, diff: nu
|
|||
oc
|
||||
.column('pubkey')
|
||||
.doUpdateSet((eb) => ({
|
||||
[stat]: eb(stat, '+', diff),
|
||||
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')),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
function incrementEventStatsQuery(eventIds: string[], stat: EventStat, diff: number) {
|
||||
const values: EventStatsRow[] = eventIds.map((event_id) => {
|
||||
function eventStatsQuery(diffs: EventStatDiff[]) {
|
||||
const values: EventStatsRow[] = diffs.map(([_, event_id, stat, diff]) => {
|
||||
const row: EventStatsRow = {
|
||||
event_id,
|
||||
replies_count: 0,
|
||||
|
@ -63,13 +95,11 @@ function incrementEventStatsQuery(eventIds: string[], stat: EventStat, diff: num
|
|||
oc
|
||||
.column('event_id')
|
||||
.doUpdateSet((eb) => ({
|
||||
[stat]: eb(stat, '+', diff),
|
||||
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')),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
function findFirstTag({ tags }: Event, name: string): string | undefined {
|
||||
return tags.find(([n]) => n === name)?.[1];
|
||||
}
|
||||
|
||||
export { updateStats };
|
||||
|
|
Loading…
Reference in New Issue