skip to Main Content

I am facing a strange bug since I upgraded to TypeORM 0.3, I generate my first migration as the database is empty, and it is generated correctly. If I generate a second migration afterwards, without making a single change at the entities, the migration generated recognizes changes on every table, with scripts like this

await queryRunner.query(`ALTER TABLE `clients` CHANGE `deletedAt` `deletedAt` datetime(6) NULL`);
await queryRunner.query(`ALTER TABLE `clients` CHANGE `type` `type` varchar(255) NULL`);
await queryRunner.query(`ALTER TABLE `clients` CHANGE `first_name` `first_name` varchar(255) NULL`);
await queryRunner.query(`ALTER TABLE `clients` CHANGE `last_name` `last_name` varchar(255) NULL`);
await queryRunner.query(`ALTER TABLE `clients` CHANGE `company_name` `company_name` varchar(255) NULL`);
await queryRunner.query(`ALTER TABLE `clients` CHANGE `administrator_name` `administrator_name` varchar(255) NULL`);

These are just some of the lines of the second migrations, practically all my tables’ columns are written in the second migration with the ALTER TABLE CHANGE script, and it is weird because I didn’t make a single change. Even in the following migrations, these scripts continue to show.

Expected Behavior

I expect only changes made to the entities to be shown, not every column every time I generate a migration

package.json

"build": "tsc -p tsconfig.build.json",
"typeorm": "node -r ts-node/register ./node_modules/typeorm/cli.js -d src/ormconfig.ts",
"migration:revert": "npm run typeorm migration:revert",
"migration:run": "npm run build && npm run typeorm migration:run",
"migration:generate": "npm run build && npm run typeorm migration:generate",

ormconfig.ts

const ormconfiguration = {
type: getConnectionType(process.env.TYPEORM_CONNECTION),
host: process.env.TYPEORM_HOST,
port: Number(process.env.TYPEORM_PORT),
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
database: process.env.TYPEORM_DATABASE,
entities: [process.env.TYPEORM_ENTITIES],
migrations: [process.env.TYPEORM_MIGRATIONS],
},

.env

 #APP_CONFIG
 HOST=http://localhost:5000
 NODE_ENV=development
 #DATABASE
 TYPEORM_CONNECTION=mysql
 TYPEORM_HOST=db-dev
 TYPEORM_USERNAME=root
 TYPEORM_PASSWORD=admin321
 TYPEORM_DATABASE=suitcase_db
 TYPEORM_PORT=3306
 TYPEORM_SYNCHRONIZE=false
 TYPEORM_LOGGING=false
 # TYPEORM_ENTITIES= ./src/entities/*.entity.ts
 # TYPEORM_MIGRATIONS= ./src/migrations/*.ts

 # for working with npm run start:dev
 TYPEORM_ENTITIES=./dist/**/entities/*.entity.js
 TYPEORM_MIGRATIONS=./dist/**/migrations/*.js

 TYPEORM_ENTITIES_DIR= ./src/entities/
 TYPEORM_MIGRATIONS_DIR= ./src/migrations/
 TYPEORM_MIGRATIONS_RUN=false
 TYPEORM_DROP_SCHEMA=false

My Environment

Dependency  Version
Operating System    Ubuntu 20.04
Node.js version 16.13
Typescript version  4.5.2
TypeORM version 0.3.9

2

Answers


  1. Got this one figured out. Pretty ugly breaking changes in the CLI >= 0.3.x unfortunately but I stand firm that it’s still the best ORM out there. Here’s what I had to do to stop it from generating a HUGE migration of nonsense after updating to 0.3.11 from 0.2.x.

    NOTE: This assumes you’re able to generate migrations currently but that it’s generating a bunch of nonsensical updates when it does run despite no entity changes.

    1. Fully backup your local database. Full export of data/structure. This is what you’ll use if things go sideways to start fresh.

    2. Export just the data from your database into a separate file. We’ll use this later to restore your db back to its current state.

    3. Completely wipe your local database – all tables, all data. Empty database.

    4. From your /migrations folder copy any one single migration that has already run in other environments to a safe place. We’ll use this later to squash all migrations into this file since we’re guaranteed it has already run in other environments. Just pick one you know for sure exists in the migrations table in any/all environments. It’ll get skipped when we deploy and allow us to reset ourselves back to just 1 migration which frankly needs to be done every now and again anyway.

    5. Completely Empty your /migrations folder of all migrations.

    6. Clean your /dist folder – rm -rf ./dist

    Important: I found it safest to run against compiled entities so cleaning this out is important if you’re messing with migrations since any old ones will be left in the dist folder if not cleaned out.

    1. Generate your baseline schema migration. The command I use is configured like so in package.json, and called with npm run migration:generate:
      "prebuild": "rm -rf ./dist",
      "build": "nest build api",
      "typeorm": "typeorm-ts-node-commonjs -d ormconfig.ts",
      "migration:generate": "npm run build && npm run typeorm migration:generate -- ./migrations/schema"
    
    

    This outputs into ./migrations/1673535486257-schema.ts (as an example filename) and should contain the full migration to create the entire database fresh.

    1. Start your NestJs server (with runMigrations: true in the config) and let it fully start up. At this point your database should be fresh with the full schema of your local entities but of course completely empty except the 1 migration entry.

    2. Using whatever tool you use for SQL imports, go and try to import the data only export from earlier. This should import with only a single error on your migrations table which can be ignored. If all goes well with the import then now your database is fully back to where it was before.

    3. Important step! – Squash your migrations. Don’t skip this out of sheer joy that your migrations are working again! You’ll want to go back and reference that old migration file we tucked away and do a couple of things:

      1. Change the filename of the new (and only) migration in your /migrations folder to match exactly the name of the file you tucked away.
      2. Inside the migration file itself change the literal classname of the migration class it generates to exactly match the classname in the old file. You’ll also need to change the name attribute directly underneath the classname to the same as the old file. E.g.:
    export class schema1673535486257 implements MigrationInterface {
        name = 'schema1673535486257'
        public async up(queryRunner: QueryRunner): Promise<void> { ... }
        public async down(queryRunner: QueryRunner): Promise<void> { ... }
    }
    

    Doing this ensures that your one big migration gets skipped by environments that are up to date.

    Now the next time you make a change to an entity and run npm run migration:generate it will be the differential migration you’d expect!

    Login or Signup to reply.
  2. The same thing happened in a project of mine, I still don’t know how to solve it from the orm configuration, but this way solved the problem.

    The column that was displaying the error was defined as follows

    @Column({
        type: 'text',
        nullable: true,
        name: 'action_name',
        default: null
    })
    action_name: string;
    

    or

    @Column({
        type: 'text',
        nullable: true,
        name: 'action_name'
    })
    action_name: string;
    

    in this way ALTER TABLE were generated, and the manner in which it was resolved by analyzing the same queries was as follows

    @Column({
        type: 'text',
        nullable: true,
        name: 'action_name',
        default: () => 'NULL'
    })
    action_name: string;
    

    If you check the down function you will see that the form to which it restores the column has a DEFAULT ‘NULL’.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search