Migrations does not register on TypeORM on Ionic and Vue using Capacitor

Issue

I am creating an Ionic5 app(with Vue3) using capacitor-sqlite plugin. I am also trying to use TypeORM on top all this.

I can connect to the sqlite database using capacitor but for some reason the migrations does not seem to be getting registered at all and always comes out as an empty array with the following code:

// App.vue

import {createConnection} from "typeorm";
import {CapacitorSQLite, SQLiteConnection} from "@capacitor-community/sqlite";

onBeforeMount(async () > {
    const sqlite  new SQLiteConnection(CapacitorSQLite);
    createConnection({
        type: 'capacitor',
        driver: sqlite,
        database: 'mydrivetime',
        synchronize: false,
        migrationsRun: false,
        logging: true,
        entities: [
            "User"
        ],
        migrations: [
            "1626771964722-UserCreate"
        ],
    }).then(async connection > {

        console.log('migrations', connection.migrations);
        console.log('isConnected', connection.isConnected);

        connection.runMigrations()
          .then(() > {
            console.log("migrations successful");
          }).catch(error > console.log(JSON.stringify(error)));

    });
});

I get the following output for this even though I have the migration setup on the same path:

⚡️  [log] - migrations []
⚡️  [log] - isConnected true
⚡️  [log] - migrations successful

This is the migration file which I have in the same path as App.vue. I also tried putting it in a separate folder and trying to glob it but no luck.

import {MigrationInterface, QueryRunner} from "typeorm";

export class UserCreate1626771964722 implements MigrationInterface {

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`
            CREATE TABLE "user" (
                "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
                "firstName" varchar NOT NULL,
                "age" integer NOT NULL
            )
        `);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`
            DROP TABLE "user"
        `);
    }

}

I don’t have any other settings anywhere else and I am not sure why the migration (or entity) are not getting registered. Here is the full console.log of the connection object:

{
    "migrations": [],
    "subscribers": [],
    "entityMetadatas": [],
    "name": "default",
    "options": {
        "type": "capacitor",
        "driver": {
            "sqlite": {},
            "_connectionDict": {}
        },
        "database": "mydrivetime",
        "synchronize": false,
        "migrationsRun": false,
        "logging": true,
        "entities": [
            "User"
        ],
        "migrations": [
            "1626771964722-UserCreate"
        ]
    },
    "logger": {
        "options": true
    },
    "driver": {
        "isReplicated": false,
        "treeSupport": true,
        "supportedDataTypes": [
            "int",
            "integer",
            "tinyint",
            "smallint",
            "mediumint",
            "bigint",
            "unsigned big int",
            "int2",
            "int8",
            "integer",
            "character",
            "varchar",
            "varying character",
            "nchar",
            "native character",
            "nvarchar",
            "text",
            "clob",
            "text",
            "blob",
            "real",
            "double",
            "double precision",
            "float",
            "real",
            "numeric",
            "decimal",
            "boolean",
            "date",
            "time",
            "datetime"
        ],
        "withLengthColumnTypes": [
            "character",
            "varchar",
            "varying character",
            "nchar",
            "native character",
            "nvarchar",
            "text",
            "blob",
            "clob"
        ],
        "spatialTypes": [],
        "withPrecisionColumnTypes": [
            "real",
            "double",
            "double precision",
            "float",
            "real",
            "numeric",
            "decimal",
            "date",
            "time",
            "datetime"
        ],
        "withScaleColumnTypes": [
            "real",
            "double",
            "double precision",
            "float",
            "real",
            "numeric",
            "decimal"
        ],
        "mappedDataTypes": {
            "createDate": "datetime",
            "createDateDefault": "datetime('now')",
            "updateDate": "datetime",
            "updateDateDefault": "datetime('now')",
            "deleteDate": "datetime",
            "deleteDateNullable": true,
            "version": "integer",
            "treeLevel": "integer",
            "migrationId": "integer",
            "migrationName": "varchar",
            "migrationTimestamp": "bigint",
            "cacheId": "int",
            "cacheIdentifier": "varchar",
            "cacheTime": "bigint",
            "cacheDuration": "int",
            "cacheQuery": "text",
            "cacheResult": "text",
            "metadataType": "varchar",
            "metadataDatabase": "varchar",
            "metadataSchema": "varchar",
            "metadataTable": "varchar",
            "metadataName": "varchar",
            "metadataValue": "text"
        },
        "connection": "...",
        "options": "...",
        "database": "mydrivetime",
        "driver": "...",
        "sqlite": "...",
        "databaseConnection": {}
    },
    "manager": {
        "repositories": [],
        "plainObjectToEntityTransformer": {},
        "connection": "..."
    },
    "namingStrategy": {
        "nestedSetColumnNames": {
            "left": "nsleft",
            "right": "nsright"
        },
        "materializedPathColumnName": "mpath"
    },
    "relationLoader": {
        "connection": "..."
    },
    "relationIdLoader": {
        "connection": "..."
    },
    "isConnected": true
}

Solution

The issue turned out to be a well known issue with the TypeORM entity/migrations not working when they are minified. The fix is add vue config to prevent the classnames from being minified as follows:

//vue.config.js (in the root folder)
module.exports  {
  chainWebpack: config > {
    if (process.env.NODE_ENV  'production') {
      config.optimization.minimizer('terser').tap((args) > {
        // see https://cli.vuejs.org/guide/webpack.html#chaining-advanced
        // https://cli.vuejs.org/migrating-from-v3/#vue-cli-service
        //   > chainWebpack for a chain override example
        // https://github.com/terser/terser#minify-options for terser options
        const terserOptions  args[0].terserOptions
        // Avoid to mangle entities (leads to query errors)
        terserOptions["keep_classnames"]  true
        terserOptions["keep_fnames"]  true
        // console.log(JSON.stringify(args[0], null, 2))
        return args
      })
    }
  },
  // ...rest of your vue.config.js...
}

For further info, please check this github issue

Answered By – Niraj Pandey

Leave a Comment