Add tagging of workflows (#1647)

* clean up dropdown

* clean up focusoncreate

*  Ignore mistaken ID in POST /workflows

*  Fix undefined tag ID in PATCH /workflows

*  Shorten response for POST /tags

* remove scss mixins

* clean up imports

*  Implement validation with class-validator

* address ivan's comments

* implement modals

* Fix lint issues

* fix disabling shortcuts

* fix focus issues

* fix focus issues

* fix focus issues with modal

* fix linting issues

* use dispatch

* use constants for modal keys

* fix focus

* fix lint issues

* remove unused prop

* add modal root

* fix lint issues

* remove unused methods

* fix shortcut

* remove max width

*  Fix duplicate entry error for pg and MySQL

* update rename messaging

* update order of buttons

* fix firefox overflow on windows

* fix dropdown height

* 🔨 refactor tag crud controllers

* 🧹 remove unused imports

* use variable for number of items

* fix dropdown spacing

*  Restore type to fix build

*  Fix post-refactor PATCH /workflows/:id

*  Fix PATCH /workflows/:id for zero tags

*  Fix usage count becoming stringified

* address max's comments

* fix filter spacing

* fix blur bug

* address most of ivan's comments

* address tags type concern

* remove defaults

*  return tag id as string

* 🔨 add hooks to tag CUD operations

* 🏎 simplify timestamp pruning

* remove blur event

* fix onblur bug

*  Fix fs import to fix build

* address max's comments

* implement responsive tag container

* fix lint issues

* Set default dates in entities

* 👕 Fix lint in migrations

* update tag limits

* address ivan's comments

* remove rename, refactor header, implement new designs for save, remove responsive tag container

* update styling

* update styling

* implement responsive tag container

* implement header tags edit

* implement header tags edit

* fix lint issues

* implement expandable input

* minor fixes

* minor fixes

* use variable

* rename save as

* duplicate fixes

*  Implement unique workflow names

*  Create /workflows/new endpoint

* minor edit fixes

* lint fixes

* style fixes

* hook up saving name

* hook up tags

* clean up impl

* fix dirty state bug

* update limit

* update notification messages

* on click outside

* fix minor bug with count

* lint fixes

*  Add query string params to /workflows/new

* handle minor edge cases

* handle minor edge cases

* handle minor bugs; fix firefox dropdown issue

* Fix min width

* apply tags only after api success

* remove count fix

* 🚧 Adjust to new qs requirements

* clean up workflow tags impl, fix tags delete bug

* fix minor issue

* fix minor spacing issue

* disable wrap for ops

* fix viewport root; save on click in dropdown

* save button loading when saving name/tags

* implement max width on tags container

* implement cleaner create experience

* disable edit while updating

* codacy hex color

* refactor tags container

* fix clickability

* fix workflow open and count

* clean up structure

* fix up lint issues

*  Create migrations for unique workflow names

* fix button size

* increase workflow name limit for larger screen

* tslint fixes

* disable responsiveness for workflow modal

* rename event

* change min width for tags

* clean up pr

*  Adjust quotes in MySQL migration

*  Adjust quotes in Postgres migration

* address max's comments on styles

* remove success toasts

* add hover mode to name

* minor fixes

* refactor name preview

* fix name input not to jiggle

* finish up name input

* Fix up add tags

* clean up param

* clean up scss

* fix resizing name

* fix resizing name

* fix resize bug

* clean up edit spacing

* ignore on esc

* fix input bug

* focus input on clear

* build

* fix up add tags clickablity

* remove scrollbars

* move into folders

* clean up multiple patch req

* remove padding top from edit

* update tags on enter

* build

* rollout blur on enter behavior

* rollout esc behavior

* fix tags bug when duplicating tags

* move key to reload tags

* update header spacing

* build

* update hex case

* refactor workflow title

* remove unusued prop

* keep focus on error, fix bug on error

* Fix bug with name / tags toggle on error

* impl creating new workflow name

*  Refactor endpoint per new guidelines

* support naming endpoint

*  Refactor to support numeric suffixes

* 👕 Lint migrations for unique workflow names

*  Add migrations set default dates to indexes

* fix connection push bug

*  Lowercase default workflow name

*  Add prefixes to set default dates migration

*  Fix indentation on default dates migrations

*  Add temp ts-ignore for unrelated change

*  Adjust default dates migration for MySQL

Remove change to data column in credentials_entity, already covered by Omar's migration. Also, fix quotes from table prefix addition.

*  Adjust quotes in dates migration for PG

* fix safari color bug

* fix count bug

* fix scroll bugs in dropdown

* expand filter size

* apply box-sizing to main header

* update workflow names in executions to be wrapped by quotes

* fix bug where key is same in dropdown

* fix firefox bug

* move up push connection session

* 🔨 Remove mistakenly added nullable property

* 🔥 Remove unneeded index drop-create (PG)

* 🔥 Remove unneeded table copying

*  Merge dates migration with tags migration

* 🔨 Refactor endpoint and make wf name env

* dropdown colors in firefox

* update colors to use variables

* update thumb color

* change error message

* remove 100 char maximum

* fix bug with saving tags dropdowns multiple times

* update error message when no name

*  Update name missing toast message

*  Update workflow already exists message

* disable saving for executions

* fix bug causing modal to close

* make tags in workflow open clickable

* increase workflow limit to 3

* remove success notifications

* update header spacing

* escape tag names

* update tag and table colors

* remove tags from export

* build

* clean up push connection dependencies

* address ben's comments

* revert tags optional interface

* address comments

* update duplicate message

* build

* fix eol

* add one more eol

*  Update comment

* add hover style for workflow open, fix up font weight

Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
This commit is contained in:
Ben Hesseldieck
2021-05-29 20:31:21 +02:00
committed by GitHub
parent 335673d329
commit 05eec87d1d
92 changed files with 4602 additions and 1236 deletions

View File

@@ -3,14 +3,22 @@ import {
} from 'n8n-workflow';
import {
ICredentialsDb,
} from '../../';
getTimestampSyntax,
resolveDataType
} from '../utils';
import {
ICredentialsDb,
} from '../..';
import {
BeforeUpdate,
Column,
CreateDateColumn,
Entity,
Index,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
@Entity()
@@ -33,13 +41,17 @@ export class CredentialsEntity implements ICredentialsDb {
})
type: string;
@Column('json')
@Column(resolveDataType('json'))
nodesAccess: ICredentialNodeAccess[];
@Column('timestamp')
@CreateDateColumn({ precision: 3, default: () => getTimestampSyntax() })
createdAt: Date;
@Column('timestamp')
@UpdateDateColumn({ precision: 3, default: () => getTimestampSyntax(), onUpdate: getTimestampSyntax() })
updatedAt: Date;
@BeforeUpdate()
setUpdateDate() {
this.updatedAt = new Date();
}
}

View File

@@ -7,14 +7,18 @@ import {
IWorkflowDb,
} from '../../';
import {
resolveDataType
} from '../utils';
import {
Column,
ColumnOptions,
Entity,
Index,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class ExecutionEntity implements IExecutionFlattedDb {
@@ -36,14 +40,14 @@ export class ExecutionEntity implements IExecutionFlattedDb {
@Column({ nullable: true })
retrySuccessId: string;
@Column('datetime')
@Column(resolveDataType('datetime'))
startedAt: Date;
@Index()
@Column('datetime', { nullable: true })
@Column({ type: resolveDataType('datetime') as ColumnOptions['type'], nullable: true })
stoppedAt: Date;
@Column('json')
@Column(resolveDataType('json'))
workflowData: IWorkflowDb;
@Index()

View File

@@ -0,0 +1,37 @@
import { BeforeUpdate, Column, CreateDateColumn, Entity, Index, ManyToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
import { IsDate, IsOptional, IsString, Length } from 'class-validator';
import { ITagDb } from '../../Interfaces';
import { WorkflowEntity } from './WorkflowEntity';
import { getTimestampSyntax } from '../utils';
@Entity()
export class TagEntity implements ITagDb {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 24 })
@Index({ unique: true })
@IsString({ message: 'Tag name must be of type string.' })
@Length(1, 24, { message: 'Tag name must be 1 to 24 characters long.' })
name: string;
@CreateDateColumn({ precision: 3, default: () => getTimestampSyntax() })
@IsOptional() // ignored by validation because set at DB level
@IsDate()
createdAt: Date;
@UpdateDateColumn({ precision: 3, default: () => getTimestampSyntax(), onUpdate: getTimestampSyntax() })
@IsOptional() // ignored by validation because set at DB level
@IsDate()
updatedAt: Date;
@ManyToMany(() => WorkflowEntity, workflow => workflow.tags)
workflows: WorkflowEntity[];
@BeforeUpdate()
setUpdateDate() {
this.updatedAt = new Date();
}
}

View File

@@ -0,0 +1,94 @@
import {
Length,
} from 'class-validator';
import {
IConnections,
IDataObject,
INode,
IWorkflowSettings,
} from 'n8n-workflow';
import {
BeforeUpdate,
Column,
ColumnOptions,
CreateDateColumn,
Entity,
Index,
JoinTable,
ManyToMany,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import {
IWorkflowDb,
} from '../../';
import {
getTimestampSyntax,
resolveDataType
} from '../utils';
import {
TagEntity,
} from './TagEntity';
@Entity()
export class WorkflowEntity implements IWorkflowDb {
@PrimaryGeneratedColumn()
id: number;
@Index({ unique: true })
@Length(1, 128, { message: 'Workflow name must be 1 to 128 characters long.' })
@Column({ length: 128 })
name: string;
@Column()
active: boolean;
@Column(resolveDataType('json'))
nodes: INode[];
@Column(resolveDataType('json'))
connections: IConnections;
@CreateDateColumn({ precision: 3, default: () => getTimestampSyntax() })
createdAt: Date;
@UpdateDateColumn({ precision: 3, default: () => getTimestampSyntax(), onUpdate: getTimestampSyntax() })
updatedAt: Date;
@Column({
type: resolveDataType('json') as ColumnOptions['type'],
nullable: true,
})
settings?: IWorkflowSettings;
@Column({
type: resolveDataType('json') as ColumnOptions['type'],
nullable: true,
})
staticData?: IDataObject;
@ManyToMany(() => TagEntity, tag => tag.workflows)
@JoinTable({
name: "workflows_tags", // table name for the junction table of this relation
joinColumn: {
name: "workflowId",
referencedColumnName: "id",
},
inverseJoinColumn: {
name: "tagId",
referencedColumnName: "id",
},
})
tags: TagEntity[];
@BeforeUpdate()
setUpdateDate() {
this.updatedAt = new Date();
}
}

View File

@@ -0,0 +1,13 @@
import { CredentialsEntity } from './CredentialsEntity';
import { ExecutionEntity } from './ExecutionEntity';
import { WorkflowEntity } from './WorkflowEntity';
import { WebhookEntity } from './WebhookEntity';
import { TagEntity } from './TagEntity';
export const entities = {
CredentialsEntity,
ExecutionEntity,
WorkflowEntity,
WebhookEntity,
TagEntity,
};

View File

@@ -1,9 +0,0 @@
import * as PostgresDb from './postgresdb';
import * as SQLite from './sqlite';
import * as MySQLDb from './mysqldb';
export {
PostgresDb,
SQLite,
MySQLDb,
};

View File

@@ -1,44 +0,0 @@
import {
ICredentialNodeAccess,
} from 'n8n-workflow';
import {
ICredentialsDb,
} from '../../';
import {
Column,
Entity,
Index,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class CredentialsEntity implements ICredentialsDb {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 128,
})
name: string;
@Column('text')
data: string;
@Index()
@Column({
length: 32,
})
type: string;
@Column('json')
nodesAccess: ICredentialNodeAccess[];
@Column('datetime')
createdAt: Date;
@Column('datetime')
updatedAt: Date;
}

View File

@@ -1,55 +0,0 @@
import {
IConnections,
IDataObject,
INode,
IWorkflowSettings,
} from 'n8n-workflow';
import {
IWorkflowDb,
} from '../../';
import {
Column,
Entity,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class WorkflowEntity implements IWorkflowDb {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 128,
})
name: string;
@Column()
active: boolean;
@Column('json')
nodes: INode[];
@Column('json')
connections: IConnections;
@Column('datetime')
createdAt: Date;
@Column('datetime')
updatedAt: Date;
@Column({
type: 'json',
nullable: true,
})
settings?: IWorkflowSettings;
@Column({
type: 'json',
nullable: true,
})
staticData?: IDataObject;
}

View File

@@ -1,4 +0,0 @@
export * from './CredentialsEntity';
export * from './ExecutionEntity';
export * from './WorkflowEntity';
export * from './WebhookEntity';

View File

@@ -0,0 +1,50 @@
import {MigrationInterface, QueryRunner} from "typeorm";
import * as config from '../../../../config';
export class CreateTagEntity1617268711084 implements MigrationInterface {
name = 'CreateTagEntity1617268711084';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
// create tags table + relationship with workflow entity
await queryRunner.query('CREATE TABLE `' + tablePrefix + 'tag_entity` (`id` int NOT NULL AUTO_INCREMENT, `name` varchar(24) NOT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, UNIQUE INDEX `IDX_' + tablePrefix + '8f949d7a3a984759044054e89b` (`name`), PRIMARY KEY (`id`)) ENGINE=InnoDB');
await queryRunner.query('CREATE TABLE `' + tablePrefix + 'workflows_tags` (`workflowId` int NOT NULL, `tagId` int NOT NULL, INDEX `IDX_' + tablePrefix + '54b2f0343d6a2078fa13744386` (`workflowId`), INDEX `IDX_' + tablePrefix + '77505b341625b0b4768082e217` (`tagId`), PRIMARY KEY (`workflowId`, `tagId`)) ENGINE=InnoDB');
await queryRunner.query('ALTER TABLE `' + tablePrefix + 'workflows_tags` ADD CONSTRAINT `FK_' + tablePrefix + '54b2f0343d6a2078fa137443869` FOREIGN KEY (`workflowId`) REFERENCES `' + tablePrefix + 'workflow_entity`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION');
await queryRunner.query('ALTER TABLE `' + tablePrefix + 'workflows_tags` ADD CONSTRAINT `FK_' + tablePrefix + '77505b341625b0b4768082e2171` FOREIGN KEY (`tagId`) REFERENCES `' + tablePrefix + 'tag_entity`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION');
// set default dates for `createdAt` and `updatedAt`
await queryRunner.query("ALTER TABLE `" + tablePrefix + "credentials_entity` CHANGE `createdAt` `createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "credentials_entity` CHANGE `updatedAt` `updatedAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "tag_entity` CHANGE `createdAt` `createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "tag_entity` CHANGE `updatedAt` `updatedAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "workflow_entity` CHANGE `createdAt` `createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "workflow_entity` CHANGE `updatedAt` `updatedAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)");
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
// tags
await queryRunner.query('ALTER TABLE `' + tablePrefix + 'workflows_tags` DROP FOREIGN KEY `FK_' + tablePrefix + '77505b341625b0b4768082e2171`');
await queryRunner.query('ALTER TABLE `' + tablePrefix + 'workflows_tags` DROP FOREIGN KEY `FK_' + tablePrefix + '54b2f0343d6a2078fa137443869`');
await queryRunner.query('DROP INDEX `IDX_' + tablePrefix + '77505b341625b0b4768082e217` ON `' + tablePrefix + 'workflows_tags`');
await queryRunner.query('DROP INDEX `IDX_' + tablePrefix + '54b2f0343d6a2078fa13744386` ON `' + tablePrefix + 'workflows_tags`');
await queryRunner.query('DROP TABLE `' + tablePrefix + 'workflows_tags`');
await queryRunner.query('DROP INDEX `IDX_' + tablePrefix + '8f949d7a3a984759044054e89b` ON `' + tablePrefix + 'tag_entity`');
await queryRunner.query('DROP TABLE `' + tablePrefix + 'tag_entity`');
// `createdAt` and `updatedAt`
await queryRunner.query("ALTER TABLE `" + tablePrefix + "workflow_entity` CHANGE `updatedAt` `updatedAt` datetime(0) NOT NULL");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "workflow_entity` CHANGE `createdAt` `createdAt` datetime(0) NOT NULL");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "tag_entity` CHANGE `updatedAt` `updatedAt` datetime(0) NOT NULL");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "tag_entity` CHANGE `createdAt` `createdAt` datetime(0) NOT NULL");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "credentials_entity` CHANGE `updatedAt` `updatedAt` datetime(0) NOT NULL");
await queryRunner.query("ALTER TABLE `" + tablePrefix + "credentials_entity` CHANGE `createdAt` `createdAt` datetime(0) NOT NULL");
}
}

View File

@@ -0,0 +1,48 @@
import {MigrationInterface, QueryRunner} from "typeorm";
import config = require("../../../../config");
export class UniqueWorkflowNames1620826335440 implements MigrationInterface {
name = 'UniqueWorkflowNames1620826335440';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
const workflowNames = await queryRunner.query(`
SELECT name
FROM ${tablePrefix}workflow_entity
`);
for (const { name } of workflowNames) {
const duplicates = await queryRunner.query(`
SELECT id, name
FROM ${tablePrefix}workflow_entity
WHERE name = '${name}'
ORDER BY createdAt ASC
`);
if (duplicates.length > 1) {
await Promise.all(duplicates.map(({ id, name }: { id: number; name: string; }, index: number) => {
if (index === 0) return Promise.resolve();
return queryRunner.query(`
UPDATE ${tablePrefix}workflow_entity
SET name = '${name} ${index + 1}'
WHERE id = '${id}'
`);
}));
}
}
await queryRunner.query('ALTER TABLE `' + tablePrefix + 'workflow_entity` ADD UNIQUE INDEX `IDX_' + tablePrefix + '943d8f922be094eb507cb9a7f9` (`name`)');
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
await queryRunner.query('ALTER TABLE `' + tablePrefix + 'workflow_entity` DROP INDEX `IDX_' + tablePrefix + '943d8f922be094eb507cb9a7f9`');
}
}

View File

@@ -5,6 +5,8 @@ import { AddWebhookId1611149998770 } from './1611149998770-AddWebhookId';
import { MakeStoppedAtNullable1607431743767 } from './1607431743767-MakeStoppedAtNullable';
import { ChangeDataSize1615306975123 } from './1615306975123-ChangeDataSize';
import { ChangeCredentialDataSize1620729500000 } from './1620729500000-ChangeCredentialDataSize';
import { CreateTagEntity1617268711084 } from './1617268711084-CreateTagEntity';
import { UniqueWorkflowNames1620826335440 } from './1620826335440-UniqueWorkflowNames';
export const mysqlMigrations = [
InitialMigration1588157391238,
@@ -14,4 +16,6 @@ export const mysqlMigrations = [
MakeStoppedAtNullable1607431743767,
ChangeDataSize1615306975123,
ChangeCredentialDataSize1620729500000,
CreateTagEntity1617268711084,
UniqueWorkflowNames1620826335440,
];

View File

@@ -1,52 +0,0 @@
import {
WorkflowExecuteMode,
} from 'n8n-workflow';
import {
IExecutionFlattedDb,
IWorkflowDb,
} from '../../';
import {
Column,
Entity,
Index,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class ExecutionEntity implements IExecutionFlattedDb {
@PrimaryGeneratedColumn()
id: number;
@Column('text')
data: string;
@Column()
finished: boolean;
@Column('varchar')
mode: WorkflowExecuteMode;
@Column({ nullable: true })
retryOf: string;
@Column({ nullable: true })
retrySuccessId: string;
@Column('timestamp')
startedAt: Date;
@Index()
@Column('timestamp', { nullable: true })
stoppedAt: Date;
@Column('json')
workflowData: IWorkflowDb;
@Index()
@Column({ nullable: true })
workflowId: string;
}

View File

@@ -1,33 +0,0 @@
import {
Column,
Entity,
Index,
PrimaryColumn,
} from 'typeorm';
import {
IWebhookDb,
} from '../../';
@Entity()
@Index(['webhookId', 'method', 'pathLength'])
export class WebhookEntity implements IWebhookDb {
@Column()
workflowId: number;
@PrimaryColumn()
webhookPath: string;
@PrimaryColumn()
method: string;
@Column()
node: string;
@Column({ nullable: true })
webhookId: string;
@Column({ nullable: true })
pathLength: number;
}

View File

@@ -1,55 +0,0 @@
import {
IConnections,
IDataObject,
INode,
IWorkflowSettings,
} from 'n8n-workflow';
import {
IWorkflowDb,
} from '../../';
import {
Column,
Entity,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class WorkflowEntity implements IWorkflowDb {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 128,
})
name: string;
@Column()
active: boolean;
@Column('json')
nodes: INode[];
@Column('json')
connections: IConnections;
@Column('timestamp')
createdAt: Date;
@Column('timestamp')
updatedAt: Date;
@Column({
type: 'json',
nullable: true,
})
settings?: IWorkflowSettings;
@Column({
type: 'json',
nullable: true,
})
staticData?: IDataObject;
}

View File

@@ -1,5 +0,0 @@
export * from './CredentialsEntity';
export * from './ExecutionEntity';
export * from './WorkflowEntity';
export * from './WebhookEntity';

View File

@@ -0,0 +1,76 @@
import {MigrationInterface, QueryRunner} from "typeorm";
import * as config from '../../../../config';
export class CreateTagEntity1617270242566 implements MigrationInterface {
name = 'CreateTagEntity1617270242566';
async up(queryRunner: QueryRunner): Promise<void> {
let tablePrefix = config.get('database.tablePrefix');
const tablePrefixPure = tablePrefix;
const schema = config.get('database.postgresdb.schema');
if (schema) {
tablePrefix = schema + '.' + tablePrefix;
}
// create tags table + relationship with workflow entity
await queryRunner.query(`CREATE TABLE ${tablePrefix}tag_entity ("id" SERIAL NOT NULL, "name" character varying(24) NOT NULL, "createdAt" TIMESTAMP NOT NULL, "updatedAt" TIMESTAMP NOT NULL, CONSTRAINT "PK_${tablePrefixPure}7a50a9b74ae6855c0dcaee25052" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE UNIQUE INDEX IDX_${tablePrefixPure}812eb05f7451ca757fb98444ce ON ${tablePrefix}tag_entity ("name") `);
await queryRunner.query(`CREATE TABLE ${tablePrefix}workflows_tags ("workflowId" integer NOT NULL, "tagId" integer NOT NULL, CONSTRAINT "PK_${tablePrefixPure}a60448a90e51a114e95e2a125b3" PRIMARY KEY ("workflowId", "tagId"))`);
await queryRunner.query(`CREATE INDEX IDX_${tablePrefixPure}31140eb41f019805b40d008744 ON ${tablePrefix}workflows_tags ("workflowId") `);
await queryRunner.query(`CREATE INDEX IDX_${tablePrefixPure}5e29bfe9e22c5d6567f509d4a4 ON ${tablePrefix}workflows_tags ("tagId") `);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflows_tags ADD CONSTRAINT "FK_${tablePrefixPure}31140eb41f019805b40d0087449" FOREIGN KEY ("workflowId") REFERENCES ${tablePrefix}workflow_entity ("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflows_tags ADD CONSTRAINT "FK_${tablePrefixPure}5e29bfe9e22c5d6567f509d4a46" FOREIGN KEY ("tagId") REFERENCES ${tablePrefix}tag_entity ("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
// set default dates for `createdAt` and `updatedAt`
await queryRunner.query(`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "createdAt" TYPE TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "updatedAt" TYPE TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "updatedAt" SET DEFAULT CURRENT_TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}tag_entity ALTER COLUMN "createdAt" TYPE TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}tag_entity ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}tag_entity ALTER COLUMN "updatedAt" TYPE TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}tag_entity ALTER COLUMN "updatedAt" SET DEFAULT CURRENT_TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ALTER COLUMN "createdAt" TYPE TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ALTER COLUMN "updatedAt" TYPE TIMESTAMP(3)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ALTER COLUMN "updatedAt" SET DEFAULT CURRENT_TIMESTAMP(3)`);
}
async down(queryRunner: QueryRunner): Promise<void> {
let tablePrefix = config.get('database.tablePrefix');
const tablePrefixPure = tablePrefix;
const schema = config.get('database.postgresdb.schema');
if (schema) {
tablePrefix = schema + '.' + tablePrefix;
}
// tags
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflows_tags DROP CONSTRAINT "FK_${tablePrefixPure}5e29bfe9e22c5d6567f509d4a46"`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflows_tags DROP CONSTRAINT "FK_${tablePrefixPure}31140eb41f019805b40d0087449"`);
await queryRunner.query(`DROP INDEX IDX_${tablePrefixPure}5e29bfe9e22c5d6567f509d4a4`);
await queryRunner.query(`DROP INDEX IDX_${tablePrefixPure}31140eb41f019805b40d008744`);
await queryRunner.query(`DROP TABLE ${tablePrefix}workflows_tags`);
await queryRunner.query(`DROP INDEX IDX_${tablePrefixPure}812eb05f7451ca757fb98444ce`);
await queryRunner.query(`DROP TABLE ${tablePrefix}tag_entity`);
// `createdAt` and `updatedAt`
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ALTER COLUMN "updatedAt" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ALTER COLUMN "updatedAt" TYPE TIMESTAMP(6)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ALTER COLUMN "createdAt" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}workflow_entity ALTER COLUMN "createdAt" TYPE TIMESTAMP(6)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}tag_entity ALTER COLUMN "updatedAt" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}tag_entity ALTER COLUMN "updatedAt" TYPE TIMESTAMP(6)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}tag_entity ALTER COLUMN "createdAt" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}tag_entity ALTER COLUMN "createdAt" TYPE TIMESTAMP(6)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "updatedAt" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "updatedAt" TYPE TIMESTAMP(6)`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "createdAt" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE ${tablePrefix}credentials_entity ALTER COLUMN "createdAt" TYPE TIMESTAMP(6)`);
}
}

View File

@@ -0,0 +1,60 @@
import {MigrationInterface, QueryRunner} from "typeorm";
import config = require("../../../../config");
export class UniqueWorkflowNames1620824779533 implements MigrationInterface {
name = 'UniqueWorkflowNames1620824779533';
async up(queryRunner: QueryRunner): Promise<void> {
let tablePrefix = config.get('database.tablePrefix');
const tablePrefixPure = tablePrefix;
const schema = config.get('database.postgresdb.schema');
if (schema) {
tablePrefix = schema + '.' + tablePrefix;
}
const workflowNames = await queryRunner.query(`
SELECT name
FROM ${tablePrefix}workflow_entity
`);
for (const { name } of workflowNames) {
const duplicates = await queryRunner.query(`
SELECT id, name
FROM ${tablePrefix}workflow_entity
WHERE name = '${name}'
ORDER BY "createdAt" ASC
`);
if (duplicates.length > 1) {
await Promise.all(duplicates.map(({ id, name }: { id: number; name: string; }, index: number) => {
if (index === 0) return Promise.resolve();
return queryRunner.query(`
UPDATE ${tablePrefix}workflow_entity
SET name = '${name} ${index + 1}'
WHERE id = '${id}'
`);
}));
}
}
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_${tablePrefixPure}a252c527c4c89237221fe2c0ab" ON ${tablePrefix}workflow_entity ("name") `);
}
async down(queryRunner: QueryRunner): Promise<void> {
let tablePrefix = config.get('database.tablePrefix');
const tablePrefixPure = tablePrefix;
const schema = config.get('database.postgresdb.schema');
if (schema) {
tablePrefix = schema + '.' + tablePrefix;
}
await queryRunner.query(`DROP INDEX "public"."IDX_${tablePrefixPure}a252c527c4c89237221fe2c0ab"`);
}
}

View File

@@ -3,6 +3,8 @@ import { WebhookModel1589476000887 } from './1589476000887-WebhookModel';
import { CreateIndexStoppedAt1594828256133 } from './1594828256133-CreateIndexStoppedAt';
import { AddWebhookId1611144599516 } from './1611144599516-AddWebhookId';
import { MakeStoppedAtNullable1607431743768 } from './1607431743768-MakeStoppedAtNullable';
import { CreateTagEntity1617270242566 } from './1617270242566-CreateTagEntity';
import { UniqueWorkflowNames1620824779533 } from './1620824779533-UniqueWorkflowNames';
export const postgresMigrations = [
InitialMigration1587669153312,
@@ -10,4 +12,6 @@ export const postgresMigrations = [
CreateIndexStoppedAt1594828256133,
AddWebhookId1611144599516,
MakeStoppedAtNullable1607431743768,
CreateTagEntity1617270242566,
UniqueWorkflowNames1620824779533,
];

View File

@@ -1,44 +0,0 @@
import {
ICredentialNodeAccess,
} from 'n8n-workflow';
import {
ICredentialsDb,
} from '../../';
import {
Column,
Entity,
Index,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class CredentialsEntity implements ICredentialsDb {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 128,
})
name: string;
@Column('text')
data: string;
@Index()
@Column({
length: 32,
})
type: string;
@Column('simple-json')
nodesAccess: ICredentialNodeAccess[];
@Column()
createdAt: Date;
@Column()
updatedAt: Date;
}

View File

@@ -1,52 +0,0 @@
import {
WorkflowExecuteMode,
} from 'n8n-workflow';
import {
IExecutionFlattedDb,
IWorkflowDb,
} from '../../';
import {
Column,
Entity,
Index,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class ExecutionEntity implements IExecutionFlattedDb {
@PrimaryGeneratedColumn()
id: number;
@Column('text')
data: string;
@Column()
finished: boolean;
@Column('varchar')
mode: WorkflowExecuteMode;
@Column({ nullable: true })
retryOf: string;
@Column({ nullable: true })
retrySuccessId: string;
@Column()
startedAt: Date;
@Index()
@Column({ nullable: true })
stoppedAt: Date;
@Column('simple-json')
workflowData: IWorkflowDb;
@Index()
@Column({ nullable: true })
workflowId: string;
}

View File

@@ -1,33 +0,0 @@
import {
Column,
Entity,
Index,
PrimaryColumn,
} from 'typeorm';
import {
IWebhookDb,
} from '../../Interfaces';
@Entity()
@Index(['webhookId', 'method', 'pathLength'])
export class WebhookEntity implements IWebhookDb {
@Column()
workflowId: number;
@PrimaryColumn()
webhookPath: string;
@PrimaryColumn()
method: string;
@Column()
node: string;
@Column({ nullable: true })
webhookId: string;
@Column({ nullable: true })
pathLength: number;
}

View File

@@ -1,55 +0,0 @@
import {
IConnections,
IDataObject,
INode,
IWorkflowSettings,
} from 'n8n-workflow';
import {
IWorkflowDb,
} from '../../';
import {
Column,
Entity,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class WorkflowEntity implements IWorkflowDb {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 128,
})
name: string;
@Column()
active: boolean;
@Column('simple-json')
nodes: INode[];
@Column('simple-json')
connections: IConnections;
@Column()
createdAt: Date;
@Column()
updatedAt: Date;
@Column({
type: 'simple-json',
nullable: true,
})
settings?: IWorkflowSettings;
@Column({
type: 'simple-json',
nullable: true,
})
staticData?: IDataObject;
}

View File

@@ -1,4 +0,0 @@
export * from './CredentialsEntity';
export * from './ExecutionEntity';
export * from './WorkflowEntity';
export * from './WebhookEntity';

View File

@@ -0,0 +1,69 @@
import {MigrationInterface, QueryRunner} from "typeorm";
import * as config from '../../../../config';
export class CreateTagEntity1617213344594 implements MigrationInterface {
name = 'CreateTagEntity1617213344594';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
// create tags table + relationship with workflow entity
await queryRunner.query(`CREATE TABLE "${tablePrefix}tag_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(24) NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL)`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_${tablePrefix}8f949d7a3a984759044054e89b" ON "${tablePrefix}tag_entity" ("name") `);
await queryRunner.query(`CREATE TABLE "${tablePrefix}workflows_tags" ("workflowId" integer NOT NULL, "tagId" integer NOT NULL, CONSTRAINT "FK_54b2f0343d6a2078fa137443869" FOREIGN KEY ("workflowId") REFERENCES "${tablePrefix}workflow_entity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_77505b341625b0b4768082e2171" FOREIGN KEY ("tagId") REFERENCES "${tablePrefix}tag_entity" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, PRIMARY KEY ("workflowId", "tagId"))`);
await queryRunner.query(`CREATE INDEX "IDX_${tablePrefix}54b2f0343d6a2078fa13744386" ON "${tablePrefix}workflows_tags" ("workflowId") `);
await queryRunner.query(`CREATE INDEX "IDX_${tablePrefix}77505b341625b0b4768082e217" ON "${tablePrefix}workflows_tags" ("tagId") `);
// set default dates for `createdAt` and `updatedAt`
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8"`);
await queryRunner.query(`CREATE TABLE "${tablePrefix}temporary_credentials_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "data" text NOT NULL, "type" varchar(32) NOT NULL, "nodesAccess" text 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')))`);
await queryRunner.query(`INSERT INTO "${tablePrefix}temporary_credentials_entity"("id", "name", "data", "type", "nodesAccess", "createdAt", "updatedAt") SELECT "id", "name", "data", "type", "nodesAccess", "createdAt", "updatedAt" FROM "${tablePrefix}credentials_entity"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}credentials_entity"`);
await queryRunner.query(`ALTER TABLE "${tablePrefix}temporary_credentials_entity" RENAME TO "${tablePrefix}credentials_entity"`);
await queryRunner.query(`CREATE INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8" ON "${tablePrefix}credentials_entity" ("type") `);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}8f949d7a3a984759044054e89b"`);
await queryRunner.query(`CREATE TABLE "${tablePrefix}temporary_tag_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(24) 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')))`);
await queryRunner.query(`INSERT INTO "${tablePrefix}temporary_tag_entity"("id", "name", "createdAt", "updatedAt") SELECT "id", "name", "createdAt", "updatedAt" FROM "${tablePrefix}tag_entity"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}tag_entity"`);
await queryRunner.query(`ALTER TABLE "${tablePrefix}temporary_tag_entity" RENAME TO "${tablePrefix}tag_entity"`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_${tablePrefix}8f949d7a3a984759044054e89b" ON "${tablePrefix}tag_entity" ("name") `);
await queryRunner.query(`CREATE TABLE "${tablePrefix}temporary_workflow_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "active" boolean NOT NULL, "nodes" text, "connections" text 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')), "settings" text, "staticData" text)`);
await queryRunner.query(`INSERT INTO "${tablePrefix}temporary_workflow_entity"("id", "name", "active", "nodes", "connections", "createdAt", "updatedAt", "settings", "staticData") SELECT "id", "name", "active", "nodes", "connections", "createdAt", "updatedAt", "settings", "staticData" FROM "${tablePrefix}workflow_entity"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}workflow_entity"`);
await queryRunner.query(`ALTER TABLE "${tablePrefix}temporary_workflow_entity" RENAME TO "${tablePrefix}workflow_entity"`);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
// tags
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}77505b341625b0b4768082e217"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}54b2f0343d6a2078fa13744386"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}workflows_tags"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}8f949d7a3a984759044054e89b"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}tag_entity"`);
// `createdAt` and `updatedAt`
await queryRunner.query(`ALTER TABLE "${tablePrefix}workflow_entity" RENAME TO "${tablePrefix}temporary_workflow_entity"`);
await queryRunner.query(`CREATE TABLE "${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)`);
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 "${tablePrefix}temporary_workflow_entity"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}temporary_workflow_entity"`);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}8f949d7a3a984759044054e89b"`);
await queryRunner.query(`ALTER TABLE "${tablePrefix}tag_entity" RENAME TO "${tablePrefix}temporary_tag_entity"`);
await queryRunner.query(`CREATE TABLE "${tablePrefix}tag_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(24) NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL)`);
await queryRunner.query(`INSERT INTO "${tablePrefix}tag_entity"("id", "name", "createdAt", "updatedAt") SELECT "id", "name", "createdAt", "updatedAt" FROM "${tablePrefix}temporary_tag_entity"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}temporary_tag_entity"`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_${tablePrefix}8f949d7a3a984759044054e89b" ON "${tablePrefix}tag_entity" ("name") `);
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8"`);
await queryRunner.query(`ALTER TABLE "${tablePrefix}credentials_entity" RENAME TO "temporary_credentials_entity"`);
await queryRunner.query(`CREATE TABLE "${tablePrefix}credentials_entity" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(128) NOT NULL, "data" text NOT NULL, "type" varchar(32) NOT NULL, "nodesAccess" text NOT NULL, "createdAt" datetime NOT NULL, "updatedAt" datetime NOT NULL)`);
await queryRunner.query(`INSERT INTO "${tablePrefix}credentials_entity"("id", "name", "data", "type", "nodesAccess", "createdAt", "updatedAt") SELECT "id", "name", "data", "type", "nodesAccess", "createdAt", "updatedAt" FROM "${tablePrefix}temporary_credentials_entity"`);
await queryRunner.query(`DROP TABLE "${tablePrefix}temporary_credentials_entity"`);
await queryRunner.query(`CREATE INDEX "IDX_${tablePrefix}07fde106c0b471d8cc80a64fc8" ON "credentials_entity" ("type") `);
}
}

View File

@@ -0,0 +1,47 @@
import {MigrationInterface, QueryRunner} from "typeorm";
import config = require("../../../../config");
export class UniqueWorkflowNames1620821879465 implements MigrationInterface {
name = 'UniqueWorkflowNames1620821879465';
async up(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
const workflowNames = await queryRunner.query(`
SELECT name
FROM "${tablePrefix}workflow_entity"
`);
for (const { name } of workflowNames) {
const duplicates = await queryRunner.query(`
SELECT id, name
FROM "${tablePrefix}workflow_entity"
WHERE name = "${name}"
ORDER BY createdAt ASC
`);
if (duplicates.length > 1) {
await Promise.all(duplicates.map(({ id, name }: { id: number; name: string; }, index: number) => {
if (index === 0) return Promise.resolve();
return queryRunner.query(`
UPDATE "${tablePrefix}workflow_entity"
SET name = "${name} ${index + 1}"
WHERE id = '${id}'
`);
}));
}
}
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9" ON "${tablePrefix}workflow_entity" ("name") `);
}
async down(queryRunner: QueryRunner): Promise<void> {
const tablePrefix = config.get('database.tablePrefix');
await queryRunner.query(`DROP INDEX "IDX_${tablePrefix}943d8f922be094eb507cb9a7f9"`);
}
}

View File

@@ -3,6 +3,8 @@ import { WebhookModel1592445003908 } from './1592445003908-WebhookModel';
import { CreateIndexStoppedAt1594825041918 } from './1594825041918-CreateIndexStoppedAt';
import { AddWebhookId1611071044839 } from './1611071044839-AddWebhookId';
import { MakeStoppedAtNullable1607431743769 } from './1607431743769-MakeStoppedAtNullable';
import { CreateTagEntity1617213344594 } from './1617213344594-CreateTagEntity';
import { UniqueWorkflowNames1620821879465 } from './1620821879465-UniqueWorkflowNames';
export const sqliteMigrations = [
InitialMigration1588102412422,
@@ -10,4 +12,6 @@ export const sqliteMigrations = [
CreateIndexStoppedAt1594825041918,
AddWebhookId1611071044839,
MakeStoppedAtNullable1607431743769,
CreateTagEntity1617213344594,
UniqueWorkflowNames1620821879465,
];

View File

@@ -0,0 +1,42 @@
import {
DatabaseType,
} from '../index';
import { getConfigValueSync } from '../../src/GenericHelpers';
/**
* Resolves the data type for the used database type
*
* @export
* @param {string} dataType
* @returns {string}
*/
export function resolveDataType(dataType: string) {
const dbType = getConfigValueSync('database.type') as DatabaseType;
const typeMap: { [key in DatabaseType]: { [key: string]: string } } = {
sqlite: {
json: 'simple-json',
},
postgresdb: {
datetime: 'timestamp',
},
mysqldb: {},
mariadb: {},
};
return typeMap[dbType][dataType] ?? dataType;
}
export function getTimestampSyntax() {
const dbType = getConfigValueSync('database.type') as DatabaseType;
const map: { [key in DatabaseType]: string } = {
sqlite: "STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')",
postgresdb: "CURRENT_TIMESTAMP(3)",
mysqldb: "CURRENT_TIMESTAMP(3)",
mariadb: "CURRENT_TIMESTAMP(3)",
};
return map[dbType];
}