-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(CostSurface): Adds endpoint to link a CostSurface to a Scenario
- Loading branch information
1 parent
f22f385
commit 694f639
Showing
33 changed files
with
1,233 additions
and
55 deletions.
There are no files selected for viewing
25 changes: 25 additions & 0 deletions
25
api/apps/api/src/migrations/api/1696603545456-AddCostSurfaceLinkingNewEvents.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { MigrationInterface, QueryRunner } from 'typeorm'; | ||
|
||
export class AddCostSurfaceLinkingNewEvents1696603545456 | ||
implements MigrationInterface { | ||
public async up(queryRunner: QueryRunner): Promise<void> { | ||
await queryRunner.query(` | ||
INSERT INTO api_event_kinds (id) values | ||
('scenario.costSurface.link.submitted/v1/alpha1'), | ||
('scenario.costSurface.link.finished/v1/alpha1'), | ||
('scenario.costSurface.link.failed/v1/alpha1'); | ||
`); | ||
} | ||
|
||
public async down(queryRunner: QueryRunner): Promise<void> { | ||
await queryRunner.query( | ||
`DELETE FROM api_event_kinds WHERE id = 'scenario.costSurface.link.submitted/v1/alpha1';`, | ||
); | ||
await queryRunner.query( | ||
`DELETE FROM api_event_kinds WHERE id = 'scenario.costSurface.link.finished/v1/alpha1';`, | ||
); | ||
await queryRunner.query( | ||
`DELETE FROM api_event_kinds WHERE id = 'scenario.costSurface.link.failed/v1/alpha1';`, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
api/apps/api/src/modules/cost-surface/adapters/scenario-cost-surface-adapters.module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { ApiEventsModule } from '../../api-events'; | ||
import { CqrsModule } from '@nestjs/cqrs'; | ||
import { ScenarioCostSurfaceEventsPort } from '@marxan-api/modules/cost-surface/ports/scenario/scenario-cost-surface-events.port'; | ||
import { ScenarioCostSurfaceApiEvents } from '@marxan-api/modules/cost-surface/adapters/scenario/scenario-cost-surface-api-events'; | ||
|
||
@Module({ | ||
imports: [ApiEventsModule, CqrsModule], | ||
providers: [ | ||
{ | ||
provide: ScenarioCostSurfaceEventsPort, | ||
useClass: ScenarioCostSurfaceApiEvents, | ||
}, | ||
], | ||
exports: [ScenarioCostSurfaceEventsPort], | ||
}) | ||
export class ScenarioCostSurfaceAdaptersModule {} |
36 changes: 36 additions & 0 deletions
36
api/apps/api/src/modules/cost-surface/adapters/scenario/scenario-cost-surface-api-events.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
import { API_EVENT_KINDS } from '@marxan/api-events'; | ||
import { ApiEventsService } from '@marxan-api/modules/api-events'; | ||
import { | ||
ScenarioCostSurfaceEventsPort, | ||
ScenarioCostSurfaceState, | ||
} from '@marxan-api/modules/cost-surface/ports/scenario/scenario-cost-surface-events.port'; | ||
|
||
@Injectable() | ||
export class ScenarioCostSurfaceApiEvents | ||
extends ApiEventsService | ||
implements ScenarioCostSurfaceEventsPort { | ||
private readonly eventsMap: Record< | ||
ScenarioCostSurfaceState, | ||
API_EVENT_KINDS | ||
> = { | ||
[ScenarioCostSurfaceState.LinkToScenarioFailed]: | ||
API_EVENT_KINDS.scenario__costSurface__link__failed__v1_alpha1, | ||
[ScenarioCostSurfaceState.LinkToScenarioFinished]: | ||
API_EVENT_KINDS.scenario__costSurface__link__finished__v1_alpha1, | ||
[ScenarioCostSurfaceState.LinkToScenarioSubmitted]: | ||
API_EVENT_KINDS.scenario__costSurface__link__submitted__v1_alpha1, | ||
}; | ||
|
||
async event( | ||
scenarioId: string, | ||
state: ScenarioCostSurfaceState, | ||
context?: Record<string, unknown>, | ||
): Promise<void> { | ||
await this.create({ | ||
data: context ?? {}, | ||
topic: scenarioId, | ||
kind: this.eventsMap[state], | ||
}); | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
...pi/src/modules/cost-surface/application/scenario/link-cost-surface-to-scenario.command.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Command } from '@nestjs-architects/typed-cqrs'; | ||
import { Either } from 'fp-ts/lib/Either'; | ||
|
||
export const linkCostSurfaceToScenarioFailed = Symbol( | ||
'link surface cost to scenario failed', | ||
); | ||
|
||
export type LinkCostSurfaceToScenarioError = typeof linkCostSurfaceToScenarioFailed; | ||
|
||
export type LinkCostSurfaceToScenarioResponse = Either< | ||
LinkCostSurfaceToScenarioError, | ||
true | ||
>; | ||
|
||
/** | ||
* @todo: Temporal substitute for UpdateCostSurface command, which works at scenario level. It should be | ||
* removed and use there once the implementation is fully validated | ||
*/ | ||
export class LinkCostSurfaceToScenarioCommand extends Command<LinkCostSurfaceToScenarioResponse> { | ||
constructor( | ||
public readonly scenarioId: string, | ||
public readonly costSurfaceId: string, | ||
public readonly mode: 'creation' | 'update', | ||
) { | ||
super(); | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
...pi/src/modules/cost-surface/application/scenario/link-cost-surface-to-scenario.handler.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { Inject, Logger } from '@nestjs/common'; | ||
import { CommandHandler, IInferredCommandHandler } from '@nestjs/cqrs'; | ||
import { Queue } from 'bullmq'; | ||
import { left, right } from 'fp-ts/lib/Either'; | ||
import { LinkCostSurfaceToScenarioJobInput } from '@marxan/artifact-cache/surface-cost-job-input'; | ||
import { | ||
LinkCostSurfaceToScenarioCommand, | ||
linkCostSurfaceToScenarioFailed, | ||
LinkCostSurfaceToScenarioResponse, | ||
} from '@marxan-api/modules/cost-surface/application/scenario/link-cost-surface-to-scenario.command'; | ||
import { InjectRepository } from '@nestjs/typeorm'; | ||
import { Scenario } from '@marxan-api/modules/scenarios/scenario.api.entity'; | ||
import { Repository } from 'typeorm'; | ||
import { | ||
ScenarioCostSurfaceEventsPort, | ||
ScenarioCostSurfaceState, | ||
} from '@marxan-api/modules/cost-surface/ports/scenario/scenario-cost-surface-events.port'; | ||
import { scenarioCostSurfaceQueueToken } from '@marxan-api/modules/cost-surface/infra/scenario/scenario-cost-surface-queue.provider'; | ||
|
||
@CommandHandler(LinkCostSurfaceToScenarioCommand) | ||
export class LinkCostSurfaceToScenarioHandler | ||
implements IInferredCommandHandler<LinkCostSurfaceToScenarioCommand> { | ||
private readonly logger: Logger = new Logger( | ||
LinkCostSurfaceToScenarioHandler.name, | ||
); | ||
|
||
constructor( | ||
@Inject(scenarioCostSurfaceQueueToken) | ||
private readonly queue: Queue<LinkCostSurfaceToScenarioJobInput>, | ||
@InjectRepository(Scenario) | ||
private readonly scenarioRepo: Repository<Scenario>, | ||
private readonly events: ScenarioCostSurfaceEventsPort, | ||
) {} | ||
|
||
async execute({ | ||
scenarioId, | ||
costSurfaceId, | ||
mode, | ||
}: LinkCostSurfaceToScenarioCommand): Promise<LinkCostSurfaceToScenarioResponse> { | ||
try { | ||
const scenario = await this.scenarioRepo.findOneOrFail({ | ||
where: { id: scenarioId }, | ||
}); | ||
const originalCostSurfaceId = scenario.costSurfaceId; | ||
|
||
await this.queue.add(`link-cost-surface-for-scenario-${scenarioId}`, { | ||
type: 'LinkCostSurfaceToScenarioJobInput', | ||
scenarioId, | ||
costSurfaceId, | ||
originalCostSurfaceId, | ||
mode, | ||
}); | ||
|
||
await this.scenarioRepo.update(scenarioId, { costSurfaceId }); | ||
|
||
await this.events.event( | ||
scenarioId, | ||
ScenarioCostSurfaceState.LinkToScenarioSubmitted, | ||
); | ||
} catch (error) { | ||
await this.markAsFailed(scenarioId, error); | ||
return left(linkCostSurfaceToScenarioFailed); | ||
} | ||
|
||
return right(true); | ||
} | ||
|
||
private markAsFailed = async (scenarioId: string, error: unknown) => { | ||
this.logger.error( | ||
`Failed executing link-cost-surface-to-scenario command for scenario ${scenarioId}`, | ||
String(error), | ||
); | ||
await this.events.event( | ||
scenarioId, | ||
ScenarioCostSurfaceState.LinkToScenarioFailed, | ||
{ | ||
error, | ||
}, | ||
); | ||
}; | ||
} |
18 changes: 18 additions & 0 deletions
18
...src/modules/cost-surface/application/scenario/scenario-cost-surface-application.module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { CqrsModule } from '@nestjs/cqrs'; | ||
import { LinkCostSurfaceToScenarioHandler } from '@marxan-api/modules/cost-surface/application/scenario/link-cost-surface-to-scenario.handler'; | ||
import { ScenarioCostSurfaceInfraModule } from '@marxan-api/modules/cost-surface/infra/scenario/scenario-cost-surface-infra.module'; | ||
import { ScenarioCostSurfaceAdaptersModule } from '@marxan-api/modules/cost-surface/adapters/scenario-cost-surface-adapters.module'; | ||
import { TypeOrmModule } from '@nestjs/typeorm'; | ||
import { Scenario } from '@marxan-api/modules/scenarios/scenario.api.entity'; | ||
|
||
@Module({ | ||
imports: [ | ||
ScenarioCostSurfaceInfraModule, | ||
ScenarioCostSurfaceAdaptersModule, | ||
CqrsModule, | ||
TypeOrmModule.forFeature([Scenario]), | ||
], | ||
providers: [LinkCostSurfaceToScenarioHandler], | ||
}) | ||
export class ScenarioCostSurfaceApplicationModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.