Add unfinished land use class,group,order impl

This commit is contained in:
Maciej Ziarkowski 2020-03-17 16:29:59 +00:00
parent bb30aa7098
commit 4bda0f0aa6
6 changed files with 153 additions and 8 deletions

4
app/package-lock.json generated
View File

@ -2410,7 +2410,7 @@
}, },
"babel-plugin-syntax-object-rest-spread": { "babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0", "version": "6.13.0",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
"dev": true "dev": true
}, },
@ -9729,7 +9729,7 @@
}, },
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"

View File

@ -1,6 +1,6 @@
import db from '../../db'; import db from '../../db';
export async function getLanduseGroupFromClass(classes: string[]): Promise<string[]> { export async function getLandUseGroupFromClass(classes: string[]): Promise<string[]> {
if (classes.length === 0) return []; if (classes.length === 0) return [];
return (await db.many( return (await db.many(

View File

@ -15,3 +15,10 @@ export class DatabaseError extends Error {
this.detail = detail; this.detail = detail;
} }
} }
export class DomainLogicError extends Error {
constructor(message?: string) {
super(message);
this.name = 'DomainLogicError';
}
}

View File

@ -0,0 +1,103 @@
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',
'Manufacturing': 'Industry And Business',
'Offices': 'Industry And Business'
};
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[]) => {
const orders = _.chain(groups).map(g => testGroupToOrder[g]).uniq().value();
let result: string;
if(orders.length == 0) result = null;
else if(orders.length == 1) result = orders[0];
else result = 'Mixed Use';
return Promise.resolve(result);
})
}));
describe('updateLandUse()', () => {
beforeEach(() => {
jest.resetAllMocks();
});
it.each([
[{
landUseClass: [],
landUseGroup: [],
landUseOrder: null
}, {
landUseClass: ['Animal breeding places']
}, {
landUseClass: ['Animal breeding places'],
landUseGroup: ['Agriculture'],
landUseOrder: 'Agriculture And Fisheries'
}],
[{
landUseClass: ['Animal breeding places'],
landUseGroup: ['Agriculture'],
landUseOrder: 'Agriculture And Fisheries'
}, {
landUseClass: ['Fish farm']
}, {
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']
}, {
landUseClass: ['Animal breeding places', 'Business meeting places'],
landUseGroup: ['Agriculture', 'Offices'],
landUseOrder: 'Mixed Use'
}]
])('Should derive higher level land use classifications from lower level ones',
async (landUse: LandUseState, landUseUpdate: Partial<LandUseState>, expectedUpdate: LandUseState) => {
const result = await updateLandUse(landUse, landUseUpdate);
expect(result).toBe(expectedUpdate);
}
);
it.each([
[{
landUseClass: ['Fish farm'],
landUseGroup: ['Fisheries'],
landUseOrder: 'Agriculture And Fisheries'
}, {
landUseGroup: []
}]
])('Should error when update breaks an automatic chain of classifications',
async (landUse: LandUseState, landUseUpdate: Partial<LandUseState>) => {
const resultPromise = updateLandUse(landUse, landUseUpdate);
expect(resultPromise).rejects.toBeInstanceOf(DomainLogicError);
}
);
});

View File

@ -1,9 +1,19 @@
import * as _ from 'lodash'; import _ from 'lodash';
import { isNullishOrEmpty } from '../../../helpers'; import { isNullishOrEmpty } from '../../../helpers';
import { getLanduseGroupFromClass, getLandUseOrderFromGroup } from '../../dataAccess/landUse'; import { getLandUseGroupFromClass, getLandUseOrderFromGroup } from '../../dataAccess/landUse';
import { getCurrentBuildingDataById } from '../building'; import { getCurrentBuildingDataById } from '../building';
export interface LandUseState {
landUseClass: string[];
landUseGroup: string[];
landUseOrder: string;
}
export async function updateLandUse(landUse: LandUseState, landUseUpdate: Partial<LandUseState>): Promise<LandUseState> {
throw new Error('Not implemented');
}
export async function processCurrentLandUseClassifications(buildingId: number, buildingUpdate: any): Promise<any> { export async function processCurrentLandUseClassifications(buildingId: number, buildingUpdate: any): Promise<any> {
let updateData = _.pick(await getCurrentBuildingDataById(buildingId), [ let updateData = _.pick(await getCurrentBuildingDataById(buildingId), [
'current_landuse_class', 'current_landuse_class',
@ -16,7 +26,7 @@ export async function processCurrentLandUseClassifications(buildingId: number, b
const updateFrom = getUpdateStartingStage(buildingUpdate); const updateFrom = getUpdateStartingStage(buildingUpdate);
if(updateFrom === 'class') { if(updateFrom === 'class') {
updateData.current_landuse_class = buildingUpdate.current_landuse_class; updateData.current_landuse_class = buildingUpdate.current_landuse_class;
updateData.current_landuse_group = await getLanduseGroupFromClass(updateData.current_landuse_class); updateData.current_landuse_group = await getLandUseGroupFromClass(updateData.current_landuse_class);
updateData.current_landuse_order = await getLandUseOrderFromGroup(updateData.current_landuse_group); updateData.current_landuse_order = await getLandUseOrderFromGroup(updateData.current_landuse_group);
} else if (updateFrom === 'group') { } else if (updateFrom === 'group') {
if (isNullishOrEmpty(updateData.current_landuse_class)) { if (isNullishOrEmpty(updateData.current_landuse_class)) {

View File

@ -1,6 +1,9 @@
import { hasAnyOwnProperty } from '../../../helpers'; import * as _ from 'lodash';
import { processCurrentLandUseClassifications } from './currentLandUseClassifications'; import { hasAnyOwnProperty } from '../../../helpers';
import { getCurrentBuildingDataById } from '../building';
import { updateLandUse } from './landUse';
export async function processBuildingUpdate(buildingId: number, buildingUpdate: any): Promise<any> { export async function processBuildingUpdate(buildingId: number, buildingUpdate: any): Promise<any> {
if(hasAnyOwnProperty(buildingUpdate, ['current_landuse_class', 'current_landuse_group', 'current_landuse_order'])) { if(hasAnyOwnProperty(buildingUpdate, ['current_landuse_class', 'current_landuse_group', 'current_landuse_order'])) {
@ -9,3 +12,25 @@ export async function processBuildingUpdate(buildingId: number, buildingUpdate:
return buildingUpdate; return buildingUpdate;
} }
async function processCurrentLandUseClassifications(buildingId: number, buildingUpdate: any): Promise<any> {
const currentBuildingData = await getCurrentBuildingDataById(buildingId);
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
}
);
return Object.assign({}, buildingUpdate, {
current_landuse_class: currentLandUseUpdate.landUseClass,
current_landuse_group: currentLandUseUpdate.landUseGroup,
current_landuse_order: currentLandUseUpdate.landUseOrder,
});
}