From 4855f6686bbb696d184637d5f2a0a06d8af75ea6 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Thu, 23 Oct 2025 14:19:05 +0400 Subject: [PATCH] Improve setValue for nested values --- packages/core/src/utils/mixins.ts | 36 ++++++++++++------- .../core/test/specs/data_sources/index.ts | 25 ++++++++++--- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/packages/core/src/utils/mixins.ts b/packages/core/src/utils/mixins.ts index 1a261aab9..00cdf8380 100644 --- a/packages/core/src/utils/mixins.ts +++ b/packages/core/src/utils/mixins.ts @@ -25,7 +25,7 @@ function castPath(value: string | string[], object: ObjectAny) { return object.hasOwnProperty(value) ? [value] : stringToPath(value); } -export const get = (object: ObjectAny, path: string | string[], def: any) => { +export const get = (object: ObjectAny, path: string | string[], def?: any) => { const paths = castPath(path, object); const length = paths.length; let index = 0; @@ -40,22 +40,32 @@ export const set = (object: ObjectAny, path: string | string[], value: any): boo if (!isObject(object)) return false; const paths = castPath(path, object); const length = paths.length; - const lastIndex = length - 1; - let index = -1; - let nested = object; - while (nested != null && ++index < length) { - const key = paths[index]; - let newValue = value; + if (length === 0) return false; - if (index != lastIndex) { - const objValue = nested[key]; - newValue = isObject(objValue) ? objValue : !isNaN(+paths[index + 1]) ? [] : {}; + if (length === 1) { + object[paths[0]] = value; + return true; + } + + const parentPath = paths.slice(0, -1); + const lastKey = paths[length - 1]; + const parent = get(object, parentPath); + + if (parent) { + if (Array.isArray(parent)) { + const index = +lastKey; + if (!isNaN(index)) { + parent[index] = value; + return true; + } + } else if (isObject(parent)) { + (parent as ObjectAny)[lastKey] = value; + return true; } - nested[key] = newValue; - nested = nested[key]; } - return true; + + return false; }; export const serialize = (obj: ObjectAny) => JSON.parse(JSON.stringify(obj)); diff --git a/packages/core/test/specs/data_sources/index.ts b/packages/core/test/specs/data_sources/index.ts index efc505307..9584753ef 100644 --- a/packages/core/test/specs/data_sources/index.ts +++ b/packages/core/test/specs/data_sources/index.ts @@ -93,6 +93,7 @@ describe('DataSourceManager', () => { expect(dsm.setValue('ds1.id1.newField', 'new field value')).toBe(true); expect(dsm.getValue('ds1.id1.newField')).toBe('new field value'); expect(dsm.setValue('non-existing-ds.id1.name', 'New Name')).toBe(false); + expect(dsm.setValue('non-existing-ds.none.name', 'New Name')).toBe(false); expect(dsm.setValue('invalid-path', 'New Name')).toBe(false); }); @@ -100,22 +101,26 @@ describe('DataSourceManager', () => { test('set nested values', () => { const ds = addDataSource(); const address = { city: 'CityName' }; - const roles = ['admin', 'user']; + const roles = ['admin', 'user', 'member']; + const newObj = { newValue: '1' }; ds.addRecord({ id: 'id4', name: 'Name4', metadata: { address, roles }, }); - // Update nested object property + // Check object updates expect(dsm.setValue('ds1.id4.metadata.address.city', 'NewCity')).toBe(true); expect(dsm.getValue('ds1.id4.metadata.address.city')).toBe('NewCity'); + expect(dsm.setValue('ds1.id4.metadata.newObj', newObj)).toBe(true); + expect(dsm.getValue('ds1.id4.metadata.newObj')).toEqual(newObj); - // Update array item + // Check array updates expect(dsm.setValue('ds1.id4.metadata.roles[1]', 'editor')).toBe(true); expect(dsm.getValue('ds1.id4.metadata')).toEqual({ + newObj: { newValue: '1' }, address: { city: 'NewCity' }, - roles: ['admin', 'editor'], + roles: ['admin', 'editor', 'member'], }); // Set entirely new nested object @@ -123,16 +128,26 @@ describe('DataSourceManager', () => { expect(dsm.setValue('ds1.id4.metadata.address', newAddress)).toBe(true); expect(dsm.getValue('ds1.id4.metadata.address')).toEqual(newAddress); - // Set new array const newRoles = ['editor', 'viewer']; expect(dsm.setValue('ds1.id4.metadata.roles', newRoles)).toBe(true); expect(dsm.getValue('ds1.id4.metadata.roles')).toEqual(newRoles); + expect(dsm.getValue('ds1.id4.metadata')).toEqual({ + newObj: { newValue: '1' }, + address: { city: 'AnotherCity', country: 'SomeCountry' }, + roles: ['editor', 'viewer'], + }); + // Set completely new nested structure const newMetadata = { tags: ['tag1', 'tag2'], settings: { theme: 'dark' } }; expect(dsm.setValue('ds1.id4.metadata', newMetadata)).toBe(true); expect(dsm.getValue('ds1.id4.metadata')).toEqual(newMetadata); expect(dsm.getValue('ds1.id4.metadata.settings.theme')).toBe('dark'); + + expect(dsm.getValue('ds1.id4.metadata')).toEqual({ + tags: ['tag1', 'tag2'], + settings: { theme: 'dark' }, + }); }); }); });