From b9e02f22985887491d003ca0e9b83aa762e58cda Mon Sep 17 00:00:00 2001 From: andrea rota Date: Sun, 10 Mar 2024 12:03:11 +0000 Subject: [PATCH] port over stable_id of cost surfaces when cloning them --- .../cost-surface/cost-surface.api.entity.ts | 3 ++ .../project-cost-surfaces.piece-exporter.ts | 31 +++++++++---------- .../project-cost-surfaces.piece-importer.ts | 17 +++++----- .../clone-piece-data/project-cost-surfaces.ts | 10 ++++++ 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/api/apps/api/src/modules/cost-surface/cost-surface.api.entity.ts b/api/apps/api/src/modules/cost-surface/cost-surface.api.entity.ts index 9d5bd15e99..9f4f980386 100644 --- a/api/apps/api/src/modules/cost-surface/cost-surface.api.entity.ts +++ b/api/apps/api/src/modules/cost-surface/cost-surface.api.entity.ts @@ -33,6 +33,9 @@ export class CostSurface { @PrimaryGeneratedColumn('uuid') id!: string; + @Column({ name: 'stable_id' }) + stableId!: string; + @ApiProperty({ type: () => Project }) @ManyToOne((_type) => Project, (project) => project.costSurfaces) @JoinColumn({ diff --git a/api/apps/geoprocessing/src/export/pieces-exporters/project-cost-surfaces.piece-exporter.ts b/api/apps/geoprocessing/src/export/pieces-exporters/project-cost-surfaces.piece-exporter.ts index 38b981975d..25ec5f6551 100644 --- a/api/apps/geoprocessing/src/export/pieces-exporters/project-cost-surfaces.piece-exporter.ts +++ b/api/apps/geoprocessing/src/export/pieces-exporters/project-cost-surfaces.piece-exporter.ts @@ -2,12 +2,8 @@ import { geoprocessingConnections } from '@marxan-geoprocessing/ormconfig'; import { ClonePiece, ExportJobInput, ExportJobOutput } from '@marxan/cloning'; import { ComponentLocation, ResourceKind } from '@marxan/cloning/domain'; import { ClonePieceRelativePathResolver } from '@marxan/cloning/infrastructure/clone-piece-data'; -import { - ProjectCustomFeature, - ProjectCustomFeaturesContent, -} from '@marxan/cloning/infrastructure/clone-piece-data/project-custom-features'; +import { ProjectCustomFeature } from '@marxan/cloning/infrastructure/clone-piece-data/project-custom-features'; import { CloningFilesRepository } from '@marxan/cloning-files-repository'; -import { GeometrySource } from '@marxan/geofeatures'; import { Injectable, Logger } from '@nestjs/common'; import { InjectEntityManager } from '@nestjs/typeorm'; import { isLeft } from 'fp-ts/lib/Either'; @@ -24,6 +20,7 @@ type CreationStatus = ProjectCustomFeature['creation_status']; type ProjectCostSurfacesSelectResult = { id: string; + stable_id: string; name: string; min: number; max: number; @@ -32,6 +29,7 @@ type ProjectCostSurfacesSelectResult = { type CostSurfaceDataSelectResult = { cost_surface_id: string; + stable_id: string; cost: number; projects_pu_id: number; }; @@ -61,7 +59,14 @@ export class ProjectCostSurfacesPieceExporter implements ExportPieceProcessor { const costSurfaces: ProjectCostSurfacesSelectResult[] = await this.apiEntityManager .createQueryBuilder() - .select(['cs.id', 'cs.name', 'cs.min', 'cs.max', 'cs.is_default']) + .select([ + 'cs.id', + 'cs.stable_id', + 'cs.name', + 'cs.min', + 'cs.max', + 'cs.is_default', + ]) .from('cost_surfaces', 'cs') .where('cs.project_id = :projectId', { projectId: input.resourceId }) .execute(); @@ -94,16 +99,10 @@ export class ProjectCostSurfacesPieceExporter implements ExportPieceProcessor { (data: CostSurfaceDataSelectResult) => data.cost_surface_id === costSurface.id, ) - .map( - ({ - cost_surface_id: _cost_surface_id, - projects_pu_id, - ...data - }) => { - const puid = projectPusMap[projects_pu_id]; - return { puid, ...data }; - }, - ), + .map(({ projects_pu_id, ...data }) => { + const puid = projectPusMap[projects_pu_id]; + return { puid, ...data }; + }), })), }; diff --git a/api/apps/geoprocessing/src/import/pieces-importers/project-cost-surfaces.piece-importer.ts b/api/apps/geoprocessing/src/import/pieces-importers/project-cost-surfaces.piece-importer.ts index 5ab1ee5b2a..8029c509e0 100644 --- a/api/apps/geoprocessing/src/import/pieces-importers/project-cost-surfaces.piece-importer.ts +++ b/api/apps/geoprocessing/src/import/pieces-importers/project-cost-surfaces.piece-importer.ts @@ -1,9 +1,7 @@ import { geoprocessingConnections } from '@marxan-geoprocessing/ormconfig'; import { ClonePiece, ImportJobInput, ImportJobOutput } from '@marxan/cloning'; import { ResourceKind } from '@marxan/cloning/domain'; -import { ProjectCustomFeaturesContent } from '@marxan/cloning/infrastructure/clone-piece-data/project-custom-features'; import { CloningFilesRepository } from '@marxan/cloning-files-repository'; -import { GeoFeatureGeometry } from '@marxan/geofeatures'; import { readableToBuffer } from '@marxan/utils'; import { Injectable, Logger } from '@nestjs/common'; import { InjectEntityManager } from '@nestjs/typeorm'; @@ -14,11 +12,12 @@ import { ImportPieceProcessor, PieceImportProvider, } from '../pieces/import-piece-processor'; -import { chunk } from 'lodash'; +import { chunk, omit } from 'lodash'; import { ProjectsPuEntity } from '@marxan-jobs/planning-unit-geometry'; import { CHUNK_SIZE_FOR_BATCH_GEODB_OPERATIONS } from '@marxan-geoprocessing/utils/chunk-size-for-batch-geodb-operations'; import { CostSurfaceData, + ProjectCostSurface, ProjectCostSurfacesContent, } from '@marxan/cloning/infrastructure/clone-piece-data/project-cost-surfaces'; import { CostSurfacePuDataEntity } from '@marxan/cost-surfaces'; @@ -85,8 +84,11 @@ export class ProjectCostSurfacesPieceImporter implements ImportPieceProcessor { const projectPusMap = await this.getProjectPusMap(projectId); await this.apiEntityManager.transaction(async (apiEm) => { - const costSurfacesInsertValues: any[] = []; - let costSurfacesDataInsertValues: any[] = []; + const costSurfacesInsertValues: (Omit & { + project_id: string; + stable_id: string; + })[] = []; + let costSurfacesDataInsertValues: Record[] = []; costSurfaces.forEach(({ data, ...costSurface }) => { const costSurfaceId = v4(); @@ -94,6 +96,7 @@ export class ProjectCostSurfacesPieceImporter implements ImportPieceProcessor { ...costSurface, project_id: projectId, id: costSurfaceId, + stable_id: costSurface.stable_id, }); const costSurfaceData = data.map((data: CostSurfaceData) => ({ @@ -115,12 +118,12 @@ export class ProjectCostSurfacesPieceImporter implements ImportPieceProcessor { }); await Promise.all( - costSurfacesInsertValues.map((values) => + costSurfacesInsertValues.map((costSurfaceData) => apiEm .createQueryBuilder() .insert() .into('cost_surfaces') - .values(values) + .values(omit(costSurfaceData, ['origin_id'])) .execute(), ), ); diff --git a/api/libs/cloning/src/infrastructure/clone-piece-data/project-cost-surfaces.ts b/api/libs/cloning/src/infrastructure/clone-piece-data/project-cost-surfaces.ts index 445ebeed0b..9764c785b4 100644 --- a/api/libs/cloning/src/infrastructure/clone-piece-data/project-cost-surfaces.ts +++ b/api/libs/cloning/src/infrastructure/clone-piece-data/project-cost-surfaces.ts @@ -6,6 +6,16 @@ export type CostSurfaceData = { }; export type ProjectCostSurface = { + /** + * The stable_id of the cost surface in the original project is stored as part + * of the export, so that it can be used to port over as part of cloned + * projects any links between scenarios and cost surfaces (since the former + * are imported with a cost_surface_id matching the stable_id stored here, but + * the corresponding cost surfaces are created with a new unique id in the + * cloned project). + */ + id: string; + stable_id: string; name: string; min: number; max: number;