typeorm: Typeorm CLI not works perfectly after 0.3.0

Issue Description

After version 0.3.0 cli does not work perfectly. when I try to create an entity or migration using cli is create entity or migration in the root directory. However, in the old version, it works perfectly. It shows this error with the new version 0.3.0

$ npm run typeorm -- entity:create -n user

> nest-typeorm@0.0.1 typeorm D:\Learning\nodejs\nest-tuotrial\nest-typeorm
> ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config src/ormconfig.ts "entity:create" "-n" "user"

bin.js entity:create <path>

Generates a new entity.

Options:
  -h, --help     Show help                                             [boolean]
  -v, --version  Show version number                                   [boolean]

Not enough non-option arguments: got 0, need at least 1
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! nest-typeorm@0.0.1 typeorm: `ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config src/ormconfig.ts "entity:create" "-n" "user"`      
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the nest-typeorm@0.0.1 typeorm script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\hamja\AppData\Roaming\npm-cache\_logs\2022-03-27T06_06_50_058Z-debug.log

Expected Behavior

while when I use 0.2.17 version. it works with same command.

$ npm run typeorm -- entity:create -n user

> nest-typeorm@0.0.1 typeorm D:\Learning\nodejs\nest-tuotrial\nest-typeorm
> ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config src/ormconfig.ts "entity:create" "-n" "user"

Entity D:\Learning\nodejs\nest-tuotrial\nest-typeorm/src/entities/user.ts has been created successfully.

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 14
  • Comments: 42 (5 by maintainers)

Most upvoted comments

Okay… so it took me SOME HOURS but it’s finally working right now. My scripts in package.json are like that:

...
"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js",
"migration:generate": "./node_modules/.bin/ts-node ./node_modules/.bin/typeorm migration:generate -d ormconfig.ts ./src/api/Environment/database/migrations/$npm_config_name",
"migration:up": "./node_modules/.bin/ts-node ./node_modules/.bin/typeorm migration:run -d ormconfig.ts",
"migration:down": "./node_modules/.bin/ts-node ./node_modules/.bin/typeorm migration:revert -d ormconfig.ts"
...

My ormconfig.ts (attention to the .ts) looks like that:

import { DataSource, DataSourceOptions } from 'typeorm';

export const connectionSource = new DataSource({
  migrationsTableName: 'migrations',
  type: 'mysql',
  host: 'localhost',
  port: 3306,
  username: '-------',
  password: '-------',
  database: '------',
  logging: true,
  synchronize: false,
  entities: ['src/api/3 - Domain/entities/*.entity.ts'],
  migrations: ['src/api/Environment/database/migrations/*.ts'],
} as DataSourceOptions);

And I’m running the command to generate migrations like the following:

ᛟ npm run migration:generate --name="teste"

Now, some things I struggled and I would like to share with you guys. First of all, it seems like the support for ormconfig.js or ormconfig.json is no longer working as it were. I’m not completely sure on that, but I gave a few shots and none of them worked. But, what seems to be working properly and what seems to be the new standard is the usage of TypeORM DataSource to configure the connection. As it already was, the migrations property in the configurations of TypeORM (being set here through the ormconfig.ts) state the folder where the CLI will read the migrations, but not the folder where it will store them once generated. I tried setting the property cli.migrationsDir but it was being ignored. I even saw some threads stating this particular issue. It seems that, when generating a new migration, we need to pass not only its name but also its path. That’s why I’ve set in my migration:generate script in package.json a template-like solution. I’m leaving hardcoded the path and just using the parameter name passed when running the script.

I’m honestly disappointed by TypeORM documentation with those changes and with the overall support to community. I hope to see some improvements soon.

Syntax has changed. You need to execute command in a following manner `typeorm entity:create path/to/entity". CLI gives you a hint about it:

bin.js entity:create <path>

We didn’t update the documentation yet. Feel free to contribute.

The documentation is a joke. I wish I tried different orm

Guys, for real now. Documentation should be taken seriously. I think this is the third or fourth time i’m struggling with TypeORM Cli. The documentations should be updated ASAP and provide more examples

This issue should have more visibility, it could save hours!!

I found some information here https://github.com/typeorm/typeorm/releases/tag/0.3.0 My version 0.3.5

DEPRECATIONS entities, migrations, subscribers options inside DataSourceOptions accepting string directories support is deprecated. You’ll be only able to pass entity references in the future versions.

Like this:

// ormconfig.ts
const connectionSource = new DataSource({
  ...
  entities: [ExamplesEntity],
  migrations: [ExamleMigration1656076568327],
  ...
})
export default connectionSource;

Scripts:

{
  "scripts": {
          "typeorm": "typeorm-ts-node-esm -d ./src/db/ormconfig.ts",
          "migration:create": "typeorm-ts-node-esm migration:create ./src/db/migrations/$npm_config_name",
          "migration:generate": "npm run typeorm migration:generate ./src/db/migrations/$npm_config_name",
          "migration:show": "npm run typeorm migration:show",
          "migration:run": "npm run typeorm migration:run",
          "migration:revert": "npm run typeorm migration:revert"
   }
}

Usage:

npm run migration:generate --name=example_migration
npm run migration:create --name=example_migration
npm run migration:run

It works.

it there any way to create entity in specific folder without giving full path.

no, you need to provide full path now.

I had the same issue with migrations, and was only able to resolve it thanks to you guys.

Old:

// Generate
ts-node ./node_modules/typeorm/cli migration:generate --config build/src/configurations/ormconfig --name update

// Run
typeorm migration:run --config build/src/configurations/ormconfig

New:

// Generate
ts-node ./node_modules/typeorm/cli migration:generate ./src/orm/migration/update -d ./src/orm/datasource.ts

// Run (I had to switch to ts-node since it now runs migrations from .ts instead of .js)
ts-node ./node_modules/typeorm/cli migration:run -d ./src/orm/datasource.ts

// Revert
ts-node ./node_modules/typeorm/cli migration:revert -d ./src/orm/datasource.ts

Hey guys…faced the same issue and hated it very much since now anyone can specify a random path. I fixed this like detailed below: "typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js",

"migration:create": "npm run typeorm migration:create ./migrations/$npm_config_name",

Usage: npm run migration:create --name=test

This will generate the migration under the migrations folder

‘cli’ does not exist in type ‘PostgresConnectionOptions’

You guys, can use this. https://github.com/misostack/nestjs/blob/master/src/config/environment.ts

import 'dotenv/config';
import { DataSource, DataSourceOptions } from 'typeorm';
export const DATABASE_CONFIG = {
  MAIN_DB_TYPE: 'mysql',
  MAIN_DB_URL: process.env.MYSQL_DB_URL || 'nestjs',
  MAIN_DB_CHARSET: 'utf8mb4_unicode_ci',
  MAIN_DB_TABLE_PREFIX: 'nestjs',
};
export class Environment {
  static getMainDatabaseConfiguration(dirname): any {
    return {
      type: DATABASE_CONFIG.MAIN_DB_TYPE,
      url: DATABASE_CONFIG.MAIN_DB_URL,
      entities: [dirname + '/**/entities/*.entity{.js,.ts}'],
      // MYSQL will store Timestamp in GMT ( UTC = 0)
      timezone: 'Z', // must have this, if the response date will be marked as current timezone
      charset: DATABASE_CONFIG.MAIN_DB_CHARSET,
      // must not be synchronize automaticall, use data migration instea
      synchronize: false,
      // migrations
      migrations: [dirname + '/database/migrations/*.ts'],
      // cli
      cli: {
        migrationsDir: dirname + '/database/migrations',
      },
    };
  }
  static getMainDatasourceConfiguration(dirname): any {
    return new DataSource({
      ...Environment.getMainDatabaseConfiguration(dirname),
    } as DataSourceOptions);
  }
}

./src/database/datasource.ts

import { Environment } from '../config/environment';

export default Environment.getMainDatasourceConfiguration('./src');
    "typeorm2": "node --require tsconfig-paths/register -r ts-node/register ./node_modules/typeorm/cli.js --config ./src/database/ormconfig.ts",
    "typeorm": "node --require tsconfig-paths/register -r ts-node/register ./node_modules/typeorm/cli.js -d ./src/database/datasource.ts"

@IlayMorozoff I managed to get it working on windows using the following

"migration:create": "typeorm-ts-node-esm migration:create ./src/database/migrations/%npm_config_name%", "migration:generate": "npm run typeorm migration:generate ./src/database/migrations/%npm_config_name%",

Syntax has changed. You need to execute command in a following manner `typeorm entity:create path/to/entity". CLI gives you a hint about it:

bin.js entity:create <path>

We didn’t update the documentation yet. Feel free to contribute.

$ typeorm entity:create --help typeorm entity:create <path> Generates a new entity.

I just started using TypeORM this week. Although it’s free work and we should be grateful for it, it’s so confusing to read documentation that doesn’t work at all! You can pin a version to your documentation so new users will at least have a clue.

I found some information here https://github.com/typeorm/typeorm/releases/tag/0.3.0 My version 0.3.5 DEPRECATIONS entities, migrations, subscribers options inside DataSourceOptions accepting string directories support is deprecated. You’ll be only able to pass entity references in the future versions. Like this:

// ormconfig.ts
const connectionSource = new DataSource({
  ...
  entities: [ExamplesEntity],
  migrations: [ExamleMigration1656076568327],
  ...
})
export default connectionSource;

So maybe I’m getting it wrongs, but its looks like it means we will have to add new entities and migrations to the DataSource manually everytime we create ones? Seems like a regression to me but maybe I’m not fully understanding the vision.

We definitely need some clarity on why glob support is being removed. It is extremely useful and prevents a ton of extra development busy work. I am NOT looking forward to maintaining those arrays manually, especially when migrations are typically generated for us using the CLI.

Documentation is not updated yet … cli does not exist in DataSourceOptions?? path for migration??

I ended up rolling my own solutions to this ever since migrating to 0.3+. I’ll try to share it as best I can with this chat in hopes to help others who don’t want to maintain those arrays manually while also being able to generate migrations with the CLI…

The Issue

My understanding with the new change is that we are not able to pass in a glob path anymore into the DataSource() initialization. This requires us to manually maintain both the entities array as well as the migrations array in the config file, which I felt was a huge regression in terms of developer experience, since we now have to generate files using the CLI, and then manually remember to update that config file with new entries anytime we want to generate a migration.

Instead, I tried to incorporate a script into my CLI workflow that handles this for me.

My Solution

What I decided to do is “intercept” the CLI migrate:generate command with my own custom command that I wrote into a migrate.ts file and keep in the src/ directory of my project. In this way, I can change my package.json commands to call that custom command in place of the vanilla typeorm migration generation command. I know this sounds brittle, but I think this is actually a pretty stable solution, as it doesn’t require you to make any changes to the typeorm source. Also, just a note, I am using dotenv to pass in my configuration, but this solution should work without it. Here is a quick screenshot of my directory structure for clarity (I cropped out my other src folders): image

1. Add a migrate.ts file

Here is the migrate.ts script you will need to put in your /src directory.You should not need to modify this unless you are using a non-default (/src/migration) migration directory

View File

migrate.ts

import { exec } from 'child_process';
import * as yargs from 'yargs';
import path from 'path';

const commandDescription =
'Picks up configs from configuration.ts and uses typeorm to generate migrations';

const argv = yargs
.usage('Usage: $0 <command> [options]')
.command('migrate', commandDescription)
.example(
  '$0 migrate -n MigrationName -c ./dist/configuration.js',
  commandDescription,
)
.alias('n', 'name')
.nargs('n', 1)
.describe('n', 'Load a file')
.alias('c', 'configuration')
.alias('c', 'config')
.nargs('c', 1)
.describe('c', 'Location of dotenv configuration file')
.help('h')
.alias('h', 'help').argv;

let migrationDirectory = path.relative(process.cwd(), 'src/migration/');

// Read the dotenv configuration file if that option was passed in
if (argv.config) {
const configPath = path.resolve(process.cwd(), argv.config as string);
// eslint-disable-next-line @typescript-eslint/no-var-requires
const config = require(configPath);
migrationDirectory = config.default().migrationsSourceDir[0];
}
const migrationPath = path.join(
migrationDirectory,
(argv.name as string) || 'GenericMigration',
);
exec(
`npm run typeorm migration:generate ${migrationPath}`,
(error, stdout, stderr) => {
  if (error) {
    console.log(`error: ${error.message}`);
    return;
  }
  if (stderr) {
    console.log(`stderr: ${stderr}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
},
);

2. Modify your package.json

Now that we have our script, we want to us this in our package.json file any time we use the typeorm CLI commands. This is how your typeorm commands should look like. Notice how the migrate:generate command now routes through the migrate.ts file:

package.json

"scripts": {
    "typeorm": "node --loader ts-node/esm ./node_modules/typeorm/cli.js -d ./src/database.providers.ts",
    "migrate:up": "npm run build && npm run typeorm migration:run -- --transaction each",
    "migrate:down": "npm run build && npm run typeorm migration:revert -- --transaction each",
    "migrate:generate": "npm run build && ts-node ./src/migrate.ts --config=dist/configuration.js"
  },

3. Modify your configuration.ts file

Last step is to add some fields to our configuration.ts file so the migrate.ts script knows where to find your entities and migration folder. Here is what mine looks like. You’ll notice I have the migration, subscriber, and entity folder duplicated in this config. Because I am using typescipt, my ACTUAL files would end up in the /dist folder, but the files I used to generate migrations were my original *.ts source files. If anyone can think of a better way to do this let me know, but since I do not plan on ever changing those directories from the default, I felt it wasn’t that big of a deal to have both entries in the config file. I don’t see me ever having to modify those in the future.

View File

configuration.ts

import * as dotenv from 'dotenv';

dotenv.config();
export default () => ({
port: parseInt(process.env.PORT, 10) || 1337,
database: {
  url: process.env.DATABASE_URL,
  type: process.env.DATABASE_TYPE,
  database: process.env.DATABASE_NAME,
  host: process.env.DATABASE_HOST,
  port: parseInt(process.env.DATABASE_PORT, 10) || 5432,
  username: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
  entities: ['dist/entity/*.js'],
  migrations: ['dist/migration/*.js'],
  subscribers: ['dist/subscriber/*.js'],
},
allowableOrigins: process.env.ALLOWABLE_ORIGINS,
jwt: {
  secret: process.env.JWT_SECRET,
  expiresIn: process.env.JWT_EXPIRY,
},
entitiesSourceDir: ['src/entity'],
migrationsSourceDir: ['src/migration'],
subscribersSourceDir: ['src/subscriber'],
});

4. Use the CLI

Now whenever you want to generate migrations, you can simply use the npm script like you always would have done anyway, but the migrate.ts file handles filling in the entities for you. Here is how you would generate a migration:

$ npm run migrate:generate -- -n YourMigrationsName

You can still use all the other migrations commands as you normally would as well!

$ npm run migrate:up
$ npm run migrate:down

I know this was a long winded explanation, but let me know if anyone has any questions. I am happy to help. Hopefully we can either get some answers as to why glob support was removed, or better, we can get the feature back. I was pretty discouraged from using 0.3 after reading that change in the changelog. If you are inspired by my solution, and have come up with something better, let me know as well!

NOTICE: typeorm-ts-node-esm and typeorm-ts-node-commonjs cannot register tsconfig-paths/register. so nestjs project may not work.

still using node -r tsconfig-paths/register -r ts-node/register ./node_modules/typeorm/cli.js

I found some information here https://github.com/typeorm/typeorm/releases/tag/0.3.0 My version 0.3.5

DEPRECATIONS entities, migrations, subscribers options inside DataSourceOptions accepting string directories support is deprecated. You’ll be only able to pass entity references in the future versions.

Like this:

// ormconfig.ts
const connectionSource = new DataSource({
  ...
  entities: [ExamplesEntity],
  migrations: [ExamleMigration1656076568327],
  ...
})
export default connectionSource;

So maybe I’m getting it wrongs, but its looks like it means we will have to add new entities and migrations to the DataSource manually everytime we create ones?
Seems like a regression to me but maybe I’m not fully understanding the vision.

The thing that is destroying my mind is that I cannot understand the reason to provide the full path when trying to create/generate a migration.

Why cannot something like:

ts-node ./node_modules/typeorm/cli migration:generate --path src/orm/migrations -d ./src/orm/datasource.ts <migrationName>

instead of the current:

ts-node ./node_modules/typeorm/cli migration:generate src/orm/migrations/<migrationName> -d ./src/orm/datasource.ts <migrationName>

With maybe process.cwd() as default value if path is not provided.

Hello friends, especially NestJS friends.

Like many of you, we recently upgraded to TypeORM 0.3.x and ran into issues with the way that the docs wants you to use the CLI. We decided to use Nest’s Standalone Application feature to grab the DataSourceOptions instead of having to reimplement how our app is loading.

Here’s the list of things that we found troublesome:

  1. CLI commands call DataSource#initialize even if the DataSource is already initialized. This is a problem if you use NestJS, which automatically initializes the DataSource.
  2. Like many of you mentioned, the new method of passing the migration name doesn’t play well with package.json scripts, especially yarn. We’re forced to use an environment variable. I don’t like how TypeORM changed a perfectly good -n flag.
  3. As others have mentioned, I do not think the change for removing glob like syntax from migrations is a good one. Having to register each migration you generate as a manual step is not just tedious, it goes against tons of other ORM patterns.

Anyway, here’s the method we’ve used:

in ormconfig.ts

import { DataSource } from 'typeorm';
import { NestFactory } from '@nestjs/core';
import { getDataSourceToken } from '@nestjs/typeorm';
import { AppModule } from './app.module';

async function getOrmConfig(): Promise<DataSource> {
  const app = await NestFactory.createApplicationContext(AppModule);
  const dataSource =  app.get<DataSource>(getDataSourceToken());
  //have to destroy the datasource to disconnect since @nestjs/typeorm initializes the datasource, and typeorm calls initialize without checking in the commands.
  dataSource.destroy();
  return dataSource;
}

const dataSource = getOrmConfig();

export default dataSource;

in package.json

{
    "scripts": {
      "typeorm": "yarn ts-node -r tsconfig-paths/register ../../node_modules/typeorm/cli.js",
      "migration:generate": "yarn typeorm migration:generate -d src/ormconfig.ts src/migrations/$NAME",
      "migration:create": "yarn typeorm migration:create src/migrations/$NAME",
      "migration:run": "yarn typeorm migration:run -d src/ormconfig.ts",
      "migration:revert": "yarn typeorm migration:revert -d src/ormconfig.ts",
    },
    //[...]
}

If I were to suggest anything, perhaps a if (dataSource.isInitialized) check could be added to the commands in here. That would prevent having to destroy the datasource in the ormconfig being loaded from Nest.

I would also suggest separating the name of the migration and the folder to store it in like it used to be. Especially because it’s not particularly intuitive that typeorm migration:create src/migrations/Test generates a file in src/migrations/<timestamp>-Test.ts

$npm_config_name does not work with yarn. npm or pnpm should be fine.

Я нашел некоторую информацию здесь https://github.com/typeorm/typeorm/releases/tag/0.3.0 Моя версия 0.3.5

УСТАРЕВШИЕ entities , migrations, subscribersпараметры внутри DataSourceOptionsподдержки строковых каталогов устарели. В будущих версиях вы сможете передавать только ссылки на сущности .

Как это:

// ormconfig.ts
const connectionSource = new DataSource({
  ...
  entities: [ExamplesEntity],
  migrations: [ExamleMigration1656076568327],
  ...
})
export default connectionSource;

Скрипты:

{
  "scripts": {
          "typeorm": "typeorm-ts-node-esm -d ./src/db/ormconfig.ts",
          "migration:create": "typeorm-ts-node-esm migration:create ./src/db/migrations/$npm_config_name",
          "migration:generate": "npm run typeorm migration:generate ./src/db/migrations/$npm_config_name",
          "migration:show": "npm run typeorm migration:show",
          "migration:run": "npm run typeorm migration:run",
          "migration:revert": "npm run typeorm migration:revert"
   }
}

Применение:

npm run migration:generate --name=example_migration
npm run migration:create --name=example_migration
npm run migration:run

Оно работает.

And how to make the file name change when it is created? Otherwise, this does not work in this configuration and the name remains the current $npm_config_name. I would be grateful if you clarify