Use simpler shallow compare, drop fast-json-patch

This commit is contained in:
Tom Russell 2018-09-30 18:58:41 +01:00
parent b6ef15949e
commit 1b191a1466
3 changed files with 56 additions and 18 deletions

8
app/package-lock.json generated
View File

@ -4366,14 +4366,6 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
}, },
"fast-json-patch": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.0.7.tgz",
"integrity": "sha512-DQeoEyPYxdTtfmB3yDlxkLyKTdbJ6ABfFGcMynDqjvGhPYLto/pZyb/dG2Nyd/n9CArjEWN9ZST++AFmgzgbGw==",
"requires": {
"deep-equal": "^1.0.1"
}
},
"fast-json-stable-stringify": { "fast-json-stable-stringify": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",

View File

@ -17,7 +17,6 @@
"connect-pg-simple": "^5.0.0", "connect-pg-simple": "^5.0.0",
"express": "^4.16.3", "express": "^4.16.3",
"express-session": "^1.15.6", "express-session": "^1.15.6",
"fast-json-patch": "^2.0.7",
"leaflet": "^1.3.4", "leaflet": "^1.3.4",
"mapnik": "^4.0.1", "mapnik": "^4.0.1",
"pg-promise": "^8.4.6", "pg-promise": "^8.4.6",

View File

@ -1,5 +1,3 @@
import { compare, deepClone } from 'fast-json-patch'
import db from './db'; import db from './db';
// data type note: PostgreSQL bigint (64-bit) is handled as string in JavaScript, because of // data type note: PostgreSQL bigint (64-bit) is handled as string in JavaScript, because of
// JavaScript numerics are 64-bit double, giving only partial coverage. // JavaScript numerics are 64-bit double, giving only partial coverage.
@ -25,6 +23,7 @@ function queryBuildingsAtPoint(lng, lat) {
return undefined; return undefined;
}); });
} }
function queryBuildingsByReference(key, id) { function queryBuildingsByReference(key, id) {
if (key === 'toid'){ if (key === 'toid'){
return db.manyOrNone( return db.manyOrNone(
@ -85,11 +84,9 @@ function saveBuilding(building_id, building, user_id) {
"SELECT * FOR UPDATE FROM buildings WHERE building_id = $1 and revision_id = $2;", "SELECT * FOR UPDATE FROM buildings WHERE building_id = $1 and revision_id = $2;",
[building_id, previous_revision_id] [building_id, previous_revision_id]
).then(old_building => { ).then(old_building => {
// full new building (possibly a subset of keys were sent as building) const patches = compare(old_building, building, BUILDING_FIELD_WHITELIST);
const new_building = Object.assign(deepClone(old_building), building); const forward = patches[0];
// uses JSON Patch (see RFC6902) to identify forward- and reverse- changesets const reverse = patches[1];
const patch = compare(old_building, new_building);
const reverse = compare(new_building, old_building);
return t.one( return t.one(
`INSERT INTO logs ( `INSERT INTO logs (
forward_patch, reverse_patch, building_id, user_id forward_patch, reverse_patch, building_id, user_id
@ -97,9 +94,9 @@ function saveBuilding(building_id, building, user_id) {
$1:jsonb, $2:jsonb, $3, $4 $1:jsonb, $2:jsonb, $3, $4
) RETURNING log_id ) RETURNING log_id
`, `,
[patch, reverse, building_id, user_id] [forward, reverse, building_id, user_id]
).then(revision => { ).then(revision => {
const sets = db.$config.pgp.helpers.sets(building); const sets = db.$config.pgp.helpers.sets(forward);
return t.one( return t.one(
`UPDATE `UPDATE
buildings buildings
@ -122,4 +119,54 @@ function saveBuilding(building_id, building, user_id) {
}); });
} }
const BUILDING_FIELD_WHITELIST = new Set([
'ref_toid',
'ref_osm_id',
'location_name',
'location_number',
'location_street',
'location_line_two',
'location_town',
'location_postcode',
'location_latitude',
'location_longitude',
'date_year',
'date_lower',
'date_upper',
'date_source',
'facade_year',
'facade_upper',
'facade_lower',
'facade_source',
'size_storeys_attic',
'size_storeys_core',
'size_storeys_basement',
'size_height_apex',
'size_floor_area_ground',
'size_floor_area_total',
'size_width_frontage',
]);
/**
* Compare old and new data objects, generate shallow merge patch of changed fields
* - forward patch is object with {keys: new_values}
* - reverse patch is object with {keys: old_values}
*
* @param {object} old_obj
* @param {object} new_obj
* @param {Set} whitelist
* @returns {[object, object]}
*/
function compare(old_obj, new_obj, whitelist){
reverse_patch = {}
forward_patch = {}
for (const [key, value] of Object.entries(new_obj)) {
if (old_obj[key] !== value && whitelist.has(key)) {
reverse_patch[key] = old_obj[key];
forward_patch[key] = value;
}
}
return [forward_patch, reverse_patch]
}
export { queryBuildingsAtPoint, queryBuildingsByReference, getBuildingById, saveBuilding }; export { queryBuildingsAtPoint, queryBuildingsByReference, getBuildingById, saveBuilding };