From 5eebd91ba761d683d3ff1cffdc70a0c003cf3cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Fri, 21 Oct 2022 12:29:25 +0200 Subject: [PATCH] fix(API): reduce code duplication between DB entities (#4351) --- .../src/databases/entities/AbstractEntity.ts | 39 ++++++++++ .../src/databases/entities/CredentialUsage.ts | 50 +------------ .../databases/entities/CredentialsEntity.ts | 71 ++----------------- .../src/databases/entities/ExecutionEntity.ts | 35 +++------ .../src/databases/entities/InstalledNodes.ts | 1 - .../databases/entities/InstalledPackages.ts | 51 +------------ packages/cli/src/databases/entities/Role.ts | 52 ++------------ .../cli/src/databases/entities/Settings.ts | 3 - .../databases/entities/SharedCredentials.ts | 50 +------------ .../src/databases/entities/SharedWorkflow.ts | 50 +------------ .../cli/src/databases/entities/TagEntity.ts | 54 ++------------ packages/cli/src/databases/entities/User.ts | 56 ++------------- .../src/databases/entities/WebhookEntity.ts | 1 - .../src/databases/entities/WorkflowEntity.ts | 67 +++-------------- packages/cli/src/databases/entities/index.ts | 1 - 15 files changed, 86 insertions(+), 495 deletions(-) create mode 100644 packages/cli/src/databases/entities/AbstractEntity.ts diff --git a/packages/cli/src/databases/entities/AbstractEntity.ts b/packages/cli/src/databases/entities/AbstractEntity.ts new file mode 100644 index 0000000000..5fabaa6c3d --- /dev/null +++ b/packages/cli/src/databases/entities/AbstractEntity.ts @@ -0,0 +1,39 @@ +import { BeforeUpdate, CreateDateColumn, UpdateDateColumn } from 'typeorm'; +import { IsDate, IsOptional } from 'class-validator'; +import config from '../../../config'; + +const dbType = config.getEnv('database.type'); + +const timestampSyntax = { + sqlite: `STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')`, + postgresdb: 'CURRENT_TIMESTAMP(3)', + mysqldb: 'CURRENT_TIMESTAMP(3)', + mariadb: 'CURRENT_TIMESTAMP(3)', +}[dbType]; + +export const jsonColumnType = dbType === 'sqlite' ? 'simple-json' : 'json'; +export const datetimeColumnType = dbType === 'postgresdb' ? 'timestamptz' : 'datetime'; + +export abstract class AbstractEntity { + @CreateDateColumn({ + precision: 3, + default: () => timestampSyntax, + }) + @IsOptional() // ignored by validation because set at DB level + @IsDate() + createdAt: Date; + + @UpdateDateColumn({ + precision: 3, + default: () => timestampSyntax, + onUpdate: timestampSyntax, + }) + @IsOptional() // ignored by validation because set at DB level + @IsDate() + updatedAt: Date; + + @BeforeUpdate() + setUpdateDate(): void { + this.updatedAt = new Date(); + } +} diff --git a/packages/cli/src/databases/entities/CredentialUsage.ts b/packages/cli/src/databases/entities/CredentialUsage.ts index 6bdc8a8fcb..bf4a93317d 100644 --- a/packages/cli/src/databases/entities/CredentialUsage.ts +++ b/packages/cli/src/databases/entities/CredentialUsage.ts @@ -1,35 +1,10 @@ -/* eslint-disable import/no-cycle */ -import { - BeforeUpdate, - CreateDateColumn, - Entity, - ManyToOne, - PrimaryColumn, - RelationId, - UpdateDateColumn, -} from 'typeorm'; -import { IsDate, IsOptional } from 'class-validator'; - -import config = require('../../../config'); -import { DatabaseType } from '../../index'; +import { Entity, ManyToOne, PrimaryColumn, RelationId } from 'typeorm'; import { WorkflowEntity } from './WorkflowEntity'; import { CredentialsEntity } from './CredentialsEntity'; - -function getTimestampSyntax() { - const dbType = config.get('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]; -} +import { AbstractEntity } from './AbstractEntity'; @Entity() -export class CredentialUsage { +export class CredentialUsage extends AbstractEntity { @ManyToOne(() => WorkflowEntity, { onDelete: 'CASCADE', }) @@ -50,23 +25,4 @@ export class CredentialUsage { @RelationId((credentialUsage: CredentialUsage) => credentialUsage.credential) @PrimaryColumn() credentialId: 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; - - @BeforeUpdate() - setUpdateDate(): void { - this.updatedAt = new Date(); - } } diff --git a/packages/cli/src/databases/entities/CredentialsEntity.ts b/packages/cli/src/databases/entities/CredentialsEntity.ts index d61c5e0f2f..f87e850575 100644 --- a/packages/cli/src/databases/entities/CredentialsEntity.ts +++ b/packages/cli/src/databases/entities/CredentialsEntity.ts @@ -1,56 +1,12 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable import/no-cycle */ -import { ICredentialNodeAccess } from 'n8n-workflow'; - -import { - BeforeUpdate, - Column, - CreateDateColumn, - Entity, - Index, - OneToMany, - PrimaryGeneratedColumn, - UpdateDateColumn, -} from 'typeorm'; - +import type { ICredentialNodeAccess } from 'n8n-workflow'; +import { Column, Entity, Index, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; import { IsArray, IsObject, IsString, Length } from 'class-validator'; -import * as config from '../../../config'; -import { DatabaseType, ICredentialsDb } from '../..'; import { SharedCredentials } from './SharedCredentials'; - -function resolveDataType(dataType: string) { - const dbType = config.getEnv('database.type'); - - const typeMap: { [key in DatabaseType]: { [key: string]: string } } = { - sqlite: { - json: 'simple-json', - }, - postgresdb: { - datetime: 'timestamptz', - }, - mysqldb: {}, - mariadb: {}, - }; - - return typeMap[dbType][dataType] ?? dataType; -} - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function getTimestampSyntax() { - const dbType = config.getEnv('database.type'); - - 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]; -} +import { AbstractEntity, jsonColumnType } from './AbstractEntity'; +import type { ICredentialsDb } from '../../Interfaces'; @Entity() -export class CredentialsEntity implements ICredentialsDb { +export class CredentialsEntity extends AbstractEntity implements ICredentialsDb { @PrimaryGeneratedColumn() id: number; @@ -75,22 +31,7 @@ export class CredentialsEntity implements ICredentialsDb { @OneToMany(() => SharedCredentials, (sharedCredentials) => sharedCredentials.credentials) shared: SharedCredentials[]; - @Column(resolveDataType('json')) + @Column(jsonColumnType) @IsArray() nodesAccess: ICredentialNodeAccess[]; - - @CreateDateColumn({ precision: 3, default: () => getTimestampSyntax() }) - createdAt: Date; - - @UpdateDateColumn({ - precision: 3, - default: () => getTimestampSyntax(), - onUpdate: getTimestampSyntax(), - }) - updatedAt: Date; - - @BeforeUpdate() - setUpdateDate() { - this.updatedAt = new Date(); - } } diff --git a/packages/cli/src/databases/entities/ExecutionEntity.ts b/packages/cli/src/databases/entities/ExecutionEntity.ts index 590280496c..e2d7471d72 100644 --- a/packages/cli/src/databases/entities/ExecutionEntity.ts +++ b/packages/cli/src/databases/entities/ExecutionEntity.ts @@ -1,26 +1,7 @@ -/* eslint-disable import/no-cycle */ -import { WorkflowExecuteMode } from 'n8n-workflow'; - -import { Column, ColumnOptions, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'; -import * as config from '../../../config'; -import { DatabaseType, IExecutionFlattedDb, IWorkflowDb } from '../..'; - -function resolveDataType(dataType: string) { - const dbType = config.getEnv('database.type'); - - const typeMap: { [key in DatabaseType]: { [key: string]: string } } = { - sqlite: { - json: 'simple-json', - }, - postgresdb: { - datetime: 'timestamptz', - }, - mysqldb: {}, - mariadb: {}, - }; - - return typeMap[dbType][dataType] ?? dataType; -} +import type { WorkflowExecuteMode } from 'n8n-workflow'; +import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'; +import { datetimeColumnType, jsonColumnType } from './AbstractEntity'; +import type { IExecutionFlattedDb, IWorkflowDb } from '../../Interfaces'; @Entity() @Index(['workflowId', 'id']) @@ -47,19 +28,19 @@ export class ExecutionEntity implements IExecutionFlattedDb { @Column({ nullable: true }) retrySuccessId: string; - @Column(resolveDataType('datetime')) + @Column(datetimeColumnType) startedAt: Date; @Index() - @Column({ type: resolveDataType('datetime') as ColumnOptions['type'], nullable: true }) + @Column({ type: datetimeColumnType, nullable: true }) stoppedAt: Date; - @Column(resolveDataType('json')) + @Column(jsonColumnType) workflowData: IWorkflowDb; @Column({ nullable: true }) workflowId: string; - @Column({ type: resolveDataType('datetime') as ColumnOptions['type'], nullable: true }) + @Column({ type: datetimeColumnType, nullable: true }) waitTill: Date; } diff --git a/packages/cli/src/databases/entities/InstalledNodes.ts b/packages/cli/src/databases/entities/InstalledNodes.ts index 7885517c22..deec41b031 100644 --- a/packages/cli/src/databases/entities/InstalledNodes.ts +++ b/packages/cli/src/databases/entities/InstalledNodes.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm'; import { InstalledPackages } from './InstalledPackages'; diff --git a/packages/cli/src/databases/entities/InstalledPackages.ts b/packages/cli/src/databases/entities/InstalledPackages.ts index af4aab87f2..b339fba00f 100644 --- a/packages/cli/src/databases/entities/InstalledPackages.ts +++ b/packages/cli/src/databases/entities/InstalledPackages.ts @@ -1,35 +1,9 @@ -/* eslint-disable import/no-cycle */ -import { - BeforeUpdate, - Column, - CreateDateColumn, - Entity, - JoinColumn, - OneToMany, - PrimaryColumn, - UpdateDateColumn, -} from 'typeorm'; -import { IsDate, IsOptional } from 'class-validator'; - -import config = require('../../../config'); -import { DatabaseType } from '../../index'; +import { Column, Entity, JoinColumn, OneToMany, PrimaryColumn } from 'typeorm'; import { InstalledNodes } from './InstalledNodes'; - -function getTimestampSyntax() { - const dbType = config.get('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]; -} +import { AbstractEntity } from './AbstractEntity'; @Entity() -export class InstalledPackages { +export class InstalledPackages extends AbstractEntity { @PrimaryColumn() packageName: string; @@ -45,23 +19,4 @@ export class InstalledPackages { @OneToMany(() => InstalledNodes, (installedNode) => installedNode.package) @JoinColumn({ referencedColumnName: 'package' }) installedNodes: InstalledNodes[]; - - @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; - - @BeforeUpdate() - setUpdateDate(): void { - this.updatedAt = new Date(); - } } diff --git a/packages/cli/src/databases/entities/Role.ts b/packages/cli/src/databases/entities/Role.ts index 9107737e41..ec6831916b 100644 --- a/packages/cli/src/databases/entities/Role.ts +++ b/packages/cli/src/databases/entities/Role.ts @@ -1,42 +1,17 @@ -/* eslint-disable import/no-cycle */ -import { - BeforeUpdate, - Column, - CreateDateColumn, - Entity, - OneToMany, - PrimaryGeneratedColumn, - Unique, - UpdateDateColumn, -} from 'typeorm'; -import { IsDate, IsOptional, IsString, Length } from 'class-validator'; +import { Column, Entity, OneToMany, PrimaryGeneratedColumn, Unique } from 'typeorm'; +import { IsString, Length } from 'class-validator'; -import * as config from '../../../config'; -import { DatabaseType } from '../../index'; import { User } from './User'; import { SharedWorkflow } from './SharedWorkflow'; import { SharedCredentials } from './SharedCredentials'; +import { AbstractEntity } from './AbstractEntity'; type RoleNames = 'owner' | 'member' | 'user' | 'editor'; type RoleScopes = 'global' | 'workflow' | 'credential'; -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function getTimestampSyntax() { - const dbType = config.getEnv('database.type'); - - 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]; -} - @Entity() @Unique(['scope', 'name']) -export class Role { +export class Role extends AbstractEntity { @PrimaryGeneratedColumn() id: number; @@ -51,28 +26,9 @@ export class Role { @OneToMany(() => User, (user) => user.globalRole) globalForUsers: User[]; - @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; - @OneToMany(() => SharedWorkflow, (sharedWorkflow) => sharedWorkflow.role) sharedWorkflows: SharedWorkflow[]; @OneToMany(() => SharedCredentials, (sharedCredentials) => sharedCredentials.role) sharedCredentials: SharedCredentials[]; - - @BeforeUpdate() - setUpdateDate(): void { - this.updatedAt = new Date(); - } } diff --git a/packages/cli/src/databases/entities/Settings.ts b/packages/cli/src/databases/entities/Settings.ts index 3ae0bdc91f..0bd4bf36a9 100644 --- a/packages/cli/src/databases/entities/Settings.ts +++ b/packages/cli/src/databases/entities/Settings.ts @@ -1,6 +1,3 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable import/no-cycle */ - import { Column, Entity, PrimaryColumn } from 'typeorm'; import { ISettingsDb } from '../..'; diff --git a/packages/cli/src/databases/entities/SharedCredentials.ts b/packages/cli/src/databases/entities/SharedCredentials.ts index e7d4a8e6cf..8ff8e518f5 100644 --- a/packages/cli/src/databases/entities/SharedCredentials.ts +++ b/packages/cli/src/databases/entities/SharedCredentials.ts @@ -1,36 +1,11 @@ -/* eslint-disable import/no-cycle */ -import { - BeforeUpdate, - CreateDateColumn, - Entity, - ManyToOne, - RelationId, - UpdateDateColumn, -} from 'typeorm'; -import { IsDate, IsOptional } from 'class-validator'; - -import * as config from '../../../config'; -import { DatabaseType } from '../../index'; +import { Entity, ManyToOne, RelationId } from 'typeorm'; import { CredentialsEntity } from './CredentialsEntity'; import { User } from './User'; import { Role } from './Role'; - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function getTimestampSyntax() { - const dbType = config.getEnv('database.type'); - - 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]; -} +import { AbstractEntity } from './AbstractEntity'; @Entity() -export class SharedCredentials { +export class SharedCredentials extends AbstractEntity { @ManyToOne(() => Role, (role) => role.sharedCredentials, { nullable: false }) role: Role; @@ -48,23 +23,4 @@ export class SharedCredentials { @RelationId((sharedCredential: SharedCredentials) => sharedCredential.credentials) credentialId: number; - - @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; - - @BeforeUpdate() - setUpdateDate(): void { - this.updatedAt = new Date(); - } } diff --git a/packages/cli/src/databases/entities/SharedWorkflow.ts b/packages/cli/src/databases/entities/SharedWorkflow.ts index 669e0c1643..69e9d074c3 100644 --- a/packages/cli/src/databases/entities/SharedWorkflow.ts +++ b/packages/cli/src/databases/entities/SharedWorkflow.ts @@ -1,36 +1,11 @@ -/* eslint-disable import/no-cycle */ -import { - BeforeUpdate, - CreateDateColumn, - Entity, - ManyToOne, - RelationId, - UpdateDateColumn, -} from 'typeorm'; -import { IsDate, IsOptional } from 'class-validator'; - -import * as config from '../../../config'; -import { DatabaseType } from '../../index'; +import { Entity, ManyToOne, RelationId } from 'typeorm'; import { WorkflowEntity } from './WorkflowEntity'; import { User } from './User'; import { Role } from './Role'; - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function getTimestampSyntax() { - const dbType = config.getEnv('database.type'); - - 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]; -} +import { AbstractEntity } from './AbstractEntity'; @Entity() -export class SharedWorkflow { +export class SharedWorkflow extends AbstractEntity { @ManyToOne(() => Role, (role) => role.sharedWorkflows, { nullable: false }) role: Role; @@ -48,23 +23,4 @@ export class SharedWorkflow { @RelationId((sharedWorkflow: SharedWorkflow) => sharedWorkflow.workflow) workflowId: number; - - @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; - - @BeforeUpdate() - setUpdateDate(): void { - this.updatedAt = new Date(); - } } diff --git a/packages/cli/src/databases/entities/TagEntity.ts b/packages/cli/src/databases/entities/TagEntity.ts index 1d61a0a595..473b568ded 100644 --- a/packages/cli/src/databases/entities/TagEntity.ts +++ b/packages/cli/src/databases/entities/TagEntity.ts @@ -1,40 +1,13 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable import/no-cycle */ -import { - BeforeUpdate, - Column, - CreateDateColumn, - Entity, - Generated, - Index, - ManyToMany, - PrimaryColumn, - UpdateDateColumn, -} from 'typeorm'; -import { IsDate, IsOptional, IsString, Length } from 'class-validator'; +import { Column, Entity, Generated, Index, ManyToMany, PrimaryColumn } from 'typeorm'; +import { IsString, Length } from 'class-validator'; -import * as config from '../../../config'; -import { DatabaseType } from '../../index'; import { ITagDb } from '../../Interfaces'; import { idStringifier } from '../utils/transformers'; import { WorkflowEntity } from './WorkflowEntity'; - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function getTimestampSyntax() { - const dbType = config.getEnv('database.type'); - - 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]; -} +import { AbstractEntity } from './AbstractEntity'; @Entity() -export class TagEntity implements ITagDb { +export class TagEntity extends AbstractEntity implements ITagDb { @Generated() @PrimaryColumn({ transformer: idStringifier, @@ -47,25 +20,6 @@ export class TagEntity implements ITagDb { @Length(1, 24, { message: 'Tag name must be $constraint1 to $constraint2 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(); - } } diff --git a/packages/cli/src/databases/entities/User.ts b/packages/cli/src/databases/entities/User.ts index 628111b16a..73fca0b8fe 100644 --- a/packages/cli/src/databases/entities/User.ts +++ b/packages/cli/src/databases/entities/User.ts @@ -1,66 +1,31 @@ -/* eslint-disable import/no-cycle */ import { AfterLoad, AfterUpdate, BeforeUpdate, Column, - ColumnOptions, - CreateDateColumn, Entity, Index, OneToMany, ManyToOne, PrimaryGeneratedColumn, - UpdateDateColumn, BeforeInsert, } from 'typeorm'; import { IsEmail, IsString, Length } from 'class-validator'; import type { IUser } from 'n8n-workflow'; -import * as config from '../../../config'; -import { DatabaseType, IPersonalizationSurveyAnswers, IUserSettings } from '../..'; import { Role } from './Role'; import { SharedWorkflow } from './SharedWorkflow'; import { SharedCredentials } from './SharedCredentials'; import { NoXss } from '../utils/customValidators'; import { objectRetriever, lowerCaser } from '../utils/transformers'; +import { AbstractEntity, jsonColumnType } from './AbstractEntity'; +import type { IPersonalizationSurveyAnswers, IUserSettings } from '../../Interfaces'; export const MIN_PASSWORD_LENGTH = 8; export const MAX_PASSWORD_LENGTH = 64; -function resolveDataType(dataType: string) { - const dbType = config.getEnv('database.type'); - - const typeMap: { [key in DatabaseType]: { [key: string]: string } } = { - sqlite: { - json: 'simple-json', - }, - postgresdb: { - datetime: 'timestamptz', - }, - mysqldb: {}, - mariadb: {}, - }; - - return typeMap[dbType][dataType] ?? dataType; -} - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function getTimestampSyntax() { - const dbType = config.getEnv('database.type'); - - 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]; -} - @Entity() -export class User implements IUser { +export class User extends AbstractEntity implements IUser { @PrimaryGeneratedColumn('uuid') id: string; @@ -97,14 +62,14 @@ export class User implements IUser { resetPasswordTokenExpiration?: number | null; @Column({ - type: resolveDataType('json') as ColumnOptions['type'], + type: jsonColumnType, nullable: true, transformer: objectRetriever, }) personalizationAnswers: IPersonalizationSurveyAnswers | null; @Column({ - type: resolveDataType('json') as ColumnOptions['type'], + type: jsonColumnType, nullable: true, }) settings: IUserSettings | null; @@ -121,21 +86,10 @@ export class User implements IUser { @OneToMany(() => SharedCredentials, (sharedCredentials) => sharedCredentials.user) sharedCredentials: SharedCredentials[]; - @CreateDateColumn({ precision: 3, default: () => getTimestampSyntax() }) - createdAt: Date; - - @UpdateDateColumn({ - precision: 3, - default: () => getTimestampSyntax(), - onUpdate: getTimestampSyntax(), - }) - updatedAt: Date; - @BeforeInsert() @BeforeUpdate() preUpsertHook(): void { this.email = this.email?.toLowerCase() ?? null; - this.updatedAt = new Date(); } @Column({ type: String, nullable: true }) diff --git a/packages/cli/src/databases/entities/WebhookEntity.ts b/packages/cli/src/databases/entities/WebhookEntity.ts index 60afd83f9c..47b2941668 100644 --- a/packages/cli/src/databases/entities/WebhookEntity.ts +++ b/packages/cli/src/databases/entities/WebhookEntity.ts @@ -1,6 +1,5 @@ import { Column, Entity, Index, PrimaryColumn } from 'typeorm'; -// eslint-disable-next-line import/no-cycle import { IWebhookDb } from '../../Interfaces'; @Entity() diff --git a/packages/cli/src/databases/entities/WorkflowEntity.ts b/packages/cli/src/databases/entities/WorkflowEntity.ts index cbc7c5269d..d344c1dd25 100644 --- a/packages/cli/src/databases/entities/WorkflowEntity.ts +++ b/packages/cli/src/databases/entities/WorkflowEntity.ts @@ -1,8 +1,6 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable import/no-cycle */ import { Length } from 'class-validator'; -import { +import type { IBinaryKeyData, IConnections, IDataObject, @@ -12,58 +10,24 @@ import { } from 'n8n-workflow'; import { - BeforeUpdate, Column, - ColumnOptions, - CreateDateColumn, Entity, Index, JoinTable, ManyToMany, OneToMany, PrimaryGeneratedColumn, - UpdateDateColumn, } from 'typeorm'; import * as config from '../../../config'; -import { DatabaseType, IWorkflowDb } from '../..'; import { TagEntity } from './TagEntity'; import { SharedWorkflow } from './SharedWorkflow'; import { objectRetriever, sqlite } from '../utils/transformers'; - -function resolveDataType(dataType: string) { - const dbType = config.getEnv('database.type'); - - const typeMap: { [key in DatabaseType]: { [key: string]: string } } = { - sqlite: { - json: 'simple-json', - }, - postgresdb: { - datetime: 'timestamptz', - }, - mysqldb: {}, - mariadb: {}, - }; - - return typeMap[dbType][dataType] ?? dataType; -} - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function getTimestampSyntax() { - const dbType = config.getEnv('database.type'); - - 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]; -} +import { AbstractEntity, jsonColumnType } from './AbstractEntity'; +import type { IWorkflowDb } from '../../Interfaces'; @Entity() -export class WorkflowEntity implements IWorkflowDb { +export class WorkflowEntity extends AbstractEntity implements IWorkflowDb { @PrimaryGeneratedColumn() id: number; @@ -78,30 +42,20 @@ export class WorkflowEntity implements IWorkflowDb { @Column() active: boolean; - @Column(resolveDataType('json')) + @Column(jsonColumnType) nodes: INode[]; - @Column(resolveDataType('json')) + @Column(jsonColumnType) 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'], + type: jsonColumnType, nullable: true, }) settings?: IWorkflowSettings; @Column({ - type: resolveDataType('json') as ColumnOptions['type'], + type: jsonColumnType, nullable: true, transformer: objectRetriever, }) @@ -130,11 +84,6 @@ export class WorkflowEntity implements IWorkflowDb { transformer: sqlite.jsonColumn, }) pinData: ISimplifiedPinData; - - @BeforeUpdate() - setUpdateDate() { - this.updatedAt = new Date(); - } } /** diff --git a/packages/cli/src/databases/entities/index.ts b/packages/cli/src/databases/entities/index.ts index d22b4c4e53..b22928714f 100644 --- a/packages/cli/src/databases/entities/index.ts +++ b/packages/cli/src/databases/entities/index.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable import/no-cycle */ import { CredentialsEntity } from './CredentialsEntity'; import { ExecutionEntity } from './ExecutionEntity'; import { WorkflowEntity } from './WorkflowEntity';