mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-07-08 13:04:34 +00:00
add diff-arrays utility for efficient array diffs
This commit is contained in:
parent
45e5749cca
commit
373c60b521
2 changed files with 109 additions and 0 deletions
56
packages/backend/src/misc/diff-arrays.ts
Normal file
56
packages/backend/src/misc/diff-arrays.ts
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface DiffResult<T> {
|
||||||
|
added: T[];
|
||||||
|
removed: T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the difference between two snapshots of data.
|
||||||
|
* Null, undefined, and empty arrays are supported, and values do not have to be unique.
|
||||||
|
* Result sets are de-duplicated, and will be empty if no data was added or removed (respectively).
|
||||||
|
* @param dataBefore Array containing data before the change
|
||||||
|
* @param dataAfter Array containing data after the change
|
||||||
|
*/
|
||||||
|
export function diffArrays<T>(dataBefore: T[] | null | undefined, dataAfter: T[] | null | undefined): DiffResult<T> {
|
||||||
|
const before = dataBefore ? new Set(dataBefore) : null;
|
||||||
|
const after = dataAfter ? new Set(dataAfter) : null;
|
||||||
|
|
||||||
|
// data before AND after => changed
|
||||||
|
if (before?.size && after?.size) {
|
||||||
|
const added: T[] = [];
|
||||||
|
const removed: T[] = [];
|
||||||
|
|
||||||
|
for (const host of before) {
|
||||||
|
// before and NOT after => removed
|
||||||
|
if (!after.has(host)) {
|
||||||
|
removed.push(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const host of after) {
|
||||||
|
// after and NOT before => added
|
||||||
|
if (!before.has(host)) {
|
||||||
|
added.push(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { added, removed };
|
||||||
|
}
|
||||||
|
|
||||||
|
// data ONLY before => all removed
|
||||||
|
if (before?.size) {
|
||||||
|
return { added: [], removed: Array.from(before) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// data ONLY after => all added
|
||||||
|
if (after?.size) {
|
||||||
|
return { added: Array.from(after), removed: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// data NEITHER before nor after => no change
|
||||||
|
return { added: [], removed: [] };
|
||||||
|
}
|
53
packages/backend/test/unit/misc/diff-arrays.ts
Normal file
53
packages/backend/test/unit/misc/diff-arrays.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { diffArrays } from '@/misc/diff-arrays.js';
|
||||||
|
|
||||||
|
describe(diffArrays, () => {
|
||||||
|
it('should return empty result when both inputs are null', () => {
|
||||||
|
const result = diffArrays(null, null);
|
||||||
|
expect(result.added).toHaveLength(0);
|
||||||
|
expect(result.removed).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return empty result when both inputs are empty', () => {
|
||||||
|
const result = diffArrays([], []);
|
||||||
|
expect(result.added).toHaveLength(0);
|
||||||
|
expect(result.removed).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove before when added is empty', () => {
|
||||||
|
const result = diffArrays([1, 2, 3], []);
|
||||||
|
expect(result.added).toHaveLength(0);
|
||||||
|
expect(result.removed).toEqual([1, 2, 3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should deduplicate before when added is empty', () => {
|
||||||
|
const result = diffArrays([1, 1, 2, 2, 3], []);
|
||||||
|
expect(result.added).toHaveLength(0);
|
||||||
|
expect(result.removed).toEqual([1, 2, 3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove after when before is empty', () => {
|
||||||
|
const result = diffArrays([], [1, 2, 3]);
|
||||||
|
expect(result.added).toEqual([1, 2, 3]);
|
||||||
|
expect(result.removed).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should deduplicate after when before is empty', () => {
|
||||||
|
const result = diffArrays([], [1, 1, 2, 2, 3]);
|
||||||
|
expect(result.added).toEqual([1, 2, 3]);
|
||||||
|
expect(result.removed).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return diff when both have values', () => {
|
||||||
|
const result = diffArrays(
|
||||||
|
['a', 'b', 'c', 'd'],
|
||||||
|
['a', 'c', 'e', 'f'],
|
||||||
|
);
|
||||||
|
expect(result.added).toEqual(['e', 'f']);
|
||||||
|
expect(result.removed).toEqual(['b', 'd']);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Reference in a new issue