···11+/**
22+ * Query the unseen notification count for a DID.
33+ * Used to set the badge number on push notifications.
44+ */
55+66+function blockMuteFilter(didCol = "did"): string {
77+ return `
88+ AND ${didCol} NOT IN (SELECT subject FROM "social.grain.graph.block" WHERE did = $1)
99+ AND ${didCol} NOT IN (SELECT did FROM "social.grain.graph.block" WHERE subject = $1)
1010+ AND ${didCol} NOT IN (SELECT subject FROM _mutes WHERE did = $1)
1111+ `;
1212+}
1313+1414+export async function getUnseenCount(
1515+ db: { query: (sql: string, params?: unknown[]) => Promise<unknown[]> },
1616+ did: string,
1717+): Promise<number> {
1818+ const prefRows = (await db.query(
1919+ `SELECT value FROM _preferences WHERE did = $1 AND key = 'lastSeenNotifications'`,
2020+ [did],
2121+ )) as { value: string }[];
2222+2323+ let lastSeen: string | null = null;
2424+ if (prefRows[0]) {
2525+ try {
2626+ lastSeen = typeof prefRows[0].value === "string" ? JSON.parse(prefRows[0].value) : prefRows[0].value;
2727+ } catch {}
2828+ }
2929+3030+ const timeFilter = lastSeen ? `AND created_at > $2` : "";
3131+ const params = lastSeen ? [did, lastSeen] : [did];
3232+3333+ const rows = (await db.query(
3434+ `SELECT count(*) as cnt FROM (
3535+ SELECT uri FROM "social.grain.favorite"
3636+ WHERE subject IN (SELECT uri FROM "social.grain.gallery" WHERE did = $1)
3737+ AND did != $1 ${blockMuteFilter()} ${timeFilter}
3838+ UNION ALL
3939+ SELECT uri FROM "social.grain.comment"
4040+ WHERE subject IN (SELECT uri FROM "social.grain.gallery" WHERE did = $1)
4141+ AND did != $1 AND reply_to IS NULL ${blockMuteFilter()} ${timeFilter}
4242+ UNION ALL
4343+ SELECT c.uri FROM "social.grain.comment" c
4444+ WHERE c.reply_to IN (SELECT uri FROM "social.grain.comment" WHERE did = $1)
4545+ AND c.did != $1 ${blockMuteFilter("c.did")} ${timeFilter}
4646+ UNION ALL
4747+ SELECT uri FROM "social.grain.graph.follow"
4848+ WHERE subject = $1 AND did != $1 ${blockMuteFilter()} ${timeFilter}
4949+ UNION ALL
5050+ SELECT uri FROM "social.grain.favorite"
5151+ WHERE subject IN (SELECT uri FROM "social.grain.story" WHERE did = $1)
5252+ AND did != $1 ${blockMuteFilter()} ${timeFilter}
5353+ UNION ALL
5454+ SELECT uri FROM "social.grain.comment"
5555+ WHERE subject IN (SELECT uri FROM "social.grain.story" WHERE did = $1)
5656+ AND did != $1 AND reply_to IS NULL ${blockMuteFilter()} ${timeFilter}
5757+ )`,
5858+ params,
5959+ )) as { cnt: number }[];
6060+6161+ return rows[0]?.cnt ?? 0;
6262+}