take local value when merging with conflicts

This commit is contained in:
Sandeep Somavarapu 2020-11-18 17:11:56 +01:00
parent 8f1f1fda1b
commit f4b9edc587
2 changed files with 43 additions and 53 deletions

View file

@ -30,6 +30,25 @@ export function merge(localStorage: IStringDictionary<IStorageValue>, remoteStor
const local: { added: IStringDictionary<IStorageValue>, removed: string[], updated: IStringDictionary<IStorageValue> } = { added: {}, removed: [], updated: {} };
const remote: IStringDictionary<IStorageValue> = objects.deepClone(remoteStorage);
// Added in local
for (const key of baseToLocal.added.values()) {
remote[key] = localStorage[key];
}
// Updated in local
for (const key of baseToLocal.updated.values()) {
remote[key] = localStorage[key];
}
// Removed in local
for (const key of baseToLocal.removed.values()) {
// Do not remove from remote if key is not registered.
if (storageKeys.unregistered.includes(key)) {
continue;
}
delete remote[key];
}
// Added in remote
for (const key of baseToRemote.added.values()) {
const remoteValue = remoteStorage[key];
@ -37,15 +56,11 @@ export function merge(localStorage: IStringDictionary<IStorageValue>, remoteStor
logService.info(`GlobalState: Skipped adding ${key} in local storage because it is declared as machine scoped.`);
continue;
}
const localValue = localStorage[key];
if (localValue && localValue.value === remoteValue.value) {
// Skip if the value is also added in local
if (baseToLocal.added.has(key)) {
continue;
}
if (localValue) {
local.updated[key] = remoteValue;
} else {
local.added[key] = remoteValue;
}
local.added[key] = remoteValue;
}
// Updated in Remote
@ -55,15 +70,15 @@ export function merge(localStorage: IStringDictionary<IStorageValue>, remoteStor
logService.info(`GlobalState: Skipped updating ${key} in local storage because it is declared as machine scoped.`);
continue;
}
// Skip if the value is also updated or removed in local
if (baseToLocal.updated.has(key) || baseToLocal.removed.has(key)) {
continue;
}
const localValue = localStorage[key];
if (localValue && localValue.value === remoteValue.value) {
continue;
}
if (localValue) {
local.updated[key] = remoteValue;
} else {
local.added[key] = remoteValue;
}
local.updated[key] = remoteValue;
}
// Removed in remote
@ -72,38 +87,13 @@ export function merge(localStorage: IStringDictionary<IStorageValue>, remoteStor
logService.trace(`GlobalState: Skipped removing ${key} in local storage because it is declared as machine scoped.`);
continue;
}
// Skip if the value is also updated or removed in local
if (baseToLocal.updated.has(key) || baseToLocal.removed.has(key)) {
continue;
}
local.removed.push(key);
}
// Added in local
for (const key of baseToLocal.added.values()) {
if (baseToRemote.added.has(key)) {
continue;
}
remote[key] = localStorage[key];
}
// Updated in local
for (const key of baseToLocal.updated.values()) {
if (baseToRemote.updated.has(key) || baseToRemote.removed.has(key)) {
continue;
}
remote[key] = localStorage[key];
}
// Removed in local
for (const key of baseToLocal.removed.values()) {
// Do not remove from remote if key not registered.
if (storageKeys.unregistered.includes(key)) {
continue;
}
// do not remove from remote if it is updated in remote
if (baseToRemote.updated.has(key)) {
continue;
}
delete remote[key];
}
return { local, remote: areSame(remote, remoteStorage) ? null : remote };
}

View file

@ -209,9 +209,9 @@ suite('GlobalStateMerge', () => {
const actual = merge(local, remote, null, { machine: [], unregistered: [] }, new NullLogService());
assert.deepEqual(actual.local.added, {});
assert.deepEqual(actual.local.updated, { 'a': { version: 1, value: 'b' } });
assert.deepEqual(actual.local.updated, {});
assert.deepEqual(actual.local.removed, []);
assert.deepEqual(actual.remote, null);
assert.deepEqual(actual.remote, local);
});
test('merge when the entry is removed in remote but updated in local and a new entry is added in remote', async () => {
@ -223,8 +223,8 @@ suite('GlobalStateMerge', () => {
assert.deepEqual(actual.local.added, { 'c': { version: 1, value: 'c' } });
assert.deepEqual(actual.local.updated, {});
assert.deepEqual(actual.local.removed, ['b']);
assert.deepEqual(actual.remote, null);
assert.deepEqual(actual.local.removed, []);
assert.deepEqual(actual.remote, { 'a': { version: 1, value: 'a' }, 'c': { version: 1, value: 'c' }, 'b': { version: 1, value: 'd' } });
});
test('merge with single entry and local is empty', async () => {
@ -234,13 +234,13 @@ suite('GlobalStateMerge', () => {
const actual = merge(local, remote, base, { machine: [], unregistered: [] }, new NullLogService());
assert.deepEqual(actual.local.added, { 'a': { version: 1, value: 'b' } });
assert.deepEqual(actual.local.added, {});
assert.deepEqual(actual.local.updated, {});
assert.deepEqual(actual.local.removed, []);
assert.deepEqual(actual.remote, null);
assert.deepEqual(actual.remote, local);
});
test('merge when local and remote has moved forwareded with conflicts', async () => {
test('merge when local and remote has moved forward with conflicts', async () => {
const base = { 'a': { version: 1, value: 'a' } };
const local = { 'a': { version: 1, value: 'd' } };
const remote = { 'a': { version: 1, value: 'b' } };
@ -248,9 +248,9 @@ suite('GlobalStateMerge', () => {
const actual = merge(local, remote, base, { machine: [], unregistered: [] }, new NullLogService());
assert.deepEqual(actual.local.added, {});
assert.deepEqual(actual.local.updated, { 'a': { version: 1, value: 'b' } });
assert.deepEqual(actual.local.updated, {});
assert.deepEqual(actual.local.removed, []);
assert.deepEqual(actual.remote, null);
assert.deepEqual(actual.remote, local);
});
test('merge when a new entry is added to remote but scoped to machine locally', async () => {
@ -277,17 +277,17 @@ suite('GlobalStateMerge', () => {
assert.deepEqual(actual.remote, null);
});
test('merge when a local value is removed and iscoped to machine locally', async () => {
test('merge when a local value is removed and scoped to machine locally', async () => {
const base = { 'a': { version: 1, value: 'a' }, 'b': { version: 1, value: 'b' } };
const local = { 'a': { version: 1, value: 'a' } };
const remote = { 'b': { version: 2, value: 'b' }, 'a': { version: 1, value: 'a' } };
const remote = { 'b': { version: 1, value: 'b' }, 'a': { version: 1, value: 'a' } };
const actual = merge(local, remote, base, { machine: ['b'], unregistered: [] }, new NullLogService());
assert.deepEqual(actual.local.added, {});
assert.deepEqual(actual.local.updated, {});
assert.deepEqual(actual.local.removed, []);
assert.deepEqual(actual.remote, null);
assert.deepEqual(actual.remote, local);
});
test('merge when local moved forwared by changing a key to machine scope', async () => {