Skip to content

Commit

Permalink
passing test "DenoKvLeaderboardClient" step "sync"
Browse files Browse the repository at this point in the history
WIP. TODO: resolve failing tests
```
DenoKvLeaderboardClient ... getLatestSeason => ./lib/leaderboard/denokv/denokv_leaderboard_client_test.ts:67:11
DenoKvLeaderboardClient ... listSeasons => ./lib/leaderboard/denokv/denokv_leaderboard_client_test.ts:73:11
DenoKvLeaderboardClient ... getSeason => ./lib/leaderboard/denokv/denokv_leaderboard_client_test.ts:79:11
```
  • Loading branch information
EthanThatOneKid committed Oct 12, 2023
1 parent 4c652a8 commit 53a90d6
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 46 deletions.
2 changes: 1 addition & 1 deletion api/dailies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export interface DailyWebhookOptions {
/**
* question is the daily question.
*/
question: api.LCQuestion;
question: api.Question;

/**
* season is the season to recap.
Expand Down
56 changes: 37 additions & 19 deletions lib/leaderboard/denokv/denokv_leaderboard_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DAY, ulid, WEEK } from "lc-dailies/deps.ts";
import type * as api from "lc-dailies/api/mod.ts";
import type { LeaderboardClient } from "lc-dailies/lib/leaderboard/mod.ts";
import { sync } from "lc-dailies/lib/leaderboard/mod.ts";
import type { LCClient } from "lc-dailies/lib/lc/mod.ts";
import { LCClient } from "lc-dailies/lib/lc/mod.ts";

/**
* DenoKvLeaderboardClient is the client for the leaderboard.
Expand Down Expand Up @@ -101,27 +101,29 @@ export class DenoKvLeaderboardClient implements LeaderboardClient {
}

public async register(
discord_user_id: string,
lc_username: string,
playerID: string,
lcUsername: string,
): Promise<api.RegisterResponse> {
const key: Deno.KvKey = [LeaderboardKvPrefix.PLAYERS, discord_user_id];
const key: Deno.KvKey = [LeaderboardKvPrefix.PLAYERS, playerID];
const playerResult = await this.kv.get<api.Player>(key);
if (playerResult.value) {
throw new Error("Player already registered");
}

// Verify the user with Leetcode.
const isVerified = await this.lc.verifyUser(lc_username);
const isVerified = await this.lc.verifyUser(lcUsername);
if (!isVerified) {
throw new Error("Failed to verify user with Leetcode");
}

// Register the player.
const player: api.Player = { discord_user_id, lc_username };
const registerResult = await this.kv
.atomic()
.check(playerResult)
.set(key, player)
.set(
key,
{ discord_user_id: playerID, lc_username: lcUsername },
)
.commit();
if (!registerResult.ok) {
throw new Error("Failed to register player");
Expand All @@ -130,10 +132,14 @@ export class DenoKvLeaderboardClient implements LeaderboardClient {
return { ok: true };
}

/**
* sync syncs the leaderboard with Leetcode.
*/
public async sync(seasonID?: string): Promise<api.SyncResponse> {
public async sync(
seasonID?: string,
referenceDate = new Date(),
): Promise<api.SyncResponse> {
// startOfWeekUTC is the start of the season in UTC.
const startOfWeekUTC = getStartOfWeek(this.restartMs, referenceDate);

// Get the season.
let season: api.Season;
let seasonResult: Deno.KvEntryMaybe<api.Season> | null = null;
if (seasonID) {
Expand All @@ -144,29 +150,36 @@ export class DenoKvLeaderboardClient implements LeaderboardClient {
if (!seasonResult.value) {
throw new Error("Season not found");
}

season = seasonResult.value;
} else {
seasonResult = await this.getLatestSeasonFromKv();
season = seasonResult?.value
? seasonResult.value
: makeEmptySeason(getStartOfWeek(this.restartMs));
: makeEmptySeason(startOfWeekUTC);
}

// Sync the season.
const players = await this.listPlayers();
season = await sync({
lcClient: this.lc,
players,
season: season!,
});
season = await sync({ lcClient: this.lc, players, season });

// Update the season if it is the latest season.
const isLatestSeason =
new Date(startOfWeekUTC) === new Date(season.start_date);
if (isLatestSeason) {
await this.updateLatestSeason(season, seasonResult);
}

// Return a sync response.
return { season };
}

public async getSeason(
season_id: string,
seasonID: string,
): Promise<api.Season | null> {
const seasonResult = await this.kv.get<api.Season>([
LeaderboardKvPrefix.SEASONS,
season_id,
seasonID,
]);
return seasonResult.value;
}
Expand All @@ -181,6 +194,11 @@ export class DenoKvLeaderboardClient implements LeaderboardClient {

return seasons;
}

public async getLatestSeason(): Promise<api.Season | null> {
const seasonResult = await this.getLatestSeasonFromKv();
return seasonResult?.value ?? null;
}
}

/**
Expand Down
11 changes: 5 additions & 6 deletions lib/leaderboard/denokv/denokv_leaderboard_client_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,12 @@ Deno.test("DenoKvLeaderboardClient", async (t) => {
});
});

await t.step("submit", async () => {
const result = await client.submit(
FAKE_DISCORD_USER_ID,
fake_lc.FAKE_RECENT_SUBMISSION_ID,
new Date(fake_lc.FAKE_LC_QUESTION_DATE),
await t.step("sync", async () => {
const syncResponse = await client.sync(
undefined,
FAKE_SEASON_START_DATE,
);
assertEquals(result.ok, true);
assertSeasonsEqual(syncResponse.season, FAKE_SEASON);
});

let seasonID: string | undefined;
Expand Down
2 changes: 1 addition & 1 deletion lib/leaderboard/leaderboard_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface LeaderboardClient {
/**
* sync syncs the leaderboard with Leetcode.
*/
sync(season_id?: string): Promise<api.SyncResponse>;
sync(season_id?: string, reference_date?: Date): Promise<api.SyncResponse>;

/**
* getLatestSeason gets the latest season.
Expand Down
36 changes: 17 additions & 19 deletions lib/leaderboard/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,31 +91,29 @@ export async function sync(options: SyncOptions): Promise<api.Season> {

// Store the question in the season.
options.season.questions[questionName] ??= recentDailyQuestion;

// Store the earliest submission of the player.
options.season.submissions[playerID] ??= {};
options.season.submissions[playerID][questionName] = {
id: lcSubmission.id,
date: submissionDate.toUTCString(),
};
}

// Calculate the scores of the players.
options.season.scores = calculateScores(
makeDefaultCalculateScoresOptions(
options.season.players,
options.season.questions,
options.season.submissions,
),
);
// Store the earliest submission of the player.
options.season.submissions[playerID] ??= {};
options.season.submissions[playerID][questionName] = {
id: lcSubmission.id,
date: submissionDate.toUTCString(),
};

// // Get the submissions of the players in the date range.
// // Calculate the scores of the players.
// // Create a season with the scores, submissions, and questions.
// return makeEmptySeason(startDate.getTime());
// Store the player in the season if it is not in the season.
options.season.players[playerID] ??= player;
}
}

// Calculate the scores of the players.
options.season.scores = calculateScores(
makeDefaultCalculateScoresOptions(
options.season.players,
options.season.questions,
options.season.submissions,
),
);

return options.season;
}

Expand Down

0 comments on commit 53a90d6

Please sign in to comment.