diff --git a/app/src/api/config/dataFields.ts b/app/src/api/config/dataFields.ts index e7ce695a..9e805fbc 100644 --- a/app/src/api/config/dataFields.ts +++ b/app/src/api/config/dataFields.ts @@ -239,4 +239,10 @@ export const dataFieldsConfig = valueType()({ /* eslint-disable verify: false, }, + demolished_buildings: { + edit: true, + verify: false, + asJson: true, + sqlCast: 'jsonb', + }, }); diff --git a/app/src/api/config/fieldSchemaConfig.ts b/app/src/api/config/fieldSchemaConfig.ts index c042896f..ea530d51 100644 --- a/app/src/api/config/fieldSchemaConfig.ts +++ b/app/src/api/config/fieldSchemaConfig.ts @@ -3,5 +3,64 @@ import { SomeJSONSchema } from 'ajv/dist/types/json-schema'; import { dataFieldsConfig } from './dataFields'; export const fieldSchemaConfig: { [key in keyof typeof dataFieldsConfig]?: SomeJSONSchema} = { /*eslint-disable @typescript-eslint/camelcase */ + + demolished_buildings: { + type: 'array', + items: { + type: 'object', + required: ['year_constructed', 'year_demolished', 'overlap_present', 'links'], + properties: { + year_constructed: { + type: 'object', + required: ['min', 'max'], + additionalProperties: false, + properties: { + min: { + type: 'integer' + }, + max: { + type: 'integer' + } + } + }, + year_demolished: { + type: 'object', + required: ['min', 'max'], + additionalProperties: false, + properties: { + min: { + type: 'integer' + }, + max: { + type: 'integer' + } + } + }, + overlap_present: { + type: 'string', + enum: ['1%', '25%', '50%', '75%', '100%'] + }, + links: { + type: 'array', + items: { + type: 'string' + }, + minItems: 1 + } + }, + additionalProperties: false, + } + } as JSONSchemaType<{ + year_constructed: { + min: number; + max: number; + }; + year_demolished: { + min: number; + max: number; + } + overlap_present: string; + links: string[]; + }[]>, } as const; diff --git a/app/src/api/services/domainLogic/processBuildingUpdate.ts b/app/src/api/services/domainLogic/processBuildingUpdate.ts index 81e6b95a..bf85d0ac 100644 --- a/app/src/api/services/domainLogic/processBuildingUpdate.ts +++ b/app/src/api/services/domainLogic/processBuildingUpdate.ts @@ -6,6 +6,9 @@ import { ArgumentError } from '../../errors/general'; import { updateLandUse } from './landUse'; +/** + * Process land use classifications - derive land use order from land use groups + */ async function processCurrentLandUseClassifications(buildingId: number, buildingUpdate: any): Promise { const currentBuildingData = await getBuildingData(buildingId); @@ -31,10 +34,26 @@ async function processCurrentLandUseClassifications(buildingId: number, building } } + +/** + * Process Dynamics data - sort past buildings by construction date + */ +async function processDynamicsPastBuildings(buildingId: number, buildingUpdate: any): Promise { + buildingUpdate.demolished_buildings = buildingUpdate.demolished_buildings.sort((a, b) => b.year_constructed.min - a.year_constructed.min); + return buildingUpdate; +} + + +/** + * Define any custom processing logic for specific building attributes + */ export async function processBuildingUpdate(buildingId: number, buildingUpdate: any): Promise { if(hasAnyOwnProperty(buildingUpdate, ['current_landuse_group'])) { buildingUpdate = await processCurrentLandUseClassifications(buildingId, buildingUpdate); } + if('demolished_buildings' in buildingUpdate) { + buildingUpdate = await processDynamicsPastBuildings(buildingId, buildingUpdate); + } return buildingUpdate; } diff --git a/migrations/019.simple-dynamics.down.sql b/migrations/019.simple-dynamics.down.sql new file mode 100644 index 00000000..051a4931 --- /dev/null +++ b/migrations/019.simple-dynamics.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE buildings +DROP demolished_buildings; \ No newline at end of file diff --git a/migrations/019.simple-dynamics.up.sql b/migrations/019.simple-dynamics.up.sql new file mode 100644 index 00000000..01307579 --- /dev/null +++ b/migrations/019.simple-dynamics.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE buildings +ADD column demolished_buildings JSONB DEFAULT '[]'::JSONB; \ No newline at end of file