[READ ONLY MIRROR] Spark Social AppView Server
github.com/sprksocial/server
atproto
deno
hono
lexicon
1import { Database } from "../db/index.ts";
2import { TimeCidKeyset } from "../db/pagination.ts";
3
4export class Reposts {
5 private db: Database;
6 private timeCidKeyset: TimeCidKeyset;
7
8 constructor(db: Database) {
9 this.db = db;
10 this.timeCidKeyset = new TimeCidKeyset();
11 }
12
13 async bySubject(
14 subject?: { uri: string; cid?: string },
15 limit = 50,
16 cursor?: string,
17 ) {
18 if (!subject?.uri) {
19 return { uris: [], cursor: undefined };
20 }
21
22 // Build query for reposts of this subject
23 const repostsQuery = this.db.models.Repost.find({
24 subject: subject.uri,
25 });
26
27 // Apply pagination using TimeCidKeyset
28 const paginatedQuery = this.timeCidKeyset.paginate(repostsQuery, {
29 limit,
30 cursor,
31 direction: "desc",
32 });
33
34 const reposts = await paginatedQuery.exec();
35
36 // Generate cursor from the last item if we have a full page
37 let nextCursor: string | undefined;
38 if (reposts.length === limit && reposts.length > 0) {
39 const lastRepost = reposts[reposts.length - 1];
40 nextCursor = this.timeCidKeyset.pack({
41 primary: lastRepost.createdAt,
42 secondary: lastRepost.cid,
43 });
44 }
45
46 return {
47 uris: reposts.map((r) => r.uri),
48 cursor: nextCursor,
49 };
50 }
51
52 async byActorAndSubjects(
53 actorDid: string,
54 refs: Array<{ uri: string; cid?: string }>,
55 ) {
56 if (refs.length === 0) {
57 return { uris: [] };
58 }
59
60 // Get all reposts by this actor for the specified subjects
61 const subjectUris = refs.map(({ uri }) => uri);
62 const reposts = await this.db.models.Repost.find({
63 authorDid: actorDid,
64 subject: { $in: subjectUris },
65 });
66
67 // Create a map for quick lookup
68 const repostMap = new Map(reposts.map((r) => [r.subject, r.uri]));
69 const uris = refs.map(({ uri }) => repostMap.get(uri) || "");
70
71 return { uris };
72 }
73
74 async getActor(actorDid: string, limit = 50, cursor?: string) {
75 // Build query for reposts by this actor
76 const repostsQuery = this.db.models.Repost.find({ authorDid: actorDid });
77
78 // Apply pagination using TimeCidKeyset
79 const paginatedQuery = this.timeCidKeyset.paginate(repostsQuery, {
80 limit,
81 cursor,
82 direction: "desc",
83 });
84
85 const reposts = await paginatedQuery.exec();
86
87 // Generate cursor from the last item if we have a full page
88 let nextCursor: string | undefined;
89 if (reposts.length === limit && reposts.length > 0) {
90 const lastRepost = reposts[reposts.length - 1];
91 nextCursor = this.timeCidKeyset.pack({
92 primary: lastRepost.createdAt,
93 secondary: lastRepost.cid,
94 });
95 }
96
97 return {
98 uris: reposts.map((r) => r.uri),
99 cursor: nextCursor,
100 };
101 }
102}