feat(ui): add 'replace' and 'merge' strategies for upsertMetadata

This commit is contained in:
psychedelicious
2025-07-04 20:08:31 +10:00
parent 0d3af08d27
commit 54be9989c5
2 changed files with 29 additions and 6 deletions

View File

@@ -579,12 +579,20 @@ describe('Graph', () => {
const metadata = g.getMetadataNode();
expect(metadata).toHaveProperty('test');
});
it('should update metadata on the metadata node', () => {
it("should overwrite metadata on the metadata node if the strategy is 'replace'", () => {
const g = new Graph();
g.upsertMetadata({ test: 'test' });
g.upsertMetadata({ test: 'test2' });
g.upsertMetadata({ test: { foo: 'test' } }, 'replace');
g.upsertMetadata({ test: { bar: 'test2' } }, 'replace');
const metadata = g.getMetadataNode();
expect(metadata.test).toBe('test2');
expect(metadata.test).toEqual({ bar: 'test2' });
});
it("should merge keys if the strategy is 'merge'", () => {
const g = new Graph();
g.upsertMetadata({ test: { foo: 'test' }, arr: [1] }, 'merge');
g.upsertMetadata({ test: { bar: 'test2' }, arr: [2] }, 'merge');
const metadata = g.getMetadataNode();
expect(metadata.test).toEqual({ foo: 'test', bar: 'test2' });
expect(metadata.arr).toEqual([1, 2]);
});
});

View File

@@ -1,4 +1,5 @@
import { objectEquals } from '@observ33r/object-equals';
import { mergeWith } from 'es-toolkit';
import { forEach, groupBy, unset, values } from 'es-toolkit/compat';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import { type ModelIdentifierField, zModelIdentifierField } from 'features/nodes/types/common';
@@ -387,11 +388,25 @@ export class Graph {
* Add metadata to the graph. If the metadata node does not exist, it is created. If the specific metadata key exists,
* it is overwritten.
* @param metadata The metadata to add.
* @param strategy The strategy to use when adding metadata. If 'replace', any existing key is replaced. If 'add',
* the metadata is deeply merged with the existing metadata. Arrays will be concatenated.
* @returns The metadata node.
*/
upsertMetadata(metadata: Partial<S['CoreMetadataInvocation']>): S['CoreMetadataInvocation'] {
upsertMetadata(
metadata: Partial<S['CoreMetadataInvocation']>,
strategy: 'replace' | 'merge' = 'replace'
): S['CoreMetadataInvocation'] {
const node = this.getMetadataNode();
Object.assign(node, metadata);
if (strategy === 'replace') {
Object.assign(node, metadata);
} else {
// strategy === 'merge'
mergeWith(node, metadata, (objValue, srcValue) => {
if (Array.isArray(objValue)) {
return objValue.concat(srcValue);
}
});
}
return node;
}