From 93db3831be54fff837947e85264b165e4d398396 Mon Sep 17 00:00:00 2001 From: Tau Date: Sun, 27 Sep 2020 00:10:56 -0400 Subject: [PATCH] idz: Support multiple major versions Doesn't actually add support for any additional versions, but it does lay the groundwork. --- schema/init/idz.sql | 9 ++- schema/migrate/M0016-idz-profile-version.sql | 77 ++++++++++++++++++++ src/idz/userdb/handler/_team.ts | 4 +- src/idz/userdb/handler/createAutoTeam.ts | 5 +- src/idz/userdb/handler/createProfile.ts | 3 +- src/idz/userdb/handler/createTeam.ts | 3 +- src/idz/userdb/handler/discoverProfile.ts | 2 +- src/idz/userdb/handler/loadGarage.ts | 2 +- src/idz/userdb/handler/loadProfile.ts | 4 +- src/idz/userdb/handler/loadStocker.ts | 2 +- src/idz/userdb/handler/loadTeam.ts | 33 ++++----- src/idz/userdb/handler/saveNewCar.ts | 2 +- src/idz/userdb/handler/saveProfile.ts | 2 +- src/idz/userdb/handler/saveSettings.ts | 2 +- src/idz/userdb/handler/saveStocker.ts | 2 +- src/idz/userdb/handler/saveTeamBanner.ts | 2 +- src/idz/userdb/handler/saveTimeAttack.ts | 2 +- src/idz/userdb/handler/updateTeamLeader.ts | 4 +- src/idz/userdb/handler/updateTeamMember.ts | 4 +- src/idz/userdb/model/profile.ts | 1 + src/idz/userdb/model/team.ts | 1 + src/idz/userdb/repo.ts | 14 +++- src/idz/userdb/sql/profile.ts | 13 +++- src/idz/userdb/sql/team.ts | 1 + src/idz/userdb/sql/teamAuto.ts | 4 +- src/idz/userdb/sql/timeAttack.ts | 2 + 26 files changed, 152 insertions(+), 48 deletions(-) create mode 100644 schema/migrate/M0016-idz-profile-version.sql diff --git a/schema/init/idz.sql b/schema/init/idz.sql index 5c20eb5..6c06f48 100644 --- a/schema/init/idz.sql +++ b/schema/init/idz.sql @@ -7,6 +7,10 @@ create table "idz_profile" ( "player_id" integer not null references "aime_player"("id") on delete cascade, + -- Major version of Initial D Zero, either 1 or 2. + -- The two major versions are incompatible with each other and do not + -- permit the player to carry progress over from one to the other. + "version" integer not null, -- TODO shop_id "name" text not null, "lv" integer not null, @@ -16,7 +20,7 @@ create table "idz_profile" ( "mileage" integer not null, "register_time" timestamp not null, "access_time" timestamp not null, - constraint "idz_profile_player_uq" unique ("player_id") + constraint "idz_profile_player_uq" unique ("player_id", "version") ); create table "idz_chara" ( @@ -202,12 +206,13 @@ create table "idz_unlocks" ( create table "idz_team" ( "id" integer primary key not null, + "version" integer not null, "ext_id" integer not null, "name" text not null, "name_bg" integer not null, "name_fx" integer not null, "register_time" timestamp not null, - constraint "idz_team_uq" unique ("ext_id") + constraint "idz_team_uq" unique ("version", "ext_id") ); create table "idz_team_auto" ( diff --git a/schema/migrate/M0016-idz-profile-version.sql b/schema/migrate/M0016-idz-profile-version.sql new file mode 100644 index 0000000..bb8d11e --- /dev/null +++ b/schema/migrate/M0016-idz-profile-version.sql @@ -0,0 +1,77 @@ +create table "new_idz_profile" ( + "id" integer primary key not null, + "player_id" integer not null + references "aime_player"("id") + on delete cascade, + "version" integer not null, + "name" text not null, + "lv" integer not null, + "exp" integer not null, + "fame" integer not null, + "dpoint" integer not null, + "mileage" integer not null, + "register_time" timestamp not null, + "access_time" timestamp not null, + constraint "idz_profile_player_uq" unique ("player_id", "version") +); + +create table "new_idz_team" ( + "id" integer primary key not null, + "version" integer not null, + "ext_id" integer not null, + "name" text not null, + "name_bg" integer not null, + "name_fx" integer not null, + "register_time" timestamp not null, + constraint "idz_team_uq" unique ("version", "ext_id") +); + +insert into "new_idz_profile" ( + "id", + "player_id", + "version", + "name", + "lv", + "exp", + "fame", + "dpoint", + "mileage", + "register_time", + "access_time" +) select + x."id", + x."player_id", + 1, + x."name", + x."lv", + x."exp", + x."fame", + x."dpoint", + x."mileage", + x."register_time", + x."access_time" +from "idz_profile" as "x"; + +insert into "new_idz_team" ( + "id", + "version", + "ext_id", + "name", + "name_bg", + "name_fx", + "register_time" +) select + x."id", + 1, + x."ext_id", + x."name", + x."name_bg", + x."name_fx", + x."register_time" +from "idz_team" as "x"; + +drop table "idz_profile"; +drop table "idz_team"; + +alter table "new_idz_profile" rename to "idz_profile"; +alter table "new_idz_team" rename to "idz_team"; diff --git a/src/idz/userdb/handler/_team.ts b/src/idz/userdb/handler/_team.ts index cf6486c..cb96aac 100644 --- a/src/idz/userdb/handler/_team.ts +++ b/src/idz/userdb/handler/_team.ts @@ -26,7 +26,9 @@ export async function _fixupPrevTeam( // (need to look up new leader's db id from aime id. ick) const newLeader = remaining[remaining.length - 1]; - const newLeaderId = await w.profile().find(newLeader.profile.aimeId); + const newLeaderId = await w + .profile() + .find(newLeader.profile.aimeId, newLeader.profile.version); await w.teamMembers().makeLeader(prevTeamId, newLeaderId); } diff --git a/src/idz/userdb/handler/createAutoTeam.ts b/src/idz/userdb/handler/createAutoTeam.ts index a4d7f40..a18c59e 100644 --- a/src/idz/userdb/handler/createAutoTeam.ts +++ b/src/idz/userdb/handler/createAutoTeam.ts @@ -44,9 +44,9 @@ export async function createAutoTeam( req: CreateAutoTeamRequest ): Promise { const now = new Date(); - const { aimeId } = req; + const { aimeId, version } = req; - const peek = await w.teamAuto().peek(); + const peek = await w.teamAuto().peek(version); let nextAuto: TeamAuto; // @@ -100,6 +100,7 @@ export async function createAutoTeam( // Register the new team, make the requestor its leader const spec = { + version, name, nameBg: autoTeams[nameIdx].nameBg, nameFx: 0, diff --git a/src/idz/userdb/handler/createProfile.ts b/src/idz/userdb/handler/createProfile.ts index a81e9fb..543f072 100644 --- a/src/idz/userdb/handler/createProfile.ts +++ b/src/idz/userdb/handler/createProfile.ts @@ -11,11 +11,12 @@ export async function createProfile( w: Repositories, req: CreateProfileRequest ): Promise { - const { aimeId, name } = req; + const { aimeId, version, name } = req; const now = new Date(); const profile: Profile = { aimeId, + version, name, lv: 1, exp: 0, diff --git a/src/idz/userdb/handler/createTeam.ts b/src/idz/userdb/handler/createTeam.ts index a1247bf..df22184 100644 --- a/src/idz/userdb/handler/createTeam.ts +++ b/src/idz/userdb/handler/createTeam.ts @@ -7,7 +7,7 @@ export async function createTeam( w: Repositories, req: CreateTeamRequest ): Promise { - const profileId = await w.profile().find(req.aimeId); + const profileId = await w.profile().find(req.aimeId, req.version); const prevTeamId = await w.teamMembers().findTeam(profileId); const now = new Date(); @@ -15,6 +15,7 @@ export async function createTeam( const teamSpec = { name: req.teamName, + version: req.version, nameBg: req.nameBg, nameFx: 0, registerTime: now, diff --git a/src/idz/userdb/handler/discoverProfile.ts b/src/idz/userdb/handler/discoverProfile.ts index 667b9c4..98775c3 100644 --- a/src/idz/userdb/handler/discoverProfile.ts +++ b/src/idz/userdb/handler/discoverProfile.ts @@ -6,7 +6,7 @@ export async function discoverProfile( w: Repositories, req: DiscoverProfileRequest ): Promise { - const profileId = await w.profile().peek(req.aimeId); + const profileId = await w.profile().peek(req.aimeId, req.version); return { type: "discover_profile_res", diff --git a/src/idz/userdb/handler/loadGarage.ts b/src/idz/userdb/handler/loadGarage.ts index eff45d2..96215b0 100644 --- a/src/idz/userdb/handler/loadGarage.ts +++ b/src/idz/userdb/handler/loadGarage.ts @@ -6,7 +6,7 @@ export async function loadGarage( w: Repositories, req: LoadGarageRequest ): Promise { - const profileId = await w.profile().find(req.aimeId); + const profileId = await w.profile().find(req.aimeId, req.version); return { type: "load_garage_res", diff --git a/src/idz/userdb/handler/loadProfile.ts b/src/idz/userdb/handler/loadProfile.ts index 20051e7..de27c7a 100644 --- a/src/idz/userdb/handler/loadProfile.ts +++ b/src/idz/userdb/handler/loadProfile.ts @@ -6,9 +6,9 @@ export async function loadProfile( w: Repositories, req: LoadProfileRequest ): Promise { - const { aimeId } = req; + const { aimeId, version } = req; - const profileId = await w.profile().find(aimeId); + const profileId = await w.profile().find(aimeId, version); const teamId = await w.teamMembers().findTeam(profileId); const leaderId = teamId && (await w.teamMembers().findLeader(teamId)); diff --git a/src/idz/userdb/handler/loadStocker.ts b/src/idz/userdb/handler/loadStocker.ts index 5217f9b..3356c12 100644 --- a/src/idz/userdb/handler/loadStocker.ts +++ b/src/idz/userdb/handler/loadStocker.ts @@ -6,7 +6,7 @@ export async function loadStocker( w: Repositories, req: LoadStockerRequest ): Promise { - const profileId = await w.profile().find(req.aimeId); + const profileId = await w.profile().find(req.aimeId, req.version); const backgrounds = await w.backgrounds().loadAll(profileId); return { diff --git a/src/idz/userdb/handler/loadTeam.ts b/src/idz/userdb/handler/loadTeam.ts index 16ed97c..3ff6cb0 100644 --- a/src/idz/userdb/handler/loadTeam.ts +++ b/src/idz/userdb/handler/loadTeam.ts @@ -4,30 +4,29 @@ import { LoadTeamRequest } from "../request/loadTeam"; import { LoadTeamResponse } from "../response/loadTeam"; import { Repositories } from "../repo"; -// Even if a profile does not belong to a team, a team must still be loaded -// (and then ignored by the client). - -const dummyResp: LoadTeamResponse = { - type: "load_team_res", - team: { - extId: 0 as ExtId, - name: "", - nameBg: 0, - nameFx: 0, - registerTime: new Date(0), - }, - members: [], -}; - export async function loadTeam( w: Repositories, req: LoadTeamRequest ): Promise { if (req.teamExtId === undefined) { - return dummyResp; + // Even if a profile does not belong to a team, a team must still be loaded + // (and then ignored by the client). + + return { + type: "load_team_res", + team: { + extId: 0 as ExtId, + version: req.version, + name: "", + nameBg: 0, + nameFx: 0, + registerTime: new Date(0), + }, + members: [], + }; } - const teamId = await w.teams().find(req.teamExtId); + const teamId = await w.teams().find(req.teamExtId, req.version); return { type: "load_team_res", diff --git a/src/idz/userdb/handler/saveNewCar.ts b/src/idz/userdb/handler/saveNewCar.ts index 41f4021..1766ca3 100644 --- a/src/idz/userdb/handler/saveNewCar.ts +++ b/src/idz/userdb/handler/saveNewCar.ts @@ -6,7 +6,7 @@ export async function saveNewCar( w: Repositories, req: SaveNewCarRequest ): Promise { - const profileId = await w.profile().find(req.aimeId); + const profileId = await w.profile().find(req.aimeId, req.version); await w.car().saveCar(profileId, req.car); diff --git a/src/idz/userdb/handler/saveProfile.ts b/src/idz/userdb/handler/saveProfile.ts index 4f5ba46..8ae4ec6 100644 --- a/src/idz/userdb/handler/saveProfile.ts +++ b/src/idz/userdb/handler/saveProfile.ts @@ -7,7 +7,7 @@ export async function saveProfile( req: SaveProfileRequest ): Promise { const now = new Date(); - const profileId = await w.profile().find(req.aimeId); + const profileId = await w.profile().find(req.aimeId, req.version); const profile = await w.profile().load(profileId); const chara = await w.chara().load(profileId); diff --git a/src/idz/userdb/handler/saveSettings.ts b/src/idz/userdb/handler/saveSettings.ts index af35a08..974965c 100644 --- a/src/idz/userdb/handler/saveSettings.ts +++ b/src/idz/userdb/handler/saveSettings.ts @@ -6,7 +6,7 @@ export async function saveSettings( w: Repositories, req: SaveSettingsRequest ): Promise { - const profileId = await w.profile().find(req.aimeId); + const profileId = await w.profile().find(req.aimeId, req.version); await w.settings().save(profileId, req.settings); diff --git a/src/idz/userdb/handler/saveStocker.ts b/src/idz/userdb/handler/saveStocker.ts index 019076d..5314451 100644 --- a/src/idz/userdb/handler/saveStocker.ts +++ b/src/idz/userdb/handler/saveStocker.ts @@ -6,7 +6,7 @@ export async function saveStocker( w: Repositories, req: SaveStockerRequest ): Promise { - const profileId = await w.profile().find(req.aimeId); + const profileId = await w.profile().find(req.aimeId, req.version); await Promise.all([ w.backgrounds().saveAll(profileId, req.backgrounds), diff --git a/src/idz/userdb/handler/saveTeamBanner.ts b/src/idz/userdb/handler/saveTeamBanner.ts index 139716d..62162bb 100644 --- a/src/idz/userdb/handler/saveTeamBanner.ts +++ b/src/idz/userdb/handler/saveTeamBanner.ts @@ -6,7 +6,7 @@ export async function saveTeamBanner( w: Repositories, req: SaveTeamBannerRequest ): Promise { - const teamId = await w.teams().find(req.teamExtId); + const teamId = await w.teams().find(req.teamExtId, req.version); const orig = await w.teams().load(teamId); await w.teams().save(teamId, { diff --git a/src/idz/userdb/handler/saveTimeAttack.ts b/src/idz/userdb/handler/saveTimeAttack.ts index a325027..4d086eb 100644 --- a/src/idz/userdb/handler/saveTimeAttack.ts +++ b/src/idz/userdb/handler/saveTimeAttack.ts @@ -14,7 +14,7 @@ export async function saveTimeAttack( // avoidance time warping stuff const now = new Date(); - const profileId = await w.profile().find(req.aimeId); + const profileId = await w.profile().find(req.aimeId, req.version); await w.timeAttack().save(profileId, { ...req.payload, timestamp: now }); } diff --git a/src/idz/userdb/handler/updateTeamLeader.ts b/src/idz/userdb/handler/updateTeamLeader.ts index 4ac1d89..fe2bc8f 100644 --- a/src/idz/userdb/handler/updateTeamLeader.ts +++ b/src/idz/userdb/handler/updateTeamLeader.ts @@ -6,8 +6,8 @@ export async function updateTeamLeader( w: Repositories, req: UpdateTeamLeaderRequest ): Promise { - const profileId = await w.profile().find(req.aimeId); - const teamId = await w.teams().find(req.teamExtId); + const profileId = await w.profile().find(req.aimeId, req.version); + const teamId = await w.teams().find(req.teamExtId, req.version); await w.teamMembers().makeLeader(teamId, profileId); diff --git a/src/idz/userdb/handler/updateTeamMember.ts b/src/idz/userdb/handler/updateTeamMember.ts index 538f287..a21a2ea 100644 --- a/src/idz/userdb/handler/updateTeamMember.ts +++ b/src/idz/userdb/handler/updateTeamMember.ts @@ -8,8 +8,8 @@ export async function updateTeamMember( req: UpdateTeamMemberRequest ): Promise { const now = new Date(); - const profileId = await w.profile().find(req.aimeId); - const teamId = await w.teams().find(req.teamExtId); + const profileId = await w.profile().find(req.aimeId, req.version); + const teamId = await w.teams().find(req.teamExtId, req.version); switch (req.action) { case "add": diff --git a/src/idz/userdb/model/profile.ts b/src/idz/userdb/model/profile.ts index cc87b5e..318e47d 100644 --- a/src/idz/userdb/model/profile.ts +++ b/src/idz/userdb/model/profile.ts @@ -2,6 +2,7 @@ import { AimeId } from "../../../model"; export interface Profile { aimeId: AimeId; + version: number; name: string; lv: number; exp: number; diff --git a/src/idz/userdb/model/team.ts b/src/idz/userdb/model/team.ts index a662836..36eff39 100644 --- a/src/idz/userdb/model/team.ts +++ b/src/idz/userdb/model/team.ts @@ -4,6 +4,7 @@ import { Profile } from "./profile"; export interface Team { extId: ExtId; + version: number; name: string; nameBg: number; nameFx: number; diff --git a/src/idz/userdb/repo.ts b/src/idz/userdb/repo.ts index f1f2d0c..5079b88 100644 --- a/src/idz/userdb/repo.ts +++ b/src/idz/userdb/repo.ts @@ -49,9 +49,12 @@ export interface FlagRepository { } export interface ProfileRepository { - find(aimeId: AimeId): Promise>; + find(aimeId: AimeId, version: number): Promise>; - peek(aimeId: AimeId): Promise | undefined>; + peek( + aimeId: AimeId, + version: number + ): Promise | undefined>; load(id: Id): Promise; @@ -61,7 +64,10 @@ export interface ProfileRepository { } export interface TeamRepository { - find(extId: Model.ExtId): Promise>; + find( + extId: Model.ExtId, + version: number + ): Promise>; load(id: Id): Promise; @@ -73,7 +79,7 @@ export interface TeamRepository { } export interface TeamAutoRepository { - peek(): Promise<[Model.TeamAuto, Id] | undefined>; + peek(version: number): Promise<[Model.TeamAuto, Id] | undefined>; push(teamId: Id, auto: Model.TeamAuto): Promise; } diff --git a/src/idz/userdb/sql/profile.ts b/src/idz/userdb/sql/profile.ts index b2dd142..e94ad58 100644 --- a/src/idz/userdb/sql/profile.ts +++ b/src/idz/userdb/sql/profile.ts @@ -8,6 +8,7 @@ import { Row, Transaction } from "../../../sql"; export function _extractProfile(row: Row): Profile { return { aimeId: parseInt(row.aime_id!) as AimeId, + version: parseInt(row.version!), name: row.name!, lv: parseInt(row.lv!), exp: parseInt(row.exp!), @@ -22,8 +23,8 @@ export function _extractProfile(row: Row): Profile { export class SqlProfileRepository implements ProfileRepository { constructor(private readonly _txn: Transaction) {} - async find(aimeId: AimeId): Promise> { - const profileId = await this.peek(aimeId); + async find(aimeId: AimeId, version: number): Promise> { + const profileId = await this.peek(aimeId, version); if (profileId === undefined) { throw new Error(`Profile not found for Aime ID ${aimeId}`); @@ -32,12 +33,16 @@ export class SqlProfileRepository implements ProfileRepository { return profileId; } - async peek(aimeId: AimeId): Promise | undefined> { + async peek( + aimeId: AimeId, + version: number + ): Promise | undefined> { const lookupSql = sql .select("p.id") .from("idz_profile p") .join("aime_player r", { "p.player_id": "r.id" }) - .where("r.ext_id", aimeId); + .where("r.ext_id", aimeId) + .and("r.version", version); const row = await this._txn.fetchRow(lookupSql); diff --git a/src/idz/userdb/sql/team.ts b/src/idz/userdb/sql/team.ts index 24a4a6f..07ef401 100644 --- a/src/idz/userdb/sql/team.ts +++ b/src/idz/userdb/sql/team.ts @@ -37,6 +37,7 @@ export class SqlTeamRepository implements TeamRepository { } return { + version: parseInt(row.version!), extId: parseInt(row.ext_id!) as ExtId, name: row.name!, nameBg: parseInt(row.name_bg!), diff --git a/src/idz/userdb/sql/teamAuto.ts b/src/idz/userdb/sql/teamAuto.ts index 464b171..6793358 100644 --- a/src/idz/userdb/sql/teamAuto.ts +++ b/src/idz/userdb/sql/teamAuto.ts @@ -8,10 +8,12 @@ import { Transaction } from "../../../sql"; export class SqlTeamAutoRepository implements TeamAutoRepository { constructor(private readonly _txn: Transaction) {} - async peek(): Promise<[TeamAuto, Id] | undefined> { + async peek(version: number): Promise<[TeamAuto, Id] | undefined> { const peekSql = sql .select("tt.*") .from("idz_team_auto tt") + .join("idz_team t", { "tt.id": "t.id" }) + .where("t.version", version) .orderBy("serial_no desc", "name_idx desc") .limit(1); diff --git a/src/idz/userdb/sql/timeAttack.ts b/src/idz/userdb/sql/timeAttack.ts index 8de3af3..4b91a05 100644 --- a/src/idz/userdb/sql/timeAttack.ts +++ b/src/idz/userdb/sql/timeAttack.ts @@ -37,6 +37,7 @@ export class SqlTimeAttackRepository implements TimeAttackRepository { // Profile "p.name as profile_name", // Team + "t.version as team_version", "t.ext_id as team_ext_id", "t.name as team_name", "t.name_bg as team_name_bg", @@ -64,6 +65,7 @@ export class SqlTimeAttackRepository implements TimeAttackRepository { driverName: row.profile_name!, team: { extId: parseInt(row.team_ext_id!) as ExtId, + version: parseInt(row.team_version!), name: row.team_name!, nameBg: parseInt(row.team_name_bg!), nameFx: parseInt(row.team_name_fx!),