diff --git a/src/templates/server.ts b/src/templates/server.ts index aba2513..b621f84 100644 --- a/src/templates/server.ts +++ b/src/templates/server.ts @@ -140,26 +140,21 @@ router.post( } let attacker_loadout: number | undefined; let victim_loadout: number | undefined; - await db.transaction().execute(async (trx) => { + await checkUpdateOrCreatePlayer( - { id: attacker_id, name: attackerData.name }, - trx - ); + { id: attacker_id, name: attackerData.name }); await checkUpdateOrCreatePlayer( - { id: victim_id, name: victimData.name }, - trx + { id: victim_id, name: victimData.name } ); - await checkOrCreateWeapon(cause_of_death, trx); - await checkOrCreateWeapon(attackerData.current_weapon.id, trx); - await checkOrCreateWeapon(victimData.current_weapon.id, trx); - await checkOrCreateLoadout(attackerData.loadout, trx).then( + await checkOrCreateWeapon(cause_of_death); + await checkOrCreateWeapon(attackerData.current_weapon.id); + await checkOrCreateWeapon(victimData.current_weapon.id); + await checkOrCreateLoadout(attackerData.loadout).then( (e) => (attacker_loadout = e) ); - await checkOrCreateLoadout(victimData.loadout, trx).then( + await checkOrCreateLoadout(victimData.loadout).then( (e) => (victim_loadout = e) ); - }); - if (attacker_loadout === undefined) { throw new Error("attacker_loadout is undefined"); } diff --git a/src/utils.ts b/src/utils.ts index 3ad4ade..3ba1ef9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,140 +1,176 @@ -import { Kysely, Transaction } from 'kysely'; +import { Kysely, Transaction } from "kysely"; import db from "./db"; -import Database from './db/model'; +import Database from "./db/model"; import { LoadoutKillData } from "./types"; export async function checkUpdateOrCreatePlayer(data: { id: number; name: string; -}, trx : Kysely | Transaction) { - const player = await trx - .selectFrom("ToneAPI_v3.player") - .select(["player_name"]) - .where("player_id", "=", data.id) - .executeTakeFirst(); - if (!player) { - await trx - .insertInto("ToneAPI_v3.player") - .values({ - player_id: data.id, - player_name: data.name, - }) - .execute(); - } else if (player.player_name != data.name) { - await trx - .updateTable("ToneAPI_v3.player") - .set({ player_name: data.name }) - .where("ToneAPI_v3.player.player_id", "=", data.id) - .execute(); - } +}) { + await db + .transaction() + .setIsolationLevel("serializable") + .execute(async (trx) => { + const player = await trx + .selectFrom("ToneAPI_v3.player") + .select(["player_name"]) + .where("player_id", "=", data.id) + .executeTakeFirst(); + if (!player) { + await trx + .insertInto("ToneAPI_v3.player") + .values({ + player_id: data.id, + player_name: data.name, + }) + .execute(); + } else if (player.player_name != data.name) { + await trx + .updateTable("ToneAPI_v3.player") + .set({ player_name: data.name }) + .where("ToneAPI_v3.player.player_id", "=", data.id) + .execute(); + } + }); } -export async function checkOrCreateWeapon(weapon_id: string, trx : Kysely | Transaction) { - const weapon = await trx - .selectFrom("ToneAPI_v3.weapon") - .select("ToneAPI_v3.weapon.weapon_id") - .where("weapon_id", "=", weapon_id) - .executeTakeFirst(); - if (!weapon) { - await trx - .insertInto("ToneAPI_v3.weapon") - .values({ - weapon_id, - }) - .execute(); - } +export async function checkOrCreateWeapon(weapon_id: string) { + await db + .transaction() + .setIsolationLevel("serializable") + .execute(async (trx) => { + const weapon = await trx + .selectFrom("ToneAPI_v3.weapon") + .select("ToneAPI_v3.weapon.weapon_id") + .where("weapon_id", "=", weapon_id) + .executeTakeFirst(); + if (!weapon) { + await trx + .insertInto("ToneAPI_v3.weapon") + .values({ + weapon_id, + }) + .execute(); + } + }); } export async function checkOrCreateWeaponMods(weapon_mods: { id: string; mods: number; -}, trx : Kysely | Transaction) { - await checkOrCreateWeapon(weapon_mods.id, trx); - const weaponMods = await trx - .selectFrom("ToneAPI_v3.mods_on_weapon") - .select("ToneAPI_v3.mods_on_weapon.mod_id") - .where("mod_id", "=", weapon_mods.mods) - .where("weapon_id", "=", weapon_mods.id) - .executeTakeFirst(); - if (!weaponMods) { - await trx - .insertInto("ToneAPI_v3.mods_on_weapon") - .values({ - mod_id: weapon_mods.mods, - weapon_id: weapon_mods.id, - autogenerated: true, - }) - .execute(); - } +}) { + await checkOrCreateWeapon(weapon_mods.id); + await db + .transaction() + .setIsolationLevel("serializable") + .execute(async (trx) => { + const weaponMods = await trx + .selectFrom("ToneAPI_v3.mods_on_weapon") + .select("ToneAPI_v3.mods_on_weapon.mod_id") + .where("mod_id", "=", weapon_mods.mods) + .where("weapon_id", "=", weapon_mods.id) + .executeTakeFirst(); + if (!weaponMods) { + await trx + .insertInto("ToneAPI_v3.mods_on_weapon") + .values({ + mod_id: weapon_mods.mods, + weapon_id: weapon_mods.id, + autogenerated: true, + }) + .execute(); + } + }); } -export async function checkOrCreateTitan(titan_id: string | null, trx : Kysely | Transaction) { +export async function checkOrCreateTitan(titan_id: string | null) { if (titan_id == null) { return; } - const titan = await trx - .selectFrom("ToneAPI_v3.titan_chassis") - .select("ToneAPI_v3.titan_chassis.titan_id") - .where("titan_id", "=", titan_id) - .executeTakeFirst(); - if (!titan) { - await trx - .insertInto("ToneAPI_v3.titan_chassis") - .values({ - titan_id, - }) - .execute(); - } + await db + .transaction() + .setIsolationLevel("serializable") + .execute(async (trx) => { + const titan = await trx + .selectFrom("ToneAPI_v3.titan_chassis") + .select("ToneAPI_v3.titan_chassis.titan_id") + .where("titan_id", "=", titan_id) + .executeTakeFirst(); + if (!titan) { + await trx + .insertInto("ToneAPI_v3.titan_chassis") + .values({ + titan_id, + }) + .execute(); + } + }); } -export async function checkOrCreateLoadout(loadoutData: LoadoutKillData, trx : Kysely | Transaction) { - let loadout = await trx - .selectFrom("ToneAPI_v3.loadout") - .select("ToneAPI_v3.loadout.loadout_id") - .where("primary_weapon", "=", loadoutData.primary?.id ?? null) - .where("primary_mod_id", "=", loadoutData.primary?.mods ?? null) - .where("secondary_weapon", "=", loadoutData.secondary?.id ?? null) - .where("secondary_mod_id", "=", loadoutData.secondary?.mods ?? null) - .where("anti_titan_weapon", "=", loadoutData.anti_titan?.id ?? null) - .where("anti_titan_mod_id", "=", loadoutData.anti_titan?.mods ?? null) - .where("ToneAPI_v3.loadout.ordnance", "=", loadoutData.ordnance?.id ?? null) - .where("ToneAPI_v3.loadout.tactical", "=", loadoutData.tactical?.id ?? null) - .where("ToneAPI_v3.loadout.pilot_passive_1", "=", loadoutData.passive1) - .where("ToneAPI_v3.loadout.pilot_passive_2", "=", loadoutData.passive2) - .where("ToneAPI_v3.loadout.titan_id", "=", loadoutData.titan) - .executeTakeFirst(); +export async function checkOrCreateLoadout(loadoutData: LoadoutKillData) { + const loadout = await db + .transaction() + .setIsolationLevel("serializable") + .execute(async (trx) => { + let loadout = await trx + .selectFrom("ToneAPI_v3.loadout") + .select("ToneAPI_v3.loadout.loadout_id") + .where("primary_weapon", "=", loadoutData.primary?.id ?? null) + .where("primary_mod_id", "=", loadoutData.primary?.mods ?? null) + .where("secondary_weapon", "=", loadoutData.secondary?.id ?? null) + .where("secondary_mod_id", "=", loadoutData.secondary?.mods ?? null) + .where("anti_titan_weapon", "=", loadoutData.anti_titan?.id ?? null) + .where("anti_titan_mod_id", "=", loadoutData.anti_titan?.mods ?? null) + .where( + "ToneAPI_v3.loadout.ordnance", + "=", + loadoutData.ordnance?.id ?? null + ) + .where( + "ToneAPI_v3.loadout.tactical", + "=", + loadoutData.tactical?.id ?? null + ) + .where("ToneAPI_v3.loadout.pilot_passive_1", "=", loadoutData.passive1) + .where("ToneAPI_v3.loadout.pilot_passive_2", "=", loadoutData.passive2) + .where("ToneAPI_v3.loadout.titan_id", "=", loadoutData.titan) + .executeTakeFirst(); + if (!loadout) { + if (loadoutData.primary !== null) { + await checkOrCreateWeaponMods(loadoutData.primary); + } + if (loadoutData.secondary !== null) { + await checkOrCreateWeaponMods(loadoutData.secondary); + } + if (loadoutData.anti_titan !== null) { + await checkOrCreateWeaponMods(loadoutData.anti_titan); + } + if (loadoutData.ordnance !== null) { + await checkOrCreateWeapon(loadoutData.ordnance.id); + } + await checkOrCreateTitan(loadoutData.titan); + const result = await trx + .insertInto("ToneAPI_v3.loadout") + .values({ + primary_weapon: loadoutData.primary?.id ?? null, + primary_mod_id: loadoutData.primary?.mods ?? null, + secondary_weapon: loadoutData.secondary?.id ?? null, + secondary_mod_id: loadoutData.secondary?.mods ?? null, + anti_titan_weapon: loadoutData.anti_titan?.id ?? null, + anti_titan_mod_id: loadoutData.anti_titan?.mods ?? null, + ordnance: loadoutData.ordnance?.id ?? null, + tactical: loadoutData.tactical?.id ?? null, + pilot_passive_1: loadoutData.passive1, + pilot_passive_2: loadoutData.passive2, + titan_id: loadoutData.titan, + }) + .returning("ToneAPI_v3.loadout.loadout_id") + .executeTakeFirstOrThrow(); + return result; + } + }); if (!loadout) { - if (loadoutData.primary !== null) { - await checkOrCreateWeaponMods(loadoutData.primary, trx); - } - if (loadoutData.secondary !== null) { - await checkOrCreateWeaponMods(loadoutData.secondary, trx); - } - if (loadoutData.anti_titan !== null) { - await checkOrCreateWeaponMods(loadoutData.anti_titan, trx); - } - if (loadoutData.ordnance !== null) { - await checkOrCreateWeapon(loadoutData.ordnance.id, trx); - } - await checkOrCreateTitan(loadoutData.titan, trx); - const result = await trx - .insertInto("ToneAPI_v3.loadout") - .values({ - primary_weapon: loadoutData.primary?.id ?? null, - primary_mod_id: loadoutData.primary?.mods ?? null, - secondary_weapon: loadoutData.secondary?.id ?? null, - secondary_mod_id: loadoutData.secondary?.mods ?? null, - anti_titan_weapon: loadoutData.anti_titan?.id ?? null, - anti_titan_mod_id: loadoutData.anti_titan?.mods ?? null, - ordnance: loadoutData.ordnance?.id ?? null, - tactical: loadoutData.tactical?.id ?? null, - pilot_passive_1: loadoutData.passive1, - pilot_passive_2: loadoutData.passive2, - titan_id: loadoutData.titan, - }) - .returning("ToneAPI_v3.loadout.loadout_id") - .executeTakeFirstOrThrow(); - return result.loadout_id; + throw Error("loadout is undefined"); } return loadout.loadout_id; }