Skip to content

Commit

Permalink
(chore)properly link split features to features_data via stable ids […
Browse files Browse the repository at this point in the history
…MRXN23-543]
  • Loading branch information
hotzevzl committed Nov 29, 2024
1 parent 24b1501 commit 8f9f460
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 21 deletions.
60 changes: 48 additions & 12 deletions api/apps/api/src/modules/geo-features/geo-features.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,20 +513,31 @@ export class GeoFeaturesService extends AppBaseService<
geoFeature.id,
data.tagName,
);

const featureDataStableIds: string[] = [];
// Store geometries in features_data table
for (const featureData of featureDatas) {
await this.createFeatureData(
geoQueryRunner.manager,
geoFeature.id,
featureData.geometry,
featureData.properties,
featureDataStableIds.push(
await this.createFeatureData(
geoQueryRunner.manager,
geoFeature.id,
featureData.geometry,
featureData.properties,
),
);
}

await this.setFeatureDataStableIdsForFeature(
apiQueryRunner.manager,
geoFeature.id,
featureDataStableIds,
);

const computedFeatureAmounts =
await this.featureAmountsPerPlanningUnitService.computeMarxanAmountPerPlanningUnit(
geoFeature.id,
projectId,
featureDataStableIds,
geoQueryRunner.manager,
);

Expand Down Expand Up @@ -582,6 +593,25 @@ export class GeoFeaturesService extends AppBaseService<
return right(geoFeature);
}

private async setFeatureDataStableIdsForFeature(
apiEntityManager: EntityManager,
featureId: string,
featureDataStableIds: string[],
): Promise<void> {
this.logger.debug(
`Setting feature data stable ids for feature ${featureId}: ${featureDataStableIds}`,
);
const repo = apiEntityManager.getRepository(GeoFeature);
await repo.update(
{
id: featureId,
},
{
featureDataStableIds,
},
);
}

private async saveFeatureAmountPerPlanningUnit(
geoEntityManager: EntityManager,
projectId: string,
Expand Down Expand Up @@ -954,14 +984,20 @@ export class GeoFeaturesService extends AppBaseService<
featureId: string,
geometry: Geometry,
properties: Record<string, string | number>,
): Promise<void> {
await entityManager.query(
`INSERT INTO "features_data"
("id", "the_geom", "properties", "source", "feature_id")
VALUES (DEFAULT, ST_MakeValid(ST_GeomFromGeoJSON($1)::geometry), $2, $3,
$4);`,
[geometry, properties, GeometrySource.user_imported, featureId],
): Promise<string> {
const stableId = await entityManager
.query(
`INSERT INTO "features_data"
("id", "the_geom", "properties", "source", "feature_id")
VALUES (DEFAULT, ST_MakeValid(ST_GeomFromGeoJSON($1)::geometry), $2, $3,
$4) RETURNING stable_id;`,
[geometry, properties, GeometrySource.user_imported, featureId],
)
.then((result) => result[0].stable_id);
this.logger.debug(
`Created feature data with stable id ${stableId} for feature ${featureId} (properties: ${properties})`,
);
return stableId;
}

// TODO: this should be a 2 step process: We temporarily store the new features and their amounts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,20 @@ export class ComputeArea {
);

if (!alreadyComputed) {
const featureDataStableIds = await this.geoFeatureRepo
.findOne({
where: {
id: featureId,
projectId,
},
select: ['featureDataStableIds'],
})
.then((result) => result?.featureDataStableIds);
const amountPerPlanningUnitOfFeature =
await this.featureAmountsPerPlanningUnit.computeMarxanAmountPerPlanningUnit(
featureId,
projectId,
featureDataStableIds || [],
);

await this.featureAmountsPerPlanningUnitRepo.saveAmountPerPlanningUnitAndFeature(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { JobStatus } from '@marxan-api/modules/scenarios/scenario.api.entity';
import { SplitFeatureConfigMapper } from '@marxan-api/modules/scenarios/specification/split-feature-config.mapper';
import { FeatureConfigSplit } from '@marxan-api/modules/specification';
import { isDefined } from '@marxan/utils';
import { Injectable } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { v4 } from 'uuid';
Expand Down Expand Up @@ -67,6 +67,23 @@ export class SplitCreateFeatures {
return featuresAlreadyExisting.concat(newFeaturesCreated);
}

async setFeatureDataStableIdsForFeature(
featureId: string,
featureDataStableIds: any[],
): Promise<void> {
Logger.debug(
`Setting feature data stable ids for feature ${featureId}: ${JSON.stringify(
featureDataStableIds.map((i) => i.stable_id),
)}`,
);
await this.featuresRepo.update(
{ id: featureId },
{
featureDataStableIds: featureDataStableIds.map((i) => i.stable_id),
},
);
}

private async isBaseFeatureADerivedFeature(input: FeatureConfigSplit) {
const baseFeature = await this.getBaseFeature(input.baseFeatureId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,25 @@ export class SplitOperation {
protectedAreaFilterByIds,
project,
);
const ids: { id: string }[] = await this.geoEntityManager.query(
query,
parameters,
const scenarioFeaturePreparationIdsForFeature: {
id: string;
features_data_id: string;
}[] = await this.geoEntityManager.query(query, parameters);
scenarioFeaturePreparationIds.push(
...scenarioFeaturePreparationIdsForFeature,
);
const featureDataStableIds = await this.geoEntityManager.query(
'select stable_id from features_data where id = any($1)',
[
scenarioFeaturePreparationIdsForFeature.map(
(i) => i.features_data_id,
),
],
);
await this.splitCreateFeatures.setFeatureDataStableIdsForFeature(
singleSplitFeatureWithId.id,
featureDataStableIds,
);
scenarioFeaturePreparationIds.push(...ids);
}

await this.computeAmountPerFeature(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class SplitQuery {
or st_intersects(ST_MakeEnvelope(${fields.eastBbox
.map((coordinate) => coordinate)
.join(',')}, 4326), fd.the_geom)
returning sfp.id as id;
returning sfp.id as id, sfp.feature_class_id as features_data_id;
`;
return { parameters, query };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class FeatureAmountsPerPlanningUnitService {
public async computeMarxanAmountPerPlanningUnit(
featureId: string,
projectId: string,
featureDataStableIds: string[],
geoEntityManager: EntityManager = this.geoEntityManager,
): Promise<ComputeFeatureAmountPerPlanningUnit[]> {
/**
Expand All @@ -67,7 +68,7 @@ export class FeatureAmountsPerPlanningUnitService {
(
select st_union(the_geom) as the_geom
from features_data fd
where fd.feature_id = $2
where fd.stable_id = ANY($3)
group by fd.feature_id
) species,
(
Expand All @@ -81,7 +82,7 @@ export class FeatureAmountsPerPlanningUnitService {
)
select * from all_amount_per_planning_unit where amount > 0 order by puid;
`,
[projectId, featureId],
[projectId, featureId, featureDataStableIds],
);

return rows.map(({ featureid, projectpuid, puid, amount }) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ So this needs to be changed to:
Piece exporters and importers will need to:

- export and import the new `(geodb)features_data.stable_id` column
- export and import the new `(apidb)feature_data_stable_ids` column
- export and import the new `(apidb)features.feature_data_stable_ids` column

## Updating queries for tiles of features

Expand Down

0 comments on commit 8f9f460

Please sign in to comment.