initial schema and migrations

This commit is contained in:
2023-02-28 15:29:49 +01:00
parent 5f327c0272
commit b0a40d0971
9 changed files with 403 additions and 6 deletions
+4
View File
@@ -0,0 +1,4 @@
POSTGRES_HOST="localhost"
POSTGRES_DATABASE="postgres"
POSTGRES_USER="postgres"
POSTGRES_PASSWORD="postgres"
+5 -6
View File
@@ -1,7 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.organizeImports": true
},
"editor.formatOnSave": true
}
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"editor.formatOnSave": true
}
+169
View File
@@ -5,11 +5,15 @@
"packages": {
"": {
"dependencies": {
"dotenv": "^16.0.3",
"express": "^4.18.2",
"kysely": "^0.23.4",
"pg": "^8.9.0",
"ts-node": "^10.9.1"
},
"devDependencies": {
"@types/express": "^4.17.17",
"@types/pg": "^8.6.6",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"eslint": "^8.35.0",
"eslint-config-standard-with-typescript": "^34.0.0",
@@ -283,6 +287,17 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.2.tgz",
"integrity": "sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA=="
},
"node_modules/@types/pg": {
"version": "8.6.6",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.6.tgz",
"integrity": "sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==",
"dev": true,
"dependencies": {
"@types/node": "*",
"pg-protocol": "*",
"pg-types": "^2.2.0"
}
},
"node_modules/@types/qs": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
@@ -836,6 +851,14 @@
"node": ">=8"
}
},
"node_modules/buffer-writer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
"integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==",
"engines": {
"node": ">=4"
}
},
"node_modules/builtins": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
@@ -1044,6 +1067,14 @@
"node": ">=6.0.0"
}
},
"node_modules/dotenv": {
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
"engines": {
"node": ">=12"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -2432,6 +2463,14 @@
"json5": "lib/cli.js"
}
},
"node_modules/kysely": {
"version": "0.23.4",
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.23.4.tgz",
"integrity": "sha512-3icLnj1fahUtZsP9zzOvF4DcdhekGsLX4ZaoBaIz0ZeHegyRDdbwpJD7zezAJ+KwQZNDeKchel6MikFNLsSZIA==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -2721,6 +2760,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/packet-reader": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -2788,6 +2832,80 @@
"node": ">=8"
}
},
"node_modules/pg": {
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.9.0.tgz",
"integrity": "sha512-ZJM+qkEbtOHRuXjmvBtOgNOXOtLSbxiMiUVMgE4rV6Zwocy03RicCVvDXgx8l4Biwo8/qORUnEqn2fdQzV7KCg==",
"dependencies": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",
"pg-connection-string": "^2.5.0",
"pg-pool": "^3.5.2",
"pg-protocol": "^1.6.0",
"pg-types": "^2.1.0",
"pgpass": "1.x"
},
"engines": {
"node": ">= 8.0.0"
},
"peerDependencies": {
"pg-native": ">=3.0.1"
},
"peerDependenciesMeta": {
"pg-native": {
"optional": true
}
}
},
"node_modules/pg-connection-string": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
},
"node_modules/pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/pg-pool": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz",
"integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==",
"peerDependencies": {
"pg": ">=8.0"
}
},
"node_modules/pg-protocol": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz",
"integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q=="
},
"node_modules/pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"dependencies": {
"pg-int8": "1.0.1",
"postgres-array": "~2.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.4",
"postgres-interval": "^1.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pgpass": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"dependencies": {
"split2": "^4.1.0"
}
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -2800,6 +2918,41 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
"engines": {
"node": ">=4"
}
},
"node_modules/postgres-bytea": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-date": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-interval": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
"dependencies": {
"xtend": "^4.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -3132,6 +3285,14 @@
"node": ">=8"
}
},
"node_modules/split2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
"integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==",
"engines": {
"node": ">= 10.x"
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -3507,6 +3668,14 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"engines": {
"node": ">=0.4"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+4
View File
@@ -1,10 +1,14 @@
{
"dependencies": {
"dotenv": "^16.0.3",
"express": "^4.18.2",
"kysely": "^0.23.4",
"pg": "^8.9.0",
"ts-node": "^10.9.1"
},
"devDependencies": {
"@types/express": "^4.17.17",
"@types/pg": "^8.6.6",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"eslint": "^8.35.0",
"eslint-config-standard-with-typescript": "^34.0.0",
+43
View File
@@ -0,0 +1,43 @@
import { Kysely, PostgresDialect } from "kysely";
import { Pool } from "pg";
import migrateToLatest from "./migrations";
import Database from "./model";
migrateToLatest();
// You'd create one of these when you start your app.
const db = new Kysely<Database>({
// Use MysqlDialect for MySQL and SqliteDialect for SQLite.
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,
}),
}),
});
/*
async function demo() {
const { id } = await db
.insertInto("person")
.values({ first_name: "Jennifer", gender: "female" })
.returning("id")
.executeTakeFirstOrThrow();
await db
.insertInto("pet")
.values({ name: "Catto", species: "cat", owner_id: id })
.execute();
const person = await db
.selectFrom("person")
.innerJoin("pet", "pet.owner_id", "person.id")
.select(["first_name", "pet.name as pet_name"])
.where("person.id", "=", id)
.executeTakeFirst();
if (person) {
person.pet_name;
}
}
*/
export default "e";
+53
View File
@@ -0,0 +1,53 @@
import { promises as fs } from "fs";
import {
FileMigrationProvider,
Kysely,
Migrator,
PostgresDialect,
} from "kysely";
import * as path from "path";
import { Pool } from "pg";
import Database from "./model";
console.log(process.env.POSTGRES_HOST);
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;
+76
View File
@@ -0,0 +1,76 @@
import { Kysely, sql } from "kysely";
export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createTable("entity")
.addColumn("id", "integer", (col) => col.unique().primaryKey())
.addColumn("name", "varchar")
.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("name", "varchar", (col) => col.unique().primaryKey())
.addColumn("description", "varchar")
.addColumn("token", "varchar")
.execute();
await db.schema
.createTable("kill")
.addColumn("id", "serial", (col) => col.primaryKey())
.addColumn("server", "varchar", (col) =>
col.references("server.name").notNull()
)
.addColumn("attacker", "integer", (col) =>
col.references("entity.id").notNull()
)
.addColumn("victim", "integer", (col) =>
col.references("entity.id").notNull()
)
.addColumn("weapon", "varchar", (col) =>
col.references("weapon.id").notNull()
)
.addColumn("map", "varchar", (col) => col.references("map.id").notNull())
.addColumn("distance", "integer", (col) => col.notNull())
.addColumn("date", "varchar", (col) => col.defaultTo(sql`now()`).notNull())
.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("entity").execute();
await db.schema.dropTable("weapon").execute();
await db.schema.dropTable("map").execute();
await db.schema.dropTable("server").execute();
}
+43
View File
@@ -0,0 +1,43 @@
import { Generated } from "kysely";
interface KillTable {
id: Generated<number>;
server: string;
attacker: number;
victim: number;
weapon: string;
map: string;
distance: number;
date: Date;
}
interface EntityTable {
id: number;
name: string;
}
interface WeaponTable {
id: string;
name: string;
description: string;
image: string;
}
interface MapTable {
id: string;
name: string;
description: string;
image: string;
}
interface ServerTable {
id: string;
name: string;
description: string;
}
interface Database {
kill: KillTable;
entity: EntityTable;
weapon: WeaponTable;
maps: MapTable;
server: ServerTable;
}
export default Database;
+6
View File
@@ -1,7 +1,13 @@
import * as dotenv from "dotenv";
dotenv.config();
import express from "express";
import client from "./client";
import db from "./db/db";
import server from "./server";
console.log("dotenv");
console.log(db);
const app = express();
const port = 3000;