Skip to content

Commit

Permalink
WIP #36- Compute Diffs
Browse files Browse the repository at this point in the history
  • Loading branch information
umesh-timalsina committed Sep 9, 2022
1 parent 663a2fe commit a84d34e
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 21 deletions.
124 changes: 103 additions & 21 deletions src/common/JSONImporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,80 @@ define([

await this.apply(child, children[i], resolvedSelectors);
}

const current = await this.toJSON(node);
const changes = compare(current, state);
const sortedChanges = this._getSortedStateChanges(current, state);

for (let i = 0; i < sortedChanges.length; i++) {
if (sortedChanges[i].type === 'put') {
await this._put(node, sortedChanges[i], resolvedSelectors);
} else if (sortedChanges[i].type === 'del') {
await this._delete(node, sortedChanges[i], resolvedSelectors);
}
}

if (state.children) {
for (let i = currentChildren.length; i--;) {
this.core.deleteNode(currentChildren[i]);
}
}
}

getDiffs(prevState, newState) {
const rootPatch = new NodePatch(
new NodeSelector(prevState.id)
);
this._getDiffs(prevState, newState, rootPatch);
return rootPatch;
}

_getDiffs(prevState, newState, rootPatch) {
const children = newState.children || [];
const currentChildren = prevState.children || [];

const oldChildrenIds = new Set(currentChildren.map(currentChild => currentChild.id));
const newChildrenIds = new Set(children.map(child => child.id))
const [additions, updates] = partition(children, child => !oldChildrenIds.has(child.id));
const deletions = currentChildren.filter(currentChild => !newChildrenIds.has(currentChild.id));
rootPatch.children.push(
...additions.map(nodeState => {
return new NodePatch(
new NodeSelector(nodeState.id),
NODE_PATCH_TYPES.ADD,
[nodeState]
)
})
);

rootPatch.children.push(
...deletions.map(nodeState => {
return new NodePatch(
new NodeSelector(nodeState.id),
NODE_PATCH_TYPES.REMOVE,
[nodeState]
)
})
);

updates.forEach(updateState => {
const childPatch = new NodePatch(updateState.id, NODE_PATCH_TYPES.NO_CHANGE);
const oldState = currentChildren.find(currentChild => currentChild.id === updateState.id);
rootPatch.children.push(childPatch);
this.getDiffs(oldState, updateState, childPatch);
});

const sortedChanges = this._getSortedStateChanges(prevState, newState);

if(sortedChanges.length) {
rootPatch.type = NODE_PATCH_TYPES.UPDATES
rootPatch.patches = sortedChanges;
}
}

async patch(node, patch, resolvedSelectors=new NodeSelections()) {
// ToDo: Implement Patching
}

_getSortedStateChanges(prevState, newState) {
const keyOrder = [
'children_meta',
'pointer_meta',
Expand All @@ -195,12 +266,13 @@ define([
'member_attributes',
'member_registry',
];

const changes = compare(prevState, newState);
const singleKeyFields = ['children_meta', 'guid'];
const sortedChanges = changes
.filter(
change => change.key.length > 1 ||
(singleKeyFields.includes(change.key[0]) && change.type === 'put')
)
const sortedChanges = changes.filter(
change => change.key.length > 1 ||
(singleKeyFields.includes(change.key[0]) && change.type === 'put')
)
.map((change, index) => {
let order = 2 * keyOrder.indexOf(change.key[0]);
if (change.type === 'put') {
Expand All @@ -210,20 +282,7 @@ define([
})
.sort((p1, p2) => p1[0] - p2[0])
.map(pair => changes[pair[1]]);

for (let i = 0; i < sortedChanges.length; i++) {
if (sortedChanges[i].type === 'put') {
await this._put(node, sortedChanges[i], resolvedSelectors);
} else if (sortedChanges[i].type === 'del') {
await this._delete(node, sortedChanges[i], resolvedSelectors);
}
}

if (state.children) {
for (let i = currentChildren.length; i--;) {
this.core.deleteNode(currentChildren[i]);
}
}
return sortedChanges;
}

async resolveSelector(node, state, resolvedSelectors) {
Expand Down Expand Up @@ -732,6 +791,13 @@ define([
return object;
}

function partition(array, fn) {
return array.reduce((arr, next, index, records) => {
arr[fn(next, index, records) ? 0 : 1].push(next);
return arr;
}, [[], []]);
}

class NodeSelector {
constructor(idString='') {
if (idString.startsWith('/')) {
Expand Down Expand Up @@ -1006,6 +1072,22 @@ define([
}
}

const NODE_PATCH_TYPES = {
REMOVE: 'remove',
ADD: 'add',
UPDATES: 'updates',
NO_CHANGE: 'noChange'
};

class NodePatch {
constructor(selector, type=NODE_PATCH_TYPES.NO_CHANGE, patches=[], children=[]) {
this.selector = selector;
this.type = type;
this.patches = patches;
this.children = children;
}
}

const RELATED_PROPERTIES = {
sets: ['member_attributes', 'member_registry'],
children: ['children_meta'],
Expand Down
32 changes: 32 additions & 0 deletions test/assets/DiffStates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"putNewChildren": {
"prevState": {
"id": "@guid:12454",
"children": [
{
"id": "@guid:14523",
"attributes": {
"name": "guid-14523"
}
}
]
},
"newState": {
"id": "@guid:12454",
"children": [
{
"id": "@guid:14523",
"attributes": {
"name": "guid-14523"
}
},
{
"id": "@guid:14526",
"attributes": {
"name": "guid-14526"
}
}
]
}
}
}
24 changes: 24 additions & 0 deletions test/common/JSONImporter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ describe('JSONImporter', function () {
const assert = require('assert');
const gmeConfig = testFixture.getGmeConfig();
const path = testFixture.path;
const fs = require('fs');
const SEED_DIR = path.join(__dirname, '..', '..', 'src', 'seeds');
const ASSETS_DIR = path.join(__dirname, '..', 'assets');
const Q = testFixture.Q;
const logger = testFixture.logger.fork('JSONImporter');
const projectName = 'testProject';
Expand Down Expand Up @@ -1278,4 +1280,26 @@ describe('JSONImporter', function () {
}
});
});

describe.only('diff', function() {
let diffStates;
before(function () {
diffStates = JSON.parse(
fs.readFileSync(path.join(ASSETS_DIR, 'DiffStates.json'), 'utf-8')
);
});

it('should add single key children', () => {
const {prevState, newState} = diffStates.putNewChildren;
const diff = importer.getDiffs(prevState, newState);
console.log(JSON.stringify(diff));

});

it('should remove single key children', () => {
const {prevState, newState} = diffStates.putNewChildren;
const diff = importer.getDiffs(newState, prevState);
console.log(JSON.stringify(diff));
});
});
});

0 comments on commit a84d34e

Please sign in to comment.