idz: Add team "reservation" repository

This is a hack necessary to support certain quirks of the
Initial D Zero profile creation process.
This commit is contained in:
Tau
2019-05-28 15:54:10 -04:00
parent a5dbdef33f
commit ec214d5beb
3 changed files with 142 additions and 0 deletions

View File

@@ -11,6 +11,7 @@ import { SqlStoryRepository } from "./story";
import { SqlTeamRepository } from "./team";
import { SqlTeamAutoRepository } from "./teamAuto";
import { SqlTeamMemberRepository } from "./teamMember";
import { SqlTeamReservationRepository } from "./teamReservation";
import { SqlTicketsRepository } from "./tickets";
import { SqlTimeAttackRepository } from "./timeAttack";
import { SqlTitlesRepository } from "./titles";
@@ -66,6 +67,10 @@ class TransactionImpl implements Repo.Transaction {
return new SqlTeamMemberRepository(this._conn);
}
teamReservations(): Repo.TeamReservationRepository {
return new SqlTeamReservationRepository(this._conn);
}
tickets(): Repo.FacetRepository<Model.Tickets> {
return new SqlTicketsRepository(this._conn);
}

View File

@@ -0,0 +1,122 @@
import * as sql from "sql-bricks-postgres";
import { ClientBase } from "pg";
import { Team } from "../model/team";
import { TeamReservationRepository } from "../repo";
import { Id } from "../../db";
import { AimeId } from "../../model";
export class SqlTeamReservationRepository
implements TeamReservationRepository {
constructor(private readonly _conn: ClientBase) {}
private async _lockTeam(teamId: Id<Team>): Promise<void> {
const lockSql = sql
.select("t.id")
.from("idz.team t")
.where("t.id", teamId)
.forUpdate()
.toParams();
await this._conn.query(lockSql);
}
async occupancyHack(teamId: Id<Team>): Promise<number> {
await this._lockTeam(teamId);
// counts get returned as strings, so 1 + 0 = 10.
// it hardly needs to be said but fuck javascript.
const memberSql = sql
.select("count(*) as count")
.from("idz.team_member tm")
.where("tm.team_id", teamId)
.toParams();
const memberRes = await this._conn.query(memberSql);
const memberCount = parseInt(memberRes.rows[0].count, 10);
const reservSql = sql
.select("count(*) as count")
.from("idz.team_reservation tr")
.where("tr.team_id", teamId)
.toParams();
const reservRes = await this._conn.query(reservSql);
const reservCount = parseInt(reservRes.rows[0].count, 10);
return memberCount + reservCount;
}
async reserveHack(
teamId: Id<Team>,
aimeId: AimeId,
timestamp: Date,
leader?: "leader"
): Promise<void> {
const lookupSql = sql
.select("r.id")
.from("aime.player r")
.where("r.ext_id", aimeId)
.toParams();
const { rows } = await this._conn.query(lookupSql);
const row = rows[0];
if (row === undefined) {
throw new Error(`Unknown Aime ID ${aimeId}`);
}
const playerId = row.id;
const insertSql = sql
.insert("idz.team_reservation", {
id: playerId,
team_id: teamId,
join_time: timestamp,
leader: leader === "leader",
})
.onConflict("id")
.doUpdate(["team_id"])
.toParams();
await this._conn.query(insertSql);
}
async commitHack(aimeId: AimeId): Promise<void> {
const lookupSql = sql
.select("p.id as profile_id", "tr.*")
.from("idz.profile p")
.join("aime.player r", { "p.player_id": "r.id" })
.join("idz.team_reservation tr", { "r.id": "tr.id" })
.where("r.ext_id", aimeId)
.toParams();
const { rows } = await this._conn.query(lookupSql);
const row = rows[0];
if (row === undefined) {
throw new Error(`Reservation not found for Aime ID ${aimeId}`);
}
console.log(row);
const insertSql = sql
.insert("idz.team_member", {
id: row.profile_id,
team_id: row.team_id,
join_time: row.join_time,
leader: row.leader,
})
.toParams();
await this._conn.query(insertSql);
const cleanupSql = sql
.delete("idz.team_reservation")
.where("id", row.id)
.toParams();
await this._conn.query(cleanupSql);
}
}

View File

@@ -96,6 +96,19 @@ export interface TeamMemberRepository {
): Promise<void>;
}
export interface TeamReservationRepository {
occupancyHack(teamId: Id<Model.Team>): Promise<number>;
reserveHack(
teamId: Id<Model.Team>,
aimeId: AimeId,
timestamp: Date,
leader?: "leader"
): Promise<void>;
commitHack(aimeId: AimeId): Promise<void>;
}
// TODO extend and factorize
export interface TopTenResult {
driverName: string;
@@ -141,6 +154,8 @@ export interface Repositories {
teamMembers(): TeamMemberRepository;
teamReservations(): TeamReservationRepository;
tickets(): FacetRepository<Model.Tickets>;
timeAttack(): TimeAttackRepository;