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: [
'jest.config.js',
// TODO: Remove these
'src/databases/migrations/**',
'src/databases/ormconfig.ts',
],

View file

@ -7,7 +7,7 @@ import { Container } from 'typedi';
import type { DataSourceOptions as ConnectionOptions, EntityManager, LoggerOptions } from 'typeorm';
import { DataSource as Connection } from 'typeorm';
import type { TlsOptions } from 'tls';
import type { DatabaseType, IDatabaseCollections } from '@/Interfaces';
import type { IDatabaseCollections } from '@/Interfaces';
import config from '@/config';
@ -19,6 +19,8 @@ import {
getPostgresConnectionOptions,
getSqliteConnectionOptions,
} from '@db/config';
import { wrapMigration } from '@db/utils/migrationHelpers';
import type { DatabaseType, Migration } from '@db/types';
import {
AuthIdentityRepository,
AuthProviderSyncHistoryRepository,
@ -119,7 +121,7 @@ export async function init(
synchronize: false,
logging: loggingOption,
maxQueryExecutionTime,
migrationsTransactionMode: 'each',
migrationsRun: false,
});
connection = new Connection(connectionOptions);
@ -136,15 +138,17 @@ export async function init(
await connection.query(`SET search_path TO ${searchPath.join(',')};`);
}
(connectionOptions.migrations as Migration[]).forEach(wrapMigration);
if (!testConnectionOptions && dbType === 'sqlite') {
// This specific migration changes database metadata.
// A field is now nullable. We need to reconnect so that
// n8n knows it has changed. Happens only on sqlite.
let migrations = [];
try {
const entityPrefix = config.getEnv('database.tablePrefix');
const tablePrefix = config.getEnv('database.tablePrefix');
migrations = await connection.query(
`SELECT id FROM ${entityPrefix}migrations where name = "MakeStoppedAtNullable1607431743769"`,
`SELECT id FROM ${tablePrefix}migrations where name = "MakeStoppedAtNullable1607431743769"`,
);
} catch (error) {
// 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 { DatabaseType } from '@db/types';
import type { AuthProviderType } from '@db/entities/AuthIdentity';
import type { Role } from '@db/entities/Role';
import type { SharedCredentials } from '@db/entities/SharedCredentials';
@ -160,7 +161,6 @@ export type ICredentialsDecryptedDb = ICredentialsBase & ICredentialsDecrypted;
export type ICredentialsDecryptedResponse = ICredentialsDecryptedDb;
export type DatabaseType = 'mariadb' | 'postgresdb' | 'mysqldb' | 'sqlite';
export type SaveExecutionDataType = 'all' | 'none';
export interface IExecutionBase {

View file

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

View file

@ -1,20 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
export class InitialMigration1588157391238 implements MigrationInterface {
name = 'InitialMigration1588157391238';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class InitialMigration1588157391238 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
'CREATE TABLE IF NOT EXISTS `' +
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_' +
tablePrefix +
'07fde106c0b471d8cc80a64fc8` (`type`), PRIMARY KEY (`id`)) ENGINE=InnoDB',
undefined,
);
await queryRunner.query(
'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_' +
tablePrefix +
'c4d999a5e90784e8caccf5589d` (`workflowId`), PRIMARY KEY (`id`)) ENGINE=InnoDB',
undefined,
);
await queryRunner.query(
'CREATE TABLE IF NOT EXISTS`' +
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',
undefined,
);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query('DROP TABLE `' + tablePrefix + 'workflow_entity`', undefined);
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query('DROP TABLE `' + tablePrefix + 'workflow_entity`');
await queryRunner.query(
'DROP INDEX `IDX_' +
tablePrefix +
'c4d999a5e90784e8caccf5589d` ON `' +
tablePrefix +
'execution_entity`',
undefined,
);
await queryRunner.query('DROP TABLE `' + tablePrefix + 'execution_entity`', undefined);
await queryRunner.query('DROP TABLE `' + tablePrefix + 'execution_entity`');
await queryRunner.query(
'DROP INDEX `IDX_' +
tablePrefix +
'07fde106c0b471d8cc80a64fc8` ON `' +
tablePrefix +
'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 config from '@/config';
export class WebhookModel1592447867632 implements MigrationInterface {
name = 'WebhookModel1592447867632';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class WebhookModel1592447867632 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
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`,
);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`);
}
}

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
export class CreateIndexStoppedAt1594902918301 implements MigrationInterface {
name = 'CreateIndexStoppedAt1594902918301';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateIndexStoppedAt1594902918301 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
'CREATE INDEX `IDX_' +
tablePrefix +
@ -17,9 +11,7 @@ export class CreateIndexStoppedAt1594902918301 implements MigrationInterface {
);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
'DROP INDEX `IDX_' +
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 MigrationInterface {
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class MakeStoppedAtNullable1607431743767 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY `stoppedAt` datetime',
undefined,
);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
'ALTER TABLE `' + tablePrefix + 'execution_entity` MODIFY `stoppedAt` datetime NOT NULL',
undefined,
);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,20 +1,21 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* 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
// `nodeType: name` changes to `nodeType: { id, name }`
export class UpdateWorkflowCredentials1630451444017 implements MigrationInterface {
name = 'UpdateWorkflowCredentials1630451444017';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
const credentialsEntities = await queryRunner.query(`
export class UpdateWorkflowCredentials1630451444017 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
SELECT id, name, type
FROM ${tablePrefix}credentials_entity
`);
`)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = `
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> {
const tablePrefix = config.getEnv('database.tablePrefix');
const credentialsEntities = await queryRunner.query(`
async down({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
SELECT id, name, type
FROM ${tablePrefix}credentials_entity
`);
`)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = `
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 config from '@/config';
export class AddExecutionEntityIndexes1644424784709 implements MigrationInterface {
name = 'AddExecutionEntityIndexes1644424784709';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class AddExecutionEntityIndexes1644424784709 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`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> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`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 config from '@/config';
import { loadSurveyFromDisk } from '@db/utils/migrationHelpers';
export class CreateUserManagement1646992772331 implements MigrationInterface {
name = 'CreateUserManagement1646992772331';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class CreateUserManagement1646992772331 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE TABLE ${tablePrefix}role (
\`id\` int NOT NULL AUTO_INCREMENT,
@ -114,7 +109,9 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
`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(
`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");`,
);
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(
`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();
@ -155,9 +156,7 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD UNIQUE INDEX \`IDX_${tablePrefix}943d8f922be094eb507cb9a7f9\` (\`name\`)`,
);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,16 +1,16 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
/* 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 { runInBatches } from '@db/utils/migrationHelpers';
import { v4 as uuid } from 'uuid';
// add node ids in workflow objects
export class AddNodeIds1658932910559 implements MigrationInterface {
name = 'AddNodeIds1658932910559';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddNodeIds1658932910559 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
const workflowsQuery = `
SELECT id, nodes
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> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
const workflowsQuery = `
SELECT id, nodes
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 {
logMigrationStart,
logMigrationEnd,
runInBatches,
getTablePrefix,
} from '@db/utils/migrationHelpers';
import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { runInBatches } from '@db/utils/migrationHelpers';
import { addJsonKeyToPinDataColumn } from '../sqlite/1659888469333-AddJsonKeyPinData';
import type { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Convert JSON-type `pinData` column in `workflow_entity` table from
* `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }`
*/
export class AddJsonKeyPinData1659895550980 implements MigrationInterface {
name = 'AddJsonKeyPinData1659895550980';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const workflowTable = `${getTablePrefix()}workflow_entity`;
export class AddJsonKeyPinData1659895550980 implements IrreversibleMigration {
async up(context: MigrationContext) {
const { queryRunner, tablePrefix } = context;
const workflowTable = `${tablePrefix}workflow_entity`;
const PINDATA_SELECT_QUERY = `
SELECT id, pinData
@ -34,13 +26,7 @@ export class AddJsonKeyPinData1659895550980 implements MigrationInterface {
await runInBatches(
queryRunner,
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 config from '@/config';
export class CreateCredentialsUserRole1660062385367 implements MigrationInterface {
name = 'CreateCredentialsUserRole1660062385367';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateCredentialsUserRole1660062385367 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`
INSERT IGNORE INTO ${tablePrefix}role (name, scope)
VALUES ("user", "credential");
`);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`
DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='credential';
`);

View file

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

View file

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

View file

@ -1,20 +1,14 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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();
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateCredentialUsageTable1665484192213 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE TABLE \`${tablePrefix}credential_usage\` (` +
'`workflowId` int NOT NULL,' +
'`nodeId` char(200) NOT NULL,' +
"`credentialId` int NOT NULL DEFAULT '1'," +
`\`createdAt\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,` +
`\`updatedAt\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,` +
'`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,' +
'`updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,' +
'PRIMARY KEY (`workflowId`, `nodeId`, `credentialId`)' +
") ENGINE='InnoDB';",
);
@ -26,13 +20,9 @@ export class CreateCredentialUsageTable1665484192213 implements MigrationInterfa
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`,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner) {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE "${tablePrefix}credential_usage"`);
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -1,22 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { StatisticsNames } from '@/databases/entities/WorkflowStatistics';
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
const workflowIds: Array<{ id: number; dataLoaded: boolean }> = await queryRunner.query(`
const workflowIds = (await queryRunner.query(`
SELECT id, dataLoaded
FROM ${tablePrefix}workflow_entity
`);
`)) as Array<{ id: number; dataLoaded: boolean }>;
workflowIds.map(({ id, dataLoaded }) => {
workflowIds.map(async ({ id, dataLoaded }) => {
if (dataLoaded) {
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`);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner) {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN dataLoaded BOOLEAN DEFAULT false`,
);
// 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
FROM ${tablePrefix}workflow_statistics
WHERE name = '${StatisticsNames.dataLoaded}'
`);
workflowsIds.map(({ workflowId }) => {
return queryRunner.query(`
`)) as Array<{ workflowId: string }>;
workflowsIds.map(async ({ workflowId }) =>
queryRunner.query(`
UPDATE ${tablePrefix}workflow_entity
SET dataLoaded = true
WHERE id = '${workflowId}'`);
});
WHERE id = '${workflowId}'
`),
);
await queryRunner.query(
`DELETE FROM ${tablePrefix}workflow_statistics WHERE name = '${StatisticsNames.dataLoaded}'`,

View file

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

View file

@ -1,24 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class AddStatusToExecutions1674138566000 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
// 'ALTER TABLE `' + tablePrefix + 'execution_entity` ADD COLUMN `status` varchar',
`ALTER TABLE \`${tablePrefix}execution_entity\` ADD COLUMN \`status\` VARCHAR(255)`,
);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
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 { 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(
`ALTER TABLE \`${tablePrefix}user\` ADD COLUMN disabled BOOLEAN NOT NULL DEFAULT false;`,
);
@ -46,12 +39,9 @@ export class CreateLdapEntities1674509946020 implements MigrationInterface {
PRIMARY KEY (\`id\`)
) ENGINE='InnoDB';`,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE \`${tablePrefix}auth_provider_sync_history\``);
await queryRunner.query(`DROP TABLE \`${tablePrefix}auth_identity\``);

View file

@ -1,36 +1,29 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { IConnections, INode } from 'n8n-workflow';
import { jsonParse } from 'n8n-workflow';
import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { NodeTypes } from '@/NodeTypes';
import { IConnections, INode } from 'n8n-workflow';
import { getLogger } from '@/Logger';
import { Container } from 'typedi';
export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationInterface {
name = 'PurgeInvalidWorkflowConnections1675940580449';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
const workflows: Array<{
export class PurgeInvalidWorkflowConnections1675940580449 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix, migrationName, logger }: MigrationContext) {
const workflows = (await queryRunner.query(`
SELECT id, nodes, connections
FROM \`${tablePrefix}workflow_entity\`
`)) as Array<{
id: number;
nodes: INode[] | string;
connections: IConnections | string;
}> = await queryRunner.query(`
SELECT id, nodes, connections
FROM \`${tablePrefix}workflow_entity\`
`);
}>;
const nodeTypes = Container.get(NodeTypes);
workflows.forEach(async (workflow) => {
let connections: IConnections =
const connections =
typeof workflow.connections === 'string'
? JSON.parse(workflow.connections)
? jsonParse<IConnections>(workflow.connections)
: workflow.connections;
const nodes: INode[] =
typeof workflow.nodes === 'string' ? JSON.parse(workflow.nodes) : workflow.nodes;
const nodes =
typeof workflow.nodes === 'string' ? jsonParse<INode[]>(workflow.nodes) : workflow.nodes;
const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => {
try {
@ -39,7 +32,7 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
acc.push(node.name);
}
} 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;
}, [] as string[]);
@ -48,7 +41,7 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
const connection = connections[sourceNodeName];
const outputs = Object.keys(connection);
outputs.forEach((outputConnectionName /* Like `main` */, idx) => {
outputs.forEach((outputConnectionName /* Like `main` */) => {
const outputConnection = connection[outputConnectionName];
// 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
const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters(
`
UPDATE \`${tablePrefix}workflow_entity\`
SET connections = :connections
WHERE id = '${workflow.id}'
`,
`UPDATE \`${tablePrefix}workflow_entity\`
SET connections = :connections
WHERE id = '${workflow.id}'`,
{ connections: JSON.stringify(connections) },
{},
);
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 { 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');
import type { MigrationContext, IrreversibleMigration } from '@db/types';
export class MigrateExecutionStatus1676996103000 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`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(
`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 { 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');
import type { MigrationContext, IrreversibleMigration } from '@db/types';
export class UpdateRunningExecutionStatus1677236788851 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`UPDATE \`${tablePrefix}execution_entity\` SET status='failed' WHERE status = 'running' AND finished=0 AND \`stoppedAt\` IS NOT NULL;`,
);
await queryRunner.query(
`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 { 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();
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateVariables1677501636753 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`
CREATE TABLE ${tablePrefix}variables (
id int(11) auto_increment NOT NULL PRIMARY KEY,
@ -18,16 +12,9 @@ export class CreateVariables1677501636753 implements MigrationInterface {
)
ENGINE=InnoDB;
`);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE ${tablePrefix}variables;`);
logMigrationEnd(this.name);
}
}

View file

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

View file

@ -1,16 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { MigrationContext, ReversibleMigration } from '@db/types';
import type { UserSettings } from '@/Interfaces';
export class AddUserActivatedProperty1681134145996 implements MigrationInterface {
name = 'AddUserActivatedProperty1681134145996';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
const activatedUsers: UserSettings[] = await queryRunner.query(
export class AddUserActivatedProperty1681134145996 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
const activatedUsers = (await queryRunner.query(
`SELECT DISTINCT sw.userId AS id,
JSON_SET(COALESCE(u.settings, '{}'), '$.userActivated', true) AS settings
FROM ${tablePrefix}workflow_statistics AS ws
@ -23,15 +16,15 @@ export class AddUserActivatedProperty1681134145996 implements MigrationInterface
WHERE ws.name = 'production_success'
AND r.name = 'owner'
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
*/
const userSettings =
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}' `,
);
});
@ -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})`,
);
}
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`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 { WebhookModel1592447867632 } from './1592447867632-WebhookModel';
import { CreateIndexStoppedAt1594902918301 } from './1594902918301-CreateIndexStoppedAt';
@ -38,7 +39,7 @@ import { CreateExecutionMetadataTable1679416281779 } from './1679416281779-Creat
import { CreateVariables1677501636753 } from './1677501636753-CreateVariables';
import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty';
export const mysqlMigrations = [
export const mysqlMigrations: Migration[] = [
InitialMigration1588157391238,
WebhookModel1592447867632,
CreateIndexStoppedAt1594902918301,

View file

@ -1,41 +1,29 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix } from '@db/utils/migrationHelpers';
export class InitialMigration1587669153312 implements MigrationInterface {
name = 'InitialMigration1587669153312';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class InitialMigration1587669153312 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
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"))`,
undefined,
);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8 ON ${tablePrefix}credentials_entity (type) `,
undefined,
);
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"))`,
undefined,
);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS IDX_${tablePrefix}c4d999a5e90784e8caccf5589d ON ${tablePrefix}execution_entity ("workflowId") `,
undefined,
);
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"))`,
undefined,
);
}
async down(queryRunner: QueryRunner): Promise<void> {
let tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE ${tablePrefix}workflow_entity`, undefined);
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}c4d999a5e90784e8caccf5589d`, undefined);
await queryRunner.query(`DROP TABLE ${tablePrefix}execution_entity`, undefined);
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8`, undefined);
await queryRunner.query(`DROP TABLE ${tablePrefix}credentials_entity`, undefined);
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE ${tablePrefix}workflow_entity`);
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}c4d999a5e90784e8caccf5589d`);
await queryRunner.query(`DROP TABLE ${tablePrefix}execution_entity`);
await queryRunner.query(`DROP INDEX IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8`);
await queryRunner.query(`DROP TABLE ${tablePrefix}credentials_entity`);
}
}

View file

@ -1,19 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix } from '@db/utils/migrationHelpers';
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class WebhookModel1589476000887 implements MigrationInterface {
name = 'WebhookModel1589476000887';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class WebhookModel1589476000887 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
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"))`,
undefined,
);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`, undefined);
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`);
}
}

View file

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

View file

@ -1,18 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix } from '@db/utils/migrationHelpers';
import type { MigrationContext, IrreversibleMigration } from '@db/types';
export class MakeStoppedAtNullable1607431743768 implements MigrationInterface {
name = 'MakeStoppedAtNullable1607431743768';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class MakeStoppedAtNullable1607431743768 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
'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 { getTablePrefix } from '@db/utils/migrationHelpers';
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class AddWebhookId1611144599516 implements MigrationInterface {
name = 'AddWebhookId1611144599516';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class AddWebhookId1611144599516 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`ALTER TABLE ${tablePrefix}webhook_entity ADD "webhookId" character varying`,
);
@ -15,8 +11,7 @@ export class AddWebhookId1611144599516 implements MigrationInterface {
);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
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 "webhookId"`);

View file

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

View file

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

View file

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

View file

@ -1,19 +1,21 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, runInBatches } from '@db/utils/migrationHelpers';
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* 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
// `nodeType: name` changes to `nodeType: { id, name }`
export class UpdateWorkflowCredentials1630419189837 implements MigrationInterface {
name = 'UpdateWorkflowCredentials1630419189837';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
const credentialsEntities = await queryRunner.query(`
export class UpdateWorkflowCredentials1630419189837 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
SELECT id, name, type
FROM ${tablePrefix}credentials_entity
`);
`)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = `
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> {
const tablePrefix = getTablePrefix();
const credentialsEntities = await queryRunner.query(`
async down({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
SELECT id, name, type
FROM ${tablePrefix}credentials_entity
`);
`)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = `
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 { getTablePrefix } from '@db/utils/migrationHelpers';
export class AddExecutionEntityIndexes1644422880309 implements MigrationInterface {
name = 'AddExecutionEntityIndexes1644422880309';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
import type { MigrationContext, ReversibleMigration } from '@db/types';
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}ca4a71b47f28ac6ea88293a8e2`);
await queryRunner.query(
@ -29,9 +24,7 @@ export class AddExecutionEntityIndexes1644422880309 implements MigrationInterfac
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}d160d4771aba5a0d78943edbe3"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}85b981df7b444f905f8bf50747"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}72ffaaab9f04c2c1f1ea86e662"`);

View file

@ -1,15 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix } from '@db/utils/migrationHelpers';
import type { MigrationContext, IrreversibleMigration } from '@db/types';
export class IncreaseTypeVarcharLimit1646834195327 implements MigrationInterface {
name = 'IncreaseTypeVarcharLimit1646834195327';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class IncreaseTypeVarcharLimit1646834195327 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`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 { getTablePrefix, loadSurveyFromDisk } from '@db/utils/migrationHelpers';
export class CreateUserManagement1646992772331 implements MigrationInterface {
name = 'CreateUserManagement1646992772331';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
import { loadSurveyFromDisk } from '@db/utils/migrationHelpers';
export class CreateUserManagement1646992772331 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE TABLE ${tablePrefix}role (
"id" serial NOT NULL,
@ -92,7 +88,9 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
`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(
`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');`,
);
const workflowOwnerRole = await queryRunner.query('SELECT lastval() as "insertId"');
const workflowOwnerRole = (await queryRunner.query(
'SELECT lastval() as "insertId"',
)) as InsertResult;
await queryRunner.query(
`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();
@ -133,9 +135,7 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_${tablePrefix}a252c527c4c89237221fe2c0ab" ON ${tablePrefix}workflow_entity ("name")`,
);

View file

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

View file

@ -1,14 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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();
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CommunityNodes1652254514002 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE TABLE ${tablePrefix}installed_packages (` +
'"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 ` +
');',
);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE "${tablePrefix}installed_nodes"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}installed_packages"`);
}

View file

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

View file

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

View file

@ -1,20 +1,11 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class IntroducePinData1654090467022 implements MigrationInterface {
name = 'IntroducePinData1654090467022';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
export class IntroducePinData1654090467022 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ADD "pinData" json`);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner) {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
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 { getTablePrefix, runInBatches } from '@db/utils/migrationHelpers';
import { runInBatches } from '@db/utils/migrationHelpers';
// add node ids in workflow objects
export class AddNodeIds1658932090381 implements MigrationInterface {
name = 'AddNodeIds1658932090381';
public async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class AddNodeIds1658932090381 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
const workflowsQuery = `
SELECT id, nodes
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> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
const workflowsQuery = `
SELECT id, nodes
FROM ${tablePrefix}workflow_entity
@ -57,16 +56,14 @@ export class AddNodeIds1658932090381 implements MigrationInterface {
nodes.forEach((node) => delete node.id);
const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters(
`
UPDATE ${tablePrefix}workflow_entity
SET nodes = :nodes
WHERE id = '${workflow.id}'
`,
`UPDATE ${tablePrefix}workflow_entity
SET nodes = :nodes
WHERE id = '${workflow.id}'`,
{ nodes: JSON.stringify(nodes) },
{},
);
queryRunner.query(updateQuery, updateParams);
await queryRunner.query(updateQuery, updateParams);
});
});
}

View file

@ -1,23 +1,15 @@
import {
getTablePrefix,
logMigrationEnd,
logMigrationStart,
runInBatches,
} from '@db/utils/migrationHelpers';
import type { MigrationContext, IrreversibleMigration } from '@/databases/types';
import { runInBatches } from '@db/utils/migrationHelpers';
import { addJsonKeyToPinDataColumn } from '../sqlite/1659888469333-AddJsonKeyPinData';
import type { MigrationInterface, QueryRunner } from 'typeorm';
/**
* Convert JSON-type `pinData` column in `workflow_entity` table from
* `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }`
*/
export class AddJsonKeyPinData1659902242948 implements MigrationInterface {
name = 'AddJsonKeyPinData1659902242948';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const workflowTable = `${getTablePrefix()}workflow_entity`;
export class AddJsonKeyPinData1659902242948 implements IrreversibleMigration {
async up(context: MigrationContext) {
const { queryRunner, tablePrefix } = context;
const workflowTable = `${tablePrefix}workflow_entity`;
const PINDATA_SELECT_QUERY = `
SELECT id, "pinData"
@ -34,13 +26,7 @@ export class AddJsonKeyPinData1659902242948 implements MigrationInterface {
await runInBatches(
queryRunner,
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 { getTablePrefix } from '@db/utils/migrationHelpers';
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateCredentialsUserRole1660062385367 implements MigrationInterface {
name = 'CreateCredentialsUserRole1660062385367';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
export class CreateCredentialsUserRole1660062385367 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`
INSERT INTO ${tablePrefix}role (name, scope)
VALUES ('user', 'credential')
@ -13,8 +9,7 @@ export class CreateCredentialsUserRole1660062385367 implements MigrationInterfac
`);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`
DELETE FROM ${tablePrefix}role WHERE name='user' AND scope='credential';
`);

View file

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

View file

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

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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();
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateCredentialUsageTable1665484192212 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE TABLE ${tablePrefix}credential_usage (` +
'"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 ` +
');',
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner) {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE "${tablePrefix}credential_usage"`);
}
}

View file

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

View file

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

View file

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

View file

@ -1,21 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import { StatisticsNames } from '@db/entities/WorkflowStatistics';
export class RemoveWorkflowDataLoadedFlag1671726148421 implements MigrationInterface {
name = 'RemoveWorkflowDataLoadedFlag1671726148421';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { StatisticsNames } from '@/databases/entities/WorkflowStatistics';
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
const workflowIds: Array<{ id: number; dataLoaded: boolean }> = await queryRunner.query(`
const workflowIds = (await queryRunner.query(`
SELECT id, "dataLoaded"
FROM ${tablePrefix}workflow_entity
`);
`)) as Array<{ id: number; dataLoaded: boolean }>;
workflowIds.map(({ id, dataLoaded }) => {
workflowIds.map(async ({ id, dataLoaded }) => {
if (dataLoaded) {
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"`);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner) {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`ALTER TABLE ${tablePrefix}workflow_entity ADD COLUMN "dataLoaded" BOOLEAN DEFAULT false`,
);
// 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"
FROM ${tablePrefix}workflow_statistics
WHERE name = '${StatisticsNames.dataLoaded}'
`);
workflowsIds.map(({ workflowId }) => {
`)) as Array<{ workflowId: string }>;
workflowsIds.map(async ({ workflowId }) => {
return queryRunner.query(`
UPDATE ${tablePrefix}workflow_entity
SET "dataLoaded" = true

View file

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

View file

@ -1,21 +1,11 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class AddStatusToExecutions1674138566000 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`ALTER TABLE ${tablePrefix}execution_entity ADD COLUMN status varchar`);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
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 { 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(
`ALTER TABLE "${tablePrefix}user" ADD COLUMN disabled BOOLEAN NOT NULL DEFAULT false;`,
);
@ -45,12 +38,9 @@ export class CreateLdapEntities1674509946020 implements MigrationInterface {
"error" TEXT
);`,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE "${tablePrefix}auth_provider_sync_history"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}auth_identity"`);

View file

@ -1,28 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { IConnections, INode } from 'n8n-workflow';
import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { NodeTypes } from '@/NodeTypes';
import { IConnections, INode } from 'n8n-workflow';
import { getLogger } from '@/Logger';
import { Container } from 'typedi';
export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationInterface {
name = 'PurgeInvalidWorkflowConnections1675940580449';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
const workflows: Array<{ id: number; nodes: INode[]; connections: IConnections }> =
await queryRunner.query(`
export class PurgeInvalidWorkflowConnections1675940580449 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix, migrationName, logger }: MigrationContext) {
const workflows = (await queryRunner.query(`
SELECT id, nodes, connections
FROM "${tablePrefix}workflow_entity"
`);
`)) as Array<{ id: number; nodes: INode[]; connections: IConnections }>;
const nodeTypes = Container.get(NodeTypes);
workflows.forEach(async (workflow) => {
let connections: IConnections = workflow.connections;
const nodes: INode[] = workflow.nodes;
const { connections, nodes } = workflow;
const nodesThatCannotReceiveInput: string[] = nodes.reduce((acc, node) => {
try {
@ -31,7 +22,7 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
acc.push(node.name);
}
} 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;
}, [] as string[]);
@ -40,7 +31,7 @@ export class PurgeInvalidWorkflowConnections1675940580449 implements MigrationIn
const connection = connections[sourceNodeName];
const outputs = Object.keys(connection);
outputs.forEach((outputConnectionName /* Like `main` */, idx) => {
outputs.forEach((outputConnectionName /* Like `main` */) => {
const outputConnection = connection[outputConnectionName];
// 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
const [updateQuery, updateParams] = queryRunner.connection.driver.escapeQueryWithParameters(
`
UPDATE "${tablePrefix}workflow_entity"
SET connections = :connections
WHERE id = '${workflow.id}'
`,
`UPDATE "${tablePrefix}workflow_entity"
SET connections = :connections
WHERE id = '${workflow.id}'`,
{ connections: JSON.stringify(connections) },
{},
);
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 { 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');
import type { MigrationContext, IrreversibleMigration } from '@db/types';
export class MigrateExecutionStatus1676996103000 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`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(
`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 { 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');
import type { MigrationContext, IrreversibleMigration } from '@db/types';
export class UpdateRunningExecutionStatus1677236854063 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`UPDATE "${tablePrefix}execution_entity" SET "status" = 'failed' WHERE "status" = 'running' AND "finished"=false AND "stoppedAt" IS NOT NULL;`,
);
await queryRunner.query(
`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 { 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();
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateVariables1677501636754 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`
CREATE TABLE ${tablePrefix}variables (
id serial4 NOT NULL PRIMARY KEY,
@ -17,16 +11,9 @@ export class CreateVariables1677501636754 implements MigrationInterface {
UNIQUE ("key")
);
`);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE ${tablePrefix}variables;`);
logMigrationEnd(this.name);
}
}

View file

@ -1,13 +1,7 @@
import { MigrationInterface, QueryRunner, Table } from 'typeorm';
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();
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateExecutionMetadataTable1679416281778 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE TABLE ${tablePrefix}execution_metadata (
"id" serial4 NOT NULL PRIMARY KEY,
@ -32,13 +26,9 @@ export class CreateExecutionMetadataTable1679416281778 implements MigrationInter
await queryRunner.query(
`CREATE INDEX "IDX_${tablePrefix}8b6f3f9ae234f137d707b98f3bf43584" ON "${tablePrefix}execution_entity" ("status", "workflowId");`,
);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
// Re-add removed indices
await queryRunner.query(
`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 { getTablePrefix, logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { MigrationContext, ReversibleMigration } from '@db/types';
import type { UserSettings } from '@/Interfaces';
export class AddUserActivatedProperty1681134145996 implements MigrationInterface {
name = 'AddUserActivatedProperty1681134145996';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = getTablePrefix();
const activatedUsers: UserSettings[] = await queryRunner.query(
export class AddUserActivatedProperty1681134145996 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
const activatedUsers = (await queryRunner.query(
`SELECT DISTINCT sw."userId" AS id,
JSONB_SET(COALESCE(u.settings::jsonb, '{}'), '{userActivated}', 'true', true) as settings
FROM ${tablePrefix}workflow_statistics ws
@ -23,9 +16,9 @@ export class AddUserActivatedProperty1681134145996 implements MigrationInterface
WHERE ws.name = 'production_success'
AND r.name = 'owner'
AND r.scope = 'workflow'`,
);
)) as UserSettings[];
const updatedUsers = activatedUsers.map((user) =>
const updatedUsers = activatedUsers.map(async (user) =>
queryRunner.query(
`UPDATE "${tablePrefix}user" SET settings = '${JSON.stringify(
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})`,
);
}
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = getTablePrefix();
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`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 { WebhookModel1589476000887 } from './1589476000887-WebhookModel';
import { CreateIndexStoppedAt1594828256133 } from './1594828256133-CreateIndexStoppedAt';
@ -36,7 +37,7 @@ import { CreateExecutionMetadataTable1679416281778 } from './1679416281778-Creat
import { CreateVariables1677501636754 } from './1677501636754-CreateVariables';
import { AddUserActivatedProperty1681134145996 } from './1681134145996-AddUserActivatedProperty';
export const postgresMigrations = [
export const postgresMigrations: Migration[] = [
InitialMigration1587669153312,
WebhookModel1589476000887,
CreateIndexStoppedAt1594828256133,

View file

@ -1,46 +1,29 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class InitialMigration1588102412422 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
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)`,
undefined,
);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8" ON "${tablePrefix}credentials_entity" ("type") `,
undefined,
);
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)`,
undefined,
);
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d" ON "${tablePrefix}execution_entity" ("workflowId") `,
undefined,
);
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)`,
undefined,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
await queryRunner.query(`DROP TABLE "${tablePrefix}workflow_entity"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d"`, undefined);
await queryRunner.query(`DROP TABLE "${tablePrefix}execution_entity"`, undefined);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8"`, undefined);
await queryRunner.query(`DROP TABLE "${tablePrefix}credentials_entity"`, undefined);
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE "${tablePrefix}workflow_entity"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}c4d999a5e90784e8caccf5589d"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}execution_entity"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}credentials_entity"`);
}
}

View file

@ -1,24 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class WebhookModel1592445003908 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
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"))`,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE ${tablePrefix}webhook_entity`);
}
}

View file

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

View file

@ -1,30 +1,16 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { MigrationContext, IrreversibleMigration } from '@db/types';
export class MakeStoppedAtNullable1607431743769 implements MigrationInterface {
name = 'MakeStoppedAtNullable1607431743769';
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class MakeStoppedAtNullable1607431743769 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
// SQLite does not allow us to simply "alter column"
// We're hacking the way sqlite identifies tables
// Allowing a column to become nullable
// This is a very strict case when this can be done safely
// As no collateral effects exist.
await queryRunner.query(`PRAGMA writable_schema = 1; `, undefined);
await queryRunner.query('PRAGMA writable_schema = 1;');
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";`,
undefined,
);
await queryRunner.query(`PRAGMA writable_schema = 0;`, undefined);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
// This cannot be undone as the table might already have nullable values
await queryRunner.query('PRAGMA writable_schema = 0;');
}
}

View file

@ -1,17 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class AddWebhookId1611071044839 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
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(
`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(
`CREATE INDEX "IDX_${tablePrefix}742496f199721a057051acf4c2" ON "${tablePrefix}webhook_entity" ("webhookId", "method", "pathLength") `,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}742496f199721a057051acf4c2"`);
await queryRunner.query(
`ALTER TABLE "${tablePrefix}webhook_entity" RENAME TO "temporary_webhook_entity"`,
@ -40,6 +28,6 @@ export class AddWebhookId1611071044839 implements MigrationInterface {
await queryRunner.query(
`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 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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CreateTagEntity1617213344594 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
// create tags table + relationship with workflow entity
await queryRunner.query(
@ -68,13 +60,9 @@ export class CreateTagEntity1617213344594 implements MigrationInterface {
await queryRunner.query(
`ALTER TABLE "${tablePrefix}temporary_workflow_entity" RENAME TO "${tablePrefix}workflow_entity"`,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
// `createdAt` and `updatedAt`
await queryRunner.query(

View file

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

View file

@ -1,19 +1,10 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class AddWaitColumn1621707690587 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE IF EXISTS "${tablePrefix}temporary_execution_entity"`);
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)`,
undefined,
);
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"`,
@ -28,16 +19,11 @@ export class AddWaitColumn1621707690587 implements MigrationInterface {
await queryRunner.query(
`CREATE INDEX "IDX_${tablePrefix}ca4a71b47f28ac6ea88293a8e2" ON "${tablePrefix}execution_entity" ("waitTill")`,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
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)`,
undefined,
);
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"`,

View file

@ -1,23 +1,22 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
/* eslint-disable n8n-local-rules/no-uncaught-json-parse */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* 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
// `nodeType: name` changes to `nodeType: { id, name }`
export class UpdateWorkflowCredentials1630330987096 implements MigrationInterface {
name = 'UpdateWorkflowCredentials1630330987096';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
const credentialsEntities = await queryRunner.query(`
export class UpdateWorkflowCredentials1630330987096 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
SELECT id, name, type
FROM "${tablePrefix}credentials_entity"
`);
`)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = `
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> {
const tablePrefix = config.getEnv('database.tablePrefix');
const credentialsEntities = await queryRunner.query(`
async down({ queryRunner, tablePrefix }: MigrationContext) {
const credentialsEntities = (await queryRunner.query(`
SELECT id, name, type
FROM "${tablePrefix}credentials_entity"
`);
`)) as Array<{ id: string; name: string; type: string }>;
const workflowsQuery = `
SELECT id, nodes
@ -176,7 +171,9 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
for (const [type, creds] of allNodeCredentials) {
if (typeof creds === 'object') {
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,
);
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) {
if (typeof creds === 'object') {
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,
);
if (matchingCredentials) {
@ -276,7 +275,9 @@ export class UpdateWorkflowCredentials1630330987096 implements MigrationInterfac
for (const [type, creds] of allNodeCredentials) {
if (typeof creds === 'object') {
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,
);
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 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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
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}ca4a71b47f28ac6ea88293a8e2'`);
@ -28,12 +21,9 @@ export class AddExecutionEntityIndexes1644421939510 implements MigrationInterfac
await queryRunner.query(
`CREATE INDEX IF NOT EXISTS 'IDX_${tablePrefix}81fc04c8a17de15835713505e4' ON '${tablePrefix}execution_entity' ('workflowId', 'id') `,
);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP INDEX 'IDX_${tablePrefix}81fc04c8a17de15835713505e4'`);
await queryRunner.query(`DROP INDEX 'IDX_${tablePrefix}b94b45ce2c73ce46c54f20b5f9'`);
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 config from '@/config';
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');
import { loadSurveyFromDisk } from '@db/utils/migrationHelpers';
export class CreateUserManagement1646992772331 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
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"))`,
);
@ -49,7 +42,9 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
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(`
INSERT INTO "${tablePrefix}role" (name, scope)
@ -61,14 +56,18 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
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(`
INSERT INTO "${tablePrefix}role" (name, scope)
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();
@ -95,12 +94,9 @@ export class CreateUserManagement1646992772331 implements MigrationInterface {
INSERT INTO "${tablePrefix}settings" (key, value, loadOnStartup) values
('userManagement.isInstanceOwnerSetUp', 'false', true), ('userManagement.skipInstanceOwnerSetup', 'false', true)
`);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9" ON "${tablePrefix}workflow_entity" ("name") `,
);

View file

@ -1,22 +1,10 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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');
import type { MigrationContext, IrreversibleMigration } from '@db/types';
export class LowerCaseUserEmail1648740597343 implements IrreversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`
UPDATE "${tablePrefix}user"
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 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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class CommunityNodes1652254514001 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`CREATE TABLE "${tablePrefix}installed_packages" (` +
`"packageName" char(214) NOT NULL,` +
`"installedVersion" char(50) NOT NULL,` +
`"authorName" char(70) NULL,` +
`"authorEmail" char(70) 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'')',` +
`PRIMARY KEY("packageName")` +
`);`,
'"packageName" char(214) NOT NULL,' +
'"installedVersion" char(50) NOT NULL,' +
'"authorName" char(70) NULL,' +
'"authorEmail" char(70) 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'')'," +
'PRIMARY KEY("packageName")' +
');',
);
await queryRunner.query(
`CREATE TABLE "${tablePrefix}installed_nodes" (` +
`"name" char(200) NOT NULL,` +
`"type" char(200) NOT NULL,` +
`"latestVersion" INTEGER DEFAULT 1,` +
`"package" char(214) NOT NULL,` +
`PRIMARY KEY("name"),` +
'"name" char(200) NOT NULL,' +
'"type" char(200) NOT NULL,' +
'"latestVersion" INTEGER DEFAULT 1,' +
'"package" char(214) NOT NULL,' +
'PRIMARY KEY("name"),' +
`FOREIGN KEY("package") REFERENCES "${tablePrefix}installed_packages"("packageName") ON DELETE CASCADE ON UPDATE CASCADE` +
`);`,
');',
);
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`DROP TABLE "${tablePrefix}installed_nodes"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}installed_packages"`);
}

View file

@ -1,17 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class AddUserSettings1652367743993 implements MigrationInterface {
name = 'AddUserSettings1652367743993';
transaction = false;
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddUserSettings1652367743993 implements ReversibleMigration {
transaction = false as const;
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query('PRAGMA foreign_keys=OFF');
await queryRunner.query(
@ -28,13 +20,9 @@ export class AddUserSettings1652367743993 implements MigrationInterface {
);
await queryRunner.query('PRAGMA foreign_keys=ON');
logMigrationEnd(this.name);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" RENAME TO "temporary_user"`);
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)`,
@ -42,7 +30,7 @@ export class AddUserSettings1652367743993 implements MigrationInterface {
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"`,
);
await queryRunner.query(`DROP TABLE "temporary_user"`);
await queryRunner.query('DROP TABLE "temporary_user"');
await queryRunner.query(
`CREATE UNIQUE INDEX "UQ_${tablePrefix}e12875dfb3b1d92d7d7c5377e2" ON "${tablePrefix}user" ("email")`,
);

View file

@ -1,17 +1,9 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class AddAPIKeyColumn1652905585850 implements MigrationInterface {
name = 'AddAPIKeyColumn1652905585850';
transaction = false;
async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddAPIKeyColumn1652905585850 implements ReversibleMigration {
transaction = false as const;
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query('PRAGMA foreign_keys=OFF');
await queryRunner.query(
@ -31,13 +23,9 @@ export class AddAPIKeyColumn1652905585850 implements MigrationInterface {
);
await queryRunner.query('PRAGMA foreign_keys=ON');
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(`ALTER TABLE "${tablePrefix}user" RENAME TO "temporary_user"`);
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)`,
@ -45,7 +33,7 @@ export class AddAPIKeyColumn1652905585850 implements MigrationInterface {
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"`,
);
await queryRunner.query(`DROP TABLE "temporary_user"`);
await queryRunner.query('DROP TABLE "temporary_user"');
await queryRunner.query(
`CREATE UNIQUE INDEX "UQ_${tablePrefix}e12875dfb3b1d92d7d7c5377e2" ON "${tablePrefix}user" ("email")`,
);

View file

@ -1,25 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
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');
import type { MigrationContext, ReversibleMigration } from '@db/types';
export class IntroducePinData1654089251344 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`ALTER TABLE \`${tablePrefix}workflow_entity\` ADD COLUMN "pinData" text`,
);
logMigrationEnd(this.name);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
await queryRunner.query(
`ALTER TABLE \`${tablePrefix}workflow_entity\` RENAME TO "temporary_workflow_entity"`,
);
@ -30,6 +18,6 @@ export class IntroducePinData1654089251344 implements MigrationInterface {
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"`,
);
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';
import { MigrationInterface, QueryRunner } from 'typeorm';
import config from '@/config';
import { logMigrationEnd, logMigrationStart } from '@db/utils/migrationHelpers';
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* 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 { INode } from 'n8n-workflow';
import type { MigrationContext, ReversibleMigration } from '@db/types';
import { runInBatches } from '@db/utils/migrationHelpers';
import { v4 as uuid } from 'uuid';
// add node ids in workflow objects
export class AddNodeIds1658930531669 implements MigrationInterface {
name = 'AddNodeIds1658930531669';
public async up(queryRunner: QueryRunner): Promise<void> {
logMigrationStart(this.name);
const tablePrefix = config.getEnv('database.tablePrefix');
export class AddNodeIds1658930531669 implements ReversibleMigration {
async up({ queryRunner, tablePrefix }: MigrationContext) {
const workflowsQuery = `
SELECT id, nodes
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> {
const tablePrefix = config.getEnv('database.tablePrefix');
async down({ queryRunner, tablePrefix }: MigrationContext) {
const workflowsQuery = `
SELECT id, nodes
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 {
logMigrationStart,
logMigrationEnd,
runInBatches,
getTablePrefix,
escapeQuery,
} from '@db/utils/migrationHelpers';
import type { MigrationInterface, QueryRunner } from 'typeorm';
import { isJsonKeyObject, PinData } from '@db/utils/migrations.types';
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-use-before-define */
import type { IDataObject, INodeExecutionData } from 'n8n-workflow';
import type { MigrationContext, IrreversibleMigration } from '@db/types';
import { runInBatches, escapeQuery } from '@db/utils/migrationHelpers';
/**
* Convert TEXT-type `pinData` column in `workflow_entity` table from
* `{ [nodeName: string]: IDataObject[] }` to `{ [nodeName: string]: INodeExecutionData[] }`
*/
export class AddJsonKeyPinData1659888469333 implements MigrationInterface {
name = 'AddJsonKeyPinData1659888469333';
async up(queryRunner: QueryRunner) {
logMigrationStart(this.name);
const workflowTable = `${getTablePrefix()}workflow_entity`;
export class AddJsonKeyPinData1659888469333 implements IrreversibleMigration {
async up(context: MigrationContext) {
const { queryRunner, tablePrefix } = context;
const workflowTable = `${tablePrefix}workflow_entity`;
const PINDATA_SELECT_QUERY = `
SELECT id, pinData
@ -35,30 +28,45 @@ export class AddJsonKeyPinData1659888469333 implements MigrationInterface {
await runInBatches(
queryRunner,
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 =
(queryRunner: QueryRunner, updateStatement: string) =>
({ queryRunner }: MigrationContext, updateStatement: string) =>
async (fetchedWorkflows: PinData.FetchedWorkflow[]) => {
makeUpdateParams(fetchedWorkflows).forEach((param) => {
const params = {
pinData: param.pinData,
id: param.id,
};
await Promise.all(
makeUpdateParams(fetchedWorkflows).map(async (param) => {
const params = {
pinData: param.pinData,
id: param.id,
};
const [escapedStatement, escapedParams] = escapeQuery(queryRunner, updateStatement, params);
queryRunner.query(escapedStatement, escapedParams);
});
const [escapedStatement, escapedParams] = escapeQuery(queryRunner, updateStatement, params);
return queryRunner.query(escapedStatement, escapedParams);
}),
);
};
function makeUpdateParams(fetchedWorkflows: PinData.FetchedWorkflow[]) {
@ -77,6 +85,7 @@ function makeUpdateParams(fetchedWorkflows: PinData.FetchedWorkflow[]) {
}
const newPinDataPerWorkflow = Object.keys(pinDataPerWorkflow).reduce<PinData.New>(
// eslint-disable-next-line @typescript-eslint/no-shadow
(newPinDataPerWorkflow, nodeName) => {
let pinDataPerNode = pinDataPerWorkflow[nodeName];

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