kysely-org / kysely

A type-safe typescript SQL query builder
https://kysely.dev
MIT License
9.82k stars 250 forks source link

Calling Migrator.migrateToLast() exits process #980

Closed lucassilvas1 closed 2 months ago

lucassilvas1 commented 2 months ago

Description

Out of nowhere, calls to Migrator.migrateToLatest() are simply causing the Node process to exit with code 0. This happens even when the migration folder is empty, so I know it's not a specific migration causing the issue. In the snippet below, only console.log("BEFORE migrateToLast CALL") is called, but not console.log("AFTER migrateToLast CALL") or console.log("ERROR AFTER migrateToLast CALL", error). The process straight up exits after await migrator.migrateToLatest().

import * as path from "path";
import { promises as fs } from "fs";
import { Kysely, Migrator, FileMigrationProvider, SqliteDialect } from "kysely";
import { Database } from "better-sqlite3";

export async function migrateToLatest(database: Database) {
  const db = new Kysely<any>({
    dialect: new SqliteDialect({ database: database }),
  });

  const migrator = new Migrator({
    db,
    provider: new FileMigrationProvider({
      fs,
      path,
      // This needs to be an absolute path.
      migrationFolder: path.join(__dirname, "./migrations"),
    }),
  });

  console.log("BEFORE migrateToLast CALL");

  try {
    const { error, results } = await migrator.migrateToLatest();

    console.log("AFTER migrateToLast CALL");
  } catch (error) {
    console.log("ERROR AFTER migrateToLast CALL", error);
  }

  await db.destroy();
}

EDIT: Turns out I forgot to delete the transpiled migration JavaScript files when I was checking if one of my migrations was the culprit. I managed to narrow down the cause of the problem to one of my migrations, but I still don't know why it is causing the process to exit.

This is migration file:

// 2024-05-06T20-18 - add index columns.ts

import { Kysely } from "kysely";

export async function up(db: Kysely<any>) {
  await db.transaction().execute(async (trx) => {
    // copy all media_tagged_user rows before deleting them
    const mediaTaggedUsers = await trx
      .selectFrom("media_tagged_user")
      .selectAll()
      .execute();
    // same goes for media
    const media = await trx.selectFrom("media").selectAll().execute();
    // get every post in ascending order by taken_at
    const posts = await trx
      .selectFrom("post")
      .selectAll()
      .orderBy("taken_at asc")
      .execute();
    // delete these tables first due to reference constraints
    await trx.deleteFrom("media_tagged_user").execute();
    await trx.deleteFrom("media").execute();
    // drop post table and its index
    await db.schema.dropIndex("post_user_id_index").execute();
    await db.schema.dropTable("post").execute();
    // create table with new schema and index
    await trx.schema
      .createTable("post")
      .addColumn("index", "integer", (col) => col.autoIncrement())
      .addColumn("id", "text", (col) => col.primaryKey())
      .addColumn("owner_id", "text", (col) =>
        col.references("user.id").onDelete("cascade").notNull()
      )
      .addColumn("code", "text", (col) => col.notNull())
      .addColumn("taken_at", "timestamptz", (col) => col.notNull())
      .addColumn("caption", "text")
      .execute();
    await trx.schema
      .createIndex("post_user_id_index")
      .on("post")
      .column("owner_id")
      .execute();
    // create index for index row
    await trx.schema
      .createIndex("post_index_index")
      .on("post")
      .column("index")
      .execute();
    // re-insert rows
    await trx.insertInto("post").values(posts).execute();
    await trx.insertInto("media").values(media).execute();
    await trx
      .insertInto("media_tagged_user")
      .values(mediaTaggedUsers)
      .execute();
  });
}

export async function down(_: Kysely<any>) {
  throw new Error(
    "Cannot revert back to previous version because old IDs cannot be recovered."
  );
}

I'm not experienced with SQL, specially not SQLite which is what this project uses, so there's likely better ways of doing it, but surely it shouldn't cause the app to just exit?

lucassilvas1 commented 2 months ago

Why was this closed? I still don't know why the migration is causing the process to exit, I get no errors or anything, so I have no idea what to look for.

igalklebanov commented 2 months ago

Hey 👋

If you don't post an error message/stacktrace, or a reproduction repository, there's nothing we can do to help. You haven't made the minimal steps towards that. We are not here to debug with you.

Try wrapping the migration with a try-catch block and print errors and rethrow.