sendou.ink/app/features/plus-suggestions/PlusSuggestionRepository.server.ts
Kalle c8ea75ebb6
SQL solution migration to Kysely + getting rid of routes folder (#1530)
* Kysely initial

* Badges initial

* Badge routes migrated

* Badges migrated

* Calendar work

* Fix one type problem

* Calendar work

* findResultsByUserId work

* Calendar reworking finished

* PlusSuggestions work

* Migrated suggestions

* Builds progress

* Migrated builds

* Admin migrated

* Migrate articles

* User search

* Faster getUser

* Selectable/insertable as global

* Refresh prod db script + patronTier index

* identifierToUserId

* updateProfile

* findByIdentifier

* More indexes

* User upsert

* upsertLite

* findAllPlusMembers

* updateResultHighlights

* updateMany

* User finished migration

* Fix types

* Fix PlusVotingResult typing

* PlusVotingRepository WIP

* Migrated resultsByMonthYear

* Migrated plusVotes (done with db. related migrations)

* Plus code to features folder

* Fix TODOs

* Export

* Fix range

* Migrate some user pages

* Move rest user routes

* Move /play

* Map list generator

* Front page

* Move map list generation logic

* Move plus voting logic

* Info

* API

* Adjust TODOs

* theme

* Auth

* Remove TODO
2023-11-04 13:15:36 +02:00

133 lines
3.5 KiB
TypeScript

import { formatDistance } from "date-fns";
import type { Insertable } from "kysely";
import { jsonObjectFrom } from "kysely/helpers/sqlite";
import { db } from "~/db/sql";
import type { DB } from "~/db/tables";
import type { MonthYear } from "~/features/plus-voting/core";
import { databaseTimestampToDate } from "~/utils/dates";
import { COMMON_USER_FIELDS } from "~/utils/kysely.server";
import type { Unwrapped } from "~/utils/types";
// TODO: can be made better when $narrowNotNull lands
type FindAllByMonthRow = {
tier: number;
id: number;
text: string;
createdAt: number;
author: {
id: number;
discordName: string;
discordId: string;
discordAvatar: string | null;
};
suggested: {
id: number;
discordName: string;
discordId: string;
discordAvatar: string | null;
bio: string | null;
};
};
// TODO: naming is a bit weird here (suggestion inside suggestions)
export type FindAllByMonthItem = Unwrapped<typeof findAllByMonth>;
export async function findAllByMonth(args: MonthYear) {
const rows = (await db
.selectFrom("PlusSuggestion")
.select(({ eb }) => [
"PlusSuggestion.id",
"PlusSuggestion.createdAt",
"PlusSuggestion.text",
"PlusSuggestion.tier",
jsonObjectFrom(
eb
.selectFrom("User")
.select(COMMON_USER_FIELDS)
.whereRef("PlusSuggestion.authorId", "=", "User.id"),
).as("author"),
jsonObjectFrom(
eb
.selectFrom("User")
.select([...COMMON_USER_FIELDS, "User.bio"])
.whereRef("PlusSuggestion.suggestedId", "=", "User.id"),
).as("suggested"),
])
.where("PlusSuggestion.month", "=", args.month)
.where("PlusSuggestion.year", "=", args.year)
.orderBy("PlusSuggestion.createdAt", "asc")
.execute()) as FindAllByMonthRow[];
const result: Array<{
suggested: FindAllByMonthRow["suggested"];
tier: FindAllByMonthRow["tier"];
suggestions: Array<{
author: FindAllByMonthRow["author"];
createdAtRelative: string;
createdAt: number;
id: FindAllByMonthRow["id"];
text: FindAllByMonthRow["text"];
}>;
}> = [];
for (const row of rows) {
const existing = result.find(
(suggestion) =>
suggestion.tier === row.tier &&
row.suggested.id === suggestion.suggested.id,
);
const mappedSuggestion = {
id: row.id,
text: row.text,
createdAtRelative: formatDistance(
databaseTimestampToDate(row.createdAt),
new Date(),
{ addSuffix: true },
),
createdAt: row.createdAt,
author: row.author,
};
if (existing) {
existing.suggestions.push(mappedSuggestion);
} else {
result.push({
tier: row.tier,
suggested: row.suggested,
suggestions: [mappedSuggestion],
});
}
}
return result.sort(
(a, b) => b.suggestions[0].createdAt - a.suggestions[0].createdAt,
);
}
export function create(args: Insertable<DB["PlusSuggestion"]>) {
return db.insertInto("PlusSuggestion").values(args).execute();
}
export function deleteById(id: number) {
return db.deleteFrom("PlusSuggestion").where("id", "=", id).execute();
}
export function deleteWithCommentsBySuggestedUserId({
tier,
userId,
month,
year,
}: {
tier: number;
userId: number;
month: number;
year: number;
}) {
return db
.deleteFrom("PlusSuggestion")
.where("PlusSuggestion.suggestedId", "=", userId)
.where("PlusSuggestion.tier", "=", tier)
.where("PlusSuggestion.month", "=", month)
.where("PlusSuggestion.year", "=", year)
.execute();
}