diff --git a/package.json b/package.json index 3b33440..07164d4 100755 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "scripts": { "start": "pnpm -F backend start", "dev": "pnpm -r --parallel --no-bail dev", - "build": "pnpm -r --parallel build" + "build": "pnpm -r --parallel build", + "migrator": "pnpm -F backend migrator" }, "packageManager": "pnpm@10.29.1" } diff --git a/packages/backend/package.json b/packages/backend/package.json index b3a699c..ec37ff9 100755 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -7,7 +7,7 @@ "start": "cross-env NODE_ENV=production node .", "build": "tsc && tsc-alias", "dev": "tsx watch src/index.ts", - "mikro": "tsx ./node_modules/@mikro-orm/cli/esm.js" + "migrator": "node scripts/migrator.js" }, "author": { "name": "Last2014", @@ -30,7 +30,6 @@ "fs": "0.0.1-security", "os": "^0.1.2", "tsc-alias": "^1.8.16", - "tsx": "^4.21.0", "typescript": "^5.9.3", "util": "^0.12.5", "uuid": "^13.0.0", @@ -39,6 +38,7 @@ "zod": "^4.3.6" }, "devDependencies": { - "@types/node": "^24.1.0" + "@types/node": "^24.1.0", + "tsx": "^4.21.0" } } diff --git a/packages/backend/scripts/migrator.js b/packages/backend/scripts/migrator.js new file mode 100644 index 0000000..8244dc9 --- /dev/null +++ b/packages/backend/scripts/migrator.js @@ -0,0 +1,23 @@ +import config from "../dist/mikro-orm.config.js"; +import { MikroORM } from "@mikro-orm/postgresql"; + +const orm = await MikroORM.init({ + ...config, + logger: (msg) => console.log(msg), +}); + +switch (process.argv[2]) { + case "up": + await orm.migrator.up(); + break; + case "down": + await orm.migrator.down(); + break; + case "create": + await orm.migrator.createMigration(); + break; + default: + console.log("Only the options up, down, and create are available."); +} + +process.exit(); \ No newline at end of file diff --git a/packages/backend/src/migrations/.snapshot-chat.json b/packages/backend/src/migrations/.snapshot-chat.json index 9b9adce..f946015 100644 --- a/packages/backend/src/migrations/.snapshot-chat.json +++ b/packages/backend/src/migrations/.snapshot-chat.json @@ -11,20 +11,32 @@ "type": "varchar(255)", "unsigned": false, "autoincrement": false, - "primary": false, + "primary": true, "nullable": false, + "unique": false, "length": 255, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], "mappedType": "string" }, "value": { "name": "value", - "type": "varchar(255)", + "type": "text", "unsigned": false, "autoincrement": false, "primary": false, "nullable": false, - "length": 255, - "mappedType": "string" + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "text" } }, "name": "config", @@ -47,6 +59,22 @@ }, { "columns": { + "id": { + "name": "id", + "type": "varchar(10)", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": 10, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "string" + }, "userid": { "name": "userid", "type": "varchar(20)", @@ -54,7 +82,13 @@ "autoincrement": false, "primary": false, "nullable": false, + "unique": false, "length": 20, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], "mappedType": "string" }, "username": { @@ -64,33 +98,141 @@ "autoincrement": false, "primary": false, "nullable": false, + "unique": false, "length": 30, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "string" + }, + "profile": { + "name": "profile", + "type": "varchar(4096)", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": 4096, + "precision": null, + "scale": null, + "default": "''", + "comment": null, + "enumItems": [], "mappedType": "string" }, "email": { "name": "email", - "type": "varchar(254)", + "type": "varchar(256)", "unsigned": false, "autoincrement": false, "primary": false, "nullable": false, - "length": 254, + "unique": false, + "length": 256, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], "mappedType": "string" }, "password": { "name": "password", - "type": "varchar(60)", + "type": "text", "unsigned": false, "autoincrement": false, "primary": false, "nullable": false, - "length": 60, - "mappedType": "string" + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "text" + }, + "is_owner": { + "name": "is_owner", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "false", + "comment": null, + "enumItems": [], + "mappedType": "boolean" + }, + "is_suspended": { + "name": "is_suspended", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": "false", + "comment": null, + "enumItems": [], + "mappedType": "boolean" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": 6, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "datetime" + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": 6, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "datetime" } }, "name": "user", "schema": "public", "indexes": [ + { + "columnNames": [ + "userid" + ], + "composite": false, + "keyName": "user_userid_unique", + "constraint": true, + "primary": false, + "unique": true + }, { "columnNames": [ "email" @@ -104,7 +246,7 @@ { "keyName": "user_pkey", "columnNames": [ - "userid" + "id" ], "composite": false, "constraint": true, @@ -115,6 +257,146 @@ "checks": [], "foreignKeys": {}, "nativeEnums": {} + }, + { + "columns": { + "name": { + "name": "name", + "type": "varchar(64)", + "unsigned": false, + "autoincrement": false, + "primary": true, + "nullable": false, + "unique": false, + "length": 64, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "string" + }, + "passphrase": { + "name": "passphrase", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "text" + }, + "user_id": { + "name": "user_id", + "type": "varchar(10)", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": 10, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "string" + }, + "is_native": { + "name": "is_native", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": null, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "boolean" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "unique": false, + "length": 6, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "datetime" + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "unique": false, + "length": 6, + "precision": null, + "scale": null, + "default": null, + "comment": null, + "enumItems": [], + "mappedType": "datetime" + } + }, + "name": "token", + "schema": "public", + "indexes": [ + { + "columnNames": [ + "user_id" + ], + "composite": false, + "keyName": "token_user_id_index", + "constraint": false, + "primary": false, + "unique": false + }, + { + "keyName": "token_pkey", + "columnNames": [ + "name" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": { + "token_user_id_foreign": { + "constraintName": "token_user_id_foreign", + "columnNames": [ + "user_id" + ], + "localTableName": "public.token", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.user", + "updateRule": "cascade" + } + }, + "nativeEnums": {} } ], "nativeEnums": {} diff --git a/packages/backend/src/migrations/Migration20260327135046.ts b/packages/backend/src/migrations/Migration20260327135046.ts new file mode 100644 index 0000000..9cf4771 --- /dev/null +++ b/packages/backend/src/migrations/Migration20260327135046.ts @@ -0,0 +1,36 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20260327135046 extends Migration { + + override async up(): Promise { + this.addSql(`create table "token" ("name" varchar(64) not null, "passphrase" text not null, "user_id" varchar(10) not null, "is_native" boolean not null, "created_at" timestamptz not null, "last_used_at" timestamptz null, constraint "token_pkey" primary key ("name"));`); + this.addSql(`create index "token_user_id_index" on "token" ("user_id");`); + + this.addSql(`alter table "token" add constraint "token_user_id_foreign" foreign key ("user_id") references "user" ("id") on update cascade;`); + + this.addSql(`alter table "config" alter column "value" type text using ("value"::text);`); + + this.addSql(`alter table "user" drop constraint "user_pkey";`); + + this.addSql(`alter table "user" add column "id" varchar(10) not null, add column "profile" varchar(4096) not null default '', add column "is_owner" boolean not null default false, add column "is_suspended" boolean not null default false, add column "created_at" timestamptz not null, add column "last_used_at" timestamptz null;`); + this.addSql(`alter table "user" alter column "email" type varchar(256) using ("email"::varchar(256));`); + this.addSql(`alter table "user" alter column "password" type text using ("password"::text);`); + this.addSql(`alter table "user" add constraint "user_userid_unique" unique ("userid");`); + this.addSql(`alter table "user" add constraint "user_pkey" primary key ("id");`); + } + + override async down(): Promise { + this.addSql(`drop table if exists "token" cascade;`); + + this.addSql(`alter table "config" alter column "value" type varchar(255) using ("value"::varchar(255));`); + + this.addSql(`alter table "user" drop constraint "user_userid_unique";`); + this.addSql(`alter table "user" drop constraint "user_pkey";`); + this.addSql(`alter table "user" drop column "id", drop column "profile", drop column "is_owner", drop column "is_suspended", drop column "created_at", drop column "last_used_at";`); + + this.addSql(`alter table "user" alter column "email" type varchar(254) using ("email"::varchar(254));`); + this.addSql(`alter table "user" alter column "password" type varchar(60) using ("password"::varchar(60));`); + this.addSql(`alter table "user" add constraint "user_pkey" primary key ("userid");`); + } + +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2569dbe..7fab176 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,9 +50,6 @@ importers: tsc-alias: specifier: ^1.8.16 version: 1.8.16 - tsx: - specifier: ^4.21.0 - version: 4.21.0 typescript: specifier: ^5.9.3 version: 5.9.3 @@ -75,6 +72,9 @@ importers: '@types/node': specifier: ^24.1.0 version: 24.1.0 + tsx: + specifier: ^4.21.0 + version: 4.21.0 packages/frontend: dependencies: