DEV Community

Discussion on: Nx NestJs - Typeorm database connection with environment variables

Collapse
 
ipreda profile image
Iulian Preda

Personally I wouldn't run anything from docker, it's not exacyly it's purpose.
Most probably you would do better with a custom script and config for production env.
In that way you can run local migrations without deploying the code to the docker image, and you just need the connection string and the migrations.

Collapse
 
artifex profile image
Artifex

Doing migrations has changed since type orm 0.3 old cli into typeormoptions are not there anymore. am i right?

Thread Thread
 
ipreda profile image
Iulian Preda

From what I read on their website you just need to create a class for migrations and use it in a cli command. Technically you can inject/create the options object in the same way and reuse it in that class.

Unfortunately I can't provide yet some boilerplate for that. In my current project I switched rather early on from Typeorm to MikroOrm, but in this aspect they seem rather similar so this approach should work.

The only noticeable difference is that for MikroOrm I managed to find a third party executable that is able to run for a specific project, for this you might need to either have a global config or a custom script to run from a different path.

Thread Thread
 
artifex profile image
Artifex

Looking forward into your posts about migration, i'm still trying to grasp the concepts of monorepo and all that jazz witnin this series of posts worked well for me, I also tried your approach into mirkoorm and it worked, still my concerns are on migrations, what third party tool did you use?

Thread Thread
 
ipreda profile image
Iulian Preda

I used @alexy4744/nx-mikro-orm-cli

I can actually provide some snippets for this., they might be useful for after you use the instructions from the package's page.

./mikro-orm.base.ts - at the root of the nx project I have a config that can be propagated for any number of projects

import { LoadStrategy, MikroORMOptions } from '@mikro-orm/core';
import { TSMigrationGenerator } from '@mikro-orm/migrations';
import { PostgreSqlDriver } from '@mikro-orm/postgresql';
import { SqlHighlighter } from '@mikro-orm/sql-highlighter';

export function mikroOrmConfigBase(path = __dirname): Partial<MikroORMOptions<PostgreSqlDriver>> {
  const undocumentedConfig: any = {
    ignoreSchema: ['columnar'], // schema generated by and for citus
  };
  return {
    entities: [path + '/src/**/*.entity{.ts,.js}'],
    entitiesTs: [path + '/src/**/*.entity.ts'],
    type: 'postgresql',
    persistOnCreate: false, // we have to manually call persistAndFlush


    allowGlobalContext: true,
    forceUtcTimezone: true,
    strict: true, // disable automatic type casting
    loadStrategy: LoadStrategy.JOINED,
    highlighter: new SqlHighlighter(), // default values:
    schemaGenerator: {
      disableForeignKeys: true, // wrap statements with `set foreign_key_checks = 0` or equivalent
      createForeignKeyConstraints: true, // whether to generate FK constraints
      ...undocumentedConfig,
    },

    migrations: {
      tableName: 'mikro_orm_migrations', // name of database table with log of executed transactions
      path: path + '/src/**/data-access/migrations', // path to the folder with migrations
      pathTs: path + '/src/**/data-access/migrations', // path to the folder with TS migrations (if used, we should put path to compiled files in `path`)
      glob: '!(*.d).{js,ts}', // how to match migration files (all .js and .ts files, but not .d.ts)
      transactional: true, // wrap each migration in a transaction
      disableForeignKeys: true, // wrap statements with `set foreign_key_checks = 0` or equivalent
      allOrNothing: true, // wrap all migrations in master transaction
      dropTables: true, // allow to disable table dropping
      safe: true, // allow to disable table and column dropping
      snapshot: true, // save snapshot when creating new migrations
      emit: 'ts', // migration generation mode
      generator: TSMigrationGenerator, // migration generator, e.g. to allow custom formatting
    },

    seeder: {
      path: path + '/src/**/data-access/seeder', // path to the folder with seeders
      pathTs: path + '/src/**/data-access/seeder', // path to the folder with TS seeders (if used, we should put path to compiled files in `path`)
      defaultSeeder: 'DatabaseSeeder', // default seeder class name
      glob: '!(*.d).{js,ts}', // how to match seeder files (all .js and .ts files, but not .d.ts)
      emit: 'ts', // seeder generation mode
      fileName: (className: string) => className, // seeder file naming convention
    },
  };
}
Enter fullscreen mode Exit fullscreen mode

Please change any paths that might be different for your project.

Then in my backend project I have

/apps/backend/project.json -> under the "target" options

  "mikro-orm": {
      "executor": "@alexy4744/nx-mikro-orm-cli:run",
      "options": {
        "config": {
          "configPaths": ["./mikro-orm.config.ts"],
          "tsConfigPath": "./tsconfig.json",
          "useTsNode": true
        }
      }
    },
    "schema-create": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx mikro-orm backend --args=\"schema:create --run\""
      }
    },
    "schema-fresh": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx mikro-orm backend --args=\"schema:fresh --run --seed\""
      }
    },
    "schema-update": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx mikro-orm backend --args=\"schema:update --safe --run\""
      }
    },
    "schema-drop": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx mikro-orm backend --args=\"schema:drop --run\""
      }
    },
    "migration-initial": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx mikro-orm backend --args=\"migration:create --initial\""
      }
    },
    "migration-create": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx mikro-orm backend --args=\"migration:create\""
      }
    },
    "migration-fresh": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx mikro-orm backend --args=\"migration:fresh --seed\""
      }
    },
    "seed": {
      "executor": "nx:run-commands",
      "options": {
        "command": "nx mikro-orm backend --args=\"seeder:run\""
      }
    }
Enter fullscreen mode Exit fullscreen mode

/apps/backend/mikro-orm.ts

import { mikroOrmConfigBase } from 'mikro-orm.config.base';

import { getEnvConfig } from './src/environments/env-config';
import { env } from './src/environments/environment';

const db = getEnvConfig(env).database;

const config = {
  ...mikroOrmConfigBase(__dirname),
  host: db.host,
  port: db.port,
  dbName: db.database,
  user: db.username,
  password: db.password,
};
export default Promise.resolve(config);
Enter fullscreen mode Exit fullscreen mode

As you can see I just reused the functions from the previous articles to get the env variables from the env file or from the environment.

Also in the data acces folder which for me hosts the entities i have a DatabaseSeeder.ts file that gets the repositories and populates the data.

I cannot post that one as it is 100% custom made for my project's needs and it wouldn't be useful at all, but I can post a small snippet

export class DatabaseSeeder extends Seeder {
  async run(em: EntityManager): Promise<void> {
    const repo = em.getRepository(Entity);
    const entity = repo.create(//customEntityData);


    em.persistAndFlush(entity);
  }
}

Enter fullscreen mode Exit fullscreen mode

I hope this helps!

Thread Thread
 
artifex profile image
Artifex

There must be something wrong with webpack i tried your approach it wont detect entities on runtime thats just sad, i just made another class to do my migrations i use this approach on runtime i use your previous service inject approach, but i manually override entity locations. Thank you!

Thread Thread
 
ipreda profile image
Iulian Preda

Yes. Webpack packs everything together in a single bundle and i suppose the paths are ruined in that case.
For that Nest has the "autoLoadEntories" option vut you need to import every entity in the ORM's module for it to work.