diff --git a/packages/cli/src/databases/dsl/table.ts b/packages/cli/src/databases/dsl/table.ts index 78ed98272cc43..f598b674d7a88 100644 --- a/packages/cli/src/databases/dsl/table.ts +++ b/packages/cli/src/databases/dsl/table.ts @@ -50,8 +50,8 @@ export class CreateTable extends TableOperation { ref: { tableName: string; columnName: string; - onDelete?: 'CASCADE'; - onUpdate?: 'CASCADE'; + onDelete?: 'RESTRICT' | 'CASCADE' | 'NO ACTION' | 'SET NULL'; + onUpdate?: 'RESTRICT' | 'CASCADE' | 'NO ACTION' | 'SET NULL'; name?: string; }, ) { diff --git a/packages/cli/src/databases/entities/index.ts b/packages/cli/src/databases/entities/index.ts index 39f67b325296b..b73b348d8a2fb 100644 --- a/packages/cli/src/databases/entities/index.ts +++ b/packages/cli/src/databases/entities/index.ts @@ -20,6 +20,7 @@ import { Settings } from './settings'; import { SharedCredentials } from './shared-credentials'; import { SharedWorkflow } from './shared-workflow'; import { TagEntity } from './tag-entity'; +import { TestDefinition } from './test-definition'; import { User } from './user'; import { Variables } from './variables'; import { WebhookEntity } from './webhook-entity'; @@ -58,4 +59,5 @@ export const entities = { ProjectRelation, ApiKey, ProcessedData, + TestDefinition, }; diff --git a/packages/cli/src/databases/entities/test-definition.ts b/packages/cli/src/databases/entities/test-definition.ts new file mode 100644 index 0000000000000..b83ee6f527eaf --- /dev/null +++ b/packages/cli/src/databases/entities/test-definition.ts @@ -0,0 +1,61 @@ +import { + Column, + Entity, + Generated, + Index, + ManyToOne, + OneToOne, + PrimaryColumn, + RelationId, +} from '@n8n/typeorm'; +import { Length } from 'class-validator'; + +import { AnnotationTagEntity } from '@/databases/entities/annotation-tag-entity.ee'; +import { WorkflowEntity } from '@/databases/entities/workflow-entity'; + +import { WithTimestamps } from './abstract-entity'; + +/** + * Entity representing a Test + * It combines: + * - the workflow under test + * - the workflow used to evaluate the results of test execution + * - the filter used to select test cases from previous executions of the workflow under test - annotation tag + */ +@Entity() +@Index(['workflow']) +@Index(['evaluationWorkflow']) +export class TestDefinition extends WithTimestamps { + @Generated() + @PrimaryColumn() + id: number; + + @Column({ length: 255 }) + @Length(1, 255, { message: 'Test name must be $constraint1 to $constraint2 characters long.' }) + name: string; + + /** + * Relation to the workflow under test + */ + @ManyToOne('WorkflowEntity', 'tests') + workflow: WorkflowEntity; + + @RelationId((test: TestDefinition) => test.workflow) + workflowId: string; + + /** + * Relation to the workflow used to evaluate the results of test execution + */ + @ManyToOne('WorkflowEntity', 'evaluationTests') + evaluationWorkflow: WorkflowEntity; + + @RelationId((test: TestDefinition) => test.evaluationWorkflow) + evaluationWorkflowId: string; + + /** + * Relation to the annotation tag associated with the test + * This tag will be used to select the test cases to run from previous executions + */ + @OneToOne('AnnotationTagEntity', 'test') + annotationTag: AnnotationTagEntity; +} diff --git a/packages/cli/src/databases/migrations/common/1730386903556-CreateTestDefinitionTable.ts b/packages/cli/src/databases/migrations/common/1730386903556-CreateTestDefinitionTable.ts new file mode 100644 index 0000000000000..d71353ee73cb7 --- /dev/null +++ b/packages/cli/src/databases/migrations/common/1730386903556-CreateTestDefinitionTable.ts @@ -0,0 +1,37 @@ +import type { MigrationContext, ReversibleMigration } from '@/databases/types'; + +const testEntityTableName = 'test_definition'; + +export class CreateTestDefinitionTable1730386903556 implements ReversibleMigration { + async up({ schemaBuilder: { createTable, column } }: MigrationContext) { + await createTable(testEntityTableName) + .withColumns( + column('id').int.notNull.primary.autoGenerate, + column('name').varchar(255).notNull, + column('workflowId').varchar(36).notNull, + column('evaluationWorkflowId').varchar(36), + column('annotationTagId').varchar(16), + ) + .withIndexOn('workflowId') + .withIndexOn('evaluationWorkflowId') + .withForeignKey('workflowId', { + tableName: 'workflow_entity', + columnName: 'id', + onDelete: 'CASCADE', + }) + .withForeignKey('evaluationWorkflowId', { + tableName: 'workflow_entity', + columnName: 'id', + onDelete: 'SET NULL', + }) + .withForeignKey('annotationTagId', { + tableName: 'annotation_tag_entity', + columnName: 'id', + onDelete: 'SET NULL', + }).withTimestamps; + } + + async down({ schemaBuilder: { dropTable } }: MigrationContext) { + await dropTable(testEntityTableName); + } +} diff --git a/packages/cli/src/databases/migrations/mysqldb/index.ts b/packages/cli/src/databases/migrations/mysqldb/index.ts index ff40fd9dc003a..ebe7cf76c0c08 100644 --- a/packages/cli/src/databases/migrations/mysqldb/index.ts +++ b/packages/cli/src/databases/migrations/mysqldb/index.ts @@ -68,6 +68,7 @@ import { CreateProcessedDataTable1726606152711 } from '../common/1726606152711-C import { SeparateExecutionCreationFromStart1727427440136 } from '../common/1727427440136-SeparateExecutionCreationFromStart'; import { AddMissingPrimaryKeyOnAnnotationTagMapping1728659839644 } from '../common/1728659839644-AddMissingPrimaryKeyOnAnnotationTagMapping'; import { UpdateProcessedDataValueColumnToText1729607673464 } from '../common/1729607673464-UpdateProcessedDataValueColumnToText'; +import { CreateTestDefinitionTable1730386903556 } from '../common/1730386903556-CreateTestDefinitionTable'; export const mysqlMigrations: Migration[] = [ InitialMigration1588157391238, @@ -138,4 +139,5 @@ export const mysqlMigrations: Migration[] = [ CreateProcessedDataTable1726606152711, AddMissingPrimaryKeyOnAnnotationTagMapping1728659839644, UpdateProcessedDataValueColumnToText1729607673464, + CreateTestDefinitionTable1730386903556, ]; diff --git a/packages/cli/src/databases/migrations/postgresdb/index.ts b/packages/cli/src/databases/migrations/postgresdb/index.ts index f3ac7e0474b85..731ddc26800e9 100644 --- a/packages/cli/src/databases/migrations/postgresdb/index.ts +++ b/packages/cli/src/databases/migrations/postgresdb/index.ts @@ -68,6 +68,7 @@ import { CreateProcessedDataTable1726606152711 } from '../common/1726606152711-C import { SeparateExecutionCreationFromStart1727427440136 } from '../common/1727427440136-SeparateExecutionCreationFromStart'; import { AddMissingPrimaryKeyOnAnnotationTagMapping1728659839644 } from '../common/1728659839644-AddMissingPrimaryKeyOnAnnotationTagMapping'; import { UpdateProcessedDataValueColumnToText1729607673464 } from '../common/1729607673464-UpdateProcessedDataValueColumnToText'; +import { CreateTestDefinitionTable1730386903556 } from '../common/1730386903556-CreateTestDefinitionTable'; export const postgresMigrations: Migration[] = [ InitialMigration1587669153312, @@ -138,4 +139,5 @@ export const postgresMigrations: Migration[] = [ CreateProcessedDataTable1726606152711, AddMissingPrimaryKeyOnAnnotationTagMapping1728659839644, UpdateProcessedDataValueColumnToText1729607673464, + CreateTestDefinitionTable1730386903556, ]; diff --git a/packages/cli/src/databases/migrations/sqlite/index.ts b/packages/cli/src/databases/migrations/sqlite/index.ts index e53b5f43bd025..8004894ccfaea 100644 --- a/packages/cli/src/databases/migrations/sqlite/index.ts +++ b/packages/cli/src/databases/migrations/sqlite/index.ts @@ -65,6 +65,7 @@ import { CreateAnnotationTables1724753530828 } from '../common/1724753530828-Cre import { CreateProcessedDataTable1726606152711 } from '../common/1726606152711-CreateProcessedDataTable'; import { SeparateExecutionCreationFromStart1727427440136 } from '../common/1727427440136-SeparateExecutionCreationFromStart'; import { UpdateProcessedDataValueColumnToText1729607673464 } from '../common/1729607673464-UpdateProcessedDataValueColumnToText'; +import { CreateTestDefinitionTable1730386903556 } from '../common/1730386903556-CreateTestDefinitionTable'; const sqliteMigrations: Migration[] = [ InitialMigration1588102412422, @@ -132,6 +133,7 @@ const sqliteMigrations: Migration[] = [ CreateProcessedDataTable1726606152711, AddMissingPrimaryKeyOnAnnotationTagMapping1728659839644, UpdateProcessedDataValueColumnToText1729607673464, + CreateTestDefinitionTable1730386903556, ]; export { sqliteMigrations }; diff --git a/packages/cli/src/generic-helpers.ts b/packages/cli/src/generic-helpers.ts index e5978bb34a40a..378619a4e906a 100644 --- a/packages/cli/src/generic-helpers.ts +++ b/packages/cli/src/generic-helpers.ts @@ -3,6 +3,7 @@ import { validate } from 'class-validator'; import type { AnnotationTagEntity } from '@/databases/entities/annotation-tag-entity.ee'; import type { CredentialsEntity } from '@/databases/entities/credentials-entity'; import type { TagEntity } from '@/databases/entities/tag-entity'; +import type { TestDefinition } from '@/databases/entities/test-definition'; import type { User } from '@/databases/entities/user'; import type { WorkflowEntity } from '@/databases/entities/workflow-entity'; @@ -12,6 +13,7 @@ import { BadRequestError } from './errors/response-errors/bad-request.error'; export async function validateEntity( entity: | WorkflowEntity + | TestDefinition | CredentialsEntity | TagEntity | AnnotationTagEntity