diff --git a/src/sync-plugins/crud.ts b/src/sync-plugins/crud.ts index 38cd8a53..ed1bf5cd 100644 --- a/src/sync-plugins/crud.ts +++ b/src/sync-plugins/crud.ts @@ -605,7 +605,7 @@ export function syncedCrud = any>( ): boolean { if (a === b) return true; if (isNullOrUndefined(a) !== isNullOrUndefined(b)) return false; + + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) { + if (!deepEqual(a[i], b[i], ignoreFields, nullVsUndefined)) return false; + } + return true; + } + if (!isObject(a) || !isObject(b)) return a === b; if (nullVsUndefined) { diff --git a/tests/crud.test.ts b/tests/crud.test.ts index e2064fb7..82e97a59 100644 --- a/tests/crud.test.ts +++ b/tests/crud.test.ts @@ -2769,6 +2769,75 @@ describe('onSaved', () => { updatedAt: 12, }); }); + + test('onSaved gets correct value as object with deep nested object containing array', async () => { + let saved = undefined; + const obs = observable( + syncedCrud({ + as: 'object', + fieldUpdatedAt: 'updatedAt', + create: async (input: BasicValue) => { + return input; + }, + generateId: () => 'id1', + onSaved(params) { + params.saved = { + ...params.saved, + parent: { + child: { baby: 'hello baby override' }, + }, + list: [ + { parent: { child: { baby: 'hello list baby 1' } } }, + { parent: { child: { baby: 'hello list baby 2 modified' } } }, + { parent: { child: { baby: 'hello list baby 3' } } }, + ], + }; + saved = params.saved; + return params.saved; + }, + }), + ); + + await promiseTimeout(1); + + obs.id1.set({ + test: 'hello', + id: undefined as unknown as string, + parent: { child: { baby: 'hello baby' } }, + list: [ + { parent: { child: { baby: 'hello list baby 1' } } }, + { parent: { child: { baby: 'hello list baby 2' } } }, + { parent: { child: { baby: 'hello list baby 3' } } }, + ], + }); + + await promiseTimeout(1); + + expect(saved).toEqual({ + id: 'id1', + test: 'hello', + parent: { + child: { baby: 'hello baby override' }, + }, + list: [ + { parent: { child: { baby: 'hello list baby 1' } } }, + { parent: { child: { baby: 'hello list baby 2 modified' } } }, + { parent: { child: { baby: 'hello list baby 3' } } }, + ], + }); + expect(obs.id1.peek()).toEqual({ + id: 'id1', + test: 'hello', + parent: { + child: { baby: 'hello baby override' }, + }, + list: [ + { parent: { child: { baby: 'hello list baby 1' } } }, + { parent: { child: { baby: 'hello list baby 2 modified' } } }, + { parent: { child: { baby: 'hello list baby 3' } } }, + ], + }); + }); }); describe('Order of get/create', () => { test('create with no get', async () => { diff --git a/tests/testglobals.ts b/tests/testglobals.ts index a994db9e..a2ed0a9a 100644 --- a/tests/testglobals.ts +++ b/tests/testglobals.ts @@ -1,7 +1,7 @@ import { jest } from '@jest/globals'; -import { ObservablePersistLocalStorageBase } from '../src/persist-plugins/local-storage'; import type { Change, TrackingType } from '../src/observableInterfaces'; import type { Observable } from '../src/observableTypes'; +import { ObservablePersistLocalStorageBase } from '../src/persist-plugins/local-storage'; export interface BasicValue { id: string; @@ -13,6 +13,13 @@ export interface BasicValue { baby: string; }; }; + list?: { + parent?: { + child: { + baby: string; + }; + }; + }[]; } export interface BasicValue2 { id: string;