All files / apps/web/src/handlers/debts utils.ts

100% Statements 23/23
100% Branches 23/23
100% Functions 10/10
100% Lines 23/23

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 96 97 98 99 100 101 102                7x           35x 8x   27x     27x   39x                                           27x 39x 17x 4x 2x   2x           13x           27x   39x 39x     27x 39x   27x         27x       12x                 12x                   27x    
import type { Insertable } from "kysely";
import { isNonNullish, omit } from "remeda";
 
import type { Database } from "~db/database";
import type { DebtId, PeerId } from "~db/ids";
import type { DB } from "~db/types.gen";
import type { MakeUndefinedOptional } from "~utils/types";
 
export const upsertAutoAcceptedDebts = async (
	database: Database,
	debts: (MakeUndefinedOptional<Insertable<DB["debts"]>> & {
		isNew: boolean;
	})[],
) => {
	if (debts.length === 0) {
		return { newDebts: [], updatedDebts: [] };
	}
	const fetchedDebts = await database
		.selectFrom("debts")
		.where((eb) =>
			eb.or(
				debts.map((debt) =>
					debt.isNew
						? debt.receiptId
							? eb.and({
									ownerUserId: debt.ownerUserId,
									peerId: debt.peerId,
									receiptId: debt.receiptId,
								})
							: eb("debts.ownerUserId", "is", null)
						: eb.and({
								id: debt.id,
								ownerUserId: debt.ownerUserId,
							}),
				),
			),
		)
		.select([
			"debts.id",
			"debts.ownerUserId",
			"debts.peerId",
			"debts.receiptId",
		])
		.execute();
	const counterpartyDebts = debts.map((debt) =>
		fetchedDebts.find((fetchedDebt) => {
			if (debt.isNew) {
				if (!debt.receiptId || !fetchedDebt.receiptId) {
					return false;
				}
				return (
					fetchedDebt.ownerUserId === debt.ownerUserId &&
					fetchedDebt.peerId === debt.peerId &&
					fetchedDebt.receiptId === debt.receiptId
				);
			}
			return (
				fetchedDebt.ownerUserId === debt.ownerUserId &&
				fetchedDebt.id === debt.id
			);
		}),
	);
	const existentDebts = debts
		.map((nextDebt, index) => {
			const counterpartyDebt = counterpartyDebts[index];
			return counterpartyDebt ? ([nextDebt, counterpartyDebt] as const) : null;
		})
		.filter(isNonNullish);
	const nonExistentDebts = debts
		.map((nextDebt, index) => (counterpartyDebts[index] ? null : nextDebt))
		.filter(isNonNullish);
	const [newDebts, ...updatedDebts] = await Promise.all([
		nonExistentDebts.length === 0
			? ([] as { id: DebtId; peerId: PeerId }[])
			: database
					.insertInto("debts")
					.values(nonExistentDebts.map((debt) => omit(debt, ["isNew"])))
					.returning(["debts.id", "debts.peerId"])
					.execute(),
		...existentDebts.map(([nextDebt, currentDebt]) =>
			database
				.updateTable("debts")
				.set({
					amount: nextDebt.amount,
					timestamp: nextDebt.timestamp,
					currencyCode: nextDebt.currencyCode,
					receiptId: nextDebt.receiptId,
				})
				.where((eb) =>
					eb.and({
						id: currentDebt.id,
						ownerUserId: currentDebt.ownerUserId,
						peerId: currentDebt.peerId,
					}),
				)
				.returning(["debts.id", "debts.receiptId", "debts.peerId"])
				.executeTakeFirstOrThrow(),
		),
	]);
	return { newDebts, updatedDebts };
};