Search code examples
node.jstypescriptnestjstypeormdatabase-migration

TypeORM with default null value for a timestamp type column generates infinite migrations


I have the following column definition in an entity, within a NestJs project using TypeORM:

@CreateDateColumn({
    nullable: true,
    type: 'timestamp',
    default: () => 'NULL',
    })
public succeededAt?: Date;

This generates a migration that looks correct:

export class migration123 implements MigrationInterface {
   name = 'migration123';

   public async up(queryRunner: QueryRunner): Promise\<void\> {
      await queryRunner.query(
         `CREATE TABLE [...], "succeededAt" TIMESTAMP DEFAULT NULL, [...]`
   );
   \[...\]
}

But after running the migration, if I try to generate a new migration with TypeORM CLI, it still detects some differences:

[...]
public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "mercadopago_payment_request" ALTER COLUMN "succeededAt" SET DEFAULT null`);
[...]

I'm guessing that Postgres detects the default value as the global default anyways (every column has null as default if not stated otherwise) and doesn't add any special rule for it. Then TypeORM doesn't see the rule and tries to add it... again.

Any ideas on how to prevent this?


I tried removing the default value:

@CreateDateColumn({
    nullable: true,
    type: 'timestamp',
    })
public succeededAt?: Date;

But that generates a migration with a default value as now():

export class migration123 implements MigrationInterface {
   name = 'migration123';

   public async up(queryRunner: QueryRunner): Promise\<void\> {
      await queryRunner.query(
         `CREATE TABLE [...], "succeededAt" TIMESTAMP DEFAULT now(), [...]`
   );
   \[...\]
}

The reason why I'm trying to state specifically null as the default value.


Solution

  • My problem was due to the @CreateDateColumn decorator.

    I was able to achieve the correct behavior with a regular date column:

      @Column({ nullable: true, type: 'timestamp' })
      @IsDate()
      public succeededAt: Date | null;