Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/sync-plugins/crud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ export function syncedCrud<TRemote extends object, TLocal = TRemote, TAsOption e
// value is already the new value, can ignore
(saved as any)[key] === c ||
// user has changed local value
(key !== fieldId && i !== undefined && i !== c)
(key !== fieldId && i !== undefined && !deepEqual(i, c))
) {
delete (saved as any)[key];
}
Expand Down
9 changes: 9 additions & 0 deletions src/sync/syncHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ export function deepEqual<T extends Record<string, any> = 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) {
Expand Down
69 changes: 69 additions & 0 deletions tests/crud.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
9 changes: 8 additions & 1 deletion tests/testglobals.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,6 +13,13 @@ export interface BasicValue {
baby: string;
};
};
list?: {
parent?: {
child: {
baby: string;
};
};
}[];
}
export interface BasicValue2 {
id: string;
Expand Down