mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-11 03:46:52 -05:00
@@ -0,0 +1,88 @@
|
||||
import { add, sub } from "date-fns";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
import * as TournamentFactory from "~/db/seed/factories/TournamentFactory";
|
||||
import * as UserFactory from "~/db/seed/factories/UserFactory";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
import * as TournamentRepository from "./TournamentRepository.server";
|
||||
|
||||
const QUERY = "In The Zone";
|
||||
|
||||
let author: { id: number };
|
||||
|
||||
const createTournament = (name: string, startsAt: Date) =>
|
||||
TournamentFactory.create({
|
||||
authorId: author.id,
|
||||
name,
|
||||
startTimes: [dateToDatabaseTimestamp(startsAt)],
|
||||
});
|
||||
|
||||
const search = async (limit = 10) =>
|
||||
(await TournamentRepository.searchByName({ query: QUERY, limit })).map(
|
||||
(tournament) => tournament.name,
|
||||
);
|
||||
|
||||
describe("TournamentRepository.searchByName", () => {
|
||||
beforeEach(async () => {
|
||||
author = await UserFactory.create();
|
||||
});
|
||||
|
||||
test("sorts a tournament that is happening right now first", async () => {
|
||||
await createTournament(`${QUERY} Tomorrow`, add(new Date(), { days: 1 }));
|
||||
await createTournament(`${QUERY} Started`, sub(new Date(), { hours: 3 }));
|
||||
|
||||
expect(await search()).toEqual([`${QUERY} Started`, `${QUERY} Tomorrow`]);
|
||||
});
|
||||
|
||||
test("sorts the next tournament up before ones that already happened", async () => {
|
||||
await createTournament(`${QUERY} Yesterday`, sub(new Date(), { days: 2 }));
|
||||
await createTournament(
|
||||
`${QUERY} Next Month`,
|
||||
add(new Date(), { days: 30 }),
|
||||
);
|
||||
|
||||
expect(await search()).toEqual([
|
||||
`${QUERY} Next Month`,
|
||||
`${QUERY} Yesterday`,
|
||||
]);
|
||||
});
|
||||
|
||||
test("sorts the rest by their distance from now", async () => {
|
||||
await createTournament(
|
||||
`${QUERY} In 3 Weeks`,
|
||||
add(new Date(), { weeks: 3 }),
|
||||
);
|
||||
await createTournament(
|
||||
`${QUERY} 2 Weeks Ago`,
|
||||
sub(new Date(), { weeks: 2 }),
|
||||
);
|
||||
await createTournament(
|
||||
`${QUERY} In 2 Weeks`,
|
||||
add(new Date(), { weeks: 2 }),
|
||||
);
|
||||
await createTournament(
|
||||
`${QUERY} 3 Weeks Ago`,
|
||||
sub(new Date(), { weeks: 3 }),
|
||||
);
|
||||
|
||||
expect(await search()).toEqual([
|
||||
`${QUERY} In 2 Weeks`,
|
||||
`${QUERY} 2 Weeks Ago`,
|
||||
`${QUERY} In 3 Weeks`,
|
||||
`${QUERY} 3 Weeks Ago`,
|
||||
]);
|
||||
});
|
||||
|
||||
test("keeps the next tournament up in a result set the limit cuts short", async () => {
|
||||
await createTournament(`${QUERY} Next Year`, add(new Date(), { years: 1 }));
|
||||
await createTournament(`${QUERY} Last Week`, sub(new Date(), { weeks: 1 }));
|
||||
await createTournament(
|
||||
`${QUERY} Last Month`,
|
||||
sub(new Date(), { days: 30 }),
|
||||
);
|
||||
|
||||
expect(await search(2)).toEqual([
|
||||
`${QUERY} Next Year`,
|
||||
`${QUERY} Last Week`,
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -1547,6 +1547,14 @@ export function finalizeWithoutSummary(tournamentId: number) {
|
||||
.execute();
|
||||
}
|
||||
|
||||
/** How close to its start time a tournament counts as happening right now. */
|
||||
const TOURNAMENT_ONGOING_WINDOW_IN_SECONDS = 24 * 60 * 60;
|
||||
|
||||
/**
|
||||
* Searches tournaments whose calendar event name contains the query, hidden events excluded.
|
||||
*
|
||||
* Ordered so that the tournaments most likely being looked for come first
|
||||
*/
|
||||
export async function searchByName({
|
||||
query,
|
||||
limit,
|
||||
@@ -1558,6 +1566,12 @@ export async function searchByName({
|
||||
minStartTime?: Date;
|
||||
maxStartTime?: Date;
|
||||
}) {
|
||||
const now = databaseTimestampNow();
|
||||
const distanceFromNow = sql<number>`abs("CalendarEventDate"."startsAt" - ${now})`;
|
||||
// window function so that the next tournament up is the next one of all the matches,
|
||||
// not only of the ones that happen to fit in the limit
|
||||
const nextUpStartsAt = sql<number>`min(case when "CalendarEventDate"."startsAt" - ${now} >= ${TOURNAMENT_ONGOING_WINDOW_IN_SECONDS} then "CalendarEventDate"."startsAt" end) over ()`;
|
||||
|
||||
let sqlQuery = db
|
||||
.selectFrom("Tournament")
|
||||
.innerJoin("CalendarEvent", "Tournament.id", "CalendarEvent.tournamentId")
|
||||
@@ -1574,7 +1588,15 @@ export async function searchByName({
|
||||
])
|
||||
.where("CalendarEvent.name", "like", `%${query}%`)
|
||||
.where("CalendarEvent.hidden", "=", 0)
|
||||
.orderBy("CalendarEventDate.startsAt", "desc")
|
||||
.orderBy(
|
||||
sql`case
|
||||
when ${distanceFromNow} < ${TOURNAMENT_ONGOING_WINDOW_IN_SECONDS} then 0
|
||||
when "CalendarEventDate"."startsAt" = ${nextUpStartsAt} then 1
|
||||
else 2
|
||||
end`,
|
||||
)
|
||||
.orderBy(distanceFromNow)
|
||||
.orderBy("Tournament.id")
|
||||
.limit(limit);
|
||||
|
||||
if (minStartTime) {
|
||||
|
||||
Reference in New Issue
Block a user