refactor(core): Delete boilerplate code across migrations (no-changelog) (#5254)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2023-05-05 09:28:59 +00:00 committed by GitHub
parent d5c44987f4
commit 82fe6383ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
122 changed files with 879 additions and 1844 deletions

View file

@ -11,7 +11,6 @@ module.exports = {
ignorePatterns: [ ignorePatterns: [
'jest.config.js', 'jest.config.js',
// TODO: Remove these // TODO: Remove these
'src/databases/migrations/**',
'src/databases/ormconfig.ts', 'src/databases/ormconfig.ts',
], ],

View file

@ -7,7 +7,7 @@ import { Container } from 'typedi';
import type { DataSourceOptions as ConnectionOptions, EntityManager, LoggerOptions } from 'typeorm'; import type { DataSourceOptions as ConnectionOptions, EntityManager, LoggerOptions } from 'typeorm';
import { DataSource as Connection } from 'typeorm'; import { DataSource as Connection } from 'typeorm';
import type { TlsOptions } from 'tls'; import type { TlsOptions } from 'tls';
import type { DatabaseType, IDatabaseCollections } from '@/Interfaces'; import type { IDatabaseCollections } from '@/Interfaces';
import config from '@/config'; import config from '@/config';
@ -19,6 +19,8 @@ import {
getPostgresConnectionOptions, getPostgresConnectionOptions,
getSqliteConnectionOptions, getSqliteConnectionOptions,
} from '@db/config'; } from '@db/config';
import { wrapMigration } from '@db/utils/migrationHelpers';
import type { DatabaseType, Migration } from '@db/types';
import { import {
AuthIdentityRepository, AuthIdentityRepository,
AuthProviderSyncHistoryRepository, AuthProviderSyncHistoryRepository,
@ -119,7 +121,7 @@ export async function init(
synchronize: false, synchronize: false,
logging: loggingOption, logging: loggingOption,
maxQueryExecutionTime, maxQueryExecutionTime,
migrationsTransactionMode: 'each', migrationsRun: false,
}); });
connection = new Connection(connectionOptions); connection = new Connection(connectionOptions);
@ -136,15 +138,17 @@ export async function init(
await connection.query(`SET search_path TO ${searchPath.join(',')};`); await connection.query(`SET search_path TO ${searchPath.join(',')};`);
} }
(connectionOptions.migrations as Migration[]).forEach(wrapMigration);
if (!testConnectionOptions && dbType === 'sqlite') { if (!testConnectionOptions && dbType === 'sqlite') {
// This specific migration changes database metadata. // This specific migration changes database metadata.
// A field is now nullable. We need to reconnect so that // A field is now nullable. We need to reconnect so that
// n8n knows it has changed. Happens only on sqlite. // n8n knows it has changed. Happens only on sqlite.
let migrations = []; let migrations = [];
try { try {
const entityPrefix = config.getEnv('database.tablePrefix'); const tablePrefix = config.getEnv('database.tablePrefix');
migrations = await connection.query( migrations = await connection.query(
`SELECT id FROM ${entityPrefix}migrations where name = "MakeStoppedAtNullable1607431743769"`, `SELECT id FROM ${tablePrefix}migrations where name = "MakeStoppedAtNullable1607431743769"`,
); );
} catch (error) { } catch (error) {
// Migration table does not exist yet - it will be created after migrations run for the first time. // Migration table does not exist yet - it will be created after migrations run for the first time.

View file

@ -32,6 +32,7 @@ import type { FindOperator } from 'typeorm';
import type { ChildProcess } from 'child_process'; import type { ChildProcess } from 'child_process';
import type { DatabaseType } from '@db/types';
import type { AuthProviderType } from '@db/entities/AuthIdentity'; import type { AuthProviderType } from '@db/entities/AuthIdentity';
import type { Role } from '@db/entities/Role'; import type { Role } from '@db/entities/Role';
import type { SharedCredentials } from '@db/entities/SharedCredentials'; import type { SharedCredentials } from '@db/entities/SharedCredentials';
@ -160,7 +161,6 @@ export type ICredentialsDecryptedDb = ICredentialsBase & ICredentialsDecrypted;
export type ICredentialsDecryptedResponse = ICredentialsDecryptedDb; export type ICredentialsDecryptedResponse = ICredentialsDecryptedDb;
export type DatabaseType = 'mariadb' | 'postgresdb' | 'mysqldb' | 'sqlite';
export type SaveExecutionDataType = 'all' | 'none'; export type SaveExecutionDataType = 'all' | 'none';
export interface IExecutionBase { export interface IExecutionBase {

View file

@ -8,7 +8,7 @@ import { entities } from './entities';
import { mysqlMigrations } from './migrations/mysqldb'; import { mysqlMigrations } from './migrations/mysqldb';
import { postgresMigrations } from './migrations/postgresdb'; import { postgresMigrations } from './migrations/postgresdb';
import { sqliteMigrations } from './migrations/sqlite'; import { sqliteMigrations } from './migrations/sqlite';
import type { DatabaseType } from '@/Interfaces'; import type { DatabaseType } from '@db/types';
import config from '@/config'; import config from '@/config';
const entitiesDir = path.resolve(__dirname, 'entities'); const entitiesDir = path.resolve(__dirname, 'entities');
@ -35,7 +35,6 @@ const getDBConnectionOptions = (dbType: DatabaseType) => {
return { return {
entityPrefix, entityPrefix,
entities: Object.values(entities), entities: Object.values(entities),
migrationsRun: false,
migrationsTableName: `${entityPrefix}migrations`, migrationsTableName: `${entityPrefix}migrations`,
cli: { entitiesDir, migrationsDir }, cli: { entitiesDir, migrationsDir },
...connectionDetails, ...connectionDetails,

View file

@ -1,20 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class InitialMigration1588157391238 implements MigrationInterface {
name = 'InitialMigration1588157391238';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class InitialMigration1588157391238 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
'CREATE TABLE IF NOT EXISTS `' + 'CREATE TABLE IF NOT EXISTS `' +
tablePrefix + tablePrefix +
'credentials_entity` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL, `data` text NOT NULL, `type` varchar(32) NOT NULL, `nodesAccess` json NOT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, INDEX `IDX_' + 'credentials_entity` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL, `data` text NOT NULL, `type` varchar(32) NOT NULL, `nodesAccess` json NOT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, INDEX `IDX_' +
tablePrefix + tablePrefix +
'07fde106c0b471d8cc80a64fc8` (`type`), PRIMARY KEY (`id`)) ENGINE=InnoDB', '07fde106c0b471d8cc80a64fc8` (`type`), PRIMARY KEY (`id`)) ENGINE=InnoDB',
undefined,
); );
await queryRunner.query( await queryRunner.query(
'CREATE TABLE IF NOT EXISTS `' + 'CREATE TABLE IF NOT EXISTS `' +
@ -22,37 +15,31 @@ export class InitialMigration1588157391238 implements MigrationInterface {
'execution_entity` (`id` int NOT NULL AUTO_INCREMENT, `data` text NOT NULL, `finished` tinyint NOT NULL, `mode` varchar(255) NOT NULL, `retryOf` varchar(255) NULL, `retrySuccessId` varchar(255) NULL, `startedAt` datetime NOT NULL, `stoppedAt` datetime NOT NULL, `workflowData` json NOT NULL, `workflowId` varchar(255) NULL, INDEX `IDX_' + 'execution_entity` (`id` int NOT NULL AUTO_INCREMENT, `data` text NOT NULL, `finished` tinyint NOT NULL, `mode` varchar(255) NOT NULL, `retryOf` varchar(255) NULL, `retrySuccessId` varchar(255) NULL, `startedAt` datetime NOT NULL, `stoppedAt` datetime NOT NULL, `workflowData` json NOT NULL, `workflowId` varchar(255) NULL, INDEX `IDX_' +
tablePrefix + tablePrefix +
'c4d999a5e90784e8caccf5589d` (`workflowId`), PRIMARY KEY (`id`)) ENGINE=InnoDB', 'c4d999a5e90784e8caccf5589d` (`workflowId`), PRIMARY KEY (`id`)) ENGINE=InnoDB',
undefined,
); );
await queryRunner.query( await queryRunner.query(
'CREATE TABLE IF NOT EXISTS`' + 'CREATE TABLE IF NOT EXISTS`' +
tablePrefix + tablePrefix +
'workflow_entity` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL, `active` tinyint NOT NULL, `nodes` json NOT NULL, `connections` json NOT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, `settings` json NULL, `staticData` json NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB', 'workflow_entity` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL, `active` tinyint NOT NULL, `nodes` json NOT NULL, `connections` json NOT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, `settings` json NULL, `staticData` json NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB',
undefined,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix'); await queryRunner.query('DROP TABLE `' + tablePrefix + 'workflow_entity`');
await queryRunner.query('DROP TABLE `' + tablePrefix + 'workflow_entity`', undefined);
await queryRunner.query( await queryRunner.query(
'DROP INDEX `IDX_' + 'DROP INDEX `IDX_' +
tablePrefix + tablePrefix +
'c4d999a5e90784e8caccf5589d` ON `' + 'c4d999a5e90784e8caccf5589d` ON `' +
tablePrefix + tablePrefix +
'execution_entity`', 'execution_entity`',
undefined,
); );
await queryRunner.query('DROP TABLE `' + tablePrefix + 'execution_entity`', undefined); await queryRunner.query('DROP TABLE `' + tablePrefix + 'execution_entity`');
await queryRunner.query( await queryRunner.query(
'DROP INDEX `IDX_' + 'DROP INDEX `IDX_' +
tablePrefix + tablePrefix +
'07fde106c0b471d8cc80a64fc8` ON `' + '07fde106c0b471d8cc80a64fc8` ON `' +
tablePrefix + tablePrefix +
'credentials_entity`', 'credentials_entity`',
undefined,
); );
await queryRunner.query('DROP TABLE `' + tablePrefix + 'credentials_entity`', undefined); await queryRunner.query('DROP TABLE `' + tablePrefix + 'credentials_entity`');
} }
} }

View file

@ -1,20 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class WebhookModel1592447867632 implements MigrationInterface {
name = 'WebhookModel1592447867632';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class WebhookModel1592447867632 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS ${tablePrefix}webhook_entity (workflowId int NOT NULL, webhookPath varchar(255) NOT NULL, method varchar(255) NOT NULL, node varchar(255) NOT NULL, PRIMARY KEY (webhookPath, method)) ENGINE=InnoDB`, `CREATE TABLE IF NOT EXISTS ${tablePrefix}webhook_entity (workflowId int NOT NULL, webhookPath varchar(255) NOT NULL, method varchar(255) NOT NULL, node varchar(255) NOT NULL, PRIMARY KEY (webhookPath, method)) ENGINE=InnoDB`,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`); await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`);
} }
} }

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class CreateIndexStoppedAt1594902918301 implements MigrationInterface {
name = 'CreateIndexStoppedAt1594902918301';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class CreateIndexStoppedAt1594902918301 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
'CREATE INDEX `IDX_' + 'CREATE INDEX `IDX_' +
tablePrefix + tablePrefix +
@ -17,9 +11,7 @@ export class CreateIndexStoppedAt1594902918301 implements MigrationInterface {
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
'DROP INDEX `IDX_' + 'DROP INDEX `IDX_' +
tablePrefix + tablePrefix +

View file

@ -1,21 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config'; export class MakeStoppedAtNullable1607431743767 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
export class MakeStoppedAtNullable1607431743767 implements MigrationInterface {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY `stoppedAt` datetime', 'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY `stoppedAt` datetime',
undefined,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY `stoppedAt` datetime NOT NULL', 'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY `stoppedAt` datetime NOT NULL',
undefined,
); );
} }
} }

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class AddWebhookId1611149998770 implements MigrationInterface {
name = 'AddWebhookId1611149998770';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddWebhookId1611149998770 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'webhook_entity` ADD `webhookId` varchar(255) NULL', 'ALTER TABLE `' + tablePrefix + 'webhook_entity` ADD `webhookId` varchar(255) NULL',
); );
@ -22,9 +17,7 @@ export class AddWebhookId1611149998770 implements MigrationInterface {
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
'DROP INDEX `IDX_' + 'DROP INDEX `IDX_' +
tablePrefix + tablePrefix +

View file

@ -1,20 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class ChangeDataSize1615306975123 implements MigrationInterface {
name = 'ChangeDataSize1615306975123';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class ChangeDataSize1615306975123 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY COLUMN `data` MEDIUMTEXT NOT NULL', 'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY COLUMN `data` MEDIUMTEXT NOT NULL',
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY COLUMN `data` TEXT NOT NULL', 'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY COLUMN `data` TEXT NOT NULL',
); );

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class CreateTagEntity1617268711084 implements MigrationInterface {
name = 'CreateTagEntity1617268711084';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class CreateTagEntity1617268711084 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
// create tags table + relationship with workflow entity // create tags table + relationship with workflow entity
await queryRunner.query( await queryRunner.query(
@ -78,9 +73,7 @@ export class CreateTagEntity1617268711084 implements MigrationInterface {
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
// `createdAt` and `updatedAt` // `createdAt` and `updatedAt`
await queryRunner.query( await queryRunner.query(

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class ChangeCredentialDataSize1620729500000 implements MigrationInterface {
name = 'ChangeCredentialDataSize1620729500000';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class ChangeCredentialDataSize1620729500000 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + 'ALTER TABLE `' +
tablePrefix + tablePrefix +
@ -14,9 +9,7 @@ export class ChangeCredentialDataSize1620729500000 implements MigrationInterface
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + 'ALTER TABLE `' +
tablePrefix + tablePrefix +

View file

@ -1,42 +1,37 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class UniqueWorkflowNames1620826335440 implements MigrationInterface { export class UniqueWorkflowNames1620826335440 implements ReversibleMigration {
name = 'UniqueWorkflowNames1620826335440'; async up({ queryRunner, tablePrefix }: MigrationContext) {
const workflowNames = (await queryRunner.query(`
async up(queryRunner: QueryRunner): Promise<void> { SELECT name
const tablePrefix = config.getEnv('database.tablePrefix'); FROM ${tablePrefix}workflow_entity
`)) as Array<{ name: string }>;
const workflowNames = await queryRunner.query(`
SELECT name
FROM ${tablePrefix}workflow_entity
`);
for (const { name } of workflowNames) { for (const { name } of workflowNames) {
const [duplicatesQuery, parameters] = queryRunner.connection.driver.escapeQueryWithParameters( const [duplicatesQuery, parameters] = queryRunner.connection.driver.escapeQueryWithParameters(
` ` SELECT id, name
SELECT id, name
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
WHERE name = :name WHERE name = :name
ORDER BY createdAt ASC ORDER BY createdAt ASC`,
`,
{ name }, { name },
{}, {},
); );
const duplicates = await queryRunner.query(duplicatesQuery, parameters); const duplicates = (await queryRunner.query(duplicatesQuery, parameters)) as Array<{
id: number;
name: string;
}>;
if (duplicates.length > 1) { if (duplicates.length > 1) {
await Promise.all( await Promise.all(
duplicates.map(({ id, name }: { id: number; name: string }, index: number) => { // eslint-disable-next-line @typescript-eslint/no-shadow
if (index === 0) return Promise.resolve(); duplicates.map(async ({ id, name }, index: number) => {
if (index === 0) return;
const [updateQuery, updateParams] = const [updateQuery, updateParams] =
queryRunner.connection.driver.escapeQueryWithParameters( queryRunner.connection.driver.escapeQueryWithParameters(
` `UPDATE ${tablePrefix}workflow_entity
UPDATE ${tablePrefix}workflow_entity SET name = :name
SET name = :name WHERE id = '${id}'`,
WHERE id = '${id}'
`,
{ name: `${name} ${index + 1}` }, { name: `${name} ${index + 1}` },
{}, {},
); );
@ -56,9 +51,7 @@ export class UniqueWorkflowNames1620826335440 implements MigrationInterface {
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + 'ALTER TABLE `' +
tablePrefix + tablePrefix +

View file

@ -1,30 +1,22 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import config from '@/config';
export class CertifyCorrectCollation1623936588000 implements MigrationInterface { export class CertifyCorrectCollation1623936588000 implements IrreversibleMigration {
name = 'CertifyCorrectCollation1623936588000'; async up({ queryRunner, tablePrefix, dbType, dbName }: MigrationContext) {
if (dbType === 'mariadb') {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
const databaseType = config.getEnv('database.type');
if (databaseType === 'mariadb') {
// This applies to MySQL only. // This applies to MySQL only.
return; return;
} }
const checkCollationExistence = await queryRunner.query( const checkCollationExistence = (await queryRunner.query(
`show collation where collation like 'utf8mb4_0900_ai_ci';`, "show collation where collation like 'utf8mb4_0900_ai_ci';",
); )) as unknown[];
let collation = 'utf8mb4_general_ci'; let collation = 'utf8mb4_general_ci';
if (checkCollationExistence.length > 0) { if (checkCollationExistence.length > 0) {
collation = 'utf8mb4_0900_ai_ci'; collation = 'utf8mb4_0900_ai_ci';
} }
const databaseName = config.getEnv(`database.mysqldb.database`);
await queryRunner.query( await queryRunner.query(
`ALTER DATABASE \`${databaseName}\` CHARACTER SET utf8mb4 COLLATE ${collation};`, `ALTER DATABASE \`${dbName}\` CHARACTER SET utf8mb4 COLLATE ${collation};`,
); );
for (const tableName of [ for (const tableName of [
@ -41,9 +33,6 @@ export class CertifyCorrectCollation1623936588000 implements MigrationInterface
} }
} }
async down(queryRunner: QueryRunner): Promise<void> { // There is no down migration in this case as we already expect default collation to be utf8mb4
// There is nothing to undo in this case as we already expect default collation to be utf8mb4 // The up migration exists simply to enforce that n8n will work with older mysql versions
// This migration exists simply to enforce that n8n will work with
// older mysql versions
}
} }

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class AddWaitColumnId1626183952959 implements MigrationInterface {
name = 'AddWaitColumnId1626183952959';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddWaitColumnId1626183952959 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'execution_entity` ADD `waitTill` DATETIME NULL', 'ALTER TABLE `' + tablePrefix + 'execution_entity` ADD `waitTill` DATETIME NULL',
); );
@ -19,9 +14,7 @@ export class AddWaitColumnId1626183952959 implements MigrationInterface {
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
'DROP INDEX `IDX_' + 'DROP INDEX `IDX_' +
tablePrefix + tablePrefix +

View file

@ -1,20 +1,21 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; /* eslint-disable @typescript-eslint/restrict-template-expressions */
import config from '@/config'; /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { runInBatches } from '@db/utils/migrationHelpers'; import { runInBatches } from '@db/utils/migrationHelpers';
// replacing the credentials in workflows and execution // replacing the credentials in workflows and execution
// `nodeType: name` changes to `nodeType: { id, name }` // `nodeType: name` changes to `nodeType: { id, name }`
export class UpdateWorkflowCredentials1630451444017 implements MigrationInterface { export class UpdateWorkflowCredentials1630451444017 implements ReversibleMigration {
name = 'UpdateWorkflowCredentials1630451444017'; async up({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
const credentialsEntities = await queryRunner.query(`
SELECT id, name, type SELECT id, name, type
FROM ${tablePrefix}credentials_entity FROM ${tablePrefix}credentials_entity
`); `)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
@ -54,7 +55,7 @@ export class UpdateWorkflowCredentials1630451444017 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -97,7 +98,7 @@ export class UpdateWorkflowCredentials1630451444017 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -140,18 +141,16 @@ export class UpdateWorkflowCredentials1630451444017 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix'); const credentialsEntities = (await queryRunner.query(`
const credentialsEntities = await queryRunner.query(`
SELECT id, name, type SELECT id, name, type
FROM ${tablePrefix}credentials_entity FROM ${tablePrefix}credentials_entity
`); `)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
@ -195,7 +194,7 @@ export class UpdateWorkflowCredentials1630451444017 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -244,7 +243,7 @@ export class UpdateWorkflowCredentials1630451444017 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -293,7 +292,7 @@ export class UpdateWorkflowCredentials1630451444017 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
} }

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class AddExecutionEntityIndexes1644424784709 implements MigrationInterface {
name = 'AddExecutionEntityIndexes1644424784709';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddExecutionEntityIndexes1644424784709 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`DROP INDEX \`IDX_${tablePrefix}c4d999a5e90784e8caccf5589d\` ON \`${tablePrefix}execution_entity\``, `DROP INDEX \`IDX_${tablePrefix}c4d999a5e90784e8caccf5589d\` ON \`${tablePrefix}execution_entity\``,
); );
@ -30,8 +25,7 @@ export class AddExecutionEntityIndexes1644424784709 implements MigrationInterfac
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`DROP INDEX \`IDX_${tablePrefix}81fc04c8a17de15835713505e4\` ON \`${tablePrefix}execution_entity\``, `DROP INDEX \`IDX_${tablePrefix}81fc04c8a17de15835713505e4\` ON \`${tablePrefix}execution_entity\``,
); );

View file

@ -1,14 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { InsertResult, MigrationContext, ReversibleMigration } from '@db/types';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import config from '@/config';
import { loadSurveyFromDisk } from '@db/utils/migrationHelpers'; import { loadSurveyFromDisk } from '@db/utils/migrationHelpers';
export class CreateUserManagement1646992772331 implements MigrationInterface { export class CreateUserManagement1646992772331 implements ReversibleMigration {
name = 'CreateUserManagement1646992772331'; async up({ queryRunner, tablePrefix }: MigrationContext) {
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}role ( `CREATE TABLE ${tablePrefix}role (
\`id\` int NOT NULL AUTO_INCREMENT, \`id\` int NOT NULL AUTO_INCREMENT,
@ -114,7 +109,9 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
`INSERT INTO ${tablePrefix}role (name, scope) VALUES ("owner", "global");`, `INSERT INTO ${tablePrefix}role (name, scope) VALUES ("owner", "global");`,
); );
const instanceOwnerRole = await queryRunner.query('SELECT LAST_INSERT_ID() as insertId'); const instanceOwnerRole = (await queryRunner.query(
'SELECT LAST_INSERT_ID() as insertId',
)) as InsertResult;
await queryRunner.query( await queryRunner.query(
`INSERT INTO ${tablePrefix}role (name, scope) VALUES ("member", "global");`, `INSERT INTO ${tablePrefix}role (name, scope) VALUES ("member", "global");`,
@ -124,13 +121,17 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
`INSERT INTO ${tablePrefix}role (name, scope) VALUES ("owner", "workflow");`, `INSERT INTO ${tablePrefix}role (name, scope) VALUES ("owner", "workflow");`,
); );
const workflowOwnerRole = await queryRunner.query('SELECT LAST_INSERT_ID() as insertId'); const workflowOwnerRole = (await queryRunner.query(
'SELECT LAST_INSERT_ID() as insertId',
)) as InsertResult;
await queryRunner.query( await queryRunner.query(
`INSERT INTO ${tablePrefix}role (name, scope) VALUES ("owner", "credential");`, `INSERT INTO ${tablePrefix}role (name, scope) VALUES ("owner", "credential");`,
); );
const credentialOwnerRole = await queryRunner.query('SELECT LAST_INSERT_ID() as insertId'); const credentialOwnerRole = (await queryRunner.query(
'SELECT LAST_INSERT_ID() as insertId',
)) as InsertResult;
const survey = loadSurveyFromDisk(); const survey = loadSurveyFromDisk();
@ -155,9 +156,7 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD UNIQUE INDEX \`IDX_${tablePrefix}943d8f922be094eb507cb9a7f9\` (\`name\`)`, `ALTER TABLE ${tablePrefix}workflow_entity ADD UNIQUE INDEX \`IDX_${tablePrefix}943d8f922be094eb507cb9a7f9\` (\`name\`)`,
); );

View file

@ -1,17 +1,10 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import config from '@/config';
export class LowerCaseUserEmail1648740597343 implements MigrationInterface {
name = 'LowerCaseUserEmail1648740597343';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
export class LowerCaseUserEmail1648740597343 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(` await queryRunner.query(`
UPDATE ${tablePrefix}user UPDATE ${tablePrefix}user
SET email = LOWER(email); SET email = LOWER(email);
`); `);
} }
public async down(queryRunner: QueryRunner): Promise<void> {}
} }

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class CommunityNodes1652254514003 implements MigrationInterface {
name = 'CommunityNodes1652254514003';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class CommunityNodes1652254514003 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE \`${tablePrefix}installed_packages\` (` + `CREATE TABLE \`${tablePrefix}installed_packages\` (` +
'`packageName` char(214) NOT NULL,' + '`packageName` char(214) NOT NULL,' +
@ -35,9 +30,7 @@ export class CommunityNodes1652254514003 implements MigrationInterface {
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD UNIQUE INDEX \`IDX_${tablePrefix}943d8f922be094eb507cb9a7f9\` (\`name\`)`, `ALTER TABLE ${tablePrefix}workflow_entity ADD UNIQUE INDEX \`IDX_${tablePrefix}943d8f922be094eb507cb9a7f9\` (\`name\`)`,
); );

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class AddUserSettings1652367743993 implements MigrationInterface {
name = 'AddUserSettings1652367743993';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddUserSettings1652367743993 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'user` ADD COLUMN `settings` json NULL DEFAULT NULL', 'ALTER TABLE `' + tablePrefix + 'user` ADD COLUMN `settings` json NULL DEFAULT NULL',
); );
@ -17,9 +12,7 @@ export class AddUserSettings1652367743993 implements MigrationInterface {
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query('ALTER TABLE `' + tablePrefix + 'user` DROP COLUMN `settings`'); await queryRunner.query('ALTER TABLE `' + tablePrefix + 'user` DROP COLUMN `settings`');
} }
} }

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class AddAPIKeyColumn1652905585850 implements MigrationInterface {
name = 'AddAPIKeyColumn1652905585850';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddAPIKeyColumn1652905585850 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'user` ADD COLUMN `apiKey` VARCHAR(255)', 'ALTER TABLE `' + tablePrefix + 'user` ADD COLUMN `apiKey` VARCHAR(255)',
); );
@ -19,8 +14,7 @@ export class AddAPIKeyColumn1652905585850 implements MigrationInterface {
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.get('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`DROP INDEX \`UQ_${tablePrefix}ie0zomxves9w3p774drfrkxtj5\` ON \`${tablePrefix}user\``, `DROP INDEX \`UQ_${tablePrefix}ie0zomxves9w3p774drfrkxtj5\` ON \`${tablePrefix}user\``,
); );

View file

@ -1,23 +1,11 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class IntroducePinData1654090101303 implements MigrationInterface {
name = 'IntroducePinData1654090101303';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class IntroducePinData1654090101303 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`ALTER TABLE \`${tablePrefix}workflow_entity\` ADD \`pinData\` json`); await queryRunner.query(`ALTER TABLE \`${tablePrefix}workflow_entity\` ADD \`pinData\` json`);
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`ALTER TABLE \`${tablePrefix}workflow_entity\` DROP COLUMN \`pinData\``, `ALTER TABLE \`${tablePrefix}workflow_entity\` DROP COLUMN \`pinData\``,
); );

View file

@ -1,16 +1,16 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; /* eslint-disable @typescript-eslint/restrict-template-expressions */
import config from '@/config'; /* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable n8n-local-rules/no-uncaught-json-parse */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { runInBatches } from '@db/utils/migrationHelpers'; import { runInBatches } from '@db/utils/migrationHelpers';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
// add node ids in workflow objects // add node ids in workflow objects
export class AddNodeIds1658932910559 implements MigrationInterface { export class AddNodeIds1658932910559 implements ReversibleMigration {
name = 'AddNodeIds1658932910559'; async up({ queryRunner, tablePrefix }: MigrationContext) {
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
@ -41,14 +41,12 @@ export class AddNodeIds1658932910559 implements MigrationInterface {
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); });
}); });
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
@ -71,7 +69,7 @@ export class AddNodeIds1658932910559 implements MigrationInterface {
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); });
}); });
} }

View file

@ -1,23 +1,15 @@
import { import type { MigrationContext, IrreversibleMigration } from '@db/types';
logMigrationStart, import { runInBatches } from '@db/utils/migrationHelpers';
logMigrationEnd,
runInBatches,
getTablePrefix,
} from '@db/utils/migrationHelpers';
import { addJsonKeyToPinDataColumn } from '../sqlite/1659888469333-AddJsonKeyPinData'; import { addJsonKeyToPinDataColumn } from '../sqlite/1659888469333-AddJsonKeyPinData';
import type { MigrationInterface, QueryRunner } from 'typeorm';
/** /**
* Convert JSON-type `pinData` column in `workflow_entity` table from * Convert JSON-type `pinData` column in `workflow_entity` table from
* `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }` * `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }`
*/ */
export class AddJsonKeyPinData1659895550980 implements MigrationInterface { export class AddJsonKeyPinData1659895550980 implements IrreversibleMigration {
name = 'AddJsonKeyPinData1659895550980'; async up(context: MigrationContext) {
const { queryRunner, tablePrefix } = context;
async up(queryRunner: QueryRunner) { const workflowTable = `${tablePrefix}workflow_entity`;
logMigrationStart(this.name);
const workflowTable = `${getTablePrefix()}workflow_entity`;
const PINDATA_SELECT_QUERY = ` const PINDATA_SELECT_QUERY = `
SELECT id, pinData SELECT id, pinData
@ -34,13 +26,7 @@ export class AddJsonKeyPinData1659895550980 implements MigrationInterface {
await runInBatches( await runInBatches(
queryRunner, queryRunner,
PINDATA_SELECT_QUERY, PINDATA_SELECT_QUERY,
addJsonKeyToPinDataColumn(queryRunner, PINDATA_UPDATE_STATEMENT), addJsonKeyToPinDataColumn(context, PINDATA_UPDATE_STATEMENT),
); );
logMigrationEnd(this.name);
}
async down() {
// irreversible migration
} }
} }

View file

@ -1,21 +1,14 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
export class CreateCredentialsUserRole1660062385367 implements MigrationInterface {
name = 'CreateCredentialsUserRole1660062385367';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class CreateCredentialsUserRole1660062385367 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(` await queryRunner.query(`
INSERT IGNORE INTO ${tablePrefix}role (name, scope) INSERT IGNORE INTO ${tablePrefix}role (name, scope)
VALUES ("user", "credential"); VALUES ("user", "credential");
`); `);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(` await queryRunner.query(`
DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='credential'; DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='credential';
`); `);

View file

@ -1,24 +1,14 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateWorkflowsEditorRole1663755770894 implements MigrationInterface {
name = 'CreateWorkflowsEditorRole1663755770894';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateWorkflowsEditorRole1663755770894 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(` await queryRunner.query(`
INSERT IGNORE INTO ${tablePrefix}role (name, scope) INSERT IGNORE INTO ${tablePrefix}role (name, scope)
VALUES ("editor", "workflow") VALUES ("editor", "workflow")
`); `);
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(` await queryRunner.query(`
DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='workflow'; DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='workflow';
`); `);

View file

@ -1,15 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '../../utils/migrationHelpers';
import config from '@/config';
export class WorkflowStatistics1664196174002 implements MigrationInterface {
name = 'WorkflowStatistics1664196174002';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class WorkflowStatistics1664196174002 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}workflow_statistics ( `CREATE TABLE ${tablePrefix}workflow_statistics (
count INTEGER DEFAULT 0, count INTEGER DEFAULT 0,
@ -25,13 +17,9 @@ export class WorkflowStatistics1664196174002 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN dataLoaded BOOLEAN DEFAULT false`, `ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN dataLoaded BOOLEAN DEFAULT false`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`DROP TABLE "${tablePrefix}workflow_statistics"`); await queryRunner.query(`DROP TABLE "${tablePrefix}workflow_statistics"`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN dataLoaded`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN dataLoaded`);
} }

View file

@ -1,20 +1,14 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateCredentialUsageTable1665484192213 implements MigrationInterface {
name = 'CreateCredentialUsageTable1665484192213';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateCredentialUsageTable1665484192213 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE \`${tablePrefix}credential_usage\` (` + `CREATE TABLE \`${tablePrefix}credential_usage\` (` +
'`workflowId` int NOT NULL,' + '`workflowId` int NOT NULL,' +
'`nodeId` char(200) NOT NULL,' + '`nodeId` char(200) NOT NULL,' +
"`credentialId` int NOT NULL DEFAULT '1'," + "`credentialId` int NOT NULL DEFAULT '1'," +
`\`createdAt\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,` + '`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,' +
`\`updatedAt\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,` + '`updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,' +
'PRIMARY KEY (`workflowId`, `nodeId`, `credentialId`)' + 'PRIMARY KEY (`workflowId`, `nodeId`, `credentialId`)' +
") ENGINE='InnoDB';", ") ENGINE='InnoDB';",
); );
@ -26,13 +20,9 @@ export class CreateCredentialUsageTable1665484192213 implements MigrationInterfa
await queryRunner.query( await queryRunner.query(
`ALTER TABLE \`${tablePrefix}credential_usage\` ADD CONSTRAINT \`FK_${tablePrefix}7ce200a20ade7ae89fa7901da896993f\` FOREIGN KEY (\`credentialId\`) REFERENCES \`${tablePrefix}credentials_entity\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE`, `ALTER TABLE \`${tablePrefix}credential_usage\` ADD CONSTRAINT \`FK_${tablePrefix}7ce200a20ade7ae89fa7901da896993f\` FOREIGN KEY (\`credentialId\`) REFERENCES \`${tablePrefix}credentials_entity\`(\`id\`) ON DELETE CASCADE ON UPDATE CASCADE`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE "${tablePrefix}credential_usage"`); await queryRunner.query(`DROP TABLE "${tablePrefix}credential_usage"`);
} }
} }

View file

@ -1,27 +1,18 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class RemoveCredentialUsageTable1665754637026 implements MigrationInterface { export class RemoveCredentialUsageTable1665754637026 implements ReversibleMigration {
name = 'RemoveCredentialUsageTable1665754637026'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE \`${tablePrefix}credential_usage\``); await queryRunner.query(`DROP TABLE \`${tablePrefix}credential_usage\``);
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`CREATE TABLE \`${tablePrefix}credential_usage\` (` + `CREATE TABLE \`${tablePrefix}credential_usage\` (` +
'`workflowId` int NOT NULL,' + '`workflowId` int NOT NULL,' +
'`nodeId` char(200) NOT NULL,' + '`nodeId` char(200) NOT NULL,' +
"`credentialId` int NOT NULL DEFAULT '1'," + "`credentialId` int NOT NULL DEFAULT '1'," +
`\`createdAt\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,` + '`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,' +
`\`updatedAt\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,` + '`updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,' +
'PRIMARY KEY (`workflowId`, `nodeId`, `credentialId`)' + 'PRIMARY KEY (`workflowId`, `nodeId`, `credentialId`)' +
") ENGINE='InnoDB';", ") ENGINE='InnoDB';",
); );

View file

@ -1,45 +1,31 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
export class AddWorkflowVersionIdColumn1669739707125 implements MigrationInterface { export class AddWorkflowVersionIdColumn1669739707125 implements ReversibleMigration {
name = 'AddWorkflowVersionIdColumn1669739707125'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN versionId CHAR(36)`, `ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN versionId CHAR(36)`,
); );
const workflowIds: Array<{ id: number }> = await queryRunner.query(` const workflowIds = (await queryRunner.query(`
SELECT id SELECT id
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
`); `)) as Array<{ id: number }>;
workflowIds.map(({ id }) => { for (const { id } of workflowIds) {
const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters( const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters(
` `UPDATE ${tablePrefix}workflow_entity
UPDATE ${tablePrefix}workflow_entity SET versionId = :versionId
SET versionId = :versionId WHERE id = '${id}'`,
WHERE id = '${id}'
`,
{ versionId: uuidv4() }, { versionId: uuidv4() },
{}, {},
); );
return queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); }
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN versionId`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN versionId`);
} }
} }

View file

@ -1,26 +1,14 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class AddTriggerCountColumn1669823906994 implements MigrationInterface {
name = 'AddTriggerCountColumn1669823906994';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddTriggerCountColumn1669823906994 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN triggerCount integer NOT NULL DEFAULT 0`, `ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN triggerCount integer NOT NULL DEFAULT 0`,
); );
// Table will be populated by n8n startup - see ActiveWorkflowRunner.ts // Table will be populated by n8n startup - see ActiveWorkflowRunner.ts
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN triggerCount`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN triggerCount`);
} }
} }

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '../../utils/migrationHelpers';
export class MessageEventBusDestinations1671535397530 implements MigrationInterface { export class MessageEventBusDestinations1671535397530 implements ReversibleMigration {
name = 'MessageEventBusDestinations1671535397530'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}event_destinations (` + `CREATE TABLE ${tablePrefix}event_destinations (` +
'`id` varchar(36) PRIMARY KEY NOT NULL,' + '`id` varchar(36) PRIMARY KEY NOT NULL,' +
@ -15,13 +10,9 @@ export class MessageEventBusDestinations1671535397530 implements MigrationInterf
'`updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP' + '`updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP' +
") ENGINE='InnoDB';", ") ENGINE='InnoDB';",
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE "${tablePrefix}event_destinations"`); await queryRunner.query(`DROP TABLE "${tablePrefix}event_destinations"`);
logMigrationEnd(this.name);
} }
} }

View file

@ -1,22 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; import { StatisticsNames } from '@/databases/entities/WorkflowStatistics';
import config from '@/config';
import { StatisticsNames } from '@db/entities/WorkflowStatistics';
export class RemoveWorkflowDataLoadedFlag1671726148420 implements MigrationInterface {
name = 'RemoveWorkflowDataLoadedFlag1671726148420';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class RemoveWorkflowDataLoadedFlag1671726148420 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
// If any existing workflow has dataLoaded set to true, insert the relevant information to the statistics table // If any existing workflow has dataLoaded set to true, insert the relevant information to the statistics table
const workflowIds: Array<{ id: number; dataLoaded: boolean }> = await queryRunner.query(` const workflowIds = (await queryRunner.query(`
SELECT id, dataLoaded SELECT id, dataLoaded
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
`); `)) as Array<{ id: number; dataLoaded: boolean }>;
workflowIds.map(({ id, dataLoaded }) => { workflowIds.map(async ({ id, dataLoaded }) => {
if (dataLoaded) { if (dataLoaded) {
const [insertQuery, insertParams] = queryRunner.connection.driver.escapeQueryWithParameters( const [insertQuery, insertParams] = queryRunner.connection.driver.escapeQueryWithParameters(
` `
@ -33,29 +26,27 @@ export class RemoveWorkflowDataLoadedFlag1671726148420 implements MigrationInter
}); });
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN dataLoaded`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN dataLoaded`);
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN dataLoaded BOOLEAN DEFAULT false`, `ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN dataLoaded BOOLEAN DEFAULT false`,
); );
// Search through statistics for any workflows that have the dataLoaded stat // Search through statistics for any workflows that have the dataLoaded stat
const workflowsIds: Array<{ workflowId: string }> = await queryRunner.query(` const workflowsIds = (await queryRunner.query(`
SELECT workflowId SELECT workflowId
FROM ${tablePrefix}workflow_statistics FROM ${tablePrefix}workflow_statistics
WHERE name = '${StatisticsNames.dataLoaded}' WHERE name = '${StatisticsNames.dataLoaded}'
`); `)) as Array<{ workflowId: string }>;
workflowsIds.map(({ workflowId }) => {
return queryRunner.query(` workflowsIds.map(async ({ workflowId }) =>
queryRunner.query(`
UPDATE ${tablePrefix}workflow_entity UPDATE ${tablePrefix}workflow_entity
SET dataLoaded = true SET dataLoaded = true
WHERE id = '${workflowId}'`); WHERE id = '${workflowId}'
}); `),
);
await queryRunner.query( await queryRunner.query(
`DELETE FROM ${tablePrefix}workflow_statistics WHERE name = '${StatisticsNames.dataLoaded}'`, `DELETE FROM ${tablePrefix}workflow_statistics WHERE name = '${StatisticsNames.dataLoaded}'`,

View file

@ -1,17 +1,12 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class DeleteExecutionsWithWorkflows1673268682475 implements MigrationInterface {
name = 'DeleteExecutionsWithWorkflows1673268682475';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class DeleteExecutionsWithWorkflows1673268682475 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`ALTER TABLE \`${tablePrefix}execution_entity\` MODIFY workflowId INT`); await queryRunner.query(`ALTER TABLE \`${tablePrefix}execution_entity\` MODIFY workflowId INT`);
const workflowIds: Array<{ id: number }> = await queryRunner.query(` const workflowIds = (await queryRunner.query(`
SELECT id FROM \`${tablePrefix}workflow_entity\` SELECT id FROM \`${tablePrefix}workflow_entity\`
`); `)) as Array<{ id: number }>;
await queryRunner.query( await queryRunner.query(
`DELETE FROM \`${tablePrefix}execution_entity\` `DELETE FROM \`${tablePrefix}execution_entity\`
@ -25,12 +20,9 @@ export class DeleteExecutionsWithWorkflows1673268682475 implements MigrationInte
FOREIGN KEY (\`workflowId\`) REFERENCES \`${tablePrefix}workflow_entity\`(\`id\`) FOREIGN KEY (\`workflowId\`) REFERENCES \`${tablePrefix}workflow_entity\`(\`id\`)
ON DELETE CASCADE`, ON DELETE CASCADE`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`ALTER TABLE \`${tablePrefix}execution_entity\` `ALTER TABLE \`${tablePrefix}execution_entity\`
DROP FOREIGN KEY \`FK_${tablePrefix}execution_entity_workflowId\``, DROP FOREIGN KEY \`FK_${tablePrefix}execution_entity_workflowId\``,

View file

@ -1,24 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class AddStatusToExecutions1674138566000 implements MigrationInterface {
name = 'AddStatusToExecutions1674138566000';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddStatusToExecutions1674138566000 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
// 'ALTER TABLE `' + tablePrefix + 'execution_entity` ADD COLUMN `status` varchar',
`ALTER TABLE \`${tablePrefix}execution_entity\` ADD COLUMN \`status\` VARCHAR(255)`, `ALTER TABLE \`${tablePrefix}execution_entity\` ADD COLUMN \`status\` VARCHAR(255)`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`ALTER TABLE \`${tablePrefix}execution_entity\` DROP COLUMN \`status\``); await queryRunner.query(`ALTER TABLE \`${tablePrefix}execution_entity\` DROP COLUMN \`status\``);
} }
} }

View file

@ -1,15 +1,8 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/Ldap/constants'; import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/Ldap/constants';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateLdapEntities1674509946020 implements MigrationInterface {
name = 'CreateLdapEntities1674509946020';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateLdapEntities1674509946020 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE \`${tablePrefix}user\` ADD COLUMN disabled BOOLEAN NOT NULL DEFAULT false;`, `ALTER TABLE \`${tablePrefix}user\` ADD COLUMN disabled BOOLEAN NOT NULL DEFAULT false;`,
); );
@ -46,12 +39,9 @@ export class CreateLdapEntities1674509946020 implements MigrationInterface {
PRIMARY KEY (\`id\`) PRIMARY KEY (\`id\`)
) ENGINE='InnoDB';`, ) ENGINE='InnoDB';`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE \`${tablePrefix}auth_provider_sync_history\``); await queryRunner.query(`DROP TABLE \`${tablePrefix}auth_provider_sync_history\``);
await queryRunner.query(`DROP TABLE \`${tablePrefix}auth_identity\``); await queryRunner.query(`DROP TABLE \`${tablePrefix}auth_identity\``);

View file

@ -1,36 +1,29 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { IConnections, INode } from 'n8n-workflow';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; import { jsonParse } from 'n8n-workflow';
import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { NodeTypes } from '@/NodeTypes'; import { NodeTypes } from '@/NodeTypes';
import { IConnections, INode } from 'n8n-workflow';
import { getLogger } from '@/Logger';
import { Container } from 'typedi'; import { Container } from 'typedi';
export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationInterface { export class PurgeInvalidWorkflowConnections1675940580449 implements IrreversibleMigration {
name = 'PurgeInvalidWorkflowConnections1675940580449'; async up({ queryRunner, tablePrefix, migrationName, logger }: MigrationContext) {
const workflows = (await queryRunner.query(`
async up(queryRunner: QueryRunner): Promise<void> { SELECT id, nodes, connections
logMigrationStart(this.name); FROM \`${tablePrefix}workflow_entity\`
`)) as Array<{
const tablePrefix = getTablePrefix();
const workflows: Array<{
id: number; id: number;
nodes: INode[] | string; nodes: INode[] | string;
connections: IConnections | string; connections: IConnections | string;
}> = await queryRunner.query(` }>;
SELECT id, nodes, connections
FROM \`${tablePrefix}workflow_entity\`
`);
const nodeTypes = Container.get(NodeTypes); const nodeTypes = Container.get(NodeTypes);
workflows.forEach(async (workflow) => { workflows.forEach(async (workflow) => {
let connections: IConnections = const connections =
typeof workflow.connections === 'string' typeof workflow.connections === 'string'
? JSON.parse(workflow.connections) ? jsonParse<IConnections>(workflow.connections)
: workflow.connections; : workflow.connections;
const nodes: INode[] = const nodes =
typeof workflow.nodes === 'string' ? JSON.parse(workflow.nodes) : workflow.nodes; typeof workflow.nodes === 'string' ? jsonParse<INode[]>(workflow.nodes) : workflow.nodes;
const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => { const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => {
try { try {
@ -39,7 +32,7 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
acc.push(node.name); acc.push(node.name);
} }
} catch (error) { } catch (error) {
getLogger().warn(`Migration ${this.name} failed with error: ${error.message}`); logger.warn(`Migration ${migrationName} failed with error: ${(error as Error).message}`);
} }
return acc; return acc;
}, [] as string[]); }, [] as string[]);
@ -48,7 +41,7 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
const connection = connections[sourceNodeName]; const connection = connections[sourceNodeName];
const outputs = Object.keys(connection); const outputs = Object.keys(connection);
outputs.forEach((outputConnectionName /* Like `main` */, idx) => { outputs.forEach((outputConnectionName /* Like `main` */) => {
const outputConnection = connection[outputConnectionName]; const outputConnection = connection[outputConnectionName];
// It filters out all connections that are connected to a node that cannot receive input // It filters out all connections that are connected to a node that cannot receive input
@ -63,22 +56,14 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
// Update database with new connections // Update database with new connections
const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters( const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters(
` `UPDATE \`${tablePrefix}workflow_entity\`
UPDATE \`${tablePrefix}workflow_entity\` SET connections = :connections
SET connections = :connections WHERE id = '${workflow.id}'`,
WHERE id = '${workflow.id}'
`,
{ connections: JSON.stringify(connections) }, { connections: JSON.stringify(connections) },
{}, {},
); );
await queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); });
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
// No need to revert this migration
} }
} }

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class MigrateExecutionStatus1676996103000 implements MigrationInterface {
name = 'MigrateExecutionStatus1676996103000';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class MigrateExecutionStatus1676996103000 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`UPDATE \`${tablePrefix}execution_entity\` SET status='waiting' WHERE status IS NULL AND \`waitTill\` IS NOT NULL;`, `UPDATE \`${tablePrefix}execution_entity\` SET status='waiting' WHERE status IS NULL AND \`waitTill\` IS NOT NULL;`,
); );
@ -20,9 +14,5 @@ export class MigrateExecutionStatus1676996103000 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`UPDATE \`${tablePrefix}execution_entity\` SET status='crashed' WHERE status IS NULL;`, `UPDATE \`${tablePrefix}execution_entity\` SET status='crashed' WHERE status IS NULL;`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> {}
} }

View file

@ -1,22 +1,12 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class UpdateRunningExecutionStatus1677236788851 implements MigrationInterface {
name = 'UpdateRunningExecutionStatus1677236788851';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class UpdateRunningExecutionStatus1677236788851 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`UPDATE \`${tablePrefix}execution_entity\` SET status='failed' WHERE status = 'running' AND finished=0 AND \`stoppedAt\` IS NOT NULL;`, `UPDATE \`${tablePrefix}execution_entity\` SET status='failed' WHERE status = 'running' AND finished=0 AND \`stoppedAt\` IS NOT NULL;`,
); );
await queryRunner.query( await queryRunner.query(
`UPDATE \`${tablePrefix}execution_entity\` SET status='success' WHERE status = 'running' AND finished=1 AND \`stoppedAt\` IS NOT NULL;`, `UPDATE \`${tablePrefix}execution_entity\` SET status='success' WHERE status = 'running' AND finished=1 AND \`stoppedAt\` IS NOT NULL;`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> {}
} }

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart, getTablePrefix } from '@db/utils/migrationHelpers';
import config from '@/config';
export class CreateVariables1677501636753 implements MigrationInterface {
name = 'CreateVariables1677501636753';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateVariables1677501636753 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(` await queryRunner.query(`
CREATE TABLE ${tablePrefix}variables ( CREATE TABLE ${tablePrefix}variables (
id int(11) auto_increment NOT NULL PRIMARY KEY, id int(11) auto_increment NOT NULL PRIMARY KEY,
@ -18,16 +12,9 @@ export class CreateVariables1677501636753 implements MigrationInterface {
) )
ENGINE=InnoDB; ENGINE=InnoDB;
`); `);
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE ${tablePrefix}variables;`); await queryRunner.query(`DROP TABLE ${tablePrefix}variables;`);
logMigrationEnd(this.name);
} }
} }

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner, Table } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateExecutionMetadataTable1679416281779 implements MigrationInterface {
name = 'CreateExecutionMetadataTable1679416281779';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateExecutionMetadataTable1679416281779 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}execution_metadata ( `CREATE TABLE ${tablePrefix}execution_metadata (
id int(11) auto_increment NOT NULL PRIMARY KEY, id int(11) auto_increment NOT NULL PRIMARY KEY,
@ -38,13 +32,9 @@ export class CreateExecutionMetadataTable1679416281779 implements MigrationInter
await queryRunner.query( await queryRunner.query(
`CREATE INDEX \`IDX_${tablePrefix}8b6f3f9ae234f137d707b98f3bf43584\` ON \`${tablePrefix}execution_entity\` (\`status\`, \`workflowId\`)`, `CREATE INDEX \`IDX_${tablePrefix}8b6f3f9ae234f137d707b98f3bf43584\` ON \`${tablePrefix}execution_entity\` (\`status\`, \`workflowId\`)`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE "${tablePrefix}execution_metadata"`); await queryRunner.query(`DROP TABLE "${tablePrefix}execution_metadata"`);
await queryRunner.query( await queryRunner.query(
`CREATE INDEX \`IDX_${tablePrefix}06da892aaf92a48e7d3e400003\` ON \`${tablePrefix}execution_entity\` (\`workflowId\`, \`waitTill\`, \`id\`)`, `CREATE INDEX \`IDX_${tablePrefix}06da892aaf92a48e7d3e400003\` ON \`${tablePrefix}execution_entity\` (\`workflowId\`, \`waitTill\`, \`id\`)`,

View file

@ -1,16 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { UserSettings } from '@/Interfaces'; import type { UserSettings } from '@/Interfaces';
export class AddUserActivatedProperty1681134145996 implements MigrationInterface { export class AddUserActivatedProperty1681134145996 implements ReversibleMigration {
name = 'AddUserActivatedProperty1681134145996'; async up({ queryRunner, tablePrefix }: MigrationContext) {
const activatedUsers = (await queryRunner.query(
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
const activatedUsers: UserSettings[] = await queryRunner.query(
`SELECT DISTINCT sw.userId AS id, `SELECT DISTINCT sw.userId AS id,
JSON_SET(COALESCE(u.settings, '{}'), '$.userActivated', true) AS settings JSON_SET(COALESCE(u.settings, '{}'), '$.userActivated', true) AS settings
FROM ${tablePrefix}workflow_statistics AS ws FROM ${tablePrefix}workflow_statistics AS ws
@ -23,15 +16,15 @@ export class AddUserActivatedProperty1681134145996 implements MigrationInterface
WHERE ws.name = 'production_success' WHERE ws.name = 'production_success'
AND r.name = 'owner' AND r.name = 'owner'
AND r.scope = 'workflow'`, AND r.scope = 'workflow'`,
); )) as UserSettings[];
const updatedUsers = activatedUsers.map((user) => { const updatedUsers = activatedUsers.map(async (user) => {
/* /*
MariaDB returns settings as a string and MySQL as a JSON MariaDB returns settings as a string and MySQL as a JSON
*/ */
const userSettings = const userSettings =
typeof user.settings === 'string' ? user.settings : JSON.stringify(user.settings); typeof user.settings === 'string' ? user.settings : JSON.stringify(user.settings);
queryRunner.query( await queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = '${userSettings}' WHERE id = '${user.id}' `, `UPDATE ${tablePrefix}user SET settings = '${userSettings}' WHERE id = '${user.id}' `,
); );
}); });
@ -49,12 +42,9 @@ export class AddUserActivatedProperty1681134145996 implements MigrationInterface
`UPDATE ${tablePrefix}user SET settings = JSON_SET(COALESCE(settings, '{}'), '$.userActivated', false) WHERE id NOT IN (${activatedUserIds})`, `UPDATE ${tablePrefix}user SET settings = JSON_SET(COALESCE(settings, '{}'), '$.userActivated', false) WHERE id NOT IN (${activatedUserIds})`,
); );
} }
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`UPDATE ${tablePrefix}user SET settings = JSON_REMOVE(settings, '$.userActivated')`, `UPDATE ${tablePrefix}user SET settings = JSON_REMOVE(settings, '$.userActivated')`,
); );

View file

@ -1,3 +1,4 @@
import type { Migration } from '@db/types';
import { InitialMigration1588157391238 } from './1588157391238-InitialMigration'; import { InitialMigration1588157391238 } from './1588157391238-InitialMigration';
import { WebhookModel1592447867632 } from './1592447867632-WebhookModel'; import { WebhookModel1592447867632 } from './1592447867632-WebhookModel';
import { CreateIndexStoppedAt1594902918301 } from './1594902918301-CreateIndexStoppedAt'; import { CreateIndexStoppedAt1594902918301 } from './1594902918301-CreateIndexStoppedAt';
@ -38,7 +39,7 @@ import { CreateExecutionMetadataTable1679416281779 } from './1679416281779-Creat
import { CreateVariables1677501636753 } from './1677501636753-CreateVariables'; import { CreateVariables1677501636753 } from './1677501636753-CreateVariables';
import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty'; import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty';
export const mysqlMigrations = [ export const mysqlMigrations: Migration[] = [
InitialMigration1588157391238, InitialMigration1588157391238,
WebhookModel1592447867632, WebhookModel1592447867632,
CreateIndexStoppedAt1594902918301, CreateIndexStoppedAt1594902918301,

View file

@ -1,41 +1,29 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class InitialMigration1587669153312 implements MigrationInterface {
name = 'InitialMigration1587669153312';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class InitialMigration1587669153312 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS ${tablePrefix}credentials_entity ("id" SERIAL NOT NULL, "name" character varying(128) NOT NULL, "data" text NOT NULL, "type" character varying(32) NOT NULL, "nodesAccess" json NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, CONSTRAINT PK_${tablePrefix}814c3d3c36e8a27fa8edb761b0e PRIMARY KEY ("id"))`, `CREATE TABLE IF NOT EXISTS ${tablePrefix}credentials_entity ("id" SERIAL NOT NULL, "name" character varying(128) NOT NULL, "data" text NOT NULL, "type" character varying(32) NOT NULL, "nodesAccess" json NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, CONSTRAINT PK_${tablePrefix}814c3d3c36e8a27fa8edb761b0e PRIMARY KEY ("id"))`,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8 ON ${tablePrefix}credentials_entity (type) `, `CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8 ON ${tablePrefix}credentials_entity (type) `,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS ${tablePrefix}execution_entity ("id" SERIAL NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" character varying NOT NULL, "retryOf" character varying, "retrySuccessId" character varying, "startedAt" TIMESTAMP NOT NULL, "stoppedAt" TIMESTAMP NOT NULL, "workflowData" json NOT NULL, "workflowId" character varying, CONSTRAINT PK_${tablePrefix}e3e63bbf986767844bbe1166d4e PRIMARY KEY ("id"))`, `CREATE TABLE IF NOT EXISTS ${tablePrefix}execution_entity ("id" SERIAL NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" character varying NOT NULL, "retryOf" character varying, "retrySuccessId" character varying, "startedAt" TIMESTAMP NOT NULL, "stoppedAt" TIMESTAMP NOT NULL, "workflowData" json NOT NULL, "workflowId" character varying, CONSTRAINT PK_${tablePrefix}e3e63bbf986767844bbe1166d4e PRIMARY KEY ("id"))`,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}c4d999a5e90784e8caccf5589d ON ${tablePrefix}execution_entity ("workflowId") `, `CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}c4d999a5e90784e8caccf5589d ON ${tablePrefix}execution_entity ("workflowId") `,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS ${tablePrefix}workflow_entity ("id" SERIAL NOT NULL, "name" character varying(128) NOT NULL, "active" boolean NOT NULL, "nodes" json NOT NULL, "connections" json NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, "settings" json, "staticData" json, CONSTRAINT PK_${tablePrefix}eded7d72664448da7745d551207 PRIMARY KEY ("id"))`, `CREATE TABLE IF NOT EXISTS ${tablePrefix}workflow_entity ("id" SERIAL NOT NULL, "name" character varying(128) NOT NULL, "active" boolean NOT NULL, "nodes" json NOT NULL, "connections" json NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, "settings" json, "staticData" json, CONSTRAINT PK_${tablePrefix}eded7d72664448da7745d551207 PRIMARY KEY ("id"))`,
undefined,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
let tablePrefix = getTablePrefix(); await queryRunner.query(`DROP TABLE ${tablePrefix}workflow_entity`);
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}c4d999a5e90784e8caccf5589d`);
await queryRunner.query(`DROP TABLE ${tablePrefix}workflow_entity`, undefined); await queryRunner.query(`DROP TABLE ${tablePrefix}execution_entity`);
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}c4d999a5e90784e8caccf5589d`, undefined); await queryRunner.query(`DROP INDEX IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8`);
await queryRunner.query(`DROP TABLE ${tablePrefix}execution_entity`, undefined); await queryRunner.query(`DROP TABLE ${tablePrefix}credentials_entity`);
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8`, undefined);
await queryRunner.query(`DROP TABLE ${tablePrefix}credentials_entity`, undefined);
} }
} }

View file

@ -1,19 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class WebhookModel1589476000887 implements MigrationInterface { export class WebhookModel1589476000887 implements ReversibleMigration {
name = 'WebhookModel1589476000887'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS ${tablePrefix}webhook_entity ("workflowId" integer NOT NULL, "webhookPath" character varying NOT NULL, "method" character varying NOT NULL, "node" character varying NOT NULL, CONSTRAINT "PK_${tablePrefix}b21ace2e13596ccd87dc9bf4ea6" PRIMARY KEY ("webhookPath", "method"))`, `CREATE TABLE IF NOT EXISTS ${tablePrefix}webhook_entity ("workflowId" integer NOT NULL, "webhookPath" character varying NOT NULL, "method" character varying NOT NULL, "node" character varying NOT NULL, CONSTRAINT "PK_${tablePrefix}b21ace2e13596ccd87dc9bf4ea6" PRIMARY KEY ("webhookPath", "method"))`,
undefined,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix(); await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`);
await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`, undefined);
} }
} }

View file

@ -1,18 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class CreateIndexStoppedAt1594828256133 implements MigrationInterface { export class CreateIndexStoppedAt1594828256133 implements ReversibleMigration {
name = 'CreateIndexStoppedAt1594828256133'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}33228da131bb1112247cf52a42 ON ${tablePrefix}execution_entity ("stoppedAt") `, `CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}33228da131bb1112247cf52a42 ON ${tablePrefix}execution_entity ("stoppedAt") `,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}33228da131bb1112247cf52a42`); await queryRunner.query(`DROP INDEX IDX_${tablePrefix}33228da131bb1112247cf52a42`);
} }
} }

View file

@ -1,18 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class MakeStoppedAtNullable1607431743768 implements MigrationInterface { export class MakeStoppedAtNullable1607431743768 implements IrreversibleMigration {
name = 'MakeStoppedAtNullable1607431743768'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
'ALTER TABLE ' + tablePrefix + 'execution_entity ALTER COLUMN "stoppedAt" DROP NOT NULL', 'ALTER TABLE ' + tablePrefix + 'execution_entity ALTER COLUMN "stoppedAt" DROP NOT NULL',
undefined,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> {
// Cannot be undone as column might already have null values
}
} }

View file

@ -1,11 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class AddWebhookId1611144599516 implements MigrationInterface { export class AddWebhookId1611144599516 implements ReversibleMigration {
name = 'AddWebhookId1611144599516'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}webhook_entity ADD "webhookId" character varying`, `ALTER TABLE ${tablePrefix}webhook_entity ADD "webhookId" character varying`,
); );
@ -15,8 +11,7 @@ export class AddWebhookId1611144599516 implements MigrationInterface {
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}16f4436789e804e3e1c9eeb240`); await queryRunner.query(`DROP INDEX IDX_${tablePrefix}16f4436789e804e3e1c9eeb240`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}webhook_entity DROP COLUMN "pathLength"`); await queryRunner.query(`ALTER TABLE ${tablePrefix}webhook_entity DROP COLUMN "pathLength"`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}webhook_entity DROP COLUMN "webhookId"`); await queryRunner.query(`ALTER TABLE ${tablePrefix}webhook_entity DROP COLUMN "webhookId"`);

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class CreateTagEntity1617270242566 implements MigrationInterface {
name = 'CreateTagEntity1617270242566';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class CreateTagEntity1617270242566 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
// create tags table + relationship with workflow entity // create tags table + relationship with workflow entity
await queryRunner.query( await queryRunner.query(
@ -72,9 +67,7 @@ export class CreateTagEntity1617270242566 implements MigrationInterface {
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
// `createdAt` and `updatedAt` // `createdAt` and `updatedAt`
await queryRunner.query( await queryRunner.query(

View file

@ -1,16 +1,11 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class UniqueWorkflowNames1620824779533 implements MigrationInterface { export class UniqueWorkflowNames1620824779533 implements ReversibleMigration {
name = 'UniqueWorkflowNames1620824779533'; async up({ queryRunner, tablePrefix }: MigrationContext) {
const workflowNames = (await queryRunner.query(`
async up(queryRunner: QueryRunner): Promise<void> { SELECT name
const tablePrefix = getTablePrefix(); FROM ${tablePrefix}workflow_entity
`)) as Array<{ name: string }>;
const workflowNames = await queryRunner.query(`
SELECT name
FROM ${tablePrefix}workflow_entity
`);
for (const { name } of workflowNames) { for (const { name } of workflowNames) {
const [duplicatesQuery, parameters] = queryRunner.connection.driver.escapeQueryWithParameters( const [duplicatesQuery, parameters] = queryRunner.connection.driver.escapeQueryWithParameters(
@ -24,19 +19,22 @@ export class UniqueWorkflowNames1620824779533 implements MigrationInterface {
{}, {},
); );
const duplicates = await queryRunner.query(duplicatesQuery, parameters); const duplicates = (await queryRunner.query(duplicatesQuery, parameters)) as Array<{
id: number;
name: string;
}>;
if (duplicates.length > 1) { if (duplicates.length > 1) {
await Promise.all( await Promise.all(
duplicates.map(({ id, name }: { id: number; name: string }, index: number) => { // eslint-disable-next-line @typescript-eslint/no-shadow
if (index === 0) return Promise.resolve(); duplicates.map(async ({ id, name }, index: number) => {
if (index === 0) return;
const [updateQuery, updateParams] = const [updateQuery, updateParams] =
queryRunner.connection.driver.escapeQueryWithParameters( queryRunner.connection.driver.escapeQueryWithParameters(
` `UPDATE ${tablePrefix}workflow_entity
UPDATE ${tablePrefix}workflow_entity SET name = :name
SET name = :name WHERE id = '${id}'
WHERE id = '${id}' `,
`,
{ name: `${name} ${index + 1}` }, { name: `${name} ${index + 1}` },
{}, {},
); );
@ -52,8 +50,7 @@ export class UniqueWorkflowNames1620824779533 implements MigrationInterface {
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}a252c527c4c89237221fe2c0ab"`); await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}a252c527c4c89237221fe2c0ab"`);
} }
} }

View file

@ -1,19 +1,14 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class AddwaitTill1626176912946 implements MigrationInterface { export class AddwaitTill1626176912946 implements ReversibleMigration {
name = 'AddwaitTill1626176912946'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query(`ALTER TABLE ${tablePrefix}execution_entity ADD "waitTill" TIMESTAMP`); await queryRunner.query(`ALTER TABLE ${tablePrefix}execution_entity ADD "waitTill" TIMESTAMP`);
await queryRunner.query( await queryRunner.query(
`CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2 ON ${tablePrefix}execution_entity ("waitTill")`, `CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2 ON ${tablePrefix}execution_entity ("waitTill")`,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2`); await queryRunner.query(`DROP INDEX IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}webhook_entity DROP COLUMN "waitTill"`); await queryRunner.query(`ALTER TABLE ${tablePrefix}webhook_entity DROP COLUMN "waitTill"`);
} }

View file

@ -1,19 +1,21 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; /* eslint-disable @typescript-eslint/restrict-template-expressions */
import { getTablePrefix, runInBatches } from '@db/utils/migrationHelpers'; /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { runInBatches } from '@db/utils/migrationHelpers';
// replacing the credentials in workflows and execution // replacing the credentials in workflows and execution
// `nodeType: name` changes to `nodeType: { id, name }` // `nodeType: name` changes to `nodeType: { id, name }`
export class UpdateWorkflowCredentials1630419189837 implements MigrationInterface { export class UpdateWorkflowCredentials1630419189837 implements ReversibleMigration {
name = 'UpdateWorkflowCredentials1630419189837'; async up({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
const credentialsEntities = await queryRunner.query(`
SELECT id, name, type SELECT id, name, type
FROM ${tablePrefix}credentials_entity FROM ${tablePrefix}credentials_entity
`); `)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
@ -53,7 +55,7 @@ export class UpdateWorkflowCredentials1630419189837 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -96,7 +98,7 @@ export class UpdateWorkflowCredentials1630419189837 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -141,18 +143,16 @@ export class UpdateWorkflowCredentials1630419189837 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix(); const credentialsEntities = (await queryRunner.query(`
const credentialsEntities = await queryRunner.query(`
SELECT id, name, type SELECT id, name, type
FROM ${tablePrefix}credentials_entity FROM ${tablePrefix}credentials_entity
`); `)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
@ -197,7 +197,7 @@ export class UpdateWorkflowCredentials1630419189837 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -246,7 +246,7 @@ export class UpdateWorkflowCredentials1630419189837 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -295,7 +295,7 @@ export class UpdateWorkflowCredentials1630419189837 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
} }

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class AddExecutionEntityIndexes1644422880309 implements MigrationInterface {
name = 'AddExecutionEntityIndexes1644422880309';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class AddExecutionEntityIndexes1644422880309 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP INDEX IF EXISTS IDX_${tablePrefix}c4d999a5e90784e8caccf5589d`); await queryRunner.query(`DROP INDEX IF EXISTS IDX_${tablePrefix}c4d999a5e90784e8caccf5589d`);
await queryRunner.query(`DROP INDEX IF EXISTS IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2`); await queryRunner.query(`DROP INDEX IF EXISTS IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2`);
await queryRunner.query( await queryRunner.query(
@ -29,9 +24,7 @@ export class AddExecutionEntityIndexes1644422880309 implements MigrationInterfac
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}d160d4771aba5a0d78943edbe3"`); await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}d160d4771aba5a0d78943edbe3"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}85b981df7b444f905f8bf50747"`); await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}85b981df7b444f905f8bf50747"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}72ffaaab9f04c2c1f1ea86e662"`); await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}72ffaaab9f04c2c1f1ea86e662"`);

View file

@ -1,15 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class IncreaseTypeVarcharLimit1646834195327 implements MigrationInterface { export class IncreaseTypeVarcharLimit1646834195327 implements IrreversibleMigration {
name = 'IncreaseTypeVarcharLimit1646834195327'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "type" TYPE VARCHAR(128)`, `ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "type" TYPE VARCHAR(128)`,
); );
} }
async down(queryRunner: QueryRunner): Promise<void> {}
} }

View file

@ -1,13 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { InsertResult, MigrationContext, ReversibleMigration } from '@db/types';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { getTablePrefix, loadSurveyFromDisk } from '@db/utils/migrationHelpers'; import { loadSurveyFromDisk } from '@db/utils/migrationHelpers';
export class CreateUserManagement1646992772331 implements MigrationInterface {
name = 'CreateUserManagement1646992772331';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class CreateUserManagement1646992772331 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}role ( `CREATE TABLE ${tablePrefix}role (
"id" serial NOT NULL, "id" serial NOT NULL,
@ -92,7 +88,9 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
`INSERT INTO ${tablePrefix}role (name, scope) VALUES ('owner', 'global');`, `INSERT INTO ${tablePrefix}role (name, scope) VALUES ('owner', 'global');`,
); );
const instanceOwnerRole = await queryRunner.query('SELECT lastval() as "insertId"'); const instanceOwnerRole = (await queryRunner.query(
'SELECT lastval() as "insertId"',
)) as InsertResult;
await queryRunner.query( await queryRunner.query(
`INSERT INTO ${tablePrefix}role (name, scope) VALUES ('member', 'global');`, `INSERT INTO ${tablePrefix}role (name, scope) VALUES ('member', 'global');`,
@ -102,13 +100,17 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
`INSERT INTO ${tablePrefix}role (name, scope) VALUES ('owner', 'workflow');`, `INSERT INTO ${tablePrefix}role (name, scope) VALUES ('owner', 'workflow');`,
); );
const workflowOwnerRole = await queryRunner.query('SELECT lastval() as "insertId"'); const workflowOwnerRole = (await queryRunner.query(
'SELECT lastval() as "insertId"',
)) as InsertResult;
await queryRunner.query( await queryRunner.query(
`INSERT INTO ${tablePrefix}role (name, scope) VALUES ('owner', 'credential');`, `INSERT INTO ${tablePrefix}role (name, scope) VALUES ('owner', 'credential');`,
); );
const credentialOwnerRole = await queryRunner.query('SELECT lastval() as "insertId"'); const credentialOwnerRole = (await queryRunner.query(
'SELECT lastval() as "insertId"',
)) as InsertResult;
const survey = loadSurveyFromDisk(); const survey = loadSurveyFromDisk();
@ -133,9 +135,7 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_${tablePrefix}a252c527c4c89237221fe2c0ab" ON ${tablePrefix}workflow_entity ("name")`, `CREATE UNIQUE INDEX "IDX_${tablePrefix}a252c527c4c89237221fe2c0ab" ON ${tablePrefix}workflow_entity ("name")`,
); );

View file

@ -1,16 +1,10 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class LowerCaseUserEmail1648740597343 implements MigrationInterface { export class LowerCaseUserEmail1648740597343 implements IrreversibleMigration {
name = 'LowerCaseUserEmail1648740597343'; async up({ queryRunner, tablePrefix }: MigrationContext) {
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query(` await queryRunner.query(`
UPDATE "${tablePrefix}user" UPDATE "${tablePrefix}user"
SET email = LOWER(email); SET email = LOWER(email);
`); `);
} }
public async down(queryRunner: QueryRunner): Promise<void> {}
} }

View file

@ -1,14 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CommunityNodes1652254514002 implements MigrationInterface {
name = 'CommunityNodes1652254514002';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CommunityNodes1652254514002 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}installed_packages (` + `CREATE TABLE ${tablePrefix}installed_packages (` +
'"packageName" VARCHAR(214) NOT NULL,' + '"packageName" VARCHAR(214) NOT NULL,' +
@ -31,11 +24,9 @@ export class CommunityNodes1652254514002 implements MigrationInterface {
`CONSTRAINT "FK_${tablePrefix}73f857fc5dce682cef8a99c11dbddbc969618951" FOREIGN KEY ("package") REFERENCES ${tablePrefix}installed_packages ("packageName") ON DELETE CASCADE ON UPDATE CASCADE ` + `CONSTRAINT "FK_${tablePrefix}73f857fc5dce682cef8a99c11dbddbc969618951" FOREIGN KEY ("package") REFERENCES ${tablePrefix}installed_packages ("packageName") ON DELETE CASCADE ON UPDATE CASCADE ` +
');', ');',
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE "${tablePrefix}installed_nodes"`); await queryRunner.query(`DROP TABLE "${tablePrefix}installed_nodes"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}installed_packages"`); await queryRunner.query(`DROP TABLE "${tablePrefix}installed_packages"`);
} }

View file

@ -1,12 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class AddUserSettings1652367743993 implements MigrationInterface {
name = 'AddUserSettings1652367743993';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class AddUserSettings1652367743993 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" ADD COLUMN settings json`); await queryRunner.query(`ALTER TABLE "${tablePrefix}user" ADD COLUMN settings json`);
await queryRunner.query( await queryRunner.query(
@ -14,8 +9,7 @@ export class AddUserSettings1652367743993 implements MigrationInterface {
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" DROP COLUMN settings`); await queryRunner.query(`ALTER TABLE "${tablePrefix}user" DROP COLUMN settings`);
} }
} }

View file

@ -1,19 +1,14 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class AddAPIKeyColumn1652905585850 implements MigrationInterface { export class AddAPIKeyColumn1652905585850 implements ReversibleMigration {
name = 'AddAPIKeyColumn1652905585850'; async up({ queryRunner, tablePrefix }: MigrationContext) {
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" ADD COLUMN "apiKey" VARCHAR(255)`); await queryRunner.query(`ALTER TABLE "${tablePrefix}user" ADD COLUMN "apiKey" VARCHAR(255)`);
await queryRunner.query( await queryRunner.query(
`CREATE UNIQUE INDEX "UQ_${tablePrefix}ie0zomxves9w3p774drfrkxtj5" ON "${tablePrefix}user" ("apiKey")`, `CREATE UNIQUE INDEX "UQ_${tablePrefix}ie0zomxves9w3p774drfrkxtj5" ON "${tablePrefix}user" ("apiKey")`,
); );
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP INDEX "UQ_${tablePrefix}ie0zomxves9w3p774drfrkxtj5"`); await queryRunner.query(`DROP INDEX "UQ_${tablePrefix}ie0zomxves9w3p774drfrkxtj5"`);
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" DROP COLUMN "apiKey"`); await queryRunner.query(`ALTER TABLE "${tablePrefix}user" DROP COLUMN "apiKey"`);
} }

View file

@ -1,20 +1,11 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class IntroducePinData1654090467022 implements MigrationInterface { export class IntroducePinData1654090467022 implements ReversibleMigration {
name = 'IntroducePinData1654090467022'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ADD "pinData" json`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ADD "pinData" json`);
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN "pinData"`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN "pinData"`);
} }
} }

View file

@ -1,15 +1,16 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; /* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable n8n-local-rules/no-uncaught-json-parse */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { getTablePrefix, runInBatches } from '@db/utils/migrationHelpers'; import { runInBatches } from '@db/utils/migrationHelpers';
// add node ids in workflow objects // add node ids in workflow objects
export class AddNodeIds1658932090381 implements MigrationInterface { export class AddNodeIds1658932090381 implements ReversibleMigration {
name = 'AddNodeIds1658932090381'; async up({ queryRunner, tablePrefix }: MigrationContext) {
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
@ -36,14 +37,12 @@ export class AddNodeIds1658932090381 implements MigrationInterface {
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); });
}); });
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
@ -57,16 +56,14 @@ export class AddNodeIds1658932090381 implements MigrationInterface {
nodes.forEach((node) => delete node.id); nodes.forEach((node) => delete node.id);
const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters( const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters(
` `UPDATE ${tablePrefix}workflow_entity
UPDATE ${tablePrefix}workflow_entity SET nodes = :nodes
SET nodes = :nodes WHERE id = '${workflow.id}'`,
WHERE id = '${workflow.id}'
`,
{ nodes: JSON.stringify(nodes) }, { nodes: JSON.stringify(nodes) },
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); });
}); });
} }

View file

@ -1,23 +1,15 @@
import { import type { MigrationContext, IrreversibleMigration } from '@/databases/types';
getTablePrefix, import { runInBatches } from '@db/utils/migrationHelpers';
logMigrationEnd,
logMigrationStart,
runInBatches,
} from '@db/utils/migrationHelpers';
import { addJsonKeyToPinDataColumn } from '../sqlite/1659888469333-AddJsonKeyPinData'; import { addJsonKeyToPinDataColumn } from '../sqlite/1659888469333-AddJsonKeyPinData';
import type { MigrationInterface, QueryRunner } from 'typeorm';
/** /**
* Convert JSON-type `pinData` column in `workflow_entity` table from * Convert JSON-type `pinData` column in `workflow_entity` table from
* `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }` * `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }`
*/ */
export class AddJsonKeyPinData1659902242948 implements MigrationInterface { export class AddJsonKeyPinData1659902242948 implements IrreversibleMigration {
name = 'AddJsonKeyPinData1659902242948'; async up(context: MigrationContext) {
const { queryRunner, tablePrefix } = context;
async up(queryRunner: QueryRunner) { const workflowTable = `${tablePrefix}workflow_entity`;
logMigrationStart(this.name);
const workflowTable = `${getTablePrefix()}workflow_entity`;
const PINDATA_SELECT_QUERY = ` const PINDATA_SELECT_QUERY = `
SELECT id, "pinData" SELECT id, "pinData"
@ -34,13 +26,7 @@ export class AddJsonKeyPinData1659902242948 implements MigrationInterface {
await runInBatches( await runInBatches(
queryRunner, queryRunner,
PINDATA_SELECT_QUERY, PINDATA_SELECT_QUERY,
addJsonKeyToPinDataColumn(queryRunner, PINDATA_UPDATE_STATEMENT), addJsonKeyToPinDataColumn(context, PINDATA_UPDATE_STATEMENT),
); );
logMigrationEnd(this.name);
}
async down() {
// irreversible migration
} }
} }

View file

@ -1,11 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class CreateCredentialsUserRole1660062385367 implements MigrationInterface { export class CreateCredentialsUserRole1660062385367 implements ReversibleMigration {
name = 'CreateCredentialsUserRole1660062385367'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query(` await queryRunner.query(`
INSERT INTO ${tablePrefix}role (name, scope) INSERT INTO ${tablePrefix}role (name, scope)
VALUES ('user', 'credential') VALUES ('user', 'credential')
@ -13,8 +9,7 @@ export class CreateCredentialsUserRole1660062385367 implements MigrationInterfac
`); `);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(` await queryRunner.query(`
DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='credential'; DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='credential';
`); `);

View file

@ -1,25 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateWorkflowsEditorRole1663755770893 implements MigrationInterface {
name = 'CreateWorkflowsEditorRole1663755770893';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateWorkflowsEditorRole1663755770893 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(` await queryRunner.query(`
INSERT INTO ${tablePrefix}role (name, scope) INSERT INTO ${tablePrefix}role (name, scope)
VALUES ('editor', 'workflow') VALUES ('editor', 'workflow')
ON CONFLICT DO NOTHING; ON CONFLICT DO NOTHING;
`); `);
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(` await queryRunner.query(`
DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='workflow'; DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='workflow';
`); `);

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class WorkflowStatistics1664196174001 implements MigrationInterface {
name = 'WorkflowStatistics1664196174001';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class WorkflowStatistics1664196174001 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
// Create statistics table // Create statistics table
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}workflow_statistics ( `CREATE TABLE ${tablePrefix}workflow_statistics (
@ -24,12 +18,9 @@ export class WorkflowStatistics1664196174001 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "dataLoaded" BOOLEAN DEFAULT false;`, `ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "dataLoaded" BOOLEAN DEFAULT false;`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE ${tablePrefix}workflow_statistics`); await queryRunner.query(`DROP TABLE ${tablePrefix}workflow_statistics`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN dataLoaded`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN dataLoaded`);
} }

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateCredentialUsageTable1665484192212 implements MigrationInterface {
name = 'CreateCredentialUsageTable1665484192212';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateCredentialUsageTable1665484192212 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}credential_usage (` + `CREATE TABLE ${tablePrefix}credential_usage (` +
'"workflowId" int NOT NULL,' + '"workflowId" int NOT NULL,' +
@ -20,13 +14,9 @@ export class CreateCredentialUsageTable1665484192212 implements MigrationInterfa
`CONSTRAINT "FK_${tablePrefix}7ce200a20ade7ae89fa7901da896993f" FOREIGN KEY ("credentialId") REFERENCES ${tablePrefix}credentials_entity ("id") ON DELETE CASCADE ON UPDATE CASCADE ` + `CONSTRAINT "FK_${tablePrefix}7ce200a20ade7ae89fa7901da896993f" FOREIGN KEY ("credentialId") REFERENCES ${tablePrefix}credentials_entity ("id") ON DELETE CASCADE ON UPDATE CASCADE ` +
');', ');',
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE "${tablePrefix}credential_usage"`); await queryRunner.query(`DROP TABLE "${tablePrefix}credential_usage"`);
} }
} }

View file

@ -1,19 +1,11 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class RemoveCredentialUsageTable1665754637025 implements MigrationInterface { export class RemoveCredentialUsageTable1665754637025 implements ReversibleMigration {
name = 'RemoveCredentialUsageTable1665754637025'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE ${tablePrefix}credential_usage`); await queryRunner.query(`DROP TABLE ${tablePrefix}credential_usage`);
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}credential_usage (` + `CREATE TABLE ${tablePrefix}credential_usage (` +
'"workflowId" int NOT NULL,' + '"workflowId" int NOT NULL,' +

View file

@ -1,42 +1,31 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class AddWorkflowVersionIdColumn1669739707126 implements MigrationInterface { export class AddWorkflowVersionIdColumn1669739707126 implements ReversibleMigration {
name = 'AddWorkflowVersionIdColumn1669739707126'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "versionId" CHAR(36)`, `ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "versionId" CHAR(36)`,
); );
const workflowIds: Array<{ id: number }> = await queryRunner.query(` const workflowIds = (await queryRunner.query(`
SELECT id SELECT id
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
`); `)) as Array<{ id: number }>;
workflowIds.map(({ id }) => { for (const { id } of workflowIds) {
const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters( const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters(
` `UPDATE ${tablePrefix}workflow_entity
UPDATE ${tablePrefix}workflow_entity SET "versionId" = :versionId
SET "versionId" = :versionId WHERE id = '${id}'`,
WHERE id = '${id}'
`,
{ versionId: uuidv4() }, { versionId: uuidv4() },
{}, {},
); );
return queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); }
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN "versionId"`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN "versionId"`);
} }
} }

View file

@ -1,25 +1,14 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class AddTriggerCountColumn1669823906995 implements MigrationInterface {
name = 'AddTriggerCountColumn1669823906995';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class AddTriggerCountColumn1669823906995 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "triggerCount" integer NOT NULL DEFAULT 0`, `ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "triggerCount" integer NOT NULL DEFAULT 0`,
); );
// Table will be populated by n8n startup - see ActiveWorkflowRunner.ts // Table will be populated by n8n startup - see ActiveWorkflowRunner.ts
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN "triggerCount"`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN "triggerCount"`);
} }
} }

View file

@ -1,27 +1,17 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '../../utils/migrationHelpers';
export class MessageEventBusDestinations1671535397530 implements MigrationInterface { export class MessageEventBusDestinations1671535397530 implements ReversibleMigration {
name = 'MessageEventBusDestinations1671535397530'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}event_destinations (` + `CREATE TABLE ${tablePrefix}event_destinations (` +
`"id" UUID PRIMARY KEY NOT NULL,` + '"id" UUID PRIMARY KEY NOT NULL,' +
`"destination" JSONB NOT NULL,` + '"destination" JSONB NOT NULL,' +
`"createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,` + '"createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,' +
`"updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);`, '"updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);',
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE "${tablePrefix}event_destinations"`); await queryRunner.query(`DROP TABLE "${tablePrefix}event_destinations"`);
logMigrationEnd(this.name);
} }
} }

View file

@ -1,21 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; import { StatisticsNames } from '@/databases/entities/WorkflowStatistics';
import { StatisticsNames } from '@db/entities/WorkflowStatistics';
export class RemoveWorkflowDataLoadedFlag1671726148421 implements MigrationInterface {
name = 'RemoveWorkflowDataLoadedFlag1671726148421';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class RemoveWorkflowDataLoadedFlag1671726148421 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
// If any existing workflow has dataLoaded set to true, insert the relevant information to the statistics table // If any existing workflow has dataLoaded set to true, insert the relevant information to the statistics table
const workflowIds: Array<{ id: number; dataLoaded: boolean }> = await queryRunner.query(` const workflowIds = (await queryRunner.query(`
SELECT id, "dataLoaded" SELECT id, "dataLoaded"
FROM ${tablePrefix}workflow_entity FROM ${tablePrefix}workflow_entity
`); `)) as Array<{ id: number; dataLoaded: boolean }>;
workflowIds.map(({ id, dataLoaded }) => { workflowIds.map(async ({ id, dataLoaded }) => {
if (dataLoaded) { if (dataLoaded) {
const [insertQuery, insertParams] = queryRunner.connection.driver.escapeQueryWithParameters( const [insertQuery, insertParams] = queryRunner.connection.driver.escapeQueryWithParameters(
` `
@ -32,24 +26,20 @@ export class RemoveWorkflowDataLoadedFlag1671726148421 implements MigrationInter
}); });
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN "dataLoaded"`); await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity DROP COLUMN "dataLoaded"`);
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner) { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "dataLoaded" BOOLEAN DEFAULT false`, `ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "dataLoaded" BOOLEAN DEFAULT false`,
); );
// Search through statistics for any workflows that have the dataLoaded stat // Search through statistics for any workflows that have the dataLoaded stat
const workflowsIds: Array<{ workflowId: string }> = await queryRunner.query(` const workflowsIds = (await queryRunner.query(`
SELECT "workflowId" SELECT "workflowId"
FROM ${tablePrefix}workflow_statistics FROM ${tablePrefix}workflow_statistics
WHERE name = '${StatisticsNames.dataLoaded}' WHERE name = '${StatisticsNames.dataLoaded}'
`); `)) as Array<{ workflowId: string }>;
workflowsIds.map(({ workflowId }) => { workflowsIds.map(async ({ workflowId }) => {
return queryRunner.query(` return queryRunner.query(`
UPDATE ${tablePrefix}workflow_entity UPDATE ${tablePrefix}workflow_entity
SET "dataLoaded" = true SET "dataLoaded" = true

View file

@ -1,20 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class DeleteExecutionsWithWorkflows1673268682475 implements MigrationInterface {
name = 'DeleteExecutionsWithWorkflows1673268682475';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class DeleteExecutionsWithWorkflows1673268682475 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}execution_entity `ALTER TABLE ${tablePrefix}execution_entity
ALTER COLUMN "workflowId" TYPE INTEGER USING "workflowId"::integer`, ALTER COLUMN "workflowId" TYPE INTEGER USING "workflowId"::integer`,
); );
const workflowIds: Array<{ id: number }> = await queryRunner.query(` const workflowIds = (await queryRunner.query(`
SELECT id FROM ${tablePrefix}workflow_entity SELECT id FROM ${tablePrefix}workflow_entity
`); `)) as Array<{ id: number }>;
await queryRunner.query( await queryRunner.query(
`DELETE FROM ${tablePrefix}execution_entity `DELETE FROM ${tablePrefix}execution_entity
@ -32,12 +27,9 @@ export class DeleteExecutionsWithWorkflows1673268682475 implements MigrationInte
FOREIGN KEY ("workflowId") REFERENCES ${tablePrefix}workflow_entity ("id") FOREIGN KEY ("workflowId") REFERENCES ${tablePrefix}workflow_entity ("id")
ON DELETE CASCADE`, ON DELETE CASCADE`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`ALTER TABLE ${tablePrefix}execution_entity `ALTER TABLE ${tablePrefix}execution_entity
DROP CONSTRAINT "FK_${tablePrefix}execution_entity_workflowId"`, DROP CONSTRAINT "FK_${tablePrefix}execution_entity_workflowId"`,

View file

@ -1,21 +1,11 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class AddStatusToExecutions1674138566000 implements MigrationInterface {
name = 'AddStatusToExecutions1674138566000';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddStatusToExecutions1674138566000 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`ALTER TABLE ${tablePrefix}execution_entity ADD COLUMN status varchar`); await queryRunner.query(`ALTER TABLE ${tablePrefix}execution_entity ADD COLUMN status varchar`);
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`ALTER TABLE ${tablePrefix}execution_entity DROP COLUMN status`); await queryRunner.query(`ALTER TABLE ${tablePrefix}execution_entity DROP COLUMN status`);
} }
} }

View file

@ -1,15 +1,8 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/Ldap/constants'; import { LDAP_DEFAULT_CONFIGURATION, LDAP_FEATURE_NAME } from '@/Ldap/constants';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateLdapEntities1674509946020 implements MigrationInterface {
name = 'CreateLdapEntities1674509946020';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateLdapEntities1674509946020 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE "${tablePrefix}user" ADD COLUMN disabled BOOLEAN NOT NULL DEFAULT false;`, `ALTER TABLE "${tablePrefix}user" ADD COLUMN disabled BOOLEAN NOT NULL DEFAULT false;`,
); );
@ -45,12 +38,9 @@ export class CreateLdapEntities1674509946020 implements MigrationInterface {
"error" TEXT "error" TEXT
);`, );`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE "${tablePrefix}auth_provider_sync_history"`); await queryRunner.query(`DROP TABLE "${tablePrefix}auth_provider_sync_history"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}auth_identity"`); await queryRunner.query(`DROP TABLE "${tablePrefix}auth_identity"`);

View file

@ -1,28 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { IConnections, INode } from 'n8n-workflow';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { NodeTypes } from '@/NodeTypes'; import { NodeTypes } from '@/NodeTypes';
import { IConnections, INode } from 'n8n-workflow';
import { getLogger } from '@/Logger';
import { Container } from 'typedi'; import { Container } from 'typedi';
export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationInterface {
name = 'PurgeInvalidWorkflowConnections1675940580449';
async up(queryRunner: QueryRunner): Promise<void> { export class PurgeInvalidWorkflowConnections1675940580449 implements IrreversibleMigration {
logMigrationStart(this.name); async up({ queryRunner, tablePrefix, migrationName, logger }: MigrationContext) {
const workflows = (await queryRunner.query(`
const tablePrefix = getTablePrefix();
const workflows: Array<{ id: number; nodes: INode[]; connections: IConnections }> =
await queryRunner.query(`
SELECT id, nodes, connections SELECT id, nodes, connections
FROM "${tablePrefix}workflow_entity" FROM "${tablePrefix}workflow_entity"
`); `)) as Array<{ id: number; nodes: INode[]; connections: IConnections }>;
const nodeTypes = Container.get(NodeTypes); const nodeTypes = Container.get(NodeTypes);
workflows.forEach(async (workflow) => { workflows.forEach(async (workflow) => {
let connections: IConnections = workflow.connections; const { connections, nodes } = workflow;
const nodes: INode[] = workflow.nodes;
const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => { const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => {
try { try {
@ -31,7 +22,7 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
acc.push(node.name); acc.push(node.name);
} }
} catch (error) { } catch (error) {
getLogger().warn(`Migration ${this.name} failed with error: ${error.message}`); logger.warn(`Migration ${migrationName} failed with error: ${(error as Error).message}`);
} }
return acc; return acc;
}, [] as string[]); }, [] as string[]);
@ -40,7 +31,7 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
const connection = connections[sourceNodeName]; const connection = connections[sourceNodeName];
const outputs = Object.keys(connection); const outputs = Object.keys(connection);
outputs.forEach((outputConnectionName /* Like `main` */, idx) => { outputs.forEach((outputConnectionName /* Like `main` */) => {
const outputConnection = connection[outputConnectionName]; const outputConnection = connection[outputConnectionName];
// It filters out all connections that are connected to a node that cannot receive input // It filters out all connections that are connected to a node that cannot receive input
@ -55,22 +46,14 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
// Update database with new connections // Update database with new connections
const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters( const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters(
` `UPDATE "${tablePrefix}workflow_entity"
UPDATE "${tablePrefix}workflow_entity" SET connections = :connections
SET connections = :connections WHERE id = '${workflow.id}'`,
WHERE id = '${workflow.id}'
`,
{ connections: JSON.stringify(connections) }, { connections: JSON.stringify(connections) },
{}, {},
); );
await queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); });
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
// No need to revert this migration
} }
} }

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class MigrateExecutionStatus1676996103000 implements MigrationInterface {
name = 'MigrateExecutionStatus1676996103000';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class MigrateExecutionStatus1676996103000 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`UPDATE "${tablePrefix}execution_entity" SET "status" = 'waiting' WHERE "status" IS NULL AND "waitTill" IS NOT NULL;`, `UPDATE "${tablePrefix}execution_entity" SET "status" = 'waiting' WHERE "status" IS NULL AND "waitTill" IS NOT NULL;`,
); );
@ -20,9 +14,5 @@ export class MigrateExecutionStatus1676996103000 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`UPDATE "${tablePrefix}execution_entity" SET "status" = 'crashed' WHERE "status" IS NULL;`, `UPDATE "${tablePrefix}execution_entity" SET "status" = 'crashed' WHERE "status" IS NULL;`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> {}
} }

View file

@ -1,22 +1,12 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class UpdateRunningExecutionStatus1677236854063 implements MigrationInterface {
name = 'UpdateRunningExecutionStatus1677236854063';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class UpdateRunningExecutionStatus1677236854063 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`UPDATE "${tablePrefix}execution_entity" SET "status" = 'failed' WHERE "status" = 'running' AND "finished"=false AND "stoppedAt" IS NOT NULL;`, `UPDATE "${tablePrefix}execution_entity" SET "status" = 'failed' WHERE "status" = 'running' AND "finished"=false AND "stoppedAt" IS NOT NULL;`,
); );
await queryRunner.query( await queryRunner.query(
`UPDATE "${tablePrefix}execution_entity" SET "status" = 'success' WHERE "status" = 'running' AND "finished"=true AND "stoppedAt" IS NOT NULL;`, `UPDATE "${tablePrefix}execution_entity" SET "status" = 'success' WHERE "status" = 'running' AND "finished"=true AND "stoppedAt" IS NOT NULL;`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> {}
} }

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart, getTablePrefix } from '@db/utils/migrationHelpers';
import config from '@/config';
export class CreateVariables1677501636754 implements MigrationInterface {
name = 'CreateVariables1677501636754';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateVariables1677501636754 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(` await queryRunner.query(`
CREATE TABLE ${tablePrefix}variables ( CREATE TABLE ${tablePrefix}variables (
id serial4 NOT NULL PRIMARY KEY, id serial4 NOT NULL PRIMARY KEY,
@ -17,16 +11,9 @@ export class CreateVariables1677501636754 implements MigrationInterface {
UNIQUE ("key") UNIQUE ("key")
); );
`); `);
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE ${tablePrefix}variables;`); await queryRunner.query(`DROP TABLE ${tablePrefix}variables;`);
logMigrationEnd(this.name);
} }
} }

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner, Table } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateExecutionMetadataTable1679416281778 implements MigrationInterface {
name = 'CreateExecutionMetadataTable1679416281778';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class CreateExecutionMetadataTable1679416281778 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE ${tablePrefix}execution_metadata ( `CREATE TABLE ${tablePrefix}execution_metadata (
"id" serial4 NOT NULL PRIMARY KEY, "id" serial4 NOT NULL PRIMARY KEY,
@ -32,13 +26,9 @@ export class CreateExecutionMetadataTable1679416281778 implements MigrationInter
await queryRunner.query( await queryRunner.query(
`CREATE INDEX "IDX_${tablePrefix}8b6f3f9ae234f137d707b98f3bf43584" ON "${tablePrefix}execution_entity" ("status", "workflowId");`, `CREATE INDEX "IDX_${tablePrefix}8b6f3f9ae234f137d707b98f3bf43584" ON "${tablePrefix}execution_entity" ("status", "workflowId");`,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
// Re-add removed indices // Re-add removed indices
await queryRunner.query( await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}33228da131bb1112247cf52a42" ON ${tablePrefix}execution_entity ("stoppedAt") `, `CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}33228da131bb1112247cf52a42" ON ${tablePrefix}execution_entity ("stoppedAt") `,

View file

@ -1,16 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { UserSettings } from '@/Interfaces'; import type { UserSettings } from '@/Interfaces';
export class AddUserActivatedProperty1681134145996 implements MigrationInterface { export class AddUserActivatedProperty1681134145996 implements ReversibleMigration {
name = 'AddUserActivatedProperty1681134145996'; async up({ queryRunner, tablePrefix }: MigrationContext) {
const activatedUsers = (await queryRunner.query(
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
const activatedUsers: UserSettings[] = await queryRunner.query(
`SELECT DISTINCT sw."userId" AS id, `SELECT DISTINCT sw."userId" AS id,
JSONB_SET(COALESCE(u.settings::jsonb, '{}'), '{userActivated}', 'true', true) as settings JSONB_SET(COALESCE(u.settings::jsonb, '{}'), '{userActivated}', 'true', true) as settings
FROM ${tablePrefix}workflow_statistics ws FROM ${tablePrefix}workflow_statistics ws
@ -23,9 +16,9 @@ export class AddUserActivatedProperty1681134145996 implements MigrationInterface
WHERE ws.name = 'production_success' WHERE ws.name = 'production_success'
AND r.name = 'owner' AND r.name = 'owner'
AND r.scope = 'workflow'`, AND r.scope = 'workflow'`,
); )) as UserSettings[];
const updatedUsers = activatedUsers.map((user) => const updatedUsers = activatedUsers.map(async (user) =>
queryRunner.query( queryRunner.query(
`UPDATE "${tablePrefix}user" SET settings = '${JSON.stringify( `UPDATE "${tablePrefix}user" SET settings = '${JSON.stringify(
user.settings, user.settings,
@ -46,12 +39,9 @@ export class AddUserActivatedProperty1681134145996 implements MigrationInterface
`UPDATE "${tablePrefix}user" SET settings = JSONB_SET(COALESCE(settings::jsonb, '{}'), '{userActivated}', 'false', true) WHERE id NOT IN (${activatedUserIds})`, `UPDATE "${tablePrefix}user" SET settings = JSONB_SET(COALESCE(settings::jsonb, '{}'), '{userActivated}', 'false', true) WHERE id NOT IN (${activatedUserIds})`,
); );
} }
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = getTablePrefix();
await queryRunner.query( await queryRunner.query(
`UPDATE "${tablePrefix}user" SET settings = settings::jsonb - 'userActivated'`, `UPDATE "${tablePrefix}user" SET settings = settings::jsonb - 'userActivated'`,
); );

View file

@ -1,3 +1,4 @@
import type { Migration } from '@db/types';
import { InitialMigration1587669153312 } from './1587669153312-InitialMigration'; import { InitialMigration1587669153312 } from './1587669153312-InitialMigration';
import { WebhookModel1589476000887 } from './1589476000887-WebhookModel'; import { WebhookModel1589476000887 } from './1589476000887-WebhookModel';
import { CreateIndexStoppedAt1594828256133 } from './1594828256133-CreateIndexStoppedAt'; import { CreateIndexStoppedAt1594828256133 } from './1594828256133-CreateIndexStoppedAt';
@ -36,7 +37,7 @@ import { CreateExecutionMetadataTable1679416281778 } from './1679416281778-Creat
import { CreateVariables1677501636754 } from './1677501636754-CreateVariables'; import { CreateVariables1677501636754 } from './1677501636754-CreateVariables';
import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty'; import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty';
export const postgresMigrations = [ export const postgresMigrations: Migration[] = [
InitialMigration1587669153312, InitialMigration1587669153312,
WebhookModel1589476000887, WebhookModel1589476000887,
CreateIndexStoppedAt1594828256133, CreateIndexStoppedAt1594828256133,

View file

@ -1,46 +1,29 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class InitialMigration1588102412422 implements MigrationInterface {
name = 'InitialMigration1588102412422';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class InitialMigration1588102412422 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS "${tablePrefix}credentials_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "data" text NOT NULL, "type" varchar(128) NOT NULL, "nodesAccess" text NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL)`, `CREATE TABLE IF NOT EXISTS "${tablePrefix}credentials_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "data" text NOT NULL, "type" varchar(128) NOT NULL, "nodesAccess" text NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL)`,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8" ON "${tablePrefix}credentials_entity" ("type") `, `CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8" ON "${tablePrefix}credentials_entity" ("type") `,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS "${tablePrefix}execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime NOT NULL, "workflowData" text NOT NULL, "workflowId" varchar)`, `CREATE TABLE IF NOT EXISTS "${tablePrefix}execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime NOT NULL, "workflowData" text NOT NULL, "workflowId" varchar)`,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d" ON "${tablePrefix}execution_entity" ("workflowId") `, `CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d" ON "${tablePrefix}execution_entity" ("workflowId") `,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS "${tablePrefix}workflow_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "active" boolean NOT NULL, "nodes" text NOT NULL, "connections" text NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL, "settings" text, "staticData" text)`, `CREATE TABLE IF NOT EXISTS "${tablePrefix}workflow_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "active" boolean NOT NULL, "nodes" text NOT NULL, "connections" text NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL, "settings" text, "staticData" text)`,
undefined,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix'); await queryRunner.query(`DROP TABLE "${tablePrefix}workflow_entity"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}workflow_entity"`, undefined); await queryRunner.query(`DROP TABLE "${tablePrefix}execution_entity"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d"`, undefined); await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}execution_entity"`, undefined); await queryRunner.query(`DROP TABLE "${tablePrefix}credentials_entity"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8"`, undefined);
await queryRunner.query(`DROP TABLE "${tablePrefix}credentials_entity"`, undefined);
} }
} }

View file

@ -1,24 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class WebhookModel1592445003908 implements MigrationInterface {
name = 'WebhookModel1592445003908';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class WebhookModel1592445003908 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS ${tablePrefix}webhook_entity ("workflowId" integer NOT NULL, "webhookPath" varchar NOT NULL, "method" varchar NOT NULL, "node" varchar NOT NULL, PRIMARY KEY ("webhookPath", "method"))`, `CREATE TABLE IF NOT EXISTS ${tablePrefix}webhook_entity ("workflowId" integer NOT NULL, "webhookPath" varchar NOT NULL, "method" varchar NOT NULL, "node" varchar NOT NULL, PRIMARY KEY ("webhookPath", "method"))`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`); await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`);
} }
} }

View file

@ -1,25 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateIndexStoppedAt1594825041918 implements MigrationInterface {
name = 'CreateIndexStoppedAt1594825041918';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class CreateIndexStoppedAt1594825041918 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE INDEX "IDX_${tablePrefix}cefb067df2402f6aed0638a6c1" ON "${tablePrefix}execution_entity" ("stoppedAt") `, `CREATE INDEX "IDX_${tablePrefix}cefb067df2402f6aed0638a6c1" ON "${tablePrefix}execution_entity" ("stoppedAt") `,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}cefb067df2402f6aed0638a6c1"`); await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}cefb067df2402f6aed0638a6c1"`);
} }
} }

View file

@ -1,30 +1,16 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class MakeStoppedAtNullable1607431743769 implements MigrationInterface { export class MakeStoppedAtNullable1607431743769 implements IrreversibleMigration {
name = 'MakeStoppedAtNullable1607431743769'; async up({ queryRunner, tablePrefix }: MigrationContext) {
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
// SQLite does not allow us to simply "alter column" // SQLite does not allow us to simply "alter column"
// We're hacking the way sqlite identifies tables // We're hacking the way sqlite identifies tables
// Allowing a column to become nullable // Allowing a column to become nullable
// This is a very strict case when this can be done safely // This is a very strict case when this can be done safely
// As no collateral effects exist. // As no collateral effects exist.
await queryRunner.query(`PRAGMA writable_schema = 1; `, undefined); await queryRunner.query('PRAGMA writable_schema = 1;');
await queryRunner.query( await queryRunner.query(
`UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE IF NOT EXISTS "${tablePrefix}execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime, "workflowData" text NOT NULL, "workflowId" varchar)' WHERE NAME = "${tablePrefix}execution_entity";`, `UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE IF NOT EXISTS "${tablePrefix}execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime, "workflowData" text NOT NULL, "workflowId" varchar)' WHERE NAME = "${tablePrefix}execution_entity";`,
undefined,
); );
await queryRunner.query(`PRAGMA writable_schema = 0;`, undefined); await queryRunner.query('PRAGMA writable_schema = 0;');
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
// This cannot be undone as the table might already have nullable values
} }
} }

View file

@ -1,17 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class AddWebhookId1611071044839 implements MigrationInterface {
name = 'AddWebhookId1611071044839';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddWebhookId1611071044839 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE "temporary_webhook_entity" ("workflowId" integer NOT NULL, "webhookPath" varchar NOT NULL, "method" varchar NOT NULL, "node" varchar NOT NULL, "webhookId" varchar, "pathLength" integer, PRIMARY KEY ("webhookPath", "method"))`, 'CREATE TABLE "temporary_webhook_entity" ("workflowId" integer NOT NULL, "webhookPath" varchar NOT NULL, "method" varchar NOT NULL, "node" varchar NOT NULL, "webhookId" varchar, "pathLength" integer, PRIMARY KEY ("webhookPath", "method"))',
); );
await queryRunner.query( await queryRunner.query(
`INSERT INTO "temporary_webhook_entity"("workflowId", "webhookPath", "method", "node") SELECT "workflowId", "webhookPath", "method", "node" FROM "${tablePrefix}webhook_entity"`, `INSERT INTO "temporary_webhook_entity"("workflowId", "webhookPath", "method", "node") SELECT "workflowId", "webhookPath", "method", "node" FROM "${tablePrefix}webhook_entity"`,
@ -23,13 +15,9 @@ export class AddWebhookId1611071044839 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`CREATE INDEX "IDX_${tablePrefix}742496f199721a057051acf4c2" ON "${tablePrefix}webhook_entity" ("webhookId", "method", "pathLength") `, `CREATE INDEX "IDX_${tablePrefix}742496f199721a057051acf4c2" ON "${tablePrefix}webhook_entity" ("webhookId", "method", "pathLength") `,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}742496f199721a057051acf4c2"`); await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}742496f199721a057051acf4c2"`);
await queryRunner.query( await queryRunner.query(
`ALTER TABLE "${tablePrefix}webhook_entity" RENAME TO "temporary_webhook_entity"`, `ALTER TABLE "${tablePrefix}webhook_entity" RENAME TO "temporary_webhook_entity"`,
@ -40,6 +28,6 @@ export class AddWebhookId1611071044839 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`INSERT INTO "${tablePrefix}webhook_entity"("workflowId", "webhookPath", "method", "node") SELECT "workflowId", "webhookPath", "method", "node" FROM "temporary_webhook_entity"`, `INSERT INTO "${tablePrefix}webhook_entity"("workflowId", "webhookPath", "method", "node") SELECT "workflowId", "webhookPath", "method", "node" FROM "temporary_webhook_entity"`,
); );
await queryRunner.query(`DROP TABLE "temporary_webhook_entity"`); await queryRunner.query('DROP TABLE "temporary_webhook_entity"');
} }
} }

View file

@ -1,15 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateTagEntity1617213344594 implements MigrationInterface {
name = 'CreateTagEntity1617213344594';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class CreateTagEntity1617213344594 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
// create tags table + relationship with workflow entity // create tags table + relationship with workflow entity
await queryRunner.query( await queryRunner.query(
@ -68,13 +60,9 @@ export class CreateTagEntity1617213344594 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE "${tablePrefix}temporary_workflow_entity" RENAME TO "${tablePrefix}workflow_entity"`, `ALTER TABLE "${tablePrefix}temporary_workflow_entity" RENAME TO "${tablePrefix}workflow_entity"`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
// `createdAt` and `updatedAt` // `createdAt` and `updatedAt`
await queryRunner.query( await queryRunner.query(

View file

@ -1,19 +1,11 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class UniqueWorkflowNames1620821879465 implements MigrationInterface { export class UniqueWorkflowNames1620821879465 implements ReversibleMigration {
name = 'UniqueWorkflowNames1620821879465'; async up({ queryRunner, tablePrefix }: MigrationContext) {
const workflowNames = (await queryRunner.query(`
async up(queryRunner: QueryRunner): Promise<void> { SELECT name
logMigrationStart(this.name); FROM "${tablePrefix}workflow_entity"
`)) as Array<{ name: string }>;
const tablePrefix = config.getEnv('database.tablePrefix');
const workflowNames = await queryRunner.query(`
SELECT name
FROM "${tablePrefix}workflow_entity"
`);
for (const { name } of workflowNames) { for (const { name } of workflowNames) {
const [duplicatesQuery, parameters] = queryRunner.connection.driver.escapeQueryWithParameters( const [duplicatesQuery, parameters] = queryRunner.connection.driver.escapeQueryWithParameters(
@ -27,12 +19,16 @@ export class UniqueWorkflowNames1620821879465 implements MigrationInterface {
{}, {},
); );
const duplicates = await queryRunner.query(duplicatesQuery, parameters); const duplicates = (await queryRunner.query(duplicatesQuery, parameters)) as Array<{
id: number;
name: string;
}>;
if (duplicates.length > 1) { if (duplicates.length > 1) {
await Promise.all( await Promise.all(
duplicates.map(({ id, name }: { id: number; name: string }, index: number) => { // eslint-disable-next-line @typescript-eslint/no-shadow
if (index === 0) return Promise.resolve(); duplicates.map(async ({ id, name }, index: number) => {
if (index === 0) return;
const [updateQuery, updateParams] = const [updateQuery, updateParams] =
queryRunner.connection.driver.escapeQueryWithParameters( queryRunner.connection.driver.escapeQueryWithParameters(
` `
@ -53,12 +49,9 @@ export class UniqueWorkflowNames1620821879465 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9" ON "${tablePrefix}workflow_entity" ("name") `, `CREATE UNIQUE INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9" ON "${tablePrefix}workflow_entity" ("name") `,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9"`); await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9"`);
} }
} }

View file

@ -1,19 +1,10 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class AddWaitColumn1621707690587 implements MigrationInterface {
name = 'AddWaitColumn1621707690587';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddWaitColumn1621707690587 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE IF EXISTS "${tablePrefix}temporary_execution_entity"`); await queryRunner.query(`DROP TABLE IF EXISTS "${tablePrefix}temporary_execution_entity"`);
await queryRunner.query( await queryRunner.query(
`CREATE TABLE "${tablePrefix}temporary_execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime, "workflowData" text NOT NULL, "workflowId" varchar, "waitTill" DATETIME)`, `CREATE TABLE "${tablePrefix}temporary_execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime, "workflowData" text NOT NULL, "workflowId" varchar, "waitTill" DATETIME)`,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`INSERT INTO "${tablePrefix}temporary_execution_entity"("id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId") SELECT "id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId" FROM "${tablePrefix}execution_entity"`, `INSERT INTO "${tablePrefix}temporary_execution_entity"("id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId") SELECT "id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId" FROM "${tablePrefix}execution_entity"`,
@ -28,16 +19,11 @@ export class AddWaitColumn1621707690587 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`CREATE INDEX "IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2" ON "${tablePrefix}execution_entity" ("waitTill")`, `CREATE INDEX "IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2" ON "${tablePrefix}execution_entity" ("waitTill")`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`CREATE TABLE IF NOT EXISTS "${tablePrefix}temporary_execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime, "workflowData" text NOT NULL, "workflowId" varchar)`, `CREATE TABLE IF NOT EXISTS "${tablePrefix}temporary_execution_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "data" text NOT NULL, "finished" boolean NOT NULL, "mode" varchar NOT NULL, "retryOf" varchar, "retrySuccessId" varchar, "startedAt" datetime NOT NULL, "stoppedAt" datetime, "workflowData" text NOT NULL, "workflowId" varchar)`,
undefined,
); );
await queryRunner.query( await queryRunner.query(
`INSERT INTO "${tablePrefix}temporary_execution_entity"("id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId") SELECT "id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId" FROM "${tablePrefix}execution_entity"`, `INSERT INTO "${tablePrefix}temporary_execution_entity"("id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId") SELECT "id", "data", "finished", "mode", "retryOf", "retrySuccessId", "startedAt", "stoppedAt", "workflowData", "workflowId" FROM "${tablePrefix}execution_entity"`,

View file

@ -1,23 +1,22 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; /* eslint-disable n8n-local-rules/no-uncaught-json-parse */
import config from '@/config'; /* eslint-disable @typescript-eslint/restrict-template-expressions */
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { runInBatches } from '@db/utils/migrationHelpers'; import { runInBatches } from '@db/utils/migrationHelpers';
// replacing the credentials in workflows and execution // replacing the credentials in workflows and execution
// `nodeType: name` changes to `nodeType: { id, name }` // `nodeType: name` changes to `nodeType: { id, name }`
export class UpdateWorkflowCredentials1630330987096 implements MigrationInterface { export class UpdateWorkflowCredentials1630330987096 implements ReversibleMigration {
name = 'UpdateWorkflowCredentials1630330987096'; async up({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
const credentialsEntities = await queryRunner.query(`
SELECT id, name, type SELECT id, name, type
FROM "${tablePrefix}credentials_entity" FROM "${tablePrefix}credentials_entity"
`); `)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
@ -57,7 +56,7 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -100,7 +99,7 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -143,20 +142,16 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix'); const credentialsEntities = (await queryRunner.query(`
const credentialsEntities = await queryRunner.query(`
SELECT id, name, type SELECT id, name, type
FROM "${tablePrefix}credentials_entity" FROM "${tablePrefix}credentials_entity"
`); `)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
@ -176,7 +171,9 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
for (const [type, creds] of allNodeCredentials) { for (const [type, creds] of allNodeCredentials) {
if (typeof creds === 'object') { if (typeof creds === 'object') {
const matchingCredentials = credentialsEntities.find( const matchingCredentials = credentialsEntities.find(
// @ts-ignore double-equals because creds.id can be string or number // @ts-ignore
// double-equals because creds.id can be string or number
// eslint-disable-next-line eqeqeq
(credentials) => credentials.id == creds.id && credentials.type === type, (credentials) => credentials.id == creds.id && credentials.type === type,
); );
if (matchingCredentials) { if (matchingCredentials) {
@ -202,7 +199,7 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
}); });
@ -226,7 +223,9 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
for (const [type, creds] of allNodeCredentials) { for (const [type, creds] of allNodeCredentials) {
if (typeof creds === 'object') { if (typeof creds === 'object') {
const matchingCredentials = credentialsEntities.find( const matchingCredentials = credentialsEntities.find(
// @ts-ignore double-equals because creds.id can be string or number // @ts-ignore
// double-equals because creds.id can be string or number
// eslint-disable-next-line eqeqeq
(credentials) => credentials.id == creds.id && credentials.type === type, (credentials) => credentials.id == creds.id && credentials.type === type,
); );
if (matchingCredentials) { if (matchingCredentials) {
@ -276,7 +275,9 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
for (const [type, creds] of allNodeCredentials) { for (const [type, creds] of allNodeCredentials) {
if (typeof creds === 'object') { if (typeof creds === 'object') {
const matchingCredentials = credentialsEntities.find( const matchingCredentials = credentialsEntities.find(
// @ts-ignore double-equals because creds.id can be string or number // @ts-ignore
// double-equals because creds.id can be string or number
// eslint-disable-next-line eqeqeq
(credentials) => credentials.id == creds.id && credentials.type === type, (credentials) => credentials.id == creds.id && credentials.type === type,
); );
if (matchingCredentials) { if (matchingCredentials) {
@ -301,7 +302,7 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
} }
}); });
} }

View file

@ -1,14 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class AddExecutionEntityIndexes1644421939510 implements MigrationInterface {
name = 'AddExecutionEntityIndexes1644421939510';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddExecutionEntityIndexes1644421939510 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP INDEX IF EXISTS 'IDX_${tablePrefix}c4d999a5e90784e8caccf5589d'`); await queryRunner.query(`DROP INDEX IF EXISTS 'IDX_${tablePrefix}c4d999a5e90784e8caccf5589d'`);
await queryRunner.query(`DROP INDEX IF EXISTS 'IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2'`); await queryRunner.query(`DROP INDEX IF EXISTS 'IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2'`);
@ -28,12 +21,9 @@ export class AddExecutionEntityIndexes1644421939510 implements MigrationInterfac
await queryRunner.query( await queryRunner.query(
`CREATE INDEX IF NOT EXISTS 'IDX_${tablePrefix}81fc04c8a17de15835713505e4' ON '${tablePrefix}execution_entity' ('workflowId', 'id') `, `CREATE INDEX IF NOT EXISTS 'IDX_${tablePrefix}81fc04c8a17de15835713505e4' ON '${tablePrefix}execution_entity' ('workflowId', 'id') `,
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`DROP INDEX 'IDX_${tablePrefix}81fc04c8a17de15835713505e4'`); await queryRunner.query(`DROP INDEX 'IDX_${tablePrefix}81fc04c8a17de15835713505e4'`);
await queryRunner.query(`DROP INDEX 'IDX_${tablePrefix}b94b45ce2c73ce46c54f20b5f9'`); await queryRunner.query(`DROP INDEX 'IDX_${tablePrefix}b94b45ce2c73ce46c54f20b5f9'`);
await queryRunner.query(`DROP INDEX 'IDX_${tablePrefix}1688846335d274033e15c846a4'`); await queryRunner.query(`DROP INDEX 'IDX_${tablePrefix}1688846335d274033e15c846a4'`);

View file

@ -1,16 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { InsertResult, MigrationContext, ReversibleMigration } from '@db/types';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import config from '@/config'; import { loadSurveyFromDisk } from '@db/utils/migrationHelpers';
import { loadSurveyFromDisk, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CreateUserManagement1646992772331 implements MigrationInterface {
name = 'CreateUserManagement1646992772331';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class CreateUserManagement1646992772331 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE "${tablePrefix}role" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(32) NOT NULL, "scope" varchar NOT NULL, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), CONSTRAINT "UQ_${tablePrefix}5b49d0f504f7ef31045a1fb2eb8" UNIQUE ("scope", "name"))`, `CREATE TABLE "${tablePrefix}role" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(32) NOT NULL, "scope" varchar NOT NULL, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), CONSTRAINT "UQ_${tablePrefix}5b49d0f504f7ef31045a1fb2eb8" UNIQUE ("scope", "name"))`,
); );
@ -49,7 +42,9 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
VALUES ("owner", "global"); VALUES ("owner", "global");
`); `);
const instanceOwnerRole = await queryRunner.query('SELECT last_insert_rowid() as insertId'); const instanceOwnerRole = (await queryRunner.query(
'SELECT last_insert_rowid() as insertId',
)) as InsertResult;
await queryRunner.query(` await queryRunner.query(`
INSERT INTO "${tablePrefix}role" (name, scope) INSERT INTO "${tablePrefix}role" (name, scope)
@ -61,14 +56,18 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
VALUES ("owner", "workflow"); VALUES ("owner", "workflow");
`); `);
const workflowOwnerRole = await queryRunner.query('SELECT last_insert_rowid() as insertId'); const workflowOwnerRole = (await queryRunner.query(
'SELECT last_insert_rowid() as insertId',
)) as InsertResult;
await queryRunner.query(` await queryRunner.query(`
INSERT INTO "${tablePrefix}role" (name, scope) INSERT INTO "${tablePrefix}role" (name, scope)
VALUES ("owner", "credential"); VALUES ("owner", "credential");
`); `);
const credentialOwnerRole = await queryRunner.query('SELECT last_insert_rowid() as insertId'); const credentialOwnerRole = (await queryRunner.query(
'SELECT last_insert_rowid() as insertId',
)) as InsertResult;
const survey = loadSurveyFromDisk(); const survey = loadSurveyFromDisk();
@ -95,12 +94,9 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
INSERT INTO "${tablePrefix}settings" (key, value, loadOnStartup) values INSERT INTO "${tablePrefix}settings" (key, value, loadOnStartup) values
('userManagement.isInstanceOwnerSetUp', 'false', true), ('userManagement.skipInstanceOwnerSetup', 'false', true) ('userManagement.isInstanceOwnerSetUp', 'false', true), ('userManagement.skipInstanceOwnerSetup', 'false', true)
`); `);
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9" ON "${tablePrefix}workflow_entity" ("name") `, `CREATE UNIQUE INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9" ON "${tablePrefix}workflow_entity" ("name") `,
); );

View file

@ -1,22 +1,10 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, IrreversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class LowerCaseUserEmail1648740597343 implements MigrationInterface {
name = 'LowerCaseUserEmail1648740597343';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class LowerCaseUserEmail1648740597343 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(` await queryRunner.query(`
UPDATE "${tablePrefix}user" UPDATE "${tablePrefix}user"
SET email = LOWER(email); SET email = LOWER(email);
`); `);
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> {}
} }

View file

@ -1,42 +1,32 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class CommunityNodes1652254514001 implements MigrationInterface {
name = 'CommunityNodes1652254514001';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.get('database.tablePrefix');
export class CommunityNodes1652254514001 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`CREATE TABLE "${tablePrefix}installed_packages" (` + `CREATE TABLE "${tablePrefix}installed_packages" (` +
`"packageName" char(214) NOT NULL,` + '"packageName" char(214) NOT NULL,' +
`"installedVersion" char(50) NOT NULL,` + '"installedVersion" char(50) NOT NULL,' +
`"authorName" char(70) NULL,` + '"authorName" char(70) NULL,' +
`"authorEmail" char(70) NULL,` + '"authorEmail" char(70) NULL,' +
`"createdAt" datetime(3) NOT NULL DEFAULT 'STRFTIME(''%Y-%m-%d %H:%M:%f'', ''NOW'')',` + "\"createdAt\" datetime(3) NOT NULL DEFAULT 'STRFTIME(''%Y-%m-%d %H:%M:%f'', ''NOW'')'," +
`"updatedAt" datetime(3) NOT NULL DEFAULT 'STRFTIME(''%Y-%m-%d %H:%M:%f'', ''NOW'')',` + "\"updatedAt\" datetime(3) NOT NULL DEFAULT 'STRFTIME(''%Y-%m-%d %H:%M:%f'', ''NOW'')'," +
`PRIMARY KEY("packageName")` + 'PRIMARY KEY("packageName")' +
`);`, ');',
); );
await queryRunner.query( await queryRunner.query(
`CREATE TABLE "${tablePrefix}installed_nodes" (` + `CREATE TABLE "${tablePrefix}installed_nodes" (` +
`"name" char(200) NOT NULL,` + '"name" char(200) NOT NULL,' +
`"type" char(200) NOT NULL,` + '"type" char(200) NOT NULL,' +
`"latestVersion" INTEGER DEFAULT 1,` + '"latestVersion" INTEGER DEFAULT 1,' +
`"package" char(214) NOT NULL,` + '"package" char(214) NOT NULL,' +
`PRIMARY KEY("name"),` + 'PRIMARY KEY("name"),' +
`FOREIGN KEY("package") REFERENCES "${tablePrefix}installed_packages"("packageName") ON DELETE CASCADE ON UPDATE CASCADE` + `FOREIGN KEY("package") REFERENCES "${tablePrefix}installed_packages"("packageName") ON DELETE CASCADE ON UPDATE CASCADE` +
`);`, ');',
); );
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.get('database.tablePrefix');
await queryRunner.query(`DROP TABLE "${tablePrefix}installed_nodes"`); await queryRunner.query(`DROP TABLE "${tablePrefix}installed_nodes"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}installed_packages"`); await queryRunner.query(`DROP TABLE "${tablePrefix}installed_packages"`);
} }

View file

@ -1,17 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class AddUserSettings1652367743993 implements MigrationInterface { export class AddUserSettings1652367743993 implements ReversibleMigration {
name = 'AddUserSettings1652367743993'; transaction = false as const;
transaction = false;
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query('PRAGMA foreign_keys=OFF'); await queryRunner.query('PRAGMA foreign_keys=OFF');
await queryRunner.query( await queryRunner.query(
@ -28,13 +20,9 @@ export class AddUserSettings1652367743993 implements MigrationInterface {
); );
await queryRunner.query('PRAGMA foreign_keys=ON'); await queryRunner.query('PRAGMA foreign_keys=ON');
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" RENAME TO "temporary_user"`); await queryRunner.query(`ALTER TABLE "${tablePrefix}user" RENAME TO "temporary_user"`);
await queryRunner.query( await queryRunner.query(
`CREATE TABLE "${tablePrefix}user" ("id" varchar PRIMARY KEY NOT NULL, "email" varchar(255), "firstName" varchar(32), "lastName" varchar(32), "password" varchar, "resetPasswordToken" varchar, "resetPasswordTokenExpiration" integer DEFAULT NULL, "personalizationAnswers" text, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "globalRoleId" integer NOT NULL, CONSTRAINT "FK_${tablePrefix}f0609be844f9200ff4365b1bb3d" FOREIGN KEY ("globalRoleId") REFERENCES "${tablePrefix}role" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`, `CREATE TABLE "${tablePrefix}user" ("id" varchar PRIMARY KEY NOT NULL, "email" varchar(255), "firstName" varchar(32), "lastName" varchar(32), "password" varchar, "resetPasswordToken" varchar, "resetPasswordTokenExpiration" integer DEFAULT NULL, "personalizationAnswers" text, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "globalRoleId" integer NOT NULL, CONSTRAINT "FK_${tablePrefix}f0609be844f9200ff4365b1bb3d" FOREIGN KEY ("globalRoleId") REFERENCES "${tablePrefix}role" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`,
@ -42,7 +30,7 @@ export class AddUserSettings1652367743993 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`INSERT INTO "${tablePrefix}user"("id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId") SELECT "id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId" FROM "temporary_user"`, `INSERT INTO "${tablePrefix}user"("id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId") SELECT "id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId" FROM "temporary_user"`,
); );
await queryRunner.query(`DROP TABLE "temporary_user"`); await queryRunner.query('DROP TABLE "temporary_user"');
await queryRunner.query( await queryRunner.query(
`CREATE UNIQUE INDEX "UQ_${tablePrefix}e12875dfb3b1d92d7d7c5377e2" ON "${tablePrefix}user" ("email")`, `CREATE UNIQUE INDEX "UQ_${tablePrefix}e12875dfb3b1d92d7d7c5377e2" ON "${tablePrefix}user" ("email")`,
); );

View file

@ -1,17 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
export class AddAPIKeyColumn1652905585850 implements MigrationInterface { export class AddAPIKeyColumn1652905585850 implements ReversibleMigration {
name = 'AddAPIKeyColumn1652905585850'; transaction = false as const;
transaction = false;
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query('PRAGMA foreign_keys=OFF'); await queryRunner.query('PRAGMA foreign_keys=OFF');
await queryRunner.query( await queryRunner.query(
@ -31,13 +23,9 @@ export class AddAPIKeyColumn1652905585850 implements MigrationInterface {
); );
await queryRunner.query('PRAGMA foreign_keys=ON'); await queryRunner.query('PRAGMA foreign_keys=ON');
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" RENAME TO "temporary_user"`); await queryRunner.query(`ALTER TABLE "${tablePrefix}user" RENAME TO "temporary_user"`);
await queryRunner.query( await queryRunner.query(
`CREATE TABLE "${tablePrefix}user" ("id" varchar PRIMARY KEY NOT NULL, "email" varchar(255), "firstName" varchar(32), "lastName" varchar(32), "password" varchar, "resetPasswordToken" varchar, "resetPasswordTokenExpiration" integer DEFAULT NULL, "personalizationAnswers" text, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "globalRoleId" integer NOT NULL, "settings" text, CONSTRAINT "FK_${tablePrefix}f0609be844f9200ff4365b1bb3d" FOREIGN KEY ("globalRoleId") REFERENCES "${tablePrefix}role" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`, `CREATE TABLE "${tablePrefix}user" ("id" varchar PRIMARY KEY NOT NULL, "email" varchar(255), "firstName" varchar(32), "lastName" varchar(32), "password" varchar, "resetPasswordToken" varchar, "resetPasswordTokenExpiration" integer DEFAULT NULL, "personalizationAnswers" text, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "globalRoleId" integer NOT NULL, "settings" text, CONSTRAINT "FK_${tablePrefix}f0609be844f9200ff4365b1bb3d" FOREIGN KEY ("globalRoleId") REFERENCES "${tablePrefix}role" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)`,
@ -45,7 +33,7 @@ export class AddAPIKeyColumn1652905585850 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`INSERT INTO "${tablePrefix}user"("id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId", "settings") SELECT "id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId", "settings" FROM "temporary_user"`, `INSERT INTO "${tablePrefix}user"("id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId", "settings") SELECT "id", "email", "firstName", "lastName", "password", "resetPasswordToken", "resetPasswordTokenExpiration", "personalizationAnswers", "createdAt", "updatedAt", "globalRoleId", "settings" FROM "temporary_user"`,
); );
await queryRunner.query(`DROP TABLE "temporary_user"`); await queryRunner.query('DROP TABLE "temporary_user"');
await queryRunner.query( await queryRunner.query(
`CREATE UNIQUE INDEX "UQ_${tablePrefix}e12875dfb3b1d92d7d7c5377e2" ON "${tablePrefix}user" ("email")`, `CREATE UNIQUE INDEX "UQ_${tablePrefix}e12875dfb3b1d92d7d7c5377e2" ON "${tablePrefix}user" ("email")`,
); );

View file

@ -1,25 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm'; import type { MigrationContext, ReversibleMigration } from '@db/types';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import config from '@/config';
export class IntroducePinData1654089251344 implements MigrationInterface {
name = 'IntroducePinData1654089251344';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class IntroducePinData1654089251344 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query( await queryRunner.query(
`ALTER TABLE \`${tablePrefix}workflow_entity\` ADD COLUMN "pinData" text`, `ALTER TABLE \`${tablePrefix}workflow_entity\` ADD COLUMN "pinData" text`,
); );
logMigrationEnd(this.name);
} }
async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query( await queryRunner.query(
`ALTER TABLE \`${tablePrefix}workflow_entity\` RENAME TO "temporary_workflow_entity"`, `ALTER TABLE \`${tablePrefix}workflow_entity\` RENAME TO "temporary_workflow_entity"`,
); );
@ -30,6 +18,6 @@ export class IntroducePinData1654089251344 implements MigrationInterface {
await queryRunner.query( await queryRunner.query(
`INSERT INTO \`${tablePrefix}workflow_entity\` ("id", "name", "active", "nodes", "connections", "createdAt", "updatedAt", "settings", "staticData") SELECT "id", "name", "active", "nodes", "connections", "createdAt", "updatedAt", "settings", "staticData" FROM "temporary_workflow_entity"`, `INSERT INTO \`${tablePrefix}workflow_entity\` ("id", "name", "active", "nodes", "connections", "createdAt", "updatedAt", "settings", "staticData") SELECT "id", "name", "active", "nodes", "connections", "createdAt", "updatedAt", "settings", "staticData" FROM "temporary_workflow_entity"`,
); );
await queryRunner.query(`DROP TABLE "temporary_workflow_entity"`); await queryRunner.query('DROP TABLE "temporary_workflow_entity"');
} }
} }

View file

@ -1,20 +1,18 @@
import { INode } from 'n8n-workflow'; /* eslint-disable @typescript-eslint/no-unsafe-argument */
import { MigrationInterface, QueryRunner } from 'typeorm'; /* eslint-disable @typescript-eslint/restrict-template-expressions */
import config from '@/config'; /* eslint-disable @typescript-eslint/no-unsafe-call */
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers'; /* eslint-disable n8n-local-rules/no-uncaught-json-parse */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import type { INode } from 'n8n-workflow';
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { runInBatches } from '@db/utils/migrationHelpers'; import { runInBatches } from '@db/utils/migrationHelpers';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
// add node ids in workflow objects // add node ids in workflow objects
export class AddNodeIds1658930531669 implements MigrationInterface { export class AddNodeIds1658930531669 implements ReversibleMigration {
name = 'AddNodeIds1658930531669'; async up({ queryRunner, tablePrefix }: MigrationContext) {
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
FROM "${tablePrefix}workflow_entity" FROM "${tablePrefix}workflow_entity"
@ -40,16 +38,12 @@ export class AddNodeIds1658930531669 implements MigrationInterface {
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); });
}); });
logMigrationEnd(this.name);
} }
public async down(queryRunner: QueryRunner): Promise<void> { async down({ queryRunner, tablePrefix }: MigrationContext) {
const tablePrefix = config.getEnv('database.tablePrefix');
const workflowsQuery = ` const workflowsQuery = `
SELECT id, nodes SELECT id, nodes
FROM "${tablePrefix}workflow_entity" FROM "${tablePrefix}workflow_entity"
@ -72,7 +66,7 @@ export class AddNodeIds1658930531669 implements MigrationInterface {
{}, {},
); );
queryRunner.query(updateQuery, updateParams); await queryRunner.query(updateQuery, updateParams);
}); });
}); });
} }

View file

@ -1,24 +1,17 @@
import { /* eslint-disable @typescript-eslint/no-unsafe-assignment */
logMigrationStart, /* eslint-disable @typescript-eslint/no-use-before-define */
logMigrationEnd, import type { IDataObject, INodeExecutionData } from 'n8n-workflow';
runInBatches, import type { MigrationContext, IrreversibleMigration } from '@db/types';
getTablePrefix, import { runInBatches, escapeQuery } from '@db/utils/migrationHelpers';
escapeQuery,
} from '@db/utils/migrationHelpers';
import type { MigrationInterface, QueryRunner } from 'typeorm';
import { isJsonKeyObject, PinData } from '@db/utils/migrations.types';
/** /**
* Convert TEXT-type `pinData` column in `workflow_entity` table from * Convert TEXT-type `pinData` column in `workflow_entity` table from
* `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }` * `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }`
*/ */
export class AddJsonKeyPinData1659888469333 implements MigrationInterface { export class AddJsonKeyPinData1659888469333 implements IrreversibleMigration {
name = 'AddJsonKeyPinData1659888469333'; async up(context: MigrationContext) {
const { queryRunner, tablePrefix } = context;
async up(queryRunner: QueryRunner) { const workflowTable = `${tablePrefix}workflow_entity`;
logMigrationStart(this.name);
const workflowTable = `${getTablePrefix()}workflow_entity`;
const PINDATA_SELECT_QUERY = ` const PINDATA_SELECT_QUERY = `
SELECT id, pinData SELECT id, pinData
@ -35,30 +28,45 @@ export class AddJsonKeyPinData1659888469333 implements MigrationInterface {
await runInBatches( await runInBatches(
queryRunner, queryRunner,
PINDATA_SELECT_QUERY, PINDATA_SELECT_QUERY,
addJsonKeyToPinDataColumn(queryRunner, PINDATA_UPDATE_STATEMENT), addJsonKeyToPinDataColumn(context, PINDATA_UPDATE_STATEMENT),
); );
logMigrationEnd(this.name);
}
async down() {
// irreversible migration
} }
} }
namespace PinData {
export type Old = { [nodeName: string]: IDataObject[] };
export type New = { [nodeName: string]: INodeExecutionData[] };
export type FetchedWorkflow = { id: number; pinData: string | Old };
}
function isObjectLiteral(maybeObject: unknown): maybeObject is { [key: string]: string } {
return typeof maybeObject === 'object' && maybeObject !== null && !Array.isArray(maybeObject);
}
function isJsonKeyObject(item: unknown): item is {
json: unknown;
[keys: string]: unknown;
} {
if (!isObjectLiteral(item)) return false;
return Object.keys(item).includes('json');
}
export const addJsonKeyToPinDataColumn = export const addJsonKeyToPinDataColumn =
(queryRunner: QueryRunner, updateStatement: string) => ({ queryRunner }: MigrationContext, updateStatement: string) =>
async (fetchedWorkflows: PinData.FetchedWorkflow[]) => { async (fetchedWorkflows: PinData.FetchedWorkflow[]) => {
makeUpdateParams(fetchedWorkflows).forEach((param) => { await Promise.all(
const params = { makeUpdateParams(fetchedWorkflows).map(async (param) => {
pinData: param.pinData, const params = {
id: param.id, pinData: param.pinData,
}; id: param.id,
};
const [escapedStatement, escapedParams] = escapeQuery(queryRunner, updateStatement, params); const [escapedStatement, escapedParams] = escapeQuery(queryRunner, updateStatement, params);
return queryRunner.query(escapedStatement, escapedParams);
queryRunner.query(escapedStatement, escapedParams); }),
}); );
}; };
function makeUpdateParams(fetchedWorkflows: PinData.FetchedWorkflow[]) { function makeUpdateParams(fetchedWorkflows: PinData.FetchedWorkflow[]) {
@ -77,6 +85,7 @@ function makeUpdateParams(fetchedWorkflows: PinData.FetchedWorkflow[]) {
} }
const newPinDataPerWorkflow = Object.keys(pinDataPerWorkflow).reduce<PinData.New>( const newPinDataPerWorkflow = Object.keys(pinDataPerWorkflow).reduce<PinData.New>(
// eslint-disable-next-line @typescript-eslint/no-shadow
(newPinDataPerWorkflow, nodeName) => { (newPinDataPerWorkflow, nodeName) => {
let pinDataPerNode = pinDataPerWorkflow[nodeName]; let pinDataPerNode = pinDataPerWorkflow[nodeName];

Some files were not shown because too many files have changed in this diff Show more