-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add workflow query hooks #6876
Add workflow query hooks #6876
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { CustomException } from 'src/utils/custom-exception'; | ||
|
||
export class WorkflowQueryHookException extends CustomException { | ||
constructor(message: string, code: WorkflowQueryHookExceptionCode) { | ||
super(message, code); | ||
} | ||
} | ||
|
||
export enum WorkflowQueryHookExceptionCode { | ||
FORBIDDEN = 'FORBIDDEN', | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { | ||
WorkflowQueryHookException, | ||
WorkflowQueryHookExceptionCode, | ||
} from 'src/modules/workflow/common/query-hooks/workflow-query-hook.exception'; | ||
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; | ||
|
||
@WorkspaceQueryHook(`workflowRun.createMany`) | ||
export class WorkflowRunCreateManyPreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
async execute(): Promise<CreateManyResolverArgs<WorkflowRunWorkspaceEntity>> { | ||
throw new WorkflowQueryHookException( | ||
'Method not allowed.', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Consider adding a more specific error message explaining why creating multiple workflow runs is not allowed |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { | ||
WorkflowQueryHookException, | ||
WorkflowQueryHookExceptionCode, | ||
} from 'src/modules/workflow/common/query-hooks/workflow-query-hook.exception'; | ||
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; | ||
|
||
@WorkspaceQueryHook(`workflowRun.createOne`) | ||
export class WorkflowRunCreateOnePreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
async execute(): Promise<CreateOneResolverArgs<WorkflowRunWorkspaceEntity>> { | ||
throw new WorkflowQueryHookException( | ||
'Method not allowed.', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { DeleteManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { | ||
WorkflowQueryHookException, | ||
WorkflowQueryHookExceptionCode, | ||
} from 'src/modules/workflow/common/query-hooks/workflow-query-hook.exception'; | ||
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: WorkflowRunWorkspaceEntity is imported but not directly used. Consider removing if unnecessary. |
||
|
||
@WorkspaceQueryHook(`workflowRun.deleteMany`) | ||
export class WorkflowRunDeleteManyPreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
async execute(): Promise<DeleteManyResolverArgs<WorkflowRunWorkspaceEntity>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: execute method doesn't use its parameters (userId, workspaceId, payload). Consider removing them if not needed. |
||
throw new WorkflowQueryHookException( | ||
'Method not allowed.', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { | ||
WorkflowQueryHookException, | ||
WorkflowQueryHookExceptionCode, | ||
} from 'src/modules/workflow/common/query-hooks/workflow-query-hook.exception'; | ||
|
||
@WorkspaceQueryHook(`workflowRun.deleteOne`) | ||
export class WorkflowRunDeleteOnePreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
async execute(): Promise<DeleteOneResolverArgs> { | ||
throw new WorkflowQueryHookException( | ||
'Method not allowed.', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Consider adding parameters to execute() method for consistency with WorkspaceQueryHookInstance interface |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { | ||
WorkflowQueryHookException, | ||
WorkflowQueryHookExceptionCode, | ||
} from 'src/modules/workflow/common/query-hooks/workflow-query-hook.exception'; | ||
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; | ||
|
||
@WorkspaceQueryHook(`workflowRun.updateMany`) | ||
export class WorkflowRunUpdateManyPreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
async execute(): Promise<UpdateManyResolverArgs<WorkflowRunWorkspaceEntity>> { | ||
throw new WorkflowQueryHookException( | ||
'Method not allowed.', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Consider adding a more specific error message explaining why this operation is not allowed |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { | ||
WorkflowQueryHookException, | ||
WorkflowQueryHookExceptionCode, | ||
} from 'src/modules/workflow/common/query-hooks/workflow-query-hook.exception'; | ||
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; | ||
|
||
@WorkspaceQueryHook(`workflowRun.updateOne`) | ||
export class WorkflowRunUpdateOnePreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
async execute(): Promise<UpdateOneResolverArgs<WorkflowRunWorkspaceEntity>> { | ||
throw new WorkflowQueryHookException( | ||
'Method not allowed.', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Consider adding a more descriptive error message explaining why updates are not allowed |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
|
||
import { | ||
CreateOneResolverArgs, | ||
DeleteOneResolverArgs, | ||
UpdateOneResolverArgs, | ||
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; | ||
import { | ||
WorkflowQueryHookException, | ||
WorkflowQueryHookExceptionCode, | ||
} from 'src/modules/workflow/common/query-hooks/workflow-query-hook.exception'; | ||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/services/workflow-common.workspace-service'; | ||
import { | ||
WorkflowVersionStatus, | ||
WorkflowVersionWorkspaceEntity, | ||
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; | ||
import { WorkflowTrigger } from 'src/modules/workflow/common/types/workflow-trigger.type'; | ||
|
||
@Injectable() | ||
export class WorkflowVersionValidationWorkspaceService { | ||
constructor( | ||
private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService, | ||
private readonly twentyORMManager: TwentyORMManager, | ||
) {} | ||
|
||
async validateWorkflowVersionForCreateOne( | ||
payload: CreateOneResolverArgs<WorkflowVersionWorkspaceEntity>, | ||
) { | ||
if ( | ||
payload.data.status && | ||
payload.data.status !== WorkflowVersionStatus.DRAFT | ||
) { | ||
Comment on lines
+31
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Consider using optional chaining (?.) for payload.data.status to handle potential undefined values |
||
throw new WorkflowQueryHookException( | ||
'Cannot create workflow version with status other than draft', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
|
||
const workflowVersionRepository = | ||
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>( | ||
'workflowVersion', | ||
); | ||
|
||
const workflowAlreadyHasDraftVersion = | ||
await workflowVersionRepository.exists({ | ||
where: { | ||
workflowId: payload.data.workflowId, | ||
status: WorkflowVersionStatus.DRAFT, | ||
}, | ||
}); | ||
|
||
if (workflowAlreadyHasDraftVersion) { | ||
throw new WorkflowQueryHookException( | ||
'Cannot create multiple draft versions for the same workflow', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
} | ||
|
||
async validateWorkflowVersionForUpdateOne( | ||
payload: UpdateOneResolverArgs<WorkflowVersionWorkspaceEntity>, | ||
) { | ||
const workflowVersion = | ||
await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail( | ||
payload.id, | ||
); | ||
|
||
this.validateWorkflowVersionIsDraft(workflowVersion); | ||
|
||
if (payload.data.status !== workflowVersion.status) { | ||
throw new WorkflowQueryHookException( | ||
'Cannot update workflow version status manually', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: This check prevents any status updates. Ensure this is the intended behavior |
||
} | ||
|
||
async validateWorkflowVersionForDeleteOne(payload: DeleteOneResolverArgs) { | ||
const workflowVersion = | ||
await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail( | ||
payload.id, | ||
); | ||
|
||
this.validateWorkflowVersionIsDraft(workflowVersion); | ||
} | ||
|
||
private validateWorkflowVersionIsDraft( | ||
workflowVersion: Omit<WorkflowVersionWorkspaceEntity, 'trigger'> & { | ||
trigger: WorkflowTrigger; | ||
}, | ||
) { | ||
if (workflowVersion.status !== WorkflowVersionStatus.DRAFT) { | ||
throw new WorkflowQueryHookException( | ||
'Workflow version is not in draft status', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { | ||
CreateManyResolverArgs, | ||
CreateOneResolverArgs, | ||
} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; | ||
import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service'; | ||
import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; | ||
|
||
@WorkspaceQueryHook(`workflowVersion.createMany`) | ||
export class WorkflowVersionCreateManyPreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
constructor( | ||
private readonly workflowVersionValidationWorkspaceService: WorkflowVersionValidationWorkspaceService, | ||
) {} | ||
|
||
async execute( | ||
_authContext: AuthContext, | ||
_objectName: string, | ||
payload: CreateManyResolverArgs<WorkflowVersionWorkspaceEntity>, | ||
): Promise<CreateManyResolverArgs<WorkflowVersionWorkspaceEntity>> { | ||
await Promise.all( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Be careful with Promise.all, it could have an impact on the server performances so if the list is big it would be better to run those promises in batches There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be ok, we should only do |
||
payload.data.map(async (workflowVersion) => { | ||
await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForCreateOne( | ||
{ | ||
data: workflowVersion, | ||
} satisfies CreateOneResolverArgs<WorkflowVersionWorkspaceEntity>, | ||
); | ||
}), | ||
); | ||
Comment on lines
+25
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: This Promise.all could potentially throw if any validation fails. Consider wrapping it in a try-catch block to handle errors gracefully and provide meaningful feedback. |
||
|
||
return payload; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; | ||
import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service'; | ||
import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; | ||
|
||
@WorkspaceQueryHook(`workflowVersion.createOne`) | ||
export class WorkflowVersionCreateOnePreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
constructor( | ||
private readonly workflowVersionValidationWorkspaceService: WorkflowVersionValidationWorkspaceService, | ||
) {} | ||
|
||
async execute( | ||
_authContext: AuthContext, | ||
_objectName: string, | ||
payload: CreateOneResolverArgs<WorkflowVersionWorkspaceEntity>, | ||
): Promise<CreateOneResolverArgs<WorkflowVersionWorkspaceEntity>> { | ||
await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForCreateOne( | ||
payload, | ||
); | ||
|
||
return payload; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; | ||
import { DeleteManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; | ||
|
||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; | ||
import { | ||
WorkflowQueryHookException, | ||
WorkflowQueryHookExceptionCode, | ||
} from 'src/modules/workflow/common/query-hooks/workflow-query-hook.exception'; | ||
import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; | ||
|
||
@WorkspaceQueryHook(`workflowVersion.deleteMany`) | ||
export class WorkflowVersionDeleteManyPreQueryHook | ||
implements WorkspaceQueryHookInstance | ||
{ | ||
async execute(): Promise< | ||
DeleteManyResolverArgs<WorkflowVersionWorkspaceEntity> | ||
> { | ||
throw new WorkflowQueryHookException( | ||
'Method not allowed.', | ||
WorkflowQueryHookExceptionCode.FORBIDDEN, | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: The error message could be more specific, e.g., 'Bulk deletion of workflow versions is not allowed.' |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we want to call it QueryHookException? Maybe WorkflowVersionValidationException? Up to you!