change db directory to submodule

This commit is contained in:
2023-08-09 15:48:14 +02:00
parent cbd853fb56
commit c5c61d17b4
14 changed files with 0 additions and 1083 deletions
-62
View File
@@ -1,62 +0,0 @@
import * as dotenv from 'dotenv'
import { Kysely, PostgresDialect } from 'kysely'
import { Pool } from 'pg'
import migrateToLatest from './migrations'
import { type KillTable } from './model'
import type Database from './model'
dotenv.config()
const migration = migrateToLatest()
const db = new Kysely<Database>({
dialect: new PostgresDialect({
pool: new Pool({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
max: 30
})
}),
log (event) {
if (process.env.ENVIRONMENT !== 'dev') {
return
}
if (event.level === 'query') {
console.log(event.query.sql)
console.log(event.query.parameters)
}
}
})
interface RemoveFromKill {
id: unknown
unix_time: unknown
}
type KillRecord = Omit<KillTable, keyof RemoveFromKill>
export async function CreateKillRecord (data: KillRecord) {
await db
.insertInto('kill')
.values({ ...data })
.execute()
}
export async function getHostList () {
return await db.selectFrom('host').select(['id', 'host.name']).execute()
}
// tokens are stored in raw... maybe we should use something better in the future
// Using callback for express-basic-auth
export async function CheckServerToken (token: string) {
return await db.selectFrom('host').select('id')
.where('token', '=', Buffer.from(token, 'base64').toString())
.executeTakeFirst()
.then((result) => {
return result
})
}
export async function dbReady (): Promise<Kysely<Database>> {
await migration
return db
}
export default db
-52
View File
@@ -1,52 +0,0 @@
import { promises as fs } from 'fs'
import {
FileMigrationProvider,
Kysely,
Migrator,
PostgresDialect
} from 'kysely'
import * as path from 'path'
import { Pool } from 'pg'
import type Database from './model'
async function migrateToLatest () {
const db = new Kysely<Database>({
dialect: new PostgresDialect({
pool: new Pool({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
})
})
const migrator = new Migrator({
db,
provider: new FileMigrationProvider({
fs,
path,
migrationFolder: path.join(__dirname, './migrations')
})
})
const { error, results } = await migrator.migrateToLatest()
results?.forEach((it) => {
if (it.status === 'Success') {
console.log(`migration "${it.migrationName}" was executed successfully`)
} else if (it.status === 'Error') {
console.error(`failed to execute migration "${it.migrationName}"`)
}
})
if (error) {
console.error('failed to migrate')
console.error(error)
process.exit(1)
}
await db.destroy()
}
export default migrateToLatest
-104
View File
@@ -1,104 +0,0 @@
import { Kysely, sql } from 'kysely'
export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createTable('player')
.addColumn('id', 'integer', (col) => col.unique().primaryKey())
.addColumn('name', 'varchar')
.addColumn('optout', 'boolean')
.addColumn('hide_TOS', 'boolean')
.execute()
await db.schema
.createTable('weapon')
.addColumn('id', 'varchar', (col) => col.unique().primaryKey())
.addColumn('name', 'varchar')
.addColumn('description', 'varchar')
.addColumn('image', 'varchar')
.execute()
await db.schema
.createTable('map')
.addColumn('id', 'varchar', (col) => col.unique().primaryKey())
.addColumn('name', 'varchar')
.addColumn('description', 'varchar')
.addColumn('image', 'varchar')
.execute()
await db.schema
.createTable('server')
.addColumn('id', 'serial', (col) => col.primaryKey())
.addColumn('name', 'varchar', (col) => col.unique())
.addColumn('description', 'varchar')
.addColumn('token', 'varchar', (col) =>
col.notNull().defaultTo(sql`gen_random_uuid()`)
)
.execute()
await db.schema
.createTable('kill')
.addColumn('id', 'serial', (col) => col.primaryKey())
.addColumn('server', 'integer', (col) =>
col.references('server.id').notNull().onDelete('cascade')
)
.addColumn('killstat_version', 'varchar')
.addColumn('match_id', 'varchar')
.addColumn('game_mode', 'varchar')
.addColumn('map', 'varchar')
.addColumn('unix_time', 'timestamp', (col) =>
col.defaultTo(sql`now()`).notNull()
)
.addColumn('game_time', 'decimal')
.addColumn('player_count', 'integer')
.addColumn('attacker_name', 'varchar')
.addColumn('attacker_id', 'varchar')
.addColumn('attacker_current_weapon', 'varchar')
.addColumn('attacker_current_weapon_mods', 'integer')
.addColumn('attacker_weapon_1', 'varchar')
.addColumn('attacker_weapon_1_mods', 'integer')
.addColumn('attacker_weapon_2', 'varchar')
.addColumn('attacker_weapon_2_mods', 'integer')
.addColumn('attacker_weapon_3', 'varchar')
.addColumn('attacker_weapon_3_mods', 'integer')
.addColumn('attacker_offhand_weapon_1', 'integer')
.addColumn('attacker_offhand_weapon_2', 'integer')
.addColumn('victim_name', 'varchar')
.addColumn('victim_id', 'varchar')
.addColumn('victim_current_weapon', 'varchar')
.addColumn('victim_current_weapon_mods', 'integer')
.addColumn('victim_weapon_1', 'varchar')
.addColumn('victim_weapon_1_mods', 'integer')
.addColumn('victim_weapon_2', 'varchar')
.addColumn('victim_weapon_2_mods', 'integer')
.addColumn('victim_weapon_3', 'varchar')
.addColumn('victim_weapon_3_mods', 'integer')
.addColumn('victim_offhand_weapon_1', 'integer')
.addColumn('victim_offhand_weapon_2', 'integer')
.addColumn('cause_of_death', 'varchar')
.addColumn('distance', 'decimal')
.execute()
/*await db.schema
.createTable("pet")
.addColumn("id", "serial", (col) => col.primaryKey())
.addColumn("name", "varchar", (col) => col.notNull().unique())
.addColumn("owner_id", "integer", (col) =>
col.references("person.id").onDelete("cascade").notNull()
)
.addColumn("species", "varchar", (col) => col.notNull())
.execute();*/
/*
await db.schema
.createIndex("kill")
.on("pet")
.column("owner_id")
.execute();*/
}
export async function down(db: Kysely<any>): Promise<void> {
await db.schema.dropTable('kill').execute()
await db.schema.dropTable('player').execute()
await db.schema.dropTable('weapon').execute()
await db.schema.dropTable('map').execute()
await db.schema.dropTable('server').execute()
}
@@ -1,34 +0,0 @@
import { Kysely, sql } from 'kysely'
import { Client } from 'pg'
const notify_newkill = `
CREATE OR REPLACE FUNCTION notify_new_kill()
RETURNS trigger
AS
$$
BEGIN
PERFORM pg_notify('new_kill', row_to_json(NEW)::text);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
`
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
export async function up(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query(notify_newkill)
await pgClient.query(`CREATE TRIGGER insert_kills_notify AFTER INSERT ON kill FOR EACH ROW EXECUTE PROCEDURE notify_new_kill();`)
}
export async function down(db: Kysely<any>): Promise<void> {
await pgClient.query(`DROP FUNCTION IF EXISTS notify_new_kill;`)
await pgClient.query(`DROP TRIGGER IF EXISTS insert_kills_notify;`)
await pgClient.end()
}
@@ -1,40 +0,0 @@
import { Kysely, sql } from 'kysely'
import { Client } from 'pg'
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
export async function up(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query('DROP TABLE IF EXISTS player')
await pgClient.query('ALTER TABLE kill ADD COLUMN IF NOT EXISTS servername character varying NULL;')
await pgClient.query('ALTER TABLE kill ADD COLUMN IF NOT EXISTS host integer NULL;')
await pgClient.query('UPDATE kill SET servername = server.name FROM server WHERE server.id = kill.server;')
await pgClient.query('CREATE TABLE host (id SERIAL PRIMARY KEY, name character varying, token character varying)')
await pgClient.query('INSERT INTO host (token) SELECT DISTINCT token FROM server')
await pgClient.query('UPDATE kill SET host = host.id FROM host FULL JOIN server ON server.token = host.token WHERE host.token = server.token AND server.id = kill.server;')
await pgClient.query('ALTER TABLE kill ALTER COLUMN servername SET NOT NULL;')
await pgClient.query('ALTER TABLE kill DROP COLUMN server;')
await pgClient.query('DROP TABLE IF EXISTS server')
//Update the hosts column once the hoster table is manually updated
await pgClient.end()
}
export async function down(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query('ALTER TABLE kill ADD server integer NULL;')
await pgClient.query(`ALTER TABLE kill ADD server integer NULL;`)
await pgClient.query('UPDATE kill SET server = server.id FROM server where server.name = kill.servername;')
await pgClient.query('ALTER TABLE kill ALTER COLUMN server SET NOT NULL;')
await pgClient.query('ALTER TABLE kill DROP COLUMN servername;')
await pgClient.query('ALTER TABLE kill DROP COLUMN host;')
await pgClient.query('DROP TABLE IF EXISTS host')
await pgClient.end()
}
@@ -1,46 +0,0 @@
import { Kysely, sql } from 'kysely'
import { Client } from 'pg'
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
export async function up(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query(`CREATE OR REPLACE FUNCTION public.first_agg (anyelement, anyelement)
RETURNS anyelement
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
'SELECT $1';`)
await pgClient.query(`CREATE AGGREGATE public.first (anyelement) (
SFUNC = public.first_agg
, STYPE = anyelement
, PARALLEL = safe
);`)
await pgClient.query(`CREATE OR REPLACE FUNCTION public.last_agg (anyelement, anyelement)
RETURNS anyelement
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
'SELECT $2';`)
await pgClient.query(`CREATE AGGREGATE public.last (anyelement) (
SFUNC = public.last_agg
, STYPE = anyelement
, PARALLEL = safe
);`)
//Update the hosts column once the hoster table is manually updated
await pgClient.end()
}
export async function down(db: Kysely<any>): Promise<void> {
await pgClient.connect()
pgClient.query('DROP AGGREGATE public.last')
pgClient.query('DROP FUNCTION public.last_agg')
pgClient.query('DROP AGGREGATE public.first')
pgClient.query('DROP AGGREGATE public.first_agg')
await pgClient.end()
}
@@ -1,31 +0,0 @@
import { Kysely, sql } from 'kysely'
import { Client } from 'pg'
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
export async function up(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query(`ALTER TABLE kill ADD COLUMN IF NOT EXISTS attacker_titan character varying NULL;`)
await pgClient.query(`UPDATE kill SET attacker_titan = 'scorch' WHERE (cause_of_death = 'mp_titancore_flame_wave_secondary' OR cause_of_death = 'mp_titancore_flame_wave' OR cause_of_death = 'mp_titancore_flame_wall' OR cause_of_death = 'mp_titanweapon_meteor_thermite' OR cause_of_death = 'mp_titanweapon_heat_shield' OR cause_of_death = 'titan_punch_scorch' OR cause_of_death = 'mp_titanweapon_meteor')`)
await pgClient.query(`UPDATE kill SET attacker_titan = 'ronin' WHERE (cause_of_death = 'mp_titanweapon_arc_wave' OR cause_of_death = 'mp_titancore_shift_core' OR cause_of_death = 'titan_sword' OR cause_of_death = 'mp_titanweapon_leadwall')`)
await pgClient.query(`UPDATE kill SET attacker_titan = 'ion' WHERE (cause_of_death = 'titan_punch_ion' OR cause_of_death = 'mp_titanweapon_vortex_shield_ion' OR cause_of_death = 'mp_titancore_laser_cannon' OR cause_of_death = 'mp_titanability_laser_trip' OR cause_of_death = 'mp_titanweapon_laser_lite')`)
await pgClient.query(`UPDATE kill SET attacker_titan = 'tone' WHERE (cause_of_death = 'mp_titancore_salvo_core' OR cause_of_death = 'titan_punch_tone' OR cause_of_death = 'mp_titanweapon_salvo_rockets' OR cause_of_death = 'mp_titanweapon_sticky_40mm')`)
await pgClient.query(`UPDATE kill SET attacker_titan = 'northstar' WHERE (cause_of_death = 'mp_titanability_slow_trap' OR cause_of_death = 'mp_titanweapon_flightcore_rockets' OR cause_of_death = 'titan_punch_northstar' OR cause_of_death = 'mp_titanweapon_sniper')`)
await pgClient.query(`UPDATE kill SET attacker_titan = 'legion' WHERE (cause_of_death = 'titan_punch_legion' OR cause_of_death = 'mp_titanweapon_predator_cannon')`)
await pgClient.query(`UPDATE kill SET attacker_titan = 'vanguard' WHERE (cause_of_death = 'mp_titanweapon_dumbfire_rockets' OR cause_of_death = 'titan_punch_vanguard' OR cause_of_death = 'mp_titanweapon_tracker_rockets' OR cause_of_death = 'mp_titanweapon_particle_accelerator' OR cause_of_death = 'mp_titanweapon_xo16_vanguard')`)
await pgClient.query(`ALTER TABLE kill ADD COLUMN IF NOT EXISTS victim_titan character varying NULL;`)
//Update the hosts column once the hoster table is manually updated
await pgClient.end()
}
export async function down(db: Kysely<any>): Promise<void> {
await pgClient.connect()
pgClient.query('ALTER TABLE kill DROP COLUMN IF EXISTS attacker_titan')
pgClient.query('ALTER TABLE kill DROP COLUMN IF EXISTS victim_titan')
await pgClient.end()
}
@@ -1,84 +0,0 @@
import { Kysely, sql } from 'kysely'
import { Client } from 'pg'
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
const weapons = [
'car',
'alternator_smg',
'hemlok_smg',
'r97',
'hemlok',
'vinson',
'g2',
'rspn101',
'rspn101_og',
'esaw',
'lstar',
'lmg',
'shotgun',
'mastiff',
'dmr',
'sniper',
'doubletake',
'pulse_lmg',
'smr',
'softball',
'epg',
'shotgun_pistol',
'wingman_n',
'autopistol',
'semipistol',
'wingman',
'mgl',
'arc_launcher',
'rocket_launcher',
'defender', 'grenade_sonar', 'thermite_grenade', 'grenade_emp', 'smart_pistol', 'satchel', 'grenade_electric_smoke', 'frag_grenade', 'grenade_gravity', 'turretplasma',
]
export async function up(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await Promise.all(weapons.map(async (e) => {
console.log('update ' + e)
await pgClient.query(
`UPDATE KILL SET cause_of_death = 'mp_weapon_${e}' WHERE cause_of_death = '${e}';`
)
await pgClient.query(
`UPDATE KILL SET attacker_current_weapon = 'mp_weapon_${e}' WHERE attacker_current_weapon = '${e}';`
)
await pgClient.query(
`UPDATE KILL SET attacker_weapon_1 = 'mp_weapon_${e}' WHERE attacker_weapon_1 = '${e}';`
)
await pgClient.query(
`UPDATE KILL SET attacker_weapon_2 = 'mp_weapon_${e}' WHERE attacker_weapon_2 = '${e}';`
)
await pgClient.query(
`UPDATE KILL SET attacker_weapon_3 = 'mp_weapon_${e}' WHERE attacker_weapon_3 = '${e}';`
)
await pgClient.query(
`UPDATE KILL SET victim_current_weapon = 'mp_weapon_${e}' WHERE victim_current_weapon = '${e}';`
)
await pgClient.query(
`UPDATE KILL SET victim_weapon_1 = 'mp_weapon_${e}' WHERE victim_weapon_1 = '${e}';`
)
await pgClient.query(
`UPDATE KILL SET victim_weapon_2 = 'mp_weapon_${e}' WHERE victim_weapon_2 = '${e}';`
)
await pgClient.query(
`UPDATE KILL SET victim_weapon_3 = 'mp_weapon_${e}' WHERE victim_weapon_3 = '${e}';`
)
console.log('weapon ' + e + ' updated')
}))
console.log('end')
//Update the hosts column once the hoster table is manually updated
await pgClient.end()
}
export async function down(db: Kysely<any>): Promise<void> { }
@@ -1,40 +0,0 @@
import { Kysely, sql } from 'kysely'
import { Client } from 'pg'
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
export async function up(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query(`ALTER TABLE kill RENAME attacker_offhand_weapon_2 TO attacker_offhand_weapon_2_mods;`)
await pgClient.query(`ALTER TABLE kill RENAME attacker_offhand_weapon_1 TO attacker_offhand_weapon_1_mods;`)
await pgClient.query(`ALTER TABLE kill RENAME victim_offhand_weapon_2 TO victim_offhand_weapon_2_mods;`)
await pgClient.query(`ALTER TABLE kill RENAME victim_offhand_weapon_1 TO victim_offhand_weapon_1_mods;`)
await pgClient.query(`ALTER TABLE kill ADD COLUMN IF NOT EXISTS victim_offhand_weapon_1 character varying NULL;`)
await pgClient.query(`ALTER TABLE kill ADD COLUMN IF NOT EXISTS victim_offhand_weapon_2 character varying NULL;`)
await pgClient.query(`ALTER TABLE kill ADD COLUMN IF NOT EXISTS attacker_offhand_weapon_1 character varying NULL;`)
await pgClient.query(`ALTER TABLE kill ADD COLUMN IF NOT EXISTS attacker_offhand_weapon_2 character varying NULL;`)
//Update the hosts column once the hoster table is manually updated
await pgClient.end()
}
export async function down(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query(`ALTER TABLE kill DROP COLUMN IF EXISTS victim_offhand_weapon_1;`)
await pgClient.query(`ALTER TABLE kill DROP COLUMN IF EXISTS victim_offhand_weapon_2;`)
await pgClient.query(`ALTER TABLE kill DROP COLUMN IF EXISTS attacker_offhand_weapon_1;`)
await pgClient.query(`ALTER TABLE kill DROP COLUMN IF EXISTS attacker_offhand_weapon_2;`)
await pgClient.query(`ALTER TABLE kill RENAME attacker_offhand_weapon_2_mods TO victim_offhand_weapon_2;`)
await pgClient.query(`ALTER TABLE kill RENAME attacker_offhand_weapon_1_mods TO victim_offhand_weapon_1;`)
await pgClient.query(`ALTER TABLE kill RENAME victim_offhand_weapon_2_mods TO victim_offhand_weapon_2;`)
await pgClient.query(`ALTER TABLE kill RENAME victim_offhand_weapon_1_mods TO victim_offhand_weapon_1;`)
await pgClient.end()
}
@@ -1,64 +0,0 @@
import { Kysely, sql } from 'kysely'
import { Client } from 'pg'
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
const weapons = {
titan_sword: 'melee_titan_sword',
yh803_bullet: 'mp_weapon_yh803_bullet',
titan_punch_scorch: 'melee_titan_punch_scorch',
titan_punch_tone: 'melee_titan_punch_tone',
titan_punch_ion: "melee_titan_punch_ion",
titan_punch_vanguard: "melee_titan_punch_vanguard",
titan_punch_legion: "melee_titan_punch_legion",
titan_punch_northstar: "melee_titan_punch_northstar",
}
export async function up(db: Kysely<any>): Promise<void> {
await pgClient.connect()
await Promise.all(
Object.entries(weapons).map(async (e) => {
console.log('update ' + e[0])
await pgClient.query(
`UPDATE KILL SET cause_of_death = '${e[1]}' WHERE cause_of_death = '${e[0]}';`
)
await pgClient.query(
`UPDATE KILL SET attacker_current_weapon = '${e[1]}' WHERE attacker_current_weapon = '${e[0]}';`
)
await pgClient.query(
`UPDATE KILL SET attacker_weapon_1 = '${e[1]}' WHERE attacker_weapon_1 = '${e[0]}';`
)
await pgClient.query(
`UPDATE KILL SET attacker_weapon_2 = '${e[1]}' WHERE attacker_weapon_2 = '${e[0]}';`
)
await pgClient.query(
`UPDATE KILL SET attacker_weapon_3 = '${e[1]}' WHERE attacker_weapon_3 = '${e[0]}';`
)
await pgClient.query(
`UPDATE KILL SET victim_current_weapon = '${e[1]}' WHERE victim_current_weapon = '${e[0]}';`
)
await pgClient.query(
`UPDATE KILL SET victim_weapon_1 = '${e[1]}' WHERE victim_weapon_1 = '${e[0]}';`
)
await pgClient.query(
`UPDATE KILL SET victim_weapon_2 = '${e[1]}' WHERE victim_weapon_2 = '${e[0]}';`
)
await pgClient.query(
`UPDATE KILL SET victim_weapon_3 = '${e[1]}' WHERE victim_weapon_3 = '${e[0]}';`
)
console.log('weapon ' + e[1] + ' updated')
})
)
console.log('end')
//Update the hosts column once the hoster table is manually updated
await pgClient.end()
}
export async function down(db: Kysely<any>): Promise<void> { }
@@ -1,126 +0,0 @@
import { type Kysely } from 'kysely'
import { Client } from 'pg'
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
export async function up (db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query('DROP TABLE IF EXISTS kill_view;')
console.log('creating table kill_view')
await pgClient.query(`CREATE TABLE kill_view
AS (
with "kills" as (select count("id") as "kills", coalesce(max("distance"), 0) as "max_distance", coalesce(sum("distance"), 0) as "total_distance", "attacker_id", last(attacker_name) as "attacker_name", "cause_of_death", "map", "game_mode", "servername", "host" from "kill" where "attacker_id" != "victim_id" group by "attacker_id", "cause_of_death", "map", "servername", "host", "game_mode"), "deaths" as (select count("id") as "deaths", "victim_id", last(victim_name) as "victim_name", "cause_of_death", "map", "game_mode", "servername", "host" from "kill" group by "victim_id", "cause_of_death", "map", "servername", "host", "game_mode"), "deathswithweapon" as (select count("id") as "deaths", "victim_id", "victim_current_weapon", "map", "game_mode", "servername", "host" from "kill" group by "victim_id", "victim_current_weapon", "map", "servername", "host", "game_mode") select COALESCE(kills.attacker_name, deaths.victim_name) as "attacker_name", COALESCE(kills.attacker_id, deaths.victim_id) as "attacker_id", COALESCE(kills.kills, 0) as "kills", COALESCE(kills.total_distance, 0) as "total_distance", COALESCE(deathswithweapon.deaths, 0) as "deaths_with_weapon", COALESCE(kills.max_distance, 0) as "max_distance", COALESCE(deaths.deaths, 0) as "deaths", COALESCE(kills.servername, deaths.servername) as "servername", COALESCE(kills.host, deaths.host) as "host", COALESCE(kills.cause_of_death, deaths.cause_of_death) as "cause_of_death", COALESCE(kills.map, deaths.map) as "map", COALESCE(kills.game_mode, deaths.game_mode) as "game_mode" from "kills" full join "deaths" on "deaths"."victim_id" = "kills"."attacker_id" and "deaths"."cause_of_death" = "kills"."cause_of_death" and "deaths"."servername" = "kills"."servername" and "deaths"."host" = "kills"."host" and "deaths"."game_mode" = "kills"."game_mode" and "deaths"."map" = "kills"."map" left join "deathswithweapon" on "deathswithweapon"."victim_id" = "kills"."attacker_id" and "deathswithweapon"."victim_current_weapon" = "kills"."cause_of_death" and "deathswithweapon"."servername" = "kills"."servername" and "deathswithweapon"."host" = "kills"."host" and "deathswithweapon"."game_mode" = "kills"."game_mode" and "deathswithweapon"."map" = "kills"."map"
);`)
console.log('creating index on attacker_id')
await pgClient.query('CREATE INDEX ON kill_view USING HASH ("attacker_id");')
console.log('creating index on map')
await pgClient.query('CREATE INDEX ON kill_view USING HASH ("map");')
console.log('creating index on game_mode')
await pgClient.query('CREATE INDEX ON kill_view USING HASH ("game_mode");')
console.log('creating index on cause_of_death')
await pgClient.query('CREATE INDEX ON kill_view USING HASH ("cause_of_death");')
console.log('creating index on server')
await pgClient.query('CREATE INDEX ON kill_view ("servername", "host");')
console.log('creating function update_kill_view_fnct')
await pgClient.query(`CREATE OR REPLACE FUNCTION update_kill_view_fnct()
RETURNS TRIGGER
AS $$
BEGIN
IF EXISTS(
SELECT * FROM kill_view
WHERE
new.attacker_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.cause_of_death = cause_of_death AND
new.servername = servername AND
new.host = host
) THEN
UPDATE kill_view SET kills = kills + 1,
max_distance = (SELECT Max(v) FROM (VALUES (new.distance), (max_distance)) AS value(v)),
total_distance = total_distance + new.distance,
attacker_name = new.attacker_name
WHERE
new.attacker_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.cause_of_death = cause_of_death AND
new.servername = servername AND
new.host = host;
ELSE
INSERT INTO kill_view(kills,deaths, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance)
VALUES(1,0,0, new.attacker_id, new.map, new.game_mode, new.cause_of_death, new.servername, new.host,new.distance, new.distance);
END IF;
IF EXISTS(
SELECT * FROM kill_view
WHERE
new.victim_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.cause_of_death = cause_of_death AND
new.servername = servername AND
new.host = host
) THEN
UPDATE kill_view SET deaths = deaths + 1
WHERE
new.victim_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.cause_of_death = cause_of_death AND
new.servername = servername AND
new.host = host;
ELSE
INSERT INTO kill_view(deaths, kills, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance)
VALUES(1,0,0, new.victim_id, new.map, new.game_mode, new.cause_of_death, new.servername, new.host,0,0);
END IF;
IF EXISTS(
SELECT * FROM kill_view
WHERE
new.victim_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.attacker_current_weapon = cause_of_death AND
new.servername = servername AND
new.host = host
) THEN
UPDATE kill_view SET deaths_with_weapon = deaths_with_weapon + 1
WHERE
new.victim_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.attacker_current_weapon = cause_of_death AND
new.servername = servername AND
new.host = host;
ELSE
INSERT INTO kill_view(deaths, kills, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance)
VALUES(0,0,1, new.victim_id, new.map, new.game_mode, new.attacker_current_weapon, new.servername, new.host,0,0);
END IF;
RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;`)
console.log('creating trigger update_kill_view')
await pgClient.query(`CREATE OR REPLACE TRIGGER update_kill_view
AFTER INSERT ON kill
FOR EACH ROW
EXECUTE FUNCTION update_kill_view_fnct();`)
await pgClient.end()
}
export async function down (db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query('DROP TRIGGER IF EXISTS update_kill_view;')
await pgClient.query('DROP FUNCTION IF EXISTS update_kill_view_fnct')
await pgClient.query('DROP TABLE IF EXISTS kill_view;')
await pgClient.end()
}
@@ -1,100 +0,0 @@
import { type Kysely } from 'kysely'
import { Client } from 'pg'
const pgClient = new Client({
host: process.env.POSTGRES_HOST,
database: process.env.POSTGRES_DATABASE,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD
})
export async function up (db: Kysely<any>): Promise<void> {
await pgClient.connect()
await pgClient.query(`CREATE OR REPLACE FUNCTION update_kill_view_fnct()
RETURNS TRIGGER
AS $$
BEGIN
IF EXISTS(
SELECT * FROM kill_view
WHERE
new.attacker_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.cause_of_death = cause_of_death AND
new.servername = servername AND
new.host = host
) THEN
UPDATE kill_view SET kills = kills + 1,
max_distance = (SELECT Max(v) FROM (VALUES (new.distance), (max_distance)) AS value(v)),
total_distance = total_distance + new.distance,
attacker_name = new.attacker_name
WHERE
new.attacker_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.cause_of_death = cause_of_death AND
new.servername = servername AND
new.host = host;
ELSE
INSERT INTO kill_view(kills,deaths, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance, attacker_name)
VALUES(1,0,0, new.attacker_id, new.map, new.game_mode, new.cause_of_death, new.servername, new.host,new.distance, new.distance, new.attacker_name);
END IF;
IF EXISTS(
SELECT * FROM kill_view
WHERE
new.victim_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.cause_of_death = cause_of_death AND
new.servername = servername AND
new.host = host
) THEN
UPDATE kill_view SET deaths = deaths + 1
WHERE
new.victim_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.cause_of_death = cause_of_death AND
new.servername = servername AND
new.host = host;
ELSE
INSERT INTO kill_view(deaths, kills, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance, attacker_name)
VALUES(1,0,0, new.victim_id, new.map, new.game_mode, new.cause_of_death, new.servername, new.host,0,0, new.victim_name);
END IF;
IF EXISTS(
SELECT * FROM kill_view
WHERE
new.victim_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.attacker_current_weapon = cause_of_death AND
new.servername = servername AND
new.host = host
) THEN
UPDATE kill_view SET deaths_with_weapon = deaths_with_weapon + 1
WHERE
new.victim_id = attacker_id AND
new.map = map AND
new.game_mode = game_mode AND
new.attacker_current_weapon = cause_of_death AND
new.servername = servername AND
new.host = host;
ELSE
INSERT INTO kill_view(deaths, kills, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance, attacker_name)
VALUES(0,0,1, new.victim_id, new.map, new.game_mode, new.attacker_current_weapon, new.servername, new.host,0,0, new.victim_name);
END IF;
RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;`)
await pgClient.end()
}
export async function down (db: Kysely<any>): Promise<void> {
}
@@ -1,140 +0,0 @@
import { sql, type Kysely } from 'kysely'
export async function up (db: Kysely<any>): Promise<void> {
await db.schema.createSchema('ToneAPI').ifNotExists().execute()
await db.schema.createTable('ToneAPI.host')
.addColumn('host_name', 'varchar(50)', (col) => col.notNull())
.addColumn('host_id', 'integer', (col) => col.notNull().primaryKey().autoIncrement())
.addColumn('host_token', 'varchar(50)', (col) => col.notNull().defaultTo(sql`gen_random_uuid()`))
.execute()
await db.schema.createTable('ToneAPI.server')
.addColumn('server_name', 'varchar(64)', (col) => col.notNull())
.addColumn('host_id', 'integer', (col) => col.notNull().references('ToneAPI.host.host_id'))
.addPrimaryKeyConstraint('server_pkey', ['server_name', 'host_id'])
.execute()
await db.schema.createTable('ToneAPI.match')
.addColumn('match_id', 'integer', (col) => col.notNull().primaryKey().autoIncrement())
.addColumn('host_id', 'integer', (col) => col.notNull().primaryKey())
.addColumn('server_name', 'varchar(64)', (col) => col.notNull())
.addColumn('game_map', 'varchar(30)', (col) => col.notNull())
.addColumn('gamemode', 'varchar(10)', (col) => col.notNull())
.addColumn('air_accel', 'boolean', (col) => col.notNull().defaultTo(false))
.addForeignKeyConstraint('fk_match_host_of_server', ['host_id', 'server_name'], 'ToneAPI.server', ['host_id', 'server_name'])
.execute()
await db.schema.createTable('ToneAPI.player')
.addColumn('player_id', 'bigint', (col) => col.notNull().primaryKey())
.addColumn('player_name', 'varchar(50)', (col) => col.notNull())
.execute()
await db.schema.createTable('ToneAPI.weapon')
.addColumn('weapon_id', 'varchar(50)', (col) => col.notNull().primaryKey())
.addColumn('weapon_name', 'varchar(50)', (col) => col.notNull())
.execute()
await db.schema.createTable('ToneAPI.mods_on_weapon')
.addColumn('mod_id', 'integer', (col) => col.notNull().primaryKey())
.addColumn('speedloader', 'boolean', (col) => col.notNull().defaultTo(false))
.addColumn('extra_ammo', 'boolean', (col) => col.notNull().defaultTo(false))
.addColumn('gunrunner', 'boolean', (col) => col.notNull().defaultTo(false))
.addColumn('gun_ready', 'boolean', (col) => col.notNull().defaultTo(false))
.addColumn('quickswap', 'boolean', (col) => col.notNull().defaultTo(false))
.addColumn('tactikill', 'boolean', (col) => col.notNull().defaultTo(false))
.addColumn('suppressor', 'boolean', (col) => col.notNull().defaultTo(false))
.addColumn('ricochet', 'boolean', (col) => col.notNull().defaultTo(false))
.addColumn('pro_screen', 'boolean', (col) => col.notNull().defaultTo(false))
.execute()
await db.schema.createTable('ToneAPI.titan_chassis')
.addColumn('titan_id', 'varchar(30)', (col) => col.notNull().primaryKey())
.addColumn('chassis_name', 'varchar(30)', (col) => col.notNull())
.execute()
await db.schema.createTable('ToneAPI.loadout')
.addColumn('loadout_id', 'integer', (col) => col.notNull().primaryKey().autoIncrement())
.addColumn('primary_weapon', 'varchar(50)', (col) => col.references('ToneAPI.weapon.weapon_id'))
.addColumn('primary_mod_id', 'integer', (col) => col.references('ToneAPI.mods_on_weapon.mod_id'))
.addColumn('secondary_weapon', 'varchar(50)', (col) => col.references('ToneAPI.weapon.weapon_id'))
.addColumn('secondary_mod_id', 'integer', (col) => col.references('ToneAPI.mods_on_weapon.mod_id'))
.addColumn('anti_titan_weapon', 'varchar(50)', (col) => col.references('ToneAPI.weapon.weapon_id'))
.addColumn('anti_titan_mod_id', 'integer', (col) => col.references('ToneAPI.mods_on_weapon.mod_id'))
.addColumn('ordnance', 'varchar(50)', (col) => col.references('ToneAPI.weapon.weapon_id'))
.addColumn('tactical', 'varchar(50)')
.addColumn('titan_weapon', 'varchar(50)', (col) => col.references('ToneAPI.weapon.weapon_id'))
.addColumn('pilot_passive_1', 'varchar(50)')
.addColumn('pilot_passive_2', 'varchar(50)')
.addColumn('titan_passive_1', 'varchar(50)')
.addColumn('titan_passive_2', 'varchar(50)')
.addColumn('titan_passive_3', 'varchar(50)')
.addColumn('titan_passive_4', 'varchar(50)')
.addColumn('titan_passive_5', 'varchar(50)')
.addColumn('titan_passive_6', 'varchar(50)')
.addColumn('titan_special', 'varchar(50)')
.addColumn('titan_anti_rodeo', 'varchar(50)')
.addColumn('titan_primary_mod', 'varchar(50)')
.addColumn('titan_id', 'varchar(50)', (col) => col.references('ToneAPI.titan_chassis.titan_id'))
.execute()
await db.schema.createTable('ToneAPI.kill')
.addColumn('kill_id', 'bigint', (col) => col.notNull().primaryKey().autoIncrement())
.addColumn('attacker_id', 'bigint', (col) => col.notNull().references('ToneAPI.player.player_id'))
.addColumn('victim_id', 'bigint', (col) => col.notNull().references('ToneAPI.player.player_id'))
.addColumn('match_id', 'integer', (col) => col.notNull().references('ToneAPI.match.match_id'))
.addColumn('attacker_loadout_id', 'integer', (col) => col.notNull().references('ToneAPI.loadout.loadout_id'))
.addColumn('victim_loadout_id', 'integer', (col) => col.notNull().references('ToneAPI.loadout.loadout_id'))
.addColumn('attacker_speed', 'integer')
.addColumn('victim_speed', 'integer')
.addColumn('attacker_movementstate', 'varchar(50)')
.addColumn('victim_movementstate', 'varchar(50)')
.addColumn('distance', 'integer')
.addColumn('unix_time', 'timestamp')
.addColumn('game_time', 'decimal')
.addColumn('cause_of_death', 'varchar(50)', (col) => col.references('ToneAPI.weapon.weapon_id'))
.addColumn('attacker_held_weapon', 'varchar(50)', (col) => col.references('ToneAPI.weapon.weapon_id'))
.addColumn('victim_held_weapon', 'varchar(50)', (col) => col.references('ToneAPI.weapon.weapon_id'))
.execute()
await db.schema.createTable('ToneAPI.titan_stats_in_match')
.addColumn('match_id', 'integer', (col) => col.notNull().references('ToneAPI.match.match_id'))
.addColumn('player_id', 'bigint', (col) => col.notNull().references('ToneAPI.player.player_id'))
.addColumn('titan_id', 'varchar(50)', (col) => col.notNull().references('ToneAPI.titan_chassis.titan_id'))
.addColumn('playtime', 'bigint')
.addColumn('shots_fired', 'integer')
.addColumn('shots_hit', 'integer')
.addColumn('headshots', 'integer')
.addPrimaryKeyConstraint('titan_stats_in_match_pkey', ['match_id', 'player_id', 'titan_id'])
.execute()
await db.schema.createTable('ToneAPI.weapon_stats_in_match')
.addColumn('match_id', 'integer', (col) => col.notNull().references('ToneAPI.match.match_id'))
.addColumn('player_id', 'bigint', (col) => col.notNull().references('ToneAPI.player.player_id'))
.addColumn('weapon_id', 'varchar(50)', (col) => col.notNull().references('ToneAPI.weapon.weapon_id'))
.addColumn('playtime', 'bigint')
.addColumn('shots_fired', 'integer')
.addColumn('shots_hit', 'integer')
.addColumn('headshots', 'integer')
.addColumn('ricochets', 'integer')
.addPrimaryKeyConstraint('weapon_stats_in_match_pkey', ['match_id', 'player_id', 'weapon_id'])
.execute()
await db.schema.createTable('ToneAPI.player_stats_in_match')
.addColumn('match_id', 'integer', (col) => col.notNull().references('ToneAPI.match.match_id'))
.addColumn('player_id', 'bigint', (col) => col.notNull().references('ToneAPI.player.player_id'))
.addColumn('shots_fired', 'integer')
.addColumn('shots_hit', 'integer')
.addColumn('headshots', 'integer')
.addColumn('ricochets', 'integer')
.addColumn('overall_distance_covered', 'bigint')
.addColumn('time_grounded', 'bigint')
.addColumn('time_wall', 'bigint')
.addColumn('time_air', 'bigint')
.addPrimaryKeyConstraint('playerstats_in_match_pkey', ['match_id', 'player_id'])
.execute()
}
export async function down (db: Kysely<any>): Promise<void> {
}
-160
View File
@@ -1,160 +0,0 @@
import { type Generated } from 'kysely'
interface HostTable {
host_name: string
host_id: Generated<number>
host_token: Generated<string>
}
interface ServerTable {
server_name: string
host_id: number
}
interface MatchTable {
match_id: Generated<number>
host_id: number
server_name: string
game_map: string
gamemode: string
air_accel: boolean
}
interface PlayerTable {
weapon_id: string
weapon_name: string
}
interface WeaponTable {
playername: string
player_id: number
}
interface ModsOnWeaponTable {
mod_id: number
speedloader: boolean
extra_ammo: boolean
gunrunner: boolean
gun_ready: boolean
quickswap: boolean
tactikill: boolean
suppressor: boolean
ricochet: boolean
pro_screen: boolean
}
interface TitanChassisTable {
titan_id: string
chassis_name: string
}
interface LoadoutTable {
loadout_id: Generated<number>
primary_weapon: string
secondary_weapon: string
anti_titan_weapon: string
primary_mod_id: number
secondary_mod_id: number
anti_titan_mod_id: number
ordnance: string
tactical: string
titan_weapon: string
pilot_passive_1: string
pilot_passive_2: string
titan_passive_1: string
titan_passive_2: string
titan_passive_3: string
titan_passive_4: string
titan_passive_5: string
titan_passive_6: string
titan_special: string
titan_anti_rodeo: string
titan_primary_mod: string
titan_id: string
}
export interface KillTable {
kill_id: Generated<bigint>
attacker_id: bigint
victim_id: bigint
match_id: number
attacker_loadout_id: number
victim_loadout_id: number
attacker_speed: number
victim_speed: number
attacker_movementstate: string
victim_movementstate: string
distance: number
unix_time: Date
game_time: number
cause_of_death: string
attacker_held_weapon: string
victim_held_weapon: string
}
export interface TitanStatsInMatchTable {
match_id: number
player_id: bigint
titan_id: string
playtime: bigint
shots_fired: number
shots_hit: number
headshots: number
}
export interface WeaponStatsInMatchTable {
match_id: number
player_id: bigint
weapon_id: string
playtime: bigint
shots_fired: number
shots_hit: number
headshots: number
ricochets: number
}
export interface PlayerStatsInMatchTable {
match_id: number
player_id: bigint
shots_fired: number
shots_hit: number
headshots: number
ricochets: number
overall_distance_covered: bigint
time_grounded: bigint
time_wall: bigint
time_air: bigint
}
export interface KillViewTable {
kills: number
deaths: number
deaths_with_weapon: number
attacker_id: number
attacker_name: string
map: string
game_mode: string
cause_of_death: string
servername: string
host: number
max_distance: number
total_distance: number
}
interface Database {
kill_view: KillViewTable
host: HostTable
server: ServerTable
match: MatchTable
player: PlayerTable
weapon: WeaponTable
mods_on_weapon: ModsOnWeaponTable
titan_chassis: TitanChassisTable
loadout: LoadoutTable
kill: KillTable
titan_stats_in_match: TitanStatsInMatchTable
weapon_stats_in_match: WeaponStatsInMatchTable
player_stats_in_match: PlayerStatsInMatchTable
}
export default Database