Skip to content

Commit

Permalink
diff_object + tests 👉ui/state_management
Browse files Browse the repository at this point in the history
  • Loading branch information
alexwizp committed Jan 3, 2020
1 parent de51dc1 commit 76e6f4e
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 97 deletions.
2 changes: 1 addition & 1 deletion src/legacy/ui/public/state_management/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import _ from 'lodash';
import { i18n } from '@kbn/i18n';
import angular from 'angular';
import rison from 'rison-node';
import { applyDiff } from '../utils/diff_object';
import { applyDiff } from './utils/diff_object';
import { EventsProvider } from '../events';
import { fatalError, toastNotifications } from '../notify';
import './config_provider';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,76 +17,88 @@
* under the License.
*/

import expect from '@kbn/expect';
import _ from 'lodash';
import { applyDiff } from '../diff_object';
import { cloneDeep } from 'lodash';
import { applyDiff } from './diff_object';

describe('ui/utils/diff_object', function() {
it('should list the removed keys', function() {
describe('diff_object', () => {
test('should list the removed keys', () => {
const target = { test: 'foo' };
const source = { foo: 'test' };
const results = applyDiff(target, source);
expect(results).to.have.property('removed');
expect(results.removed).to.eql(['test']);

expect(results).toHaveProperty('removed');
expect(results.removed).toEqual(['test']);
});

it('should list the changed keys', function() {
test('should list the changed keys', () => {
const target = { foo: 'bar' };
const source = { foo: 'test' };
const results = applyDiff(target, source);
expect(results).to.have.property('changed');
expect(results.changed).to.eql(['foo']);

expect(results).toHaveProperty('changed');
expect(results.changed).toEqual(['foo']);
});

it('should list the added keys', function() {
test('should list the added keys', () => {
const target = {};
const source = { foo: 'test' };
const results = applyDiff(target, source);
expect(results).to.have.property('added');
expect(results.added).to.eql(['foo']);

expect(results).toHaveProperty('added');
expect(results.added).toEqual(['foo']);
});

it('should list all the keys that are change or removed', function() {
test('should list all the keys that are change or removed', () => {
const target = { foo: 'bar', test: 'foo' };
const source = { foo: 'test' };
const results = applyDiff(target, source);
expect(results).to.have.property('keys');
expect(results.keys).to.eql(['foo', 'test']);

expect(results).toHaveProperty('keys');
expect(results.keys).toEqual(['foo', 'test']);
});

it('should ignore functions', function() {
test('should ignore functions', () => {
const target = { foo: 'bar', test: 'foo' };
const source = { foo: 'test', fn: _.noop };
const source = { foo: 'test', fn: () => {} };

applyDiff(target, source);
expect(target).to.not.have.property('fn');

expect(target).not.toHaveProperty('fn');
});

it('should ignore underscores', function() {
test('should ignore underscores', () => {
const target = { foo: 'bar', test: 'foo' };
const source = { foo: 'test', _private: 'foo' };

applyDiff(target, source);
expect(target).to.not.have.property('_private');

expect(target).not.toHaveProperty('_private');
});

it('should ignore dollar signs', function() {
test('should ignore dollar signs', () => {
const target = { foo: 'bar', test: 'foo' };
const source = { foo: 'test', $private: 'foo' };

applyDiff(target, source);
expect(target).to.not.have.property('$private');

expect(target).not.toHaveProperty('$private');
});

it('should not list any changes for similar objects', function() {
test('should not list any changes for similar objects', () => {
const target = { foo: 'bar', test: 'foo' };
const source = { foo: 'bar', test: 'foo', $private: 'foo' };
const results = applyDiff(target, source);
expect(results.changed).to.be.empty();

expect(results.changed).toEqual([]);
});

it('should only change keys that actually changed', function() {
test('should only change keys that actually changed', () => {
const obj = { message: 'foo' };
const target = { obj: obj, message: 'foo' };
const source = { obj: _.cloneDeep(obj), message: 'test' };
const target = { obj, message: 'foo' };
const source = { obj: cloneDeep(obj), message: 'test' };

applyDiff(target, source);
expect(target.obj).to.be(obj);

expect(target.obj).toBe(obj);
});
});
75 changes: 75 additions & 0 deletions src/legacy/ui/public/state_management/utils/diff_object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { keys, isFunction, difference, filter, union, pick, each, assign, isEqual } from 'lodash';

export interface IDiffObject {
removed: string[];
added: string[];
changed: string[];
keys: string[];
}

/**
* Filter the private vars
* @param {string} key The keys
* @returns {boolean}
*/
const filterPrivateAndMethods = function(obj: Record<string, any>) {
return function(key: string) {
if (isFunction(obj[key])) return false;
if (key.charAt(0) === '$') return false;
return key.charAt(0) !== '_';
};
};

export function applyDiff(target: Record<string, any>, source: Record<string, any>) {
const diff: IDiffObject = {
removed: [],
added: [],
changed: [],
keys: [],
};

const targetKeys = keys(target).filter(filterPrivateAndMethods(target));
const sourceKeys = keys(source).filter(filterPrivateAndMethods(source));

// Find the keys to be removed
diff.removed = difference(targetKeys, sourceKeys);

// Find the keys to be added
diff.added = difference(sourceKeys, targetKeys);

// Find the keys that will be changed
diff.changed = filter(sourceKeys, key => !isEqual(target[key], source[key]));

// Make a list of all the keys that are changing
diff.keys = union(diff.changed, diff.removed, diff.added);

// Remove all the keys
each(diff.removed, key => {
delete target[key];
});

// Assign the changed to the source to the target
assign(target, pick(source, diff.changed));
// Assign the added to the source to the target
assign(target, pick(source, diff.added));

return diff;
}
67 changes: 0 additions & 67 deletions src/legacy/ui/public/utils/diff_object.js

This file was deleted.

0 comments on commit 76e6f4e

Please sign in to comment.