Skip to content
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

feat: scenario cloning adjustments #991

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { CqrsModule } from '@nestjs/cqrs';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Project } from '../../../projects/project.api.entity';
import { Scenario } from '../../../scenarios/scenario.api.entity';
import { AllPiecesReadySaga } from './all-pieces-ready.saga';
import { CompleteExportPieceHandler } from './complete-export-piece.handler';
import { ExportProjectHandler } from './export-project.handler';
Expand All @@ -22,7 +23,7 @@ export class ExportApplicationModule {
module: ExportApplicationModule,
imports: [
CqrsModule,
TypeOrmModule.forFeature([Project]),
TypeOrmModule.forFeature([Project, Scenario]),
...(adapters ?? []),
],
providers: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { ResourceKind } from '@marxan/cloning/domain';
import {
CommandHandler,
EventPublisher,
IInferredCommandHandler,
} from '@nestjs/cqrs';

import { ResourceKind } from '@marxan/cloning/domain';
import { Export, ExportId } from '../domain';

import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Scenario } from '../../../scenarios/scenario.api.entity';
import { Export } from '../domain';
import { ExportRepository } from './export-repository.port';
import { ExportResourcePieces } from './export-resource-pieces.port';
import {
ExportScenario,
ExportScenarioCommandResult,
} from './export-scenario.command';
import { ExportResourcePieces } from './export-resource-pieces.port';
import { ExportRepository } from './export-repository.port';

@CommandHandler(ExportScenario)
export class ExportScenarioHandler
Expand All @@ -21,8 +22,22 @@ export class ExportScenarioHandler
private readonly resourcePieces: ExportResourcePieces,
private readonly exportRepository: ExportRepository,
private readonly eventPublisher: EventPublisher,
@InjectRepository(Scenario)
private readonly scenarioRepo: Repository<Scenario>,
) {}

private async createScenarioShell(
existingScenarioId: string,
newScenarioId: string,
) {
const scenario = await this.scenarioRepo.findOneOrFail(existingScenarioId);
await this.scenarioRepo.save({
id: newScenarioId,
name: '',
projectId: scenario.projectId,
});
}

async execute({
scenarioId,
projectId,
Expand All @@ -39,6 +54,11 @@ export class ExportScenarioHandler

exportRequest.commit();

await this.createScenarioShell(
scenarioId.value,
exportRequest.importResourceId!.value,
);

return {
exportId: exportRequest.id,
importResourceId: exportRequest.importResourceId!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,48 @@ export class ScenarioMetadataPieceImporter implements ImportPieceProcessor {
return piece === ClonePiece.ScenarioMetadata;
}

private updateScenario(
em: EntityManager,
scenarioId: string,
values: ScenarioMetadataContent,
) {
return em
.createQueryBuilder()
.update('scenarios')
.set({
id: scenarioId,
name: values.name,
description: values.description,
blm: values.blm,
number_of_runs: values.numberOfRuns,
metadata: values.metadata,
})
.where('id = :scenarioId', { scenarioId })
.execute();
}

private createScenario(
em: EntityManager,
scenarioId: string,
projectId: string,
values: ScenarioMetadataContent,
) {
return em
.createQueryBuilder()
.insert()
.into('scenarios')
.values({
id: scenarioId,
name: values.name,
description: values.description,
blm: values.blm,
number_of_runs: values.numberOfRuns,
metadata: values.metadata,
project_id: projectId,
})
.execute();
}

async run(input: ImportJobInput): Promise<ImportJobOutput> {
const {
pieceResourceId: scenarioId,
Expand Down Expand Up @@ -66,31 +108,18 @@ export class ScenarioMetadataPieceImporter implements ImportPieceProcessor {
throw new Error(errorMessage);
}

const {
name,
blm,
description,
metadata,
numberOfRuns,
}: ScenarioMetadataContent = JSON.parse(
const metadata: ScenarioMetadataContent = JSON.parse(
stringScenarioMetadataOrError.right,
);

const scenarioCloning = resourceKind === ResourceKind.Scenario;

await this.entityManager.transaction(async (em) => {
await em
.createQueryBuilder()
.insert()
.into('scenarios')
.values({
id: scenarioId,
name,
description,
blm,
number_of_runs: numberOfRuns,
metadata,
project_id: projectId,
})
.execute();
if (scenarioCloning) {
await this.updateScenario(em, scenarioId, metadata);
} else {
await this.createScenario(em, scenarioId, projectId, metadata);
}

if (resourceKind === ResourceKind.Scenario) {
await em
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { v4 } from 'uuid';
import {
DeleteProjectAndOrganization,
GivenProjectExists,
GivenScenarioExists,
GivenUserExists,
PrepareZipFile,
} from '../fixtures';
Expand Down Expand Up @@ -49,17 +50,38 @@ describe(ScenarioMetadataPieceImporter, () => {

it('fails when the file cannot be retrieved from file repo', async () => {
const archiveLocation = fixtures.GivenNoScenarioMetadataFileIsAvailable();
const input = fixtures.GivenJobInput(archiveLocation);
const input = fixtures.GivenJobInput(archiveLocation, ResourceKind.Project);
await fixtures
.WhenPieceImporterIsInvoked(input)
.ThenADataNotAvailableErrorShouldBeThrown();
});

it('imports scenario metadata', async () => {
it('imports scenario metadata creating a new scenario (project import process)', async () => {
const resourceKind = ResourceKind.Project;
await fixtures.GivenProject();
await fixtures.GivenUser();
const archiveLocation = await fixtures.GivenValidScenarioMetadataFile();
const input = fixtures.GivenJobInput(archiveLocation);

const archiveLocation = await fixtures.GivenValidScenarioMetadataFile(
resourceKind,
);
const input = fixtures.GivenJobInput(archiveLocation, resourceKind);
await fixtures
.WhenPieceImporterIsInvoked(input)
.ThenScenarioMetadataShouldBeImported();
});

it('imports scenario metadata updating an existing scenario (scenario cloning process)', async () => {
const resourceKind = ResourceKind.Scenario;
await fixtures.GivenScenario();
await fixtures.GivenUser();

const archiveLocation = await fixtures.GivenValidScenarioMetadataFile(
resourceKind,
);
const input = fixtures.GivenJobInput(
archiveLocation,
ResourceKind.Scenario,
);
await fixtures
.WhenPieceImporterIsInvoked(input)
.ThenScenarioMetadataShouldBeImported();
Expand All @@ -86,7 +108,6 @@ const getFixtures = async () => {
const scenarioId = v4();
const projectId = v4();
const organizationId = v4();
const resourceKind = ResourceKind.Project;
const oldScenarioId = v4();
const userId = v4();

Expand Down Expand Up @@ -116,7 +137,18 @@ const getFixtures = async () => {
GivenProject: () => {
return GivenProjectExists(entityManager, projectId, organizationId);
},
GivenJobInput: (archiveLocation: ArchiveLocation): ImportJobInput => {
GivenScenario: () => {
return GivenScenarioExists(
entityManager,
scenarioId,
projectId,
organizationId,
);
},
GivenJobInput: (
archiveLocation: ArchiveLocation,
resourceKind: ResourceKind,
): ImportJobInput => {
const [
uri,
] = ClonePieceUrisResolver.resolveFor(
Expand All @@ -142,15 +174,15 @@ const getFixtures = async () => {
importId: v4(),
projectId,
piece: ClonePiece.ScenarioMetadata,
resourceKind,
resourceKind: ResourceKind.Project,
uris: [],
ownerId: userId,
};
},
GivenNoScenarioMetadataFileIsAvailable: () => {
return new ArchiveLocation('not found');
},
GivenValidScenarioMetadataFile: async () => {
GivenValidScenarioMetadataFile: async (resourceKind: ResourceKind) => {
const [
{ relativePath },
] = ClonePieceUrisResolver.resolveFor(
Expand Down