~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain

photography-focused photo sharing platform

grain.social
1 collaborator
0
2
40 lines · 1.4 KB Raw History
import { defineQuery } from "$hatk";
import { hydrateStories, type StoryRow } from "../hydrate/stories.ts";
import { resolveHandle } from "../helpers/resolveHandle.ts";

export default defineQuery("social.grain.unspecced.getStoryArchive", async (ctx) => {
  const { db, ok } = ctx;
  const actor = ctx.params.actor ? await resolveHandle(db, ctx.params.actor) : null;
  if (!actor) return ok({ stories: [] });

  const limit = Math.min(Number(ctx.params.limit) || 50, 100);
  const cursor = ctx.params.cursor as string | undefined;

  const queryParams: (string | number)[] = [actor, limit + 1];
  let cursorClause = "";
  if (cursor) {
    cursorClause = ` AND s.created_at < $3`;
    queryParams.push(cursor);
  }

  const rows = (await db.query(
    `SELECT s.uri, s.cid, s.did, s.media, s.aspect_ratio, s.location, s.address, s.created_at
       FROM "social.grain.story" s
       LEFT JOIN _repos r ON s.did = r.did
       WHERE s.did = $1
         AND (r.status IS NULL OR r.status NOT IN ('takendown', 'deactivated', 'deleted'))
         ${cursorClause}
       ORDER BY s.created_at DESC
       LIMIT $2`,
    queryParams,
  )) as StoryRow[];

  const hasMore = rows.length > limit;
  const pageRows = hasMore ? rows.slice(0, limit) : rows;

  const stories = await hydrateStories(ctx, actor, pageRows);

  const nextCursor = hasMore ? pageRows[pageRows.length - 1].created_at : undefined;

  return ok({ stories, ...(nextCursor ? { cursor: nextCursor } : {}) });
});