diff --git a/app/src/api/services/__tests__/domainLogic/landUse.test.ts b/app/src/api/services/__tests__/domainLogic/landUse.test.ts index 6a01ca3d..00793647 100644 --- a/app/src/api/services/__tests__/domainLogic/landUse.test.ts +++ b/app/src/api/services/__tests__/domainLogic/landUse.test.ts @@ -1,15 +1,7 @@ import * as _ from 'lodash'; -import { DomainLogicError } from '../../../errors/general'; import { LandUseState, updateLandUse } from '../../domainLogic/landUse'; -const testClassToGroup = { - 'Animal breeding places': 'Agriculture', - 'Egg grading place': 'Agriculture', - 'Fish farm': 'Fisheries', - 'Brewery': 'Manufacturing', - 'Business meeting places': 'Offices' -}; const testGroupToOrder = { 'Agriculture': 'Agriculture And Fisheries', 'Fisheries': 'Agriculture And Fisheries', @@ -18,12 +10,7 @@ const testGroupToOrder = { }; jest.mock('../../../dataAccess/landUse', () => ({ - getLandUseGroupFromClass: jest.fn((classes: string[]) => { - const groups = _.chain(classes).map(c => testClassToGroup[c]).uniq().value(); - - return Promise.resolve(groups); - }), - getLandUseOrderGromGroup: jest.fn((groups: string[]) => { + getLandUseOrderFromGroup: jest.fn((groups: string[]) => { const orders = _.chain(groups).map(g => testGroupToOrder[g]).uniq().value(); let result: string; @@ -38,66 +25,73 @@ jest.mock('../../../dataAccess/landUse', () => ({ describe('updateLandUse()', () => { beforeEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); }); it.each([ [{ - landUseClass: [], landUseGroup: [], landUseOrder: null }, { - landUseClass: ['Animal breeding places'] + landUseGroup: ['Agriculture'] }, { - landUseClass: ['Animal breeding places'], landUseGroup: ['Agriculture'], landUseOrder: 'Agriculture And Fisheries' }], [{ - landUseClass: ['Animal breeding places'], landUseGroup: ['Agriculture'], landUseOrder: 'Agriculture And Fisheries' }, { - landUseClass: ['Fish farm'] + landUseGroup: ['Fisheries'] }, { - landUseClass: ['Fish farm'], landUseGroup: ['Fisheries'], landUseOrder: 'Agriculture And Fisheries' }], [{ - landUseClass: ['Animal breeding places'], landUseGroup: ['Agriculture'], landUseOrder: 'Agriculture And Fisheries' }, { - landUseClass: ['Animal breeding places', 'Business meeting places'] + landUseGroup: ['Agriculture', 'Offices'], }, { - landUseClass: ['Animal breeding places', 'Business meeting places'], landUseGroup: ['Agriculture', 'Offices'], landUseOrder: 'Mixed Use' }] - ])('Should derive higher level land use classifications from lower level ones', + ])('Should derive land use order from group', async (landUse: LandUseState, landUseUpdate: Partial, expectedUpdate: LandUseState) => { const result = await updateLandUse(landUse, landUseUpdate); - expect(result).toBe(expectedUpdate); + expect(result).toEqual(expectedUpdate); } ); it.each([ [{ - landUseClass: ['Fish farm'], - landUseGroup: ['Fisheries'], + landUseGroup: ['Agriculture'], landUseOrder: 'Agriculture And Fisheries' }, { landUseGroup: [] - }] - ])('Should error when update breaks an automatic chain of classifications', - async (landUse: LandUseState, landUseUpdate: Partial) => { - const resultPromise = updateLandUse(landUse, landUseUpdate); + }, { + landUseGroup: [], + landUseOrder: null + }], - expect(resultPromise).rejects.toBeInstanceOf(DomainLogicError); + [{ + landUseGroup: ['Agriculture', 'Offices'], + landUseOrder: 'Mixed Use', + }, { + landUseGroup: ['Agriculture'], + }, { + landUseGroup: ['Agriculture'], + landUseOrder: 'Agriculture And Fisheries' + }] + ])('Should remove derived land use order when land use group is removed', + async (landUse: LandUseState, landUseUpdate: Partial, expectedUpdate: LandUseState) => { + const result = await updateLandUse(landUse, landUseUpdate); + + expect(result).toEqual(expectedUpdate); } ); + }); diff --git a/app/src/api/services/domainLogic/landUse.ts b/app/src/api/services/domainLogic/landUse.ts index 56bffbeb..b4b0f4b9 100644 --- a/app/src/api/services/domainLogic/landUse.ts +++ b/app/src/api/services/domainLogic/landUse.ts @@ -1,75 +1,18 @@ import _ from 'lodash'; -import { isNullishOrEmpty } from '../../../helpers'; -import { getLandUseGroupFromClass, getLandUseOrderFromGroup } from '../../dataAccess/landUse'; -import { getCurrentBuildingDataById } from '../building'; +import { getLandUseOrderFromGroup } from '../../dataAccess/landUse'; export interface LandUseState { - landUseClass: string[]; landUseGroup: string[]; landUseOrder: string; } export async function updateLandUse(landUse: LandUseState, landUseUpdate: Partial): Promise { - throw new Error('Not implemented'); -} + const landUseGroupUpdate = landUseUpdate.landUseGroup; + const landUseOrderUpdate = await getLandUseOrderFromGroup(landUseGroupUpdate); -export async function processCurrentLandUseClassifications(buildingId: number, buildingUpdate: any): Promise { - let updateData = _.pick(await getCurrentBuildingDataById(buildingId), [ - 'current_landuse_class', - 'current_landuse_group', - 'current_landuse_order' - ]); - - updateData = Object.assign({}, updateData, getClearValues(buildingUpdate)); - - const updateFrom = getUpdateStartingStage(buildingUpdate); - if(updateFrom === 'class') { - updateData.current_landuse_class = buildingUpdate.current_landuse_class; - updateData.current_landuse_group = await getLandUseGroupFromClass(updateData.current_landuse_class); - updateData.current_landuse_order = await getLandUseOrderFromGroup(updateData.current_landuse_group); - } else if (updateFrom === 'group') { - if (isNullishOrEmpty(updateData.current_landuse_class)) { - updateData.current_landuse_group = buildingUpdate.current_landuse_group; - updateData.current_landuse_order = await getLandUseOrderFromGroup(buildingUpdate.current_landuse_group); - } else { - throw new Error('Trying to update current_landuse_group field but a more detailed field (current_landuse_class) is already filled'); - } - } else if (updateFrom === 'order') { - if (isNullishOrEmpty(updateData.current_landuse_class) && isNullishOrEmpty(updateData.current_landuse_group)) { - updateData.current_landuse_order = buildingUpdate.current_landuse_order; - } else { - throw new Error('Trying to update current_landuse_order field but a more detailed field (current_landuse_class or current_landuse_group) is already filled'); - } - } - - return Object.assign({}, buildingUpdate, updateData); -} - -function getClearValues(building) { - const clearValues: any = {}; - if(building.hasOwnProperty('current_landuse_class') && isNullishOrEmpty(building.current_landuse_class)) { - clearValues.current_landuse_class = []; - } - if(building.hasOwnProperty('current_landuse_group') && isNullishOrEmpty(building.current_landuse_group)) { - clearValues.current_landuse_group = []; - } - if(building.hasOwnProperty('current_landuse_order') && isNullishOrEmpty(building.current_landuse_order)) { - clearValues.current_landuse_order = null; - } - - return clearValues; -} -/** - * Choose which level of the land use classification hierarchy the update should start from. - * @param building - */ -function getUpdateStartingStage(building) { - if(building.hasOwnProperty('current_landuse_class') && !isNullishOrEmpty(building.current_landuse_class)) { - return 'class'; - } else if(building.hasOwnProperty('current_landuse_group') && !isNullishOrEmpty(building.current_landuse_group)) { - return 'group'; - } else if(building.hasOwnProperty('current_landuse_order') && !isNullishOrEmpty(building.current_landuse_order)) { - return 'order'; - } else return 'none'; + return { + landUseGroup: landUseGroupUpdate, + landUseOrder: landUseOrderUpdate + }; } diff --git a/app/src/api/services/domainLogic/processBuildingUpdate.ts b/app/src/api/services/domainLogic/processBuildingUpdate.ts index 640b2a16..46f5f7c7 100644 --- a/app/src/api/services/domainLogic/processBuildingUpdate.ts +++ b/app/src/api/services/domainLogic/processBuildingUpdate.ts @@ -6,7 +6,7 @@ import { getCurrentBuildingDataById } from '../building'; import { updateLandUse } from './landUse'; export async function processBuildingUpdate(buildingId: number, buildingUpdate: any): Promise { - if(hasAnyOwnProperty(buildingUpdate, ['current_landuse_class', 'current_landuse_group', 'current_landuse_order'])) { + if(hasAnyOwnProperty(buildingUpdate, ['current_landuse_group'])) { buildingUpdate = await processCurrentLandUseClassifications(buildingId, buildingUpdate); } @@ -18,18 +18,14 @@ async function processCurrentLandUseClassifications(buildingId: number, building const currentLandUseUpdate = await updateLandUse( { - landUseClass: currentBuildingData.current_landuse_class, landUseGroup: currentBuildingData.current_landuse_group, landUseOrder: currentBuildingData.current_landuse_order }, { - landUseClass: buildingUpdate.current_landuse_class, - landUseGroup: buildingUpdate.current_landuse_group, - landUseOrder: buildingUpdate.current_landuse_order + landUseGroup: buildingUpdate.current_landuse_group } ); return Object.assign({}, buildingUpdate, { - current_landuse_class: currentLandUseUpdate.landUseClass, current_landuse_group: currentLandUseUpdate.landUseGroup, current_landuse_order: currentLandUseUpdate.landUseOrder, });