feat: migrations.
This commit is contained in:
1015
package-lock.json
generated
1015
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,12 @@
|
|||||||
import { Database } from "./types"; // this is the Database interface we defined earlier
|
import { Database } from "./types"; // this is the Database interface we defined earlier
|
||||||
import { createPool } from "mysql2"; // do not use 'mysql2/promises'!
|
import { createPool } from "mysql2"; // do not use 'mysql2/promises'!
|
||||||
import { Kysely, MysqlDialect } from "kysely";
|
import {
|
||||||
|
Kysely,
|
||||||
|
Migration,
|
||||||
|
MigrationProvider,
|
||||||
|
Migrator,
|
||||||
|
MysqlDialect,
|
||||||
|
} from "kysely";
|
||||||
import { env } from "process";
|
import { env } from "process";
|
||||||
|
|
||||||
const dialect = new MysqlDialect({
|
const dialect = new MysqlDialect({
|
||||||
@@ -9,7 +15,7 @@ const dialect = new MysqlDialect({
|
|||||||
host: env.DATABASE_HOST || "",
|
host: env.DATABASE_HOST || "",
|
||||||
user: env.DATABASE_USER || "",
|
user: env.DATABASE_USER || "",
|
||||||
password: env.DATABASE_PASSWORD || "",
|
password: env.DATABASE_PASSWORD || "",
|
||||||
port: parseInt(env.DATABASE_PORT || "3308", 10),
|
port: parseInt(env.DATABASE_PORT || "3306", 10),
|
||||||
connectionLimit: parseInt(
|
connectionLimit: parseInt(
|
||||||
env.CONDATABASE_CONNECTIONLIMITNECTIONLIMIT || "10",
|
env.CONDATABASE_CONNECTIONLIMITNECTIONLIMIT || "10",
|
||||||
10
|
10
|
||||||
@@ -37,3 +43,32 @@ export const db = new Kysely<Database>({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
import * as migrations from "./migrations";
|
||||||
|
|
||||||
|
class InnerMigrationProvider implements MigrationProvider {
|
||||||
|
getMigrations(): Promise<Record<string, Migration>> {
|
||||||
|
return Promise.resolve(migrations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function migrateToLatest() {
|
||||||
|
const migrator = new Migrator({
|
||||||
|
db,
|
||||||
|
provider: new InnerMigrationProvider(),
|
||||||
|
});
|
||||||
|
|
||||||
|
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) {
|
||||||
|
throw new Error(JSON.stringify(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
64
src/server/db/migrations/2025-01-07T10-45-43.020Z.ts
Normal file
64
src/server/db/migrations/2025-01-07T10-45-43.020Z.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { Kysely } from "kysely";
|
||||||
|
|
||||||
|
export async function up(db: Kysely<any>): Promise<void> {
|
||||||
|
await db.schema
|
||||||
|
.createTable("session_info")
|
||||||
|
.addColumn("id", "char(36)", (col) => col.primaryKey())
|
||||||
|
.addColumn("game_name", "varchar(255)", (col) => col.notNull())
|
||||||
|
.addColumn("version", "varchar(255)", (col) => col.notNull())
|
||||||
|
.addColumn("save_id", "char(255)", (col) => col.notNull())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.createTable("log_entries")
|
||||||
|
.addColumn("id", "int4", (col) => col.primaryKey().autoIncrement())
|
||||||
|
.addColumn("session_info_id", "char(36)", (col) =>
|
||||||
|
col
|
||||||
|
.notNull()
|
||||||
|
.references("session_info.id")
|
||||||
|
.onDelete("cascade")
|
||||||
|
.onUpdate("cascade")
|
||||||
|
)
|
||||||
|
.addColumn("message", "varchar(255)", (col) => col.notNull())
|
||||||
|
.addColumn("timestamp", "datetime", (col) => col.notNull())
|
||||||
|
.addColumn("category", "varchar(255)", (col) => col.defaultTo(null))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.createIndex("log_entries_session_info_id")
|
||||||
|
.on("log_entries")
|
||||||
|
.column("session_info_id")
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.createIndex("log_entries_category")
|
||||||
|
.on("log_entries")
|
||||||
|
.column("category")
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.createTable("log_metadata")
|
||||||
|
.addColumn("id", "int4", (col) => col.primaryKey().autoIncrement())
|
||||||
|
.addColumn("log_entry_id", "int4", (col) =>
|
||||||
|
col
|
||||||
|
.notNull()
|
||||||
|
.references("log_entries.id")
|
||||||
|
.onDelete("cascade")
|
||||||
|
.onUpdate("cascade")
|
||||||
|
)
|
||||||
|
.addColumn("key", "varchar(50)", (col) => col.notNull())
|
||||||
|
.addColumn("value", "varchar(255)", (col) => col.notNull())
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await db.schema
|
||||||
|
.createIndex("log_metadata_log_entry_id")
|
||||||
|
.on("log_metadata")
|
||||||
|
.column("log_entry_id")
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(db: Kysely<any>): Promise<void> {
|
||||||
|
await db.schema.dropTable("log_metadata").execute();
|
||||||
|
await db.schema.dropTable("log_entries").execute();
|
||||||
|
await db.schema.dropTable("session_info").execute();
|
||||||
|
}
|
||||||
1
src/server/db/migrations/index.ts
Normal file
1
src/server/db/migrations/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * as migration20250107T104543020Z from "./2025-01-07T10-45-43.020Z";
|
||||||
@@ -6,7 +6,10 @@ import path from "path";
|
|||||||
import { installCors } from "./install-cors";
|
import { installCors } from "./install-cors";
|
||||||
import { installMeta } from "./install-meta";
|
import { installMeta } from "./install-meta";
|
||||||
import { OpenAPIObject } from "openapi3-ts/oas31";
|
import { OpenAPIObject } from "openapi3-ts/oas31";
|
||||||
|
import { migrateToLatest } from "./db/init";
|
||||||
|
|
||||||
|
migrateToLatest()
|
||||||
|
.then(() => {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
// enable cors
|
// enable cors
|
||||||
@@ -23,7 +26,10 @@ app.use(bodyParser.json());
|
|||||||
const openAPIObject = installMeta(app);
|
const openAPIObject = installMeta(app);
|
||||||
|
|
||||||
// install the ts-rest router
|
// install the ts-rest router
|
||||||
installRouter(app, openAPIObject as unknown as OpenAPIObject /* required because of mixups in versioning betwee @ts-rest/open-api, @anatine/zop-openapi and openapi3-ts */);
|
installRouter(
|
||||||
|
app,
|
||||||
|
openAPIObject as unknown as OpenAPIObject /* required because of mixups in versioning betwee @ts-rest/open-api, @anatine/zop-openapi and openapi3-ts */
|
||||||
|
);
|
||||||
|
|
||||||
// handle every other GET route with index.html
|
// handle every other GET route with index.html
|
||||||
app.get("*", function (_req, res, next) {
|
app.get("*", function (_req, res, next) {
|
||||||
@@ -39,3 +45,5 @@ const host = process.env.HTTP_HOST || "localhost";
|
|||||||
app.listen(port, host, () => {
|
app.listen(port, host, () => {
|
||||||
console.log(`Listening on http://${host}:${port}`);
|
console.log(`Listening on http://${host}:${port}`);
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
|||||||
Reference in New Issue
Block a user