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

MARXAN-1684-cleanup-features-data #1179

Merged
merged 2 commits into from
Jul 15, 2022
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
@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class CreateFeaturesDataCleanupPreparation1657795596079
implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE features_data_cleanup_preparation (
feature_id uuid PRIMARY KEY
);`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
DROP TABLE features_data_cleanup_preparation;
`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class CleanupTasksService implements CleanupTasks {
constructor(
@InjectEntityManager(geoprocessingConnections.apiDB)
private readonly apiEntityManager: EntityManager,
@InjectEntityManager(geoprocessingConnections.apiDB)
@InjectEntityManager(geoprocessingConnections.default)
private readonly geoEntityManager: EntityManager,
) {}

Expand All @@ -36,7 +36,7 @@ export class CleanupTasksService implements CleanupTasks {
// Start cleaning up process inside transaction
await this.geoEntityManager.transaction(async (entityManager) => {
// Truncate table to be sure that not any projectId is inside before operation
await this.geoEntityManager.query(
await entityManager.query(
`TRUNCATE TABLE project_geodata_cleanup_preparation;`,
);

Expand All @@ -55,21 +55,21 @@ export class CleanupTasksService implements CleanupTasks {

// For every related entity, we look for non-matching ids inside entity table
// and compare it with intermediate projectId table to delete records that are not there
await this.geoEntityManager.query(
await entityManager.query(
`DELETE FROM planning_areas pa
WHERE pa.project_id IS NOT NULL
AND pa.project_id NOT IN (
SELECT pgcp.project_id FROM project_geodata_cleanup_preparation pgcp
);`,
);
await this.geoEntityManager.query(
await entityManager.query(
`DELETE FROM wdpa
WHERE wdpa.project_id IS NOT NULL
AND wdpa.project_id NOT IN (
SELECT pgcp.project_id FROM project_geodata_cleanup_preparation pgcp
);`,
);
await this.geoEntityManager.query(
await entityManager.query(
`DELETE FROM projects_pu ppu
WHERE ppu.project_id IS NOT NULL
AND ppu.project_id NOT IN (
Expand All @@ -84,7 +84,7 @@ export class CleanupTasksService implements CleanupTasks {
);`,
);

await this.geoEntityManager.query(
await entityManager.query(
`TRUNCATE TABLE project_geodata_cleanup_preparation;`,
);
});
Expand All @@ -102,7 +102,7 @@ export class CleanupTasksService implements CleanupTasks {
});

await this.geoEntityManager.transaction(async (entityManager) => {
await this.geoEntityManager.query(
await entityManager.query(
`TRUNCATE TABLE scenario_geodata_cleanup_preparation;`,
);

Expand All @@ -118,48 +118,89 @@ export class CleanupTasksService implements CleanupTasks {
);
}

await this.geoEntityManager.query(
await entityManager.query(
`DELETE FROM scenario_features_data sfd
WHERE sfd.scenario_id IS NOT NULL
AND sfd.scenario_id NOT IN (
SELECT sgcp.scenario_id FROM scenario_geodata_cleanup_preparation sgcp
);`,
);
await this.geoEntityManager.query(
await entityManager.query(
`DELETE FROM blm_final_results bfr
WHERE bfr.scenario_id IS NOT NULL
AND bfr.scenario_id NOT IN (
SELECT sgcp.scenario_id FROM scenario_geodata_cleanup_preparation sgcp
);`,
);
await this.geoEntityManager.query(
await entityManager.query(
`DELETE FROM blm_partial_results bpr
WHERE bpr.scenario_id IS NOT NULL
AND bpr.scenario_id NOT IN (
SELECT sgcp.scenario_id FROM scenario_geodata_cleanup_preparation sgcp
);`,
);
await this.geoEntityManager.query(
await entityManager.query(
`DELETE FROM marxan_execution_metadata mem
WHERE mem.scenarioId IS NOT NULL
AND mem.scenarioId NOT IN (
SELECT sgcp.scenario_id FROM scenario_geodata_cleanup_preparation sgcp
);`,
);
await this.geoEntityManager.query(
await entityManager.query(
`DELETE FROM scenarios_pu_data spd
WHERE spd.scenario_id IS NOT NULL
AND spd.scenario_id NOT IN (
SELECT sgcp.scenario_id FROM scenario_geodata_cleanup_preparation sgcp
);`,
);

await this.geoEntityManager.query(
await entityManager.query(
`TRUNCATE TABLE scenario_geodata_cleanup_preparation;`,
);
});
}

async cleanupFeaturesDanglingData() {
const featureIds = await this.apiEntityManager
.createQueryBuilder()
.from('features', 'f')
.select(['id'])
.getRawMany()
.then((result) => result.map((i) => i.id))
.catch((error) => {
throw new Error(error);
});

await this.geoEntityManager.transaction(async (entityManager) => {
await entityManager.query(
`TRUNCATE TABLE features_data_cleanup_preparation;`,
);

for (const [, summaryChunks] of chunk(
featureIds,
CHUNK_SIZE_FOR_BATCH_DB_OPERATIONS,
).entries()) {
await entityManager.insert(
'features_data_cleanup_preparation',
summaryChunks.map((chunk: string) => ({
id: chunk,
})),
);
}

await entityManager.query(
`DELETE FROM features_data fa
WHERE fa.feature_id NOT IN (
SELECT fdcp.id FROM features_data_cleanup_preparation fdcp
);`,
);

await entityManager.query(
`TRUNCATE TABLE features_data_cleanup_preparation;`,
);
});
}

@Cron(cronJobInterval)
async handleCron() {
this.logger.debug(
Expand All @@ -168,5 +209,6 @@ export class CleanupTasksService implements CleanupTasks {

await this.cleanupProjectsDanglingData();
await this.cleanupScenariosDanglingData();
await this.cleanupFeaturesDanglingData();
}
}