From 74dd87ec608a3a0790af64892c6a0749c138689b Mon Sep 17 00:00:00 2001
From: stevereis <stevereis93@gmail.com>
Date: Sat, 26 Mar 2022 16:10:56 +0100
Subject: [PATCH] fix: Typeorm issue with entity name (user) fix: Add migration
 for production DB

---
 api/.env.defaults                             |  7 ------
 api/ormconfig.ts                              | 20 ++++++++++++++++
 api/package.json                              |  5 +++-
 api/src/config/db.config.ts                   | 12 ++++++++++
 api/src/engine/models/category.model.ts       |  4 ++--
 api/src/engine/models/dataset.model.ts        |  4 ++--
 api/src/engine/models/domain.model.ts         |  4 ++--
 api/src/engine/models/entity.model.ts         |  2 +-
 api/src/engine/models/group.model.ts          |  4 ++--
 api/src/engine/models/variable.model.ts       |  4 ++--
 api/src/main.ts                               |  2 +-
 api/src/main/app.module.ts                    | 23 +++++++++++--------
 api/src/migrations/1648306965760-initSetup.ts | 15 ++++++++++++
 api/src/users/models/user.model.ts            |  4 ++--
 api/src/users/users.service.ts                |  4 ++--
 api/tsconfig.build.json                       |  2 +-
 16 files changed, 81 insertions(+), 35 deletions(-)
 create mode 100644 api/ormconfig.ts
 create mode 100644 api/src/config/db.config.ts
 create mode 100644 api/src/migrations/1648306965760-initSetup.ts

diff --git a/api/.env.defaults b/api/.env.defaults
index ec63f00..eda459d 100644
--- a/api/.env.defaults
+++ b/api/.env.defaults
@@ -14,10 +14,3 @@ AUTH_JWT_SECRET=SecretForDevPurposeOnly
 AUTH_JWT_TOKEN_EXPIRES_IN=2d
 AUTH_COOKIE_SAME_SITE=strict
 AUTH_COOKIE_SECURE=true
-
-#DB
-DB_HOST=localhost
-DB_PORT=5454
-DB_USERNAME=postgres
-DB_PASSWORD=pass123
-DB_NAME=postgres
diff --git a/api/ormconfig.ts b/api/ormconfig.ts
new file mode 100644
index 0000000..27afa05
--- /dev/null
+++ b/api/ormconfig.ts
@@ -0,0 +1,20 @@
+import { ConfigModule } from '@nestjs/config';
+import dbConfiguration from './src/config/db.config';
+
+ConfigModule.forRoot({
+  isGlobal: true,
+  envFilePath: ['.env', '.env.defaults'],
+  load: [dbConfiguration],
+});
+
+const config = {
+  ...dbConfiguration(),
+  entities: ['dist/**/*.entity.js', 'dist/**/*.model.js'],
+  migrations: ['dist/migrations/*{.ts,.js}'],
+  migrationsRun: false,
+  cli: {
+    migrationsDir: 'src/migrations',
+  },
+};
+
+export default config;
diff --git a/api/package.json b/api/package.json
index 142d29f..50b0668 100644
--- a/api/package.json
+++ b/api/package.json
@@ -20,7 +20,10 @@
     "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-config.ts",
     "test:we2e": "jest --watch --config ./test/jest.e2e-config.ts",
-    "prepare": "cd .. && husky install api/.husky"
+    "prepare": "cd .. && husky install api/.husky",
+    "typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js",
+    "typeorm:migration:generate": "npm run typeorm -- migration:generate -n",
+    "typeorm:migration:run": "npm run typeorm -- migration:run"
   },
   "dependencies": {
     "@nestjs/apollo": "^10.0.6",
diff --git a/api/src/config/db.config.ts b/api/src/config/db.config.ts
new file mode 100644
index 0000000..346dbff
--- /dev/null
+++ b/api/src/config/db.config.ts
@@ -0,0 +1,12 @@
+import { registerAs } from '@nestjs/config';
+
+export default registerAs('database', () => {
+  return {
+    type: 'postgres',
+    host: process.env.DB_HOST || 'localhost',
+    port: +process.env.DB_PORT || 5432,
+    username: process.env.DB_USERNAME || 'postgres',
+    password: process.env.DB_PASSWORD || 'pass123',
+    database: process.env.DB_NAME || 'postgres',
+  };
+});
diff --git a/api/src/engine/models/category.model.ts b/api/src/engine/models/category.model.ts
index 921ebfc..2000d8f 100644
--- a/api/src/engine/models/category.model.ts
+++ b/api/src/engine/models/category.model.ts
@@ -1,5 +1,5 @@
 import { ObjectType } from '@nestjs/graphql';
-import { Entity } from './entity.model';
+import { BaseModel } from './entity.model';
 
 @ObjectType()
-export class Category extends Entity {}
+export class Category extends BaseModel {}
diff --git a/api/src/engine/models/dataset.model.ts b/api/src/engine/models/dataset.model.ts
index a15340b..74bf78d 100644
--- a/api/src/engine/models/dataset.model.ts
+++ b/api/src/engine/models/dataset.model.ts
@@ -1,8 +1,8 @@
 import { Field, ObjectType } from '@nestjs/graphql';
-import { Entity } from './entity.model';
+import { BaseModel } from './entity.model';
 
 @ObjectType()
-export class Dataset extends Entity {
+export class Dataset extends BaseModel {
   @Field({ nullable: true, defaultValue: false })
   isLongitudinal?: boolean;
 }
diff --git a/api/src/engine/models/domain.model.ts b/api/src/engine/models/domain.model.ts
index 1cfef22..9fe8262 100644
--- a/api/src/engine/models/domain.model.ts
+++ b/api/src/engine/models/domain.model.ts
@@ -1,11 +1,11 @@
 import { Field, ObjectType } from '@nestjs/graphql';
 import { Dataset } from './dataset.model';
-import { Entity } from './entity.model';
+import { BaseModel } from './entity.model';
 import { Group } from './group.model';
 import { Variable } from './variable.model';
 
 @ObjectType()
-export class Domain extends Entity {
+export class Domain extends BaseModel {
   @Field({ nullable: true })
   description?: string;
 
diff --git a/api/src/engine/models/entity.model.ts b/api/src/engine/models/entity.model.ts
index 32183fd..7641f7b 100644
--- a/api/src/engine/models/entity.model.ts
+++ b/api/src/engine/models/entity.model.ts
@@ -2,7 +2,7 @@ import { Field, InputType, ObjectType } from '@nestjs/graphql';
 
 @InputType()
 @ObjectType()
-export class Entity {
+export class BaseModel {
   @Field()
   id: string;
 
diff --git a/api/src/engine/models/group.model.ts b/api/src/engine/models/group.model.ts
index 6a23f19..11be6a1 100644
--- a/api/src/engine/models/group.model.ts
+++ b/api/src/engine/models/group.model.ts
@@ -1,8 +1,8 @@
 import { Field, ObjectType } from '@nestjs/graphql';
-import { Entity } from './entity.model';
+import { BaseModel } from './entity.model';
 
 @ObjectType()
-export class Group extends Entity {
+export class Group extends BaseModel {
   @Field({ nullable: true })
   description?: string;
 
diff --git a/api/src/engine/models/variable.model.ts b/api/src/engine/models/variable.model.ts
index bd54afe..c48a32b 100644
--- a/api/src/engine/models/variable.model.ts
+++ b/api/src/engine/models/variable.model.ts
@@ -1,10 +1,10 @@
 import { Field, ObjectType } from '@nestjs/graphql';
 import { Category } from './category.model';
-import { Entity } from './entity.model';
+import { BaseModel } from './entity.model';
 import { Group } from './group.model';
 
 @ObjectType()
-export class Variable extends Entity {
+export class Variable extends BaseModel {
   @Field({ nullable: true })
   type?: string;
 
diff --git a/api/src/main.ts b/api/src/main.ts
index e336333..6e6fe7b 100644
--- a/api/src/main.ts
+++ b/api/src/main.ts
@@ -19,6 +19,6 @@ async function bootstrap() {
 
   app.use(cookieParser());
 
-  await app.listen(process.env.GATEWAY_PORT);
+  await app.listen(process.env.GATEWAY_PORT || 8081);
 }
 bootstrap();
diff --git a/api/src/main/app.module.ts b/api/src/main/app.module.ts
index 1555caa..56ef2df 100644
--- a/api/src/main/app.module.ts
+++ b/api/src/main/app.module.ts
@@ -1,11 +1,12 @@
 import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
 import { Module } from '@nestjs/common';
-import { ConfigModule } from '@nestjs/config';
+import { ConfigModule, ConfigService } from '@nestjs/config';
 import { GraphQLModule } from '@nestjs/graphql';
 import { TypeOrmModule } from '@nestjs/typeorm';
 import { GraphQLError } from 'graphql';
 import { join } from 'path';
 import { AuthModule } from 'src/auth/auth.module';
+import dbConfig from 'src/config/db.config';
 import { EngineModule } from 'src/engine/engine.module';
 import { FilesModule } from 'src/files/files.module';
 import { UsersModule } from 'src/users/users.module';
@@ -17,6 +18,7 @@ import { AppService } from './app.service';
     ConfigModule.forRoot({
       isGlobal: true,
       envFilePath: ['.env', '.env.defaults'],
+      load: [dbConfig],
     }),
     GraphQLModule.forRoot<ApolloDriverConfig>({
       driver: ApolloDriver,
@@ -44,15 +46,16 @@ import { AppService } from './app.service';
       type: process.env.ENGINE_TYPE,
       baseurl: process.env.ENGINE_BASE_URL,
     }),
-    TypeOrmModule.forRoot({
-      type: 'postgres', // type of our database
-      host: process.env.DB_HOST, // database host
-      port: parseInt(process.env.DB_PORT), // database host
-      username: process.env.DB_USERNAME, // username
-      password: process.env.DB_PASSWORD, // user password
-      database: process.env.DB_NAME, // name of our database,
-      autoLoadEntities: true, // models will be loaded automatically
-      synchronize: process.env.NODE_ENV !== 'production', // your entities will be synced with the database(recommended: disable in prod)
+    TypeOrmModule.forRootAsync({
+      inject: [ConfigService],
+      useFactory: (config: ConfigService) => ({
+        ...config.get('database'),
+        migrations: ['dist/migrations/*{.ts,.js}'],
+        migrationsRun: process.env.NODE_ENV !== 'dev',
+        synchronize: process.env.NODE_ENV === 'dev',
+        loggerLevel: 'debug',
+        autoLoadEntities: true,
+      }),
     }),
     AuthModule,
     UsersModule,
diff --git a/api/src/migrations/1648306965760-initSetup.ts b/api/src/migrations/1648306965760-initSetup.ts
new file mode 100644
index 0000000..ec93742
--- /dev/null
+++ b/api/src/migrations/1648306965760-initSetup.ts
@@ -0,0 +1,15 @@
+import { MigrationInterface, QueryRunner } from 'typeorm';
+
+export class initSetup1648306965760 implements MigrationInterface {
+  name = 'initSetup1648306965760';
+
+  public async up(queryRunner: QueryRunner): Promise<void> {
+    await queryRunner.query(
+      `CREATE TABLE "user" ("id" character varying NOT NULL, "agreeNDA" boolean DEFAULT false, CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`,
+    );
+  }
+
+  public async down(queryRunner: QueryRunner): Promise<void> {
+    await queryRunner.query(`DROP TABLE "user"`);
+  }
+}
diff --git a/api/src/users/models/user.model.ts b/api/src/users/models/user.model.ts
index fc63052..980d7c1 100644
--- a/api/src/users/models/user.model.ts
+++ b/api/src/users/models/user.model.ts
@@ -1,7 +1,7 @@
 import { Field, ObjectType } from '@nestjs/graphql';
 import { Entity, PrimaryColumn, Column } from 'typeorm';
 
-@Entity()
+@Entity({ name: 'user' })
 @ObjectType()
 export class User {
   @PrimaryColumn()
@@ -17,7 +17,7 @@ export class User {
   @Field({ nullable: true })
   email?: string;
 
-  @Column()
+  @Column({ nullable: true, default: false })
   @Field({ nullable: true })
   agreeNDA?: boolean;
 
diff --git a/api/src/users/users.service.ts b/api/src/users/users.service.ts
index 273abf6..d74ca14 100644
--- a/api/src/users/users.service.ts
+++ b/api/src/users/users.service.ts
@@ -33,11 +33,11 @@ export class UsersService {
    * @returns The updated user.
    */
   async update(id: string, data: UpdateUserInput): Promise<InternalUser> {
-    const test = {
+    const updateData = {
       id,
       ...data,
     };
 
-    return await this.userRepository.save(test);
+    return await this.userRepository.save(updateData);
   }
 }
diff --git a/api/tsconfig.build.json b/api/tsconfig.build.json
index 64f86c6..8580c55 100644
--- a/api/tsconfig.build.json
+++ b/api/tsconfig.build.json
@@ -1,4 +1,4 @@
 {
   "extends": "./tsconfig.json",
-  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
+  "exclude": ["node_modules", "test", "dist", "**/*spec.ts", "ormconfig.ts"]
 }
-- 
GitLab