diff --git a/packages/backend/src/controllers/api/v1/flows/create-step.js b/packages/backend/src/controllers/api/v1/flows/create-step.js index f0bb71f7..b1c49e37 100644 --- a/packages/backend/src/controllers/api/v1/flows/create-step.js +++ b/packages/backend/src/controllers/api/v1/flows/create-step.js @@ -6,7 +6,7 @@ export default async (request, response) => { .findById(request.params.flowId) .throwIfNotFound(); - const createdActionStep = await flow.createActionStep( + const createdActionStep = await flow.createStepAfter( request.body.previousStepId ); diff --git a/packages/backend/src/models/flow.js b/packages/backend/src/models/flow.js index d38e70aa..9b9a8826 100644 --- a/packages/backend/src/models/flow.js +++ b/packages/backend/src/models/flow.js @@ -153,27 +153,41 @@ class Flow extends Base { }); } - async createActionStep(previousStepId) { - const previousStep = await this.$relatedQuery('steps') - .findById(previousStepId) - .throwIfNotFound(); + async getStepById(stepId) { + return await this.$relatedQuery('steps').findById(stepId).throwIfNotFound(); + } - const createdStep = await this.$relatedQuery('steps').insertAndFetch({ + async insertActionStepAtPosition(position) { + return await this.$relatedQuery('steps').insertAndFetch({ type: 'action', - position: previousStep.position + 1, + position, }); + } - const nextSteps = await this.$relatedQuery('steps') - .where('position', '>=', createdStep.position) - .whereNot('id', createdStep.id); + async getStepsAfterPosition(position) { + return await this.$relatedQuery('steps').where('position', '>', position); + } - const nextStepQueries = nextSteps.map(async (nextStep, index) => { - return await nextStep.$query().patchAndFetch({ - position: createdStep.position + index + 1, + async updateStepPositionsFrom(startPosition, steps) { + const stepPositionUpdates = steps.map(async (step, index) => { + return await step.$query().patch({ + position: startPosition + index, }); }); - await Promise.all(nextStepQueries); + return await Promise.all(stepPositionUpdates); + } + + async createStepAfter(previousStepId) { + const previousStep = await this.getStepById(previousStepId); + + const nextSteps = await this.getStepsAfterPosition(previousStep.position); + + const createdStep = await this.insertActionStepAtPosition( + previousStep.position + 1 + ); + + await this.updateStepPositionsFrom(createdStep.position + 1, nextSteps); return createdStep; } diff --git a/packages/backend/src/models/flow.test.js b/packages/backend/src/models/flow.test.js index 77c4b682..cfaec443 100644 --- a/packages/backend/src/models/flow.test.js +++ b/packages/backend/src/models/flow.test.js @@ -245,7 +245,69 @@ describe('Flow model', () => { }); }); - it.todo('createActionStep'); + it('getStepById should return the step with the given ID from the flow', async () => { + const flow = await createFlow(); + + const step = await createStep({ flowId: flow.id }); + + expect(await flow.getStepById(step.id)).toStrictEqual(step); + }); + + it('insertActionStepAtPosition should insert action step at given position', async () => { + const flow = await createFlow(); + + await flow.createInitialSteps(); + + const createdStep = await flow.insertActionStepAtPosition(2); + + expect(createdStep).toMatchObject({ + type: 'action', + position: 2, + }); + }); + + it('getStepsAfterPosition should return steps after the given position', async () => { + const flow = await createFlow(); + + await flow.createInitialSteps(); + + await createStep({ flowId: flow.id }); + + expect(await flow.getStepsAfterPosition(1)).toMatchObject([ + { position: 2 }, + { position: 3 }, + ]); + }); + + it('updateStepPositionsFrom', async () => { + const flow = await createFlow(); + + await createStep({ type: 'trigger', flowId: flow.id, position: 6 }); + await createStep({ type: 'action', flowId: flow.id, position: 8 }); + await createStep({ type: 'action', flowId: flow.id, position: 10 }); + + await flow.updateStepPositionsFrom(2, await flow.$relatedQuery('steps')); + + expect(await flow.$relatedQuery('steps')).toMatchObject([ + { position: 2, type: 'trigger' }, + { position: 3, type: 'action' }, + { position: 4, type: 'action' }, + ]); + }); + + it('createStepAfter should create an action step after given step ID', async () => { + const flow = await createFlow(); + + const triggerStep = await createStep({ type: 'trigger', flowId: flow.id }); + const actionStep = await createStep({ type: 'action', flowId: flow.id }); + + const createdStep = await flow.createStepAfter(triggerStep.id); + + const refetchedActionStep = await actionStep.$query(); + + expect(createdStep).toMatchObject({ type: 'action', position: 2 }); + expect(refetchedActionStep.position).toBe(3); + }); it.todo('delete');