Skip to content

Commit

Permalink
Fallback to intersection when no adminregion found by district name
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeh committed Feb 27, 2024
1 parent 1bbe26d commit 5d6adb0
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 2 deletions.
79 changes: 79 additions & 0 deletions api/src/modules/import-data/eudr/eudr.dto-processor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { GeoRegion } from 'modules/geo-regions/geo-region.entity';
// @ts-ignore
import * as wellknown from 'wellknown';
import { DataSource, QueryRunner, Repository } from 'typeorm';
import { GeoCodingError } from 'modules/geo-coding/errors/geo-coding.error';
import { AdminRegion } from 'modules/admin-regions/admin-region.entity';

/**
* @debt: Define a more accurate DTO / Interface / Class for API-DB trades
Expand Down Expand Up @@ -87,6 +89,7 @@ export class EUDRDTOProcessor {
geoRegion.totalArea = row.total_area_ha;
geoRegion.theGeom = wellknown.parse(row.geometry) as unknown as JSON;
geoRegion.isCreatedByUser = true;
geoRegion.name = row.plot_name;
const foundGeoRegion: GeoRegion | null =
await geoRegionRepository.findOne({
where: { name: geoRegion.name },
Expand All @@ -108,6 +111,13 @@ export class EUDRDTOProcessor {
sourcingLocation.producer = savedSupplier;
sourcingLocation.geoRegion = savedGeoRegion;
sourcingLocation.sourcingRecords = [];
sourcingLocation.adminRegionId = row.sourcing_district
? await this.getAdminRegionByAddress(
queryRunner,
row.sourcing_district,
row.geometry,
)
: (null as unknown as string);

for (const key in row) {
const sourcingRecord: SourcingRecord = new SourcingRecord();
Expand All @@ -126,6 +136,8 @@ export class EUDRDTOProcessor {
const saved: SourcingLocation[] = await queryRunner.manager
.getRepository(SourcingLocation)
.save(sourcingLocations);

await queryRunner.commitTransaction();
return {
sourcingLocations: saved,
};
Expand All @@ -137,6 +149,73 @@ export class EUDRDTOProcessor {
}
}

private async getAdminRegionByAddress(
queryRunner: QueryRunner,
name: string,
geom: string,
): Promise<string> {
const adminRegion: AdminRegion | null = await queryRunner.manager
.getRepository(AdminRegion)
.findOne({ where: { name: name, level: 1 } });
if (!adminRegion) {
this.logger.warn(
`No admin region found for the provided address: ${name}`,
);
return this.getAdminRegionByIntersection(queryRunner, geom);
}
return adminRegion.id;
}

// TODO: temporal method to determine the most accurate admin region. For now we only consider Level 0
// as Country and Level 1 as district

private async getAdminRegionByIntersection(
queryRunner: QueryRunner,
geometry: string,
): Promise<string> {
this.logger.log(`Intersecting EUDR geometry...`);

const adminRegions: any = await queryRunner.manager.query(
`
WITH intersections AS (
SELECT
ar.id,
ar.name,
ar."geoRegionId",
gr."theGeom",
ar.level,
ST_Area(ST_Intersection(gr."theGeom", ST_GeomFromEWKT('SRID=4326;${geometry}'))) AS intersection_area
FROM admin_region ar
JOIN geo_region gr ON ar."geoRegionId" = gr.id
WHERE
ST_Intersects(gr."theGeom", ST_GeomFromEWKT('SRID=4326;${geometry}'))
AND ar.level IN (0, 1)
),
max_intersection_by_level AS (
SELECT
level,
MAX(intersection_area) AS max_area
FROM intersections
GROUP BY level
)
SELECT i.*
FROM intersections i
JOIN max_intersection_by_level m ON i.level = m.level AND i.intersection_area = m.max_area;
`,
);
if (!adminRegions.length) {
throw new GeoCodingError(
`No admin region found for the provided geometry`,
);
}

const level1AdminRegionid: string = adminRegions.find(
(ar: any) => ar.level === 1,
).id;
this.logger.log('Admin region found');
return level1AdminRegionid;
}

private async validateCleanData(nonEmptyData: SourcingData[]): Promise<void> {
const excelErrors: {
line: number;
Expand Down
7 changes: 5 additions & 2 deletions api/src/modules/import-data/eudr/eudr.import.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ export class EudrImportService {

await this.cleanDataBeforeImport();

// TODO: Check what do we need to do with indicators and specially materials:
// Do we need to ingest new materials? Activate some through the import? Activate all?

const { sourcingLocations } = await this.dtoProcessor.save(
parsedEudrData.Data,
);
Expand Down Expand Up @@ -123,9 +126,9 @@ export class EudrImportService {
await this.sourcingLocationService.clearTable();
await this.sourcingRecordService.clearTable();
await this.geoRegionsService.deleteGeoRegionsCreatedByUser();
} catch ({ message }) {
} catch (e: any) {
throw new Error(
`Database could not been cleaned before loading new dataset: ${message}`,
`Database could not been cleaned before loading new dataset: ${e.message}`,
);
}
}
Expand Down

0 comments on commit 5d6adb0

Please sign in to comment.