From 2e384b305c4c44899d82b4c11aabfc5ff7ac2167 Mon Sep 17 00:00:00 2001 From: matevszm Date: Tue, 26 Nov 2024 14:11:22 +0100 Subject: [PATCH] feat: Migrations to database --- migrations/1732626002233-initial_migration.ts | 50 +++++++++++++++++++ package.json | 6 ++- pnpm-lock.yaml | 19 ++++--- src/app.module.ts | 13 +---- src/config/typeorm.ts | 20 ++++++++ 5 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 migrations/1732626002233-initial_migration.ts create mode 100644 src/config/typeorm.ts diff --git a/migrations/1732626002233-initial_migration.ts b/migrations/1732626002233-initial_migration.ts new file mode 100644 index 0000000..0d9122b --- /dev/null +++ b/migrations/1732626002233-initial_migration.ts @@ -0,0 +1,50 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class InitialMigration1732626002233 implements MigrationInterface { + name = 'InitialMigration1732626002233' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "canvas_tag" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, "color" character varying(7), "description" character varying(1024), CONSTRAINT "UQ_dae20ed57768d3f73e575482252" UNIQUE ("name"), CONSTRAINT "UQ_dae20ed57768d3f73e575482252" UNIQUE ("name"), CONSTRAINT "PK_429116562ec9ac8dee9c869a8bd" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE TABLE "user_role" ("name" character varying NOT NULL, CONSTRAINT "UQ_31f96f2013b7ac833d7682bf021" UNIQUE ("name"), CONSTRAINT "PK_31f96f2013b7ac833d7682bf021" PRIMARY KEY ("name"))`); + await queryRunner.query(`CREATE TABLE "user" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "email" character varying NOT NULL, "displayName" character varying NOT NULL, "isEnabled" boolean NOT NULL DEFAULT true, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE TABLE "canvas_access" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "isOwner" boolean NOT NULL DEFAULT false, "canvasId" uuid NOT NULL, "userId" uuid NOT NULL, CONSTRAINT "PK_2f4498894baaca69c38a094fc68" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE TABLE "canvas" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, "description" text, "dateCreated" TIMESTAMP NOT NULL DEFAULT now(), "dateUpdated" TIMESTAMP NOT NULL DEFAULT now(), "deleted" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_0f87c183b39aec0e115707e10a0" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE TABLE "canvas_state" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "appState" jsonb NOT NULL DEFAULT '{}', "elements" jsonb NOT NULL DEFAULT '{}', "files" jsonb NOT NULL DEFAULT '{}', "dateCreated" TIMESTAMP NOT NULL DEFAULT now(), "canvasId" uuid NOT NULL, CONSTRAINT "PK_73e242d65e271e2e506aaa67feb" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE TABLE "user_roles" ("userId" uuid NOT NULL, "userRoleName" character varying NOT NULL, CONSTRAINT "PK_5b9b5cd6122add049b8bebe9a1d" PRIMARY KEY ("userId", "userRoleName"))`); + await queryRunner.query(`CREATE INDEX "IDX_472b25323af01488f1f66a06b6" ON "user_roles" ("userId") `); + await queryRunner.query(`CREATE INDEX "IDX_97bd8819dde9c827121ac3ade5" ON "user_roles" ("userRoleName") `); + await queryRunner.query(`CREATE TABLE "canvas_tags" ("canvasId" uuid NOT NULL, "canvasTagId" uuid NOT NULL, CONSTRAINT "PK_3397911823bcd30b3f7af6aa0a1" PRIMARY KEY ("canvasId", "canvasTagId"))`); + await queryRunner.query(`CREATE INDEX "IDX_bf9024c43eff5ab42b282d78d0" ON "canvas_tags" ("canvasId") `); + await queryRunner.query(`CREATE INDEX "IDX_84f0f78a44dcafdbd4fa4eb380" ON "canvas_tags" ("canvasTagId") `); + await queryRunner.query(`ALTER TABLE "canvas_access" ADD CONSTRAINT "FK_a493b634508ee1173e9507c6b2e" FOREIGN KEY ("canvasId") REFERENCES "canvas"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "canvas_access" ADD CONSTRAINT "FK_7c38522a5a09624a8321c2dbe08" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "canvas_state" ADD CONSTRAINT "FK_c8eee0b14b62b162f2f5aec8f40" FOREIGN KEY ("canvasId") REFERENCES "canvas"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "user_roles" ADD CONSTRAINT "FK_472b25323af01488f1f66a06b67" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE`); + await queryRunner.query(`ALTER TABLE "user_roles" ADD CONSTRAINT "FK_97bd8819dde9c827121ac3ade55" FOREIGN KEY ("userRoleName") REFERENCES "user_role"("name") ON DELETE CASCADE ON UPDATE CASCADE`); + await queryRunner.query(`ALTER TABLE "canvas_tags" ADD CONSTRAINT "FK_bf9024c43eff5ab42b282d78d09" FOREIGN KEY ("canvasId") REFERENCES "canvas"("id") ON DELETE CASCADE ON UPDATE CASCADE`); + await queryRunner.query(`ALTER TABLE "canvas_tags" ADD CONSTRAINT "FK_84f0f78a44dcafdbd4fa4eb3802" FOREIGN KEY ("canvasTagId") REFERENCES "canvas_tag"("id") ON DELETE CASCADE ON UPDATE CASCADE`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "canvas_tags" DROP CONSTRAINT "FK_84f0f78a44dcafdbd4fa4eb3802"`); + await queryRunner.query(`ALTER TABLE "canvas_tags" DROP CONSTRAINT "FK_bf9024c43eff5ab42b282d78d09"`); + await queryRunner.query(`ALTER TABLE "user_roles" DROP CONSTRAINT "FK_97bd8819dde9c827121ac3ade55"`); + await queryRunner.query(`ALTER TABLE "user_roles" DROP CONSTRAINT "FK_472b25323af01488f1f66a06b67"`); + await queryRunner.query(`ALTER TABLE "canvas_state" DROP CONSTRAINT "FK_c8eee0b14b62b162f2f5aec8f40"`); + await queryRunner.query(`ALTER TABLE "canvas_access" DROP CONSTRAINT "FK_7c38522a5a09624a8321c2dbe08"`); + await queryRunner.query(`ALTER TABLE "canvas_access" DROP CONSTRAINT "FK_a493b634508ee1173e9507c6b2e"`); + await queryRunner.query(`DROP INDEX "public"."IDX_84f0f78a44dcafdbd4fa4eb380"`); + await queryRunner.query(`DROP INDEX "public"."IDX_bf9024c43eff5ab42b282d78d0"`); + await queryRunner.query(`DROP TABLE "canvas_tags"`); + await queryRunner.query(`DROP INDEX "public"."IDX_97bd8819dde9c827121ac3ade5"`); + await queryRunner.query(`DROP INDEX "public"."IDX_472b25323af01488f1f66a06b6"`); + await queryRunner.query(`DROP TABLE "user_roles"`); + await queryRunner.query(`DROP TABLE "canvas_state"`); + await queryRunner.query(`DROP TABLE "canvas"`); + await queryRunner.query(`DROP TABLE "canvas_access"`); + await queryRunner.query(`DROP TABLE "user"`); + await queryRunner.query(`DROP TABLE "user_role"`); + await queryRunner.query(`DROP TABLE "canvas_tag"`); + } + +} diff --git a/package.json b/package.json index 88ae090..0c59d3b 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,10 @@ "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "jest --config ./test/jest-e2e.json" + "test:e2e": "jest --config ./test/jest-e2e.json", + "migration:run": "ts-node ./node_modules/typeorm/cli.js migration:run -d ./src/config/typeorm.ts", + "migration:generate": "ts-node ./node_modules/typeorm/cli.js migration:generate -d ./src/config/typeorm.ts", + "migration:revert": "ts-node ./node_modules/typeorm/cli.js migration:revert -d ./src/config/typeorm.ts" }, "dependencies": { "@algoan/nestjs-logging-interceptor": "^2.6.0", @@ -34,6 +37,7 @@ "@types/uuid": "^9.0.8", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", + "dotenv": "^16.4.5", "express": "^4.19.2", "express-session": "^1.18.0", "passport": "^0.7.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1d7dc3d..6a51443 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@algoan/nestjs-logging-interceptor': specifier: ^2.6.0 - version: 2.6.0(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1))(express@4.19.2)(rxjs@7.8.1) + version: 2.6.0(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)(express@4.19.2)(rxjs@7.8.1) '@nestjs/common': specifier: ^10.3.7 version: 10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -28,10 +28,10 @@ importers: version: 10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8) '@nestjs/swagger': specifier: ^7.3.1 - version: 7.3.1(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2) + version: 7.3.1(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2) '@nestjs/typeorm': specifier: ^10.0.2 - version: 10.0.2(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(pg@8.11.5)(ts-node@10.9.2(@types/node@20.12.11)(typescript@5.4.5))) + version: 10.0.2(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(pg@8.11.5)(ts-node@10.9.2(@types/node@20.12.11)(typescript@5.4.5))) '@types/passport': specifier: ^1.0.16 version: 1.0.16 @@ -50,6 +50,9 @@ importers: class-validator: specifier: ^0.14.1 version: 0.14.1 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 express: specifier: ^4.19.2 version: 4.19.2 @@ -92,7 +95,7 @@ importers: version: 10.1.1(chokidar@3.6.0)(typescript@5.4.5) '@nestjs/testing': specifier: ^10.0.0 - version: 10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)) + version: 10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)(@nestjs/platform-express@10.3.8) '@types/express': specifier: ^4.17.17 version: 4.17.21 @@ -3225,7 +3228,7 @@ packages: snapshots: - '@algoan/nestjs-logging-interceptor@2.6.0(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1))(express@4.19.2)(rxjs@7.8.1)': + '@algoan/nestjs-logging-interceptor@2.6.0(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)(express@4.19.2)(rxjs@7.8.1)': dependencies: '@nestjs/common': 10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -3840,7 +3843,7 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/swagger@7.3.1(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)': + '@nestjs/swagger@7.3.1(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)': dependencies: '@microsoft/tsdoc': 0.14.2 '@nestjs/common': 10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -3855,7 +3858,7 @@ snapshots: class-transformer: 0.5.1 class-validator: 0.14.1 - '@nestjs/testing@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8))': + '@nestjs/testing@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)(@nestjs/platform-express@10.3.8)': dependencies: '@nestjs/common': 10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -3863,7 +3866,7 @@ snapshots: optionalDependencies: '@nestjs/platform-express': 10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8) - '@nestjs/typeorm@10.0.2(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(pg@8.11.5)(ts-node@10.9.2(@types/node@20.12.11)(typescript@5.4.5)))': + '@nestjs/typeorm@10.0.2(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(pg@8.11.5)(ts-node@10.9.2(@types/node@20.12.11)(typescript@5.4.5)))': dependencies: '@nestjs/common': 10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1) diff --git a/src/app.module.ts b/src/app.module.ts index 4481990..cebf11b 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -5,20 +5,11 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { AuthModule } from './auth/auth.module'; import { UserModule } from './user/user.module'; import { CanvasModule } from './canvas/canvas.module'; +import { config } from './config/typeorm'; @Module({ imports: [ - TypeOrmModule.forRoot({ - type: 'postgres', - port: parseInt(process.env.DATABASE_PORT, 10) || 5432, - host: process.env.DATABASE_HOST || 'localhost', - username: process.env.DATABASE_USERNAME || 'excali_studio', - password: process.env.DATABASE_PASSWORD || 'excali_studio', - database: process.env.DATABASE_NAME || 'excali_studio', - autoLoadEntities: true, - logging: 'all', - synchronize: true, - }), + TypeOrmModule.forRoot(config), AuthModule, UserModule, CanvasModule, diff --git a/src/config/typeorm.ts b/src/config/typeorm.ts new file mode 100644 index 0000000..a295944 --- /dev/null +++ b/src/config/typeorm.ts @@ -0,0 +1,20 @@ +import { DataSource, DataSourceOptions } from 'typeorm'; +import { config as dotenvConfig } from 'dotenv'; + +dotenvConfig({ path: '.env' }); + +export const config: DataSourceOptions = { + type: 'postgres', + port: parseInt(process.env.DATABASE_PORT, 10) || 5432, + host: process.env.DATABASE_HOST || 'localhost', + username: process.env.DATABASE_USERNAME || 'excali_studio', + password: process.env.DATABASE_PASSWORD || 'excali_studio', + database: process.env.DATABASE_NAME || 'excali_studio', + entities: ['dist/**/*.entity{.ts,.js}'], + migrations: ['dist/migrations/*{.ts,.js}'], + logging: 'all', + synchronize: false, + migrationsRun: true, +}; + +export const dataSource = new DataSource(config);