mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(core): Add migration to create model for folders feature (#13060)
This commit is contained in:
parent
aedea7a76c
commit
03f4ed8445
45
packages/cli/src/databases/entities/folder.ts
Normal file
45
packages/cli/src/databases/entities/folder.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
} from '@n8n/typeorm';
|
||||
|
||||
import { WithTimestampsAndStringId } from './abstract-entity';
|
||||
import { Project } from './project';
|
||||
import { TagEntity } from './tag-entity';
|
||||
import { type WorkflowEntity } from './workflow-entity';
|
||||
|
||||
@Entity()
|
||||
export class Folder extends WithTimestampsAndStringId {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToOne(() => Folder, { nullable: true })
|
||||
@JoinColumn({ name: 'parentFolderId' })
|
||||
parentFolder: Folder | null;
|
||||
|
||||
@ManyToOne(() => Project)
|
||||
@JoinColumn({ name: 'projectId' })
|
||||
project: Project;
|
||||
|
||||
@OneToMany('WorkflowEntity', 'parentFolder')
|
||||
workflows: WorkflowEntity[];
|
||||
|
||||
@ManyToMany(() => TagEntity)
|
||||
@JoinTable({
|
||||
name: 'folder_tag',
|
||||
joinColumn: {
|
||||
name: 'folderId',
|
||||
referencedColumnName: 'id',
|
||||
},
|
||||
inverseJoinColumn: {
|
||||
name: 'tagId',
|
||||
referencedColumnName: 'id',
|
||||
},
|
||||
})
|
||||
tags: TagEntity[];
|
||||
}
|
|
@ -10,6 +10,7 @@ import { ExecutionAnnotation } from './execution-annotation.ee';
|
|||
import { ExecutionData } from './execution-data';
|
||||
import { ExecutionEntity } from './execution-entity';
|
||||
import { ExecutionMetadata } from './execution-metadata';
|
||||
import { Folder } from './folder';
|
||||
import { InstalledNodes } from './installed-nodes';
|
||||
import { InstalledPackages } from './installed-packages';
|
||||
import { InvalidAuthToken } from './invalid-auth-token';
|
||||
|
@ -66,4 +67,5 @@ export const entities = {
|
|||
TestMetric,
|
||||
TestRun,
|
||||
TestCaseExecution,
|
||||
Folder,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
import { Column, Entity, Index, JoinColumn, JoinTable, ManyToMany, OneToMany } from '@n8n/typeorm';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
} from '@n8n/typeorm';
|
||||
import { Length } from 'class-validator';
|
||||
import { IConnections, IDataObject, IWorkflowSettings, WorkflowFEMeta } from 'n8n-workflow';
|
||||
import type { IBinaryKeyData, INode, IPairedItemData } from 'n8n-workflow';
|
||||
|
@ -6,6 +15,7 @@ import type { IBinaryKeyData, INode, IPairedItemData } from 'n8n-workflow';
|
|||
import type { IWorkflowDb } from '@/interfaces';
|
||||
|
||||
import { WithTimestampsAndStringId, dbType, jsonColumnType } from './abstract-entity';
|
||||
import { type Folder } from './folder';
|
||||
import type { SharedWorkflow } from './shared-workflow';
|
||||
import type { TagEntity } from './tag-entity';
|
||||
import type { WorkflowStatistics } from './workflow-statistics';
|
||||
|
@ -88,6 +98,13 @@ export class WorkflowEntity extends WithTimestampsAndStringId implements IWorkfl
|
|||
@Column({ default: 0 })
|
||||
triggerCount: number;
|
||||
|
||||
@ManyToOne('Folder', 'workflows', {
|
||||
nullable: true,
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn({ name: 'parentFolderId' })
|
||||
parentFolder: Folder | null;
|
||||
|
||||
display() {
|
||||
return `"${this.name}" (ID: ${this.id})`;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import type { MigrationContext, ReversibleMigration } from '@/databases/types';
|
||||
|
||||
export class CreateFolderTable1738709609940 implements ReversibleMigration {
|
||||
async up({ runQuery, escape, schemaBuilder: { createTable, column } }: MigrationContext) {
|
||||
const workflowTable = escape.tableName('workflow_entity');
|
||||
const workflowFolderId = escape.columnName('parentFolderId');
|
||||
const folderTable = escape.tableName('folder');
|
||||
const folderId = escape.columnName('id');
|
||||
|
||||
await createTable('folder')
|
||||
.withColumns(
|
||||
column('id').varchar(36).primary.notNull,
|
||||
column('name').varchar(128).notNull,
|
||||
column('parentFolderId').varchar(36).default(null),
|
||||
column('projectId').varchar(36).notNull,
|
||||
)
|
||||
.withForeignKey('projectId', {
|
||||
tableName: 'project',
|
||||
columnName: 'id',
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
.withForeignKey('parentFolderId', {
|
||||
tableName: 'folder',
|
||||
columnName: 'id',
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
.withIndexOn(['projectId', 'id'], true).withTimestamps;
|
||||
|
||||
await createTable('folder_tag')
|
||||
.withColumns(
|
||||
column('folderId').varchar(36).primary.notNull,
|
||||
column('tagId').varchar(36).primary.notNull,
|
||||
)
|
||||
.withForeignKey('folderId', {
|
||||
tableName: 'folder',
|
||||
columnName: 'id',
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
.withForeignKey('tagId', {
|
||||
tableName: 'tag_entity',
|
||||
columnName: 'id',
|
||||
onDelete: 'CASCADE',
|
||||
});
|
||||
|
||||
await runQuery(
|
||||
`ALTER TABLE ${workflowTable} ADD COLUMN ${workflowFolderId} VARCHAR(36) DEFAULT NULL REFERENCES ${folderTable}(${folderId}) ON DELETE SET NULL`,
|
||||
);
|
||||
}
|
||||
|
||||
async down({ runQuery, escape, schemaBuilder: { dropTable } }: MigrationContext) {
|
||||
const workflowTable = escape.tableName('workflow_entity');
|
||||
const workflowFolderId = escape.columnName('parentFolderId');
|
||||
|
||||
await runQuery(`ALTER TABLE ${workflowTable} DROP COLUMN ${workflowFolderId}`);
|
||||
|
||||
await dropTable('folder_tag');
|
||||
|
||||
await dropTable('folder');
|
||||
}
|
||||
}
|
|
@ -79,6 +79,7 @@ import { AddManagedColumnToCredentialsTable1734479635324 } from '../common/17344
|
|||
import { AddStatsColumnsToTestRun1736172058779 } from '../common/1736172058779-AddStatsColumnsToTestRun';
|
||||
import { CreateTestCaseExecutionTable1736947513045 } from '../common/1736947513045-CreateTestCaseExecutionTable';
|
||||
import { AddErrorColumnsToTestRuns1737715421462 } from '../common/1737715421462-AddErrorColumnsToTestRuns';
|
||||
import { CreateFolderTable1738709609940 } from '../common/1738709609940-CreateFolderTable';
|
||||
|
||||
export const mysqlMigrations: Migration[] = [
|
||||
InitialMigration1588157391238,
|
||||
|
@ -160,4 +161,5 @@ export const mysqlMigrations: Migration[] = [
|
|||
AddStatsColumnsToTestRun1736172058779,
|
||||
CreateTestCaseExecutionTable1736947513045,
|
||||
AddErrorColumnsToTestRuns1737715421462,
|
||||
CreateFolderTable1738709609940,
|
||||
];
|
||||
|
|
|
@ -79,6 +79,7 @@ import { AddManagedColumnToCredentialsTable1734479635324 } from '../common/17344
|
|||
import { AddStatsColumnsToTestRun1736172058779 } from '../common/1736172058779-AddStatsColumnsToTestRun';
|
||||
import { CreateTestCaseExecutionTable1736947513045 } from '../common/1736947513045-CreateTestCaseExecutionTable';
|
||||
import { AddErrorColumnsToTestRuns1737715421462 } from '../common/1737715421462-AddErrorColumnsToTestRuns';
|
||||
import { CreateFolderTable1738709609940 } from '../common/1738709609940-CreateFolderTable';
|
||||
|
||||
export const postgresMigrations: Migration[] = [
|
||||
InitialMigration1587669153312,
|
||||
|
@ -160,4 +161,5 @@ export const postgresMigrations: Migration[] = [
|
|||
AddStatsColumnsToTestRun1736172058779,
|
||||
CreateTestCaseExecutionTable1736947513045,
|
||||
AddErrorColumnsToTestRuns1737715421462,
|
||||
CreateFolderTable1738709609940,
|
||||
];
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import { CreateFolderTable1738709609940 as BaseMigration } from '../common/1738709609940-CreateFolderTable';
|
||||
|
||||
export class CreateFolderTable1738709609940 extends BaseMigration {
|
||||
transaction = false as const;
|
||||
}
|
|
@ -42,6 +42,7 @@ import { AddMissingPrimaryKeyOnAnnotationTagMapping1728659839644 } from './17286
|
|||
import { AddProjectIcons1729607673469 } from './1729607673469-AddProjectIcons';
|
||||
import { AddDescriptionToTestDefinition1731404028106 } from './1731404028106-AddDescriptionToTestDefinition';
|
||||
import { MigrateTestDefinitionKeyToString1731582748663 } from './1731582748663-MigrateTestDefinitionKeyToString';
|
||||
import { CreateFolderTable1738709609940 } from './1738709609940-CreateFolderTable';
|
||||
import { UniqueWorkflowNames1620821879465 } from '../common/1620821879465-UniqueWorkflowNames';
|
||||
import { UpdateWorkflowCredentials1630330987096 } from '../common/1630330987096-UpdateWorkflowCredentials';
|
||||
import { AddNodeIds1658930531669 } from '../common/1658930531669-AddNodeIds';
|
||||
|
@ -154,6 +155,7 @@ const sqliteMigrations: Migration[] = [
|
|||
AddStatsColumnsToTestRun1736172058779,
|
||||
CreateTestCaseExecutionTable1736947513045,
|
||||
AddErrorColumnsToTestRuns1737715421462,
|
||||
CreateFolderTable1738709609940,
|
||||
];
|
||||
|
||||
export { sqliteMigrations };
|
||||
|
|
11
packages/cli/src/databases/repositories/folder.repository.ts
Normal file
11
packages/cli/src/databases/repositories/folder.repository.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { Service } from '@n8n/di';
|
||||
import { DataSource, Repository } from '@n8n/typeorm';
|
||||
|
||||
import { Folder } from '../entities/folder';
|
||||
|
||||
@Service()
|
||||
export class FolderRepository extends Repository<Folder> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(Folder, dataSource.manager);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue