diff --git a/src/idz/db/profile.ts b/src/idz/db/profile.ts new file mode 100644 index 0000000..0babcd8 --- /dev/null +++ b/src/idz/db/profile.ts @@ -0,0 +1,117 @@ +import * as sql from "sql-bricks"; +import { Client } from "pg"; + +import { _findProfile } from "./_util"; +import { ExtId } from "../model/base"; +import { Profile } from "../model/profile"; +import { Team } from "../model/team"; +import { ProfileSpec, ProfileRepository } from "../repo"; +import { generateExtId, generateId, Id } from "../../db"; +import { AimeId } from "../../model"; + +function _extractRow(row: any): Profile { + return { + id: row.ext_id, + teamId: 2 as ExtId, // TODO + name: row.name, + lv: row.lv, + exp: row.exp, + fame: row.fame, + dpoint: row.dpoint, + mileage: row.mileage, + }; +} + +export class SqlProfileRepository implements ProfileRepository { + constructor(private readonly _conn: Client) {} + + async discoverByAimeId(aimeId: AimeId): Promise { + const profileId = await this._findProfile(aimeId); + + return profileId !== undefined; + } + + async loadByAimeId(aimeId: AimeId): Promise { + const profileId = await this._findProfile(aimeId); + + if (profileId === undefined) { + throw new Error("Profile not found"); + } + + const loadSql = sql + .select() + .from("idz.profile") + .where("id", profileId) + .toParams(); + + const { rows } = await this._conn.query(loadSql); + + return _extractRow(rows[0]); + } + + async load(extId: ExtId): Promise { + const loadSql = sql + .select() + .from("idz.profile") + .where("ext_id", extId) + .toParams(); + + const { rows } = await this._conn.query(loadSql); + + return _extractRow(rows[0]); + } + + async save(profile: Profile): Promise { + const saveSql = sql + .update("idz.profile", { + lv: profile.lv, + exp: profile.exp, + fame: profile.fame, + dpoint: profile.dpoint, + mileage: profile.mileage, + }) + .where("ext_id", profile.id) + .toParams(); + + await this._conn.query(saveSql); + } + + async create(profile: ProfileSpec): Promise> { + const id = generateId(); + const extId = generateExtId() as ExtId; + + const createSql = sql + .insert("idz.profile", { + id: id, + ext_id: extId, + name: profile.name, + lv: profile.lv, + exp: profile.exp, + fame: profile.fame, + dpoint: profile.dpoint, + mileage: profile.mileage, + }) + .toParams(); + + await this._conn.query(createSql); + + return extId; + } + + async _findProfile(aimeId: AimeId): Promise | undefined> { + const lookupSql = sql + .select("r.id") + .from("idz.profile r") + .join("aime.player p", { "r.player_id": "p.id" }) + .where("p.aime_id", aimeId) + .toParams(); + + const { rows } = await this._conn.query(lookupSql); + + if (rows.length > 0) { + return rows[0].id as Id; + } else { + return undefined; + } + } +} diff --git a/src/idz/handler/createProfile.ts b/src/idz/handler/createProfile.ts index d3dc4e4..f1fd202 100644 --- a/src/idz/handler/createProfile.ts +++ b/src/idz/handler/createProfile.ts @@ -1,22 +1,18 @@ import { ExtId } from "../model/base"; import { MissionState } from "../model/mission"; -import { Profile } from "../model/profile"; import { Settings } from "../model/settings"; import { Story } from "../model/story"; import { Team } from "../model/team"; import { Unlocks } from "../model/unlocks"; import { CreateProfileRequest } from "../request/createProfile"; import { GenericResponse } from "../response/generic"; -import { Repositories } from "../repo"; +import { ProfileSpec, Repositories } from "../repo"; export async function createProfile( w: Repositories, req: CreateProfileRequest ): Promise { - const profileId = await w.profile().generateId(); - - const profile: Profile = { - id: profileId, + const profile: ProfileSpec = { teamId: 2 as ExtId, // TODO name: req.name, lv: 1, @@ -36,17 +32,16 @@ export async function createProfile( lastMileageReward: 0, }; - await Promise.all([ - w.profile().save(profile.id, profile), - w.chara().save(profile.id, req.chara), - w.car().saveCar(profile.id, req.car), - w.car().saveSelection(profile.id, req.car.selector), - w.missions().save(profile.id, missions), - w.settings().save(profile.id, settings), - w.story().save(profile.id, story), - w.unlocks().save(profile.id, unlocks), - w.tickets().save(profile.id, {}), - ]); + const profileId = await w.profile().create(profile); + + await w.chara().save(profileId, req.chara); + await w.car().saveCar(profileId, req.car); + await w.car().saveSelection(profileId, req.car.selector); + await w.missions().save(profileId, missions); + await w.settings().save(profileId, settings); + await w.story().save(profileId, story); + await w.unlocks().save(profileId, unlocks); + await w.tickets().save(profileId, {}); return { type: "generic_res", diff --git a/src/idz/handler/saveProfile.ts b/src/idz/handler/saveProfile.ts index da9db4c..45a266b 100644 --- a/src/idz/handler/saveProfile.ts +++ b/src/idz/handler/saveProfile.ts @@ -9,29 +9,29 @@ export async function saveProfile( const profile = await w.profile().load(req.profileId); const chara = await w.chara().load(req.profileId); - await Promise.all([ - w.profile().save(req.profileId, { - ...profile, - lv: req.lv, - exp: req.exp, - fame: req.fame, - dpoint: req.dpoint, - mileage: req.mileage, - }), - w.chara().save(req.profileId, { - ...chara, - title: req.title, - background: req.background, - }), - w.car().saveCar(req.profileId, req.car), - w.coursePlays().saveAll(req.profileId, req.coursePlays), - w.missions().save(req.profileId, req.missions), - w.story().save(req.profileId, req.story), - w.titles().saveAll(req.profileId, req.titles), - w.unlocks().save(req.profileId, req.unlocks), - w.settings().save(req.profileId, req.settings), - w.tickets().save(req.profileId, req.tickets), - ]); + await w.profile().save({ + ...profile, + lv: req.lv, + exp: req.exp, + fame: req.fame, + dpoint: req.dpoint, + mileage: req.mileage, + }); + + await w.chara().save(req.profileId, { + ...chara, + title: req.title, + background: req.background, + }); + + await w.car().saveCar(req.profileId, req.car); + await w.coursePlays().saveAll(req.profileId, req.coursePlays); + await w.missions().save(req.profileId, req.missions); + await w.story().save(req.profileId, req.story); + await w.titles().saveAll(req.profileId, req.titles); + await w.unlocks().save(req.profileId, req.unlocks); + await w.settings().save(req.profileId, req.settings); + await w.tickets().save(req.profileId, req.tickets); return { type: "generic_res", diff --git a/src/idz/repo.ts b/src/idz/repo.ts index 4b03b58..d0b8d4e 100644 --- a/src/idz/repo.ts +++ b/src/idz/repo.ts @@ -1,6 +1,13 @@ +import { Subtract } from "utility-types"; + import * as Model from "./model"; import { AimeId } from "../model"; +export type ProfileSpec = Subtract< + Model.Profile, + { id: Model.ExtId } +>; + export interface CarRepository { countCars(profileId: Model.ExtId): Promise; @@ -41,16 +48,15 @@ export interface FlagRepository { } export interface ProfileRepository { - // Might want to come up with something better here - generateId(): Promise>; - discoverByAimeId(id: AimeId): Promise; loadByAimeId(id: AimeId): Promise; load(id: Model.ExtId): Promise; - save(id: Model.ExtId, profile: Model.Profile): Promise; + save(profile: Model.Profile): Promise; + + create(profile: ProfileSpec): Promise>; } export interface TimeAttackRepository {