Skip to content
Merged
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
9 changes: 2 additions & 7 deletions lib/reducer/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export function defaultNormalize<T>(
const keyList = Object.keys(response);
const currentStorage = isRecord(cdeebee.storage) ? (cdeebee.storage as Record<string, unknown>) : {};

// Start with existing storage to preserve keys not in response
const result = { ...currentStorage } as Record<string, ResponseValue>;
const keyListToOmit = new Set<string>();

Expand All @@ -27,25 +26,21 @@ export function defaultNormalize<T>(
continue;
}

const isNormalized = isRecord(responseValue) && Object.keys(responseValue).length > 0;
const isNormalized = isRecord(responseValue);
const strategy = strategyList[key as keyof T] ?? 'merge';

if (isNormalized) {
const strategy = strategyList[key as keyof T] ?? 'merge';
const existingValue = key in currentStorage ? (currentStorage[key] as StorageData) : {};

if (strategy === 'replace') {
// Replace: completely replace the value
result[key] = responseValue as ResponseValue;
} else if (strategy === 'merge') {
// Merge: merge with existing value
result[key] = mergeDeepRight(existingValue, responseValue as StorageData) as ResponseValue;
} else {
// Unknown strategy: warn and fall back to merge
console.warn(`Cdeebee: Unknown strategy "${strategy}" for key "${key}". Skipping normalization.`);
result[key] = mergeDeepRight(existingValue, responseValue as StorageData) as ResponseValue;
}
} else {
// Not a normalized object, store as-is
result[key] = responseValue;
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recats/cdeebee",
"version": "3.0.0-beta.5",
"version": "3.0.0-beta.6",
"description": "React Redux data-logic library",
"repository": "git@github.com:recats/cdeebee.git",
"author": "recats",
Expand Down
71 changes: 70 additions & 1 deletion tests/lib/reducer/storage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,14 @@ describe('defaultNormalize', () => {
});
});

it('should handle empty normalized object', () => {
it('should replace existing data with empty object when using replace strategy', () => {
mockCdeebee.storage = {
userList: {
'1': { id: '1', name: 'John' },
'2': { id: '2', name: 'Jane' },
},
};

const response = {
userList: {},
};
Expand All @@ -252,6 +259,68 @@ describe('defaultNormalize', () => {
const result = defaultNormalize(mockCdeebee, response, strategyList);

expect(result.userList).toEqual({});
expect(Object.keys(result.userList as Record<string, unknown>)).toHaveLength(0);
});

it('should preserve existing data when empty object comes with merge strategy', () => {
mockCdeebee.storage = {
userList: {
'1': { id: '1', name: 'John' },
'2': { id: '2', name: 'Jane' },
},
};

const response = {
userList: {},
};

const strategyList: CdeebeeListStrategy<unknown> = {
userList: 'merge',
};

const result = defaultNormalize(mockCdeebee, response, strategyList);

expect(result.userList).toEqual({
'1': { id: '1', name: 'John' },
'2': { id: '2', name: 'Jane' },
});
expect(Object.keys(result.userList as Record<string, unknown>)).toHaveLength(2);
expect((result.userList as Record<string, unknown>)['1']).toEqual({ id: '1', name: 'John' });
expect((result.userList as Record<string, unknown>)['2']).toEqual({ id: '2', name: 'Jane' });
});

it('should handle empty objects in single request: merge preserves data, replace erases data', () => {
mockCdeebee.storage = {
userList: {
'1': { id: '1', name: 'John' },
'2': { id: '2', name: 'Jane' },
},
postList: {
'1': { id: '1', title: 'Post 1' },
'2': { id: '2', title: 'Post 2' },
},
};

const response = {
userList: {},
postList: {},
};

const strategyList: CdeebeeListStrategy<unknown> = {
userList: 'merge',
postList: 'replace',
};

const result = defaultNormalize(mockCdeebee, response, strategyList);

expect(result.userList).toEqual({
'1': { id: '1', name: 'John' },
'2': { id: '2', name: 'Jane' },
});
expect(Object.keys(result.userList as Record<string, unknown>)).toHaveLength(2);

expect(result.postList).toEqual({});
expect(Object.keys(result.postList as Record<string, unknown>)).toHaveLength(0);
});
});

Expand Down