views: avoid counting directly in the view, take from the event object if it has it

This commit is contained in:
Alex Gleason 2023-12-10 14:27:15 -06:00
parent 3147496d78
commit 21b6a02ff3
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
3 changed files with 41 additions and 19 deletions

View File

@ -80,6 +80,9 @@ type EventQuery = SelectQueryBuilder<DittoDB, 'events', {
content: string;
created_at: number;
sig: string;
stats_replies_count?: number;
stats_reposts_count?: number;
stats_reactions_count?: number;
author_id?: string;
author_tags?: string;
author_kind?: number;
@ -87,6 +90,9 @@ type EventQuery = SelectQueryBuilder<DittoDB, 'events', {
author_content?: string;
author_created_at?: number;
author_sig?: string;
author_stats_followers_count?: number;
author_stats_following_count?: number;
author_stats_notes_count?: number;
}>;
/** Build the query for a filter. */
@ -184,8 +190,12 @@ function getFiltersQuery(filters: DittoFilter[]) {
.reduce((result, query) => result.unionAll(query));
}
type AuthorStats = Omit<DittoDB['pubkey_stats'], 'pubkey'>;
type EventStats = Omit<DittoDB['event_stats'], 'event_id'>;
interface DittoEvent<K extends number = number> extends Event<K> {
author?: Event<0>;
author?: Event<0> & { stats?: AuthorStats };
stats?: EventStats;
}
/** Get events for filters from the database. */
@ -221,6 +231,22 @@ async function getFilters<K extends number>(
tags: JSON.parse(row.author_tags!),
sig: row.author_sig!,
};
if (typeof row.author_stats_followers_count === 'number') {
event.author.stats = {
followers_count: row.author_stats_followers_count,
following_count: row.author_stats_following_count!,
notes_count: row.author_stats_notes_count!,
};
}
}
if (typeof row.stats_replies_count === 'number') {
event.stats = {
replies_count: row.stats_replies_count,
reposts_count: row.stats_reposts_count!,
reactions_count: row.stats_reactions_count!,
};
}
return event;

View File

@ -1,8 +1,7 @@
import { Conf } from '@/config.ts';
import * as eventsDB from '@/db/events.ts';
import { type DittoEvent } from '@/db/events.ts';
import { findUser } from '@/db/users.ts';
import { lodash, nip19, type UnsignedEvent } from '@/deps.ts';
import { getFollowedPubkeys } from '@/queries.ts';
import { jsonMetaContentSchema } from '@/schemas/nostr.ts';
import { verifyNip05Cached } from '@/utils/nip05.ts';
import { Nip05, nostrDate, nostrNow, parseNip05 } from '@/utils.ts';
@ -12,7 +11,10 @@ interface ToAccountOpts {
withSource?: boolean;
}
async function renderAccount(event: UnsignedEvent<0>, opts: ToAccountOpts = {}) {
async function renderAccount(
event: Omit<NonNullable<DittoEvent['author']>, 'id' | 'sig'>,
opts: ToAccountOpts = {},
) {
const { withSource = false } = opts;
const { pubkey } = event;
@ -26,12 +28,9 @@ async function renderAccount(event: UnsignedEvent<0>, opts: ToAccountOpts = {})
const npub = nip19.npubEncode(pubkey);
const [user, parsed05, followersCount, followingCount, statusesCount] = await Promise.all([
const [user, parsed05] = await Promise.all([
findUser({ pubkey }),
parseAndVerifyNip05(nip05, pubkey),
eventsDB.countFilters([{ kinds: [3], '#p': [pubkey] }]),
getFollowedPubkeys(pubkey).then((pubkeys) => pubkeys.length),
eventsDB.countFilters([{ kinds: [1], authors: [pubkey] }]),
]);
return {
@ -40,14 +39,14 @@ async function renderAccount(event: UnsignedEvent<0>, opts: ToAccountOpts = {})
avatar: picture,
avatar_static: picture,
bot: false,
created_at: event ? nostrDate(event.created_at).toISOString() : new Date().toISOString(),
created_at: nostrDate(event.created_at).toISOString(),
discoverable: true,
display_name: name,
emojis: renderEmojis(event),
fields: [],
follow_requests_count: 0,
followers_count: followersCount,
following_count: followingCount,
followers_count: event.stats?.followers_count ?? 0,
following_count: event.stats?.following_count ?? 0,
fqn: parsed05?.handle || npub,
header: banner,
header_static: banner,
@ -65,7 +64,7 @@ async function renderAccount(event: UnsignedEvent<0>, opts: ToAccountOpts = {})
follow_requests_count: 0,
}
: undefined,
statuses_count: statusesCount,
statuses_count: event.stats?.notes_count ?? 0,
url: Conf.local(`/users/${pubkey}`),
username: parsed05?.nickname || npub.substring(0, 8),
pleroma: {

View File

@ -26,13 +26,10 @@ async function renderStatus(event: eventsDB.DittoEvent<1>, viewerPubkey?: string
const { html, links, firstUrl } = parseNoteContent(event.content);
const [mentions, card, repliesCount, reblogsCount, favouritesCount, [repostEvent], [reactionEvent]] = await Promise
const [mentions, card, [repostEvent], [reactionEvent]] = await Promise
.all([
Promise.all(mentionedPubkeys.map(toMention)),
firstUrl ? unfurlCardCached(firstUrl) : null,
eventsDB.countFilters([{ kinds: [1], '#e': [event.id] }]),
eventsDB.countFilters([{ kinds: [6], '#e': [event.id] }]),
eventsDB.countFilters([{ kinds: [7], '#e': [event.id] }]),
viewerPubkey
? eventsDB.getFilters([{ kinds: [6], '#e': [event.id], authors: [viewerPubkey] }], { limit: 1 })
: [],
@ -66,9 +63,9 @@ async function renderStatus(event: eventsDB.DittoEvent<1>, viewerPubkey?: string
spoiler_text: (cw ? cw[1] : subject?.[1]) || '',
visibility: 'public',
language: event.tags.find((tag) => tag[0] === 'lang')?.[1] || null,
replies_count: repliesCount,
reblogs_count: reblogsCount,
favourites_count: favouritesCount,
replies_count: event.stats?.replies_count ?? 0,
reblogs_count: event.stats?.reposts_count ?? 0,
favourites_count: event.stats?.reactions_count ?? 0,
favourited: reactionEvent?.content === '+',
reblogged: Boolean(repostEvent),
muted: false,