feat(ui): add changeNamedCollection util
parent
ea1a9fe545
commit
a51ce4d8a1
|
@ -0,0 +1,64 @@
|
||||||
|
interface Named {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
type NamedChanges = Record<string, boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ComputeNamedChanges computes changes between array of named instances
|
||||||
|
* as a Record with instance name as a key and values indicated addition (true)
|
||||||
|
* or removal (false). Undefined is returned if there are no changes detected.
|
||||||
|
*/
|
||||||
|
export function computeNamedChanges<T extends Named>(
|
||||||
|
prev: T[],
|
||||||
|
next: T[]
|
||||||
|
): NamedChanges | undefined {
|
||||||
|
const retVal = {}
|
||||||
|
// indicate all prev values as removed
|
||||||
|
prev.forEach(({name}) => (retVal[name] = false))
|
||||||
|
// indicate all new values as added, existing as undefined
|
||||||
|
next.forEach(
|
||||||
|
({name}) => (retVal[name] = retVal[name] === false ? undefined : true)
|
||||||
|
)
|
||||||
|
// filter all undefined values
|
||||||
|
let changed = false
|
||||||
|
const onlyChanges = Object.entries(retVal).reduce((acc, [key, value]) => {
|
||||||
|
if (value !== undefined) {
|
||||||
|
changed = true
|
||||||
|
acc[key] = value
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
return changed ? onlyChanges : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ChangeNamedCollection returns a collection that changes the
|
||||||
|
* supplied named collection according to changeType. True changeType
|
||||||
|
* inserts an element in a sorted way, false removes all elements
|
||||||
|
* of the same name, undefined does nothing and returns the
|
||||||
|
* supplied collection.
|
||||||
|
*/
|
||||||
|
export function changeNamedCollection<T extends Named>(
|
||||||
|
values: T[],
|
||||||
|
element: T,
|
||||||
|
changeType: boolean | undefined
|
||||||
|
): T[] {
|
||||||
|
if (changeType === undefined) {
|
||||||
|
// no changes requested, do nothing
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
if (changeType) {
|
||||||
|
// insert to the existing collection
|
||||||
|
let i = 0
|
||||||
|
for (; i < values.length; i++) {
|
||||||
|
if (values[i].name.localeCompare(element.name) >= 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const retVal = [...values]
|
||||||
|
retVal.splice(i, 0, element)
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
// remove from existing collection
|
||||||
|
return values.filter(({name}) => name !== element.name)
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
import {
|
||||||
|
computeNamedChanges,
|
||||||
|
changeNamedCollection,
|
||||||
|
} from 'src/admin/util/changeNamedCollection'
|
||||||
|
|
||||||
|
describe('admin/util/changeNamedCollection', () => {
|
||||||
|
describe('computeNamedChanges', () => {
|
||||||
|
it('returns undefined upon no change', () => {
|
||||||
|
expect(computeNamedChanges([], [])).toBe(undefined)
|
||||||
|
expect(computeNamedChanges([{name: 'a'}], [{name: 'a'}])).toBe(undefined)
|
||||||
|
})
|
||||||
|
it('returns value indicating changes', () => {
|
||||||
|
expect(
|
||||||
|
computeNamedChanges([{name: 'a'}, {name: 'b'}], [{name: 'a'}])
|
||||||
|
).toEqual({b: false})
|
||||||
|
expect(
|
||||||
|
computeNamedChanges([{name: 'a'}], [{name: 'a'}, {name: 'b'}])
|
||||||
|
).toEqual({b: true})
|
||||||
|
expect(
|
||||||
|
computeNamedChanges(
|
||||||
|
[{name: 'a'}, {name: 'c'}],
|
||||||
|
[{name: 'a'}, {name: 'b'}]
|
||||||
|
)
|
||||||
|
).toEqual({b: true, c: false})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('changeNamedCollection', () => {
|
||||||
|
it('changes nothing upon no change', () => {
|
||||||
|
const collection = [{name: 'a'}, {name: 'b'}]
|
||||||
|
expect(changeNamedCollection(collection, {name: 'c'}, undefined)).toBe(
|
||||||
|
collection
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it('removes from collection', () => {
|
||||||
|
const collection = [{name: 'a'}, {name: 'b'}]
|
||||||
|
expect(changeNamedCollection(collection, {name: 'a'}, false)).toEqual([
|
||||||
|
{name: 'b'},
|
||||||
|
])
|
||||||
|
expect(changeNamedCollection(collection, {name: 'b'}, false)).toEqual([
|
||||||
|
{name: 'a'},
|
||||||
|
])
|
||||||
|
expect(changeNamedCollection(collection, {name: 'c'}, false)).toEqual(
|
||||||
|
collection
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it('adds to collection', () => {
|
||||||
|
const collection = [{name: 'b'}, {name: 'd'}]
|
||||||
|
expect(changeNamedCollection([], {name: 'a'}, true)).toEqual([
|
||||||
|
{name: 'a'},
|
||||||
|
])
|
||||||
|
expect(changeNamedCollection(collection, {name: 'a'}, true)).toEqual([
|
||||||
|
{name: 'a'},
|
||||||
|
{name: 'b'},
|
||||||
|
{name: 'd'},
|
||||||
|
])
|
||||||
|
expect(changeNamedCollection(collection, {name: 'c'}, true)).toEqual([
|
||||||
|
{name: 'b'},
|
||||||
|
{name: 'c'},
|
||||||
|
{name: 'd'},
|
||||||
|
])
|
||||||
|
expect(changeNamedCollection(collection, {name: 'e'}, true)).toEqual([
|
||||||
|
{name: 'b'},
|
||||||
|
{name: 'd'},
|
||||||
|
{name: 'e'},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue