Skip to content

Commit

Permalink
fix: standalone migrations
Browse files Browse the repository at this point in the history
Recent fix for dropping/recreating PKs in environments with
sql_require_primary_key=1 also broke the migrations for environments
where the user doesn't have permissions to change the value of the
setting. The standalone setup is such an environment.

This commit changes those migrations so that the PKs are
dropped/recreated as one ALTER TABLE query, no longer requiring
changing the sql_require_primary_key setting.
  • Loading branch information
Dragory committed Apr 8, 2024
1 parent 928fc20 commit b28ca17
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ import { MigrationInterface, QueryRunner, TableColumn, TableIndex } from "typeor

export class AddTypeAndPermissionsToApiPermissions1573158035867 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
// Edge case: Since we're dropping the primary key temporarily, we need to disable the sql_require_primary_key setting if it's enabled
// This is restored at the end of the migration
const sqlRequirePrimaryKey = (await queryRunner.query("SELECT @@sql_require_primary_key AS value"))[0].value;
await queryRunner.query("SET SESSION sql_require_primary_key=0");

await queryRunner.dropPrimaryKey("api_permissions");

// We can't use a TableIndex object in dropIndex directly as the table name is included in the generated index name
// and the table name has changed since the original index was created
const originalIndexName = queryRunner.connection.namingStrategy.indexName("dashboard_users", ["user_id"]);
Expand All @@ -25,7 +18,11 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra

await queryRunner.renameColumn("api_permissions", "user_id", "target_id");

await queryRunner.createPrimaryKey("api_permissions", ["guild_id", "type", "target_id"]);
await queryRunner.query(`
ALTER TABLE api_permissions
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`guild_id\`, \`type\`, \`target_id\`);
`);

await queryRunner.dropColumn("api_permissions", "role");

Expand All @@ -49,14 +46,9 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
columnNames: ["type", "target_id"],
}),
);

await queryRunner.query(`SET SESSION sql_require_primary_key=${sqlRequirePrimaryKey}`);
}

public async down(queryRunner: QueryRunner): Promise<any> {
const sqlRequirePrimaryKey = (await queryRunner.query("SELECT @@sql_require_primary_key AS value"))[0].value;
await queryRunner.query("SET SESSION sql_require_primary_key=0");

await queryRunner.dropIndex(
"api_permissions",
new TableIndex({
Expand All @@ -75,7 +67,11 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
}),
);

await queryRunner.dropPrimaryKey("api_permissions");
await queryRunner.query(`
ALTER TABLE api_permissions
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`guild_id\`, \`type\`);
`);

await queryRunner.renameColumn("api_permissions", "target_id", "user_id");

Expand All @@ -87,9 +83,5 @@ export class AddTypeAndPermissionsToApiPermissions1573158035867 implements Migra
columnNames: ["user_id"],
}),
);

await queryRunner.createPrimaryKey("api_permissions", ["guild_id", "user_id"]);

await queryRunner.query(`SET SESSION sql_require_primary_key=${sqlRequirePrimaryKey}`);
}
}
60 changes: 27 additions & 33 deletions backend/src/migrations/1573248462469-MoveStarboardsToConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,58 @@ import { MigrationInterface, QueryRunner, Table, TableColumn } from "typeorm";

export class MoveStarboardsToConfig1573248462469 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
// Edge case: Since we're dropping the primary key temporarily, we need to disable the sql_require_primary_key setting if it's enabled
// This is restored at the end of the migration
const sqlRequirePrimaryKey = (await queryRunner.query("SELECT @@sql_require_primary_key AS value"))[0].value;
await queryRunner.query("SET SESSION sql_require_primary_key=0");

// Create a new column for the channel's id
const chanid_column = new TableColumn({
await queryRunner.addColumn("starboard_messages", new TableColumn({
name: "starboard_channel_id",
type: "bigint",
unsigned: true,
});
await queryRunner.addColumn("starboard_messages", chanid_column);
}));

// Since we are removing the guild_id with the starboards table, we might want it here
const guid_column = new TableColumn({
await queryRunner.addColumn("starboard_messages", new TableColumn({
name: "guild_id",
type: "bigint",
unsigned: true,
});
await queryRunner.addColumn("starboard_messages", guid_column);
}));

// Migrate the old starboard_id to the new starboard_channel_id
await queryRunner.query(`
UPDATE starboard_messages AS sm
JOIN starboards AS sb
ON sm.starboard_id = sb.id
SET sm.starboard_channel_id = sb.channel_id, sm.guild_id = sb.guild_id;
`);
UPDATE starboard_messages AS sm
JOIN starboards AS sb
ON sm.starboard_id = sb.id
SET sm.starboard_channel_id = sb.channel_id, sm.guild_id = sb.guild_id;
`);

// Drop the starboard_id column as it is now obsolete
await queryRunner.dropColumn("starboard_messages", "starboard_id");
// Set new Primary Key
await queryRunner.dropPrimaryKey("starboard_messages");
await queryRunner.createPrimaryKey("starboard_messages", ["starboard_message_id"]);
// Finally, drop the starboards channel as it is now obsolete
await queryRunner.dropTable("starboards", true);
await queryRunner.query(`
ALTER TABLE starboard_messages
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`starboard_message_id\`);
`);
// Drop the starboard_id column as it is now obsolete
// We can't use queyrRunner.dropColumn() here because TypeORM helpfully thinks that
// starboard_id is still part of the primary key and tries to drop the PK first
await queryRunner.query("ALTER TABLE starboard_messages DROP COLUMN starboard_id");

await queryRunner.query(`SET SESSION sql_require_primary_key=${sqlRequirePrimaryKey}`);
// Finally, drop the starboards table as it is now obsolete
await queryRunner.dropTable("starboards", true);
}

public async down(queryRunner: QueryRunner): Promise<any> {
const sqlRequirePrimaryKey = (await queryRunner.query("SELECT @@sql_require_primary_key AS value"))[0].value;
await queryRunner.query("SET SESSION sql_require_primary_key=0");

await queryRunner.dropColumn("starboard_messages", "starboard_channel_id");
await queryRunner.dropColumn("starboard_messages", "guild_id");

const sbId = new TableColumn({
await queryRunner.addColumn("starboard_messages", new TableColumn({
name: "starboard_id",
type: "int",
unsigned: true,
});
await queryRunner.addColumn("starboard_messages", sbId);
}));

await queryRunner.dropPrimaryKey("starboard_messages");
await queryRunner.createPrimaryKey("starboard_messages", ["starboard_id", "message_id"]);
await queryRunner.query(`
ALTER TABLE starboard_messages
DROP PRIMARY KEY,
ADD PRIMARY KEY(\`starboard_id\`, \`message_id\`);
`);

await queryRunner.createTable(
new Table({
Expand Down Expand Up @@ -109,7 +105,5 @@ export class MoveStarboardsToConfig1573248462469 implements MigrationInterface {
],
}),
);

await queryRunner.query(`SET SESSION sql_require_primary_key=${sqlRequirePrimaryKey}`);
}
}

0 comments on commit b28ca17

Please sign in to comment.