All files / apps/web/src/handlers/debts get-peers-paged.ts

100% Statements 17/17
100% Branches 0/0
100% Functions 10/10
100% Lines 17/17

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95                            6x               6x       8x   8x     8x                     8x 5x             5x             8x                     8x       8x     16x       6x 7x 7x 8x       6x                
import { z } from "zod";
 
import {
	debtsFiltersSchema,
	limitSchema,
	offsetSchema,
} from "~app/utils/validation";
import type { PeerId } from "~db/ids";
import { queueCallFactory } from "~web/handlers/batch";
import type { AuthorizedContext } from "~web/handlers/context";
import { authProcedure } from "~web/handlers/trpc";
import type { GeneralOutput } from "~web/utils/batch";
import { queueList } from "~web/utils/batch";
 
const inputSchema = z.strictObject({
	cursor: offsetSchema,
	limit: limitSchema,
	filters: debtsFiltersSchema.optional(),
});
type Input = z.infer<typeof inputSchema>;
type Output = GeneralOutput<PeerId> & { count: number };
 
const fetchPage = async (
	{ database, auth }: AuthorizedContext,
	input: Input,
) => {
	const debtSummaries = database
		.with("debtSummaries", () =>
			database
				.selectFrom("debts")
				.where("debts.ownerUserId", "=", auth.userId)
				.innerJoin("peers", (qb) => qb.onRef("peers.id", "=", "debts.peerId"))
				.select([
					"debts.peerId",
					"peers.name",
					"debts.currencyCode",
					database.fn.sum<string>("debts.amount").as("sum"),
				])
				.groupBy(["debts.peerId", "peers.name", "debts.currencyCode"]),
		)
		.selectFrom("debtSummaries");
 
	const peers = debtSummaries.$if(!input.filters?.showResolved, (qb) =>
		qb.where(
			"peerId",
			"not in",
			debtSummaries
				.select("peerId")
				.groupBy("peerId")
				.having(
					(eb) => eb.fn.count(eb.case().when("sum", "<>", "0").then(1).end()),
					"=",
					0,
				),
		),
	);
 
	const [paginatedPeers, totalCount] = await Promise.all([
		peers
			.select("peerId")
			.groupBy(["name", "peerId"])
			.orderBy("name")
			.orderBy("peerId")
			.offset(input.cursor)
			.limit(input.limit)
			.execute(),
		database
			.selectFrom(peers.select("peerId").groupBy("peerId").as("groupedPeers"))
			.select((eb) => eb.fn.count<number>("peerId").as("count"))
			.executeTakeFirstOrThrow(),
	]);
 
	return {
		count: totalCount.count,
		cursor: input.cursor,
		items: paginatedPeers.map(({ peerId }) => peerId),
	};
};
 
const queuePeerList = queueCallFactory<AuthorizedContext, Input, Output>(
	(ctx) => async (inputs) =>
		queueList<Input, PeerId, Output>(inputs, (values) =>
			fetchPage(ctx, values),
		),
);
 
export const procedure = authProcedure
	.meta({
		title: "Get peers with debts, paged",
		description:
			"Returns a page of peerIds the current  user has debts with, optionally excluding peers whose debts are fully resolved.",
	})
	.input(inputSchema)
	.query(queuePeerList);