diff --git a/package.json b/package.json index a945d45..2211196 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,8 @@ "check-types": "^7.1.5", "content-type": "^1.0.4", "handlebars": "^4.0.5", - "metrohash": "^2.3.0", "moment": "^2.22.2", + "hasha": "^5.1.0", "mongodb": "^3.1.1", "redis": "^2.8.0", "request": "^2.88.0" diff --git a/test/component.js b/test/component.js index d3402da..0c4be37 100644 --- a/test/component.js +++ b/test/component.js @@ -13,7 +13,7 @@ function generateLoremIpsumList(offset, length) { const loremArr = lorem.split(' '); const list = []; - for (var i = 0; i < length; i++) { + for (let i = 0; i < length; i++) { list.push({ _id: i, tag: loremArr[i + offset], @@ -25,7 +25,9 @@ function generateLoremIpsumList(offset, length) { return list; } -function clone(list) { return JSON.parse(JSON.stringify(list)); } +function clone(list) { + return JSON.parse(JSON.stringify(list)); +} describe('component utils', () => { @@ -44,11 +46,11 @@ describe('component utils', () => { listPhase2.shift(); // add new one listPhase2.push({ - _id: 666, - tag: 'noTag', - flag: 'x', - tstamp: new Date() - }); + _id: 666, + tag: 'noTag', + flag: 'x', + tstamp: new Date() + }); let state = []; @@ -106,12 +108,13 @@ describe('component utils', () => { } = componentUtils.checkListForChanges(listPhase1, state, '_id', { // omit timestamp - mappingFunction: ({ _id, tag, flag }) => ({ _id, tag, flag }) + mappingFunction: ({ _id, tag, flag }) => ({ _id, tag, flag }), + includeOldData: true }); // new state should contain all items expect(newState.length).to.equal(LIST_SIZE); - // expect 8 changes, ale to be of state 'new' + // expect 8 changes, all to be of state 'new' expect(changes.filter(ch => ch.state === 'new').length).to.equal(LIST_SIZE); state = newState; @@ -125,13 +128,23 @@ describe('component utils', () => { } = componentUtils.checkListForChanges(listPhase2, state, '_id', { // omit timestamp - mappingFunction: ({ _id, tag, flag }) => ({ _id, tag, flag }) + mappingFunction: ({ _id, tag, flag }) => ({ _id, tag, flag }), + includeOldData: true }); // test changes - const expected = [ [1, 'changed'], [3, 'changed'], [666, 'new'], [0, 'removed'], [7, 'removed']]; + const expected = [[1, 'changed'], [3, 'changed'], [666, 'new'], [0, 'removed'], [7, 'removed']]; // compare to expectation - const result = changes.filter((ch, i) => ch.id === expected[i][0] && ch.state === expected[i][1]); + const result = changes.filter((ch, i) => { + if (ch.state !== expected[i][1]) { + // if state does not match = error, filter out + return false; + } + if (ch.state === 'removed') { + return ch.oldItem._id === expected[i][0]; + } + return ch.item['_id'] === expected[i][0]; + }); expect(result.length).to.equal(expected.length); // test state diff --git a/util/component.js b/util/component.js index 04ee5d6..c56f9e7 100644 --- a/util/component.js +++ b/util/component.js @@ -1,6 +1,5 @@ 'use strict'; - -const metrohash128 = require('metrohash').metrohash128; +const hasha = require('hasha'); const objectUtil = require('./object'); // some helper functions @@ -49,10 +48,10 @@ function createMappingFunctionFromCSV(csv) { * Using previous state compares items of iterable and returns new state and changes * @param {Iterable} iterable * @param {Map|Array} previousState - * @param {string|function(object)s} idMapping + * @param {string|function(object)} idMapping * if string, then idMapping value is used as path to id in item - * if function, idMapping is called on item to retreive id of that item - * !!WARNING!! for components where big load of items is expected, I recomend pass + * if function, idMapping is called on item to retrieve id of that item + * !!WARNING!! for components where big load of items is expected, I recommend pass * own mapping function, because the generated one adds bit more of load. * @param {?Object=} options * @param {boolean} options.includeOldData when true, function includes difference in changed item @@ -82,7 +81,7 @@ function checkListForChanges(iterable, previousState, idMapping, options = {}) { includeOldData = false, mappingFunction = identity, stringifyFunction = JSON.stringify.bind(JSON), - hashFn = metrohash128 + hashFn = hasha } = options; let changes = []; @@ -105,7 +104,8 @@ function checkListForChanges(iterable, previousState, idMapping, options = {}) { // new item changes.push({ item: origItem, - oldItem: null + oldItem: null, + state: 'new' }); } else if (previousItem.hash === hash) { // done with this item, get rid of it @@ -114,7 +114,8 @@ function checkListForChanges(iterable, previousState, idMapping, options = {}) { // changed item changes.push({ item: origItem, - oldItem: previousItem.data + oldItem: previousItem.data, + state: 'changed' }); // done with this item, get rid of it previousState.delete(id); @@ -123,7 +124,8 @@ function checkListForChanges(iterable, previousState, idMapping, options = {}) { // at this point, previous state contains only items which were removed // so add those - changes = changes.concat([...previousState.values()].map(state => ({ item: null, oldItem: state.data }))); + changes = changes.concat([...previousState.values()] + .map(state => ({ item: null, oldItem: state.data, state: 'removed' }))); return { changes,