Skip to content

Commit 5c6ea1e

Browse files
committed
Fix Collection and Single should not mutate the provided data
1 parent 73f26e1 commit 5c6ea1e

File tree

4 files changed

+28
-5
lines changed

4 files changed

+28
-5
lines changed

src/Collection.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,18 @@ describe('Collection', () => {
989989
expect(collection.getOne(0)).toEqual({ id: 0, name: 'bar' });
990990
expect(collection.getOne(1)).toEqual({ id: 1, name: 'baz' });
991991
});
992+
993+
it('should update the original item', () => {
994+
const items = [{ name: 'foo' }, { name: 'baz' }];
995+
const collection = new Collection<CollectionItem>({
996+
items,
997+
});
998+
collection.updateOne(0, { id: 0, name: 'bar' });
999+
expect(collection.getOne(0)).toEqual({ id: 0, name: 'bar' });
1000+
expect(collection.getOne(1)).toEqual({ id: 1, name: 'baz' });
1001+
expect(items[0]).toEqual({ name: 'foo' });
1002+
expect(items[1]).toEqual({ name: 'baz' });
1003+
});
9921004
});
9931005

9941006
describe('removeOne', () => {

src/Collection.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import get from 'lodash/get.js';
22
import matches from 'lodash/matches.js';
3+
import cloneDeep from 'lodash/cloneDeep.js';
34
import type { Database } from './Database.ts';
45
import type {
56
CollectionItem,
@@ -196,7 +197,8 @@ export class Collection<T extends CollectionItem = CollectionItem> {
196197
}
197198

198199
addOne(item: T) {
199-
const identifier = item[this.identifierName];
200+
const clone = cloneDeep(item);
201+
const identifier = clone[this.identifierName];
200202
if (identifier != null) {
201203
if (this.getIndex(identifier) !== -1) {
202204
throw new Error(
@@ -208,10 +210,10 @@ export class Collection<T extends CollectionItem = CollectionItem> {
208210
}
209211
} else {
210212
// @ts-expect-error - For some reason, TS does not accept writing a generic types with the index signature
211-
item[this.identifierName] = this.getNewId();
213+
clone[this.identifierName] = this.getNewId();
212214
}
213-
this.items.push(item);
214-
return Object.assign({}, item); // clone item to avoid returning the original;
215+
this.items.push(clone);
216+
return clone; // clone item to avoid returning the original;
215217
}
216218

217219
updateOne(identifier: number | string, item: T) {

src/Single.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,5 +144,13 @@ describe('Single', () => {
144144
single.updateOnly({ name: 'bar' });
145145
expect(single.getOnly()).toEqual({ name: 'bar' });
146146
});
147+
148+
it('should not update the original item', () => {
149+
const data = { name: 'foo' };
150+
const single = new Single(data);
151+
single.updateOnly({ name: 'bar' });
152+
expect(single.getOnly()).toEqual({ name: 'bar' });
153+
expect(data).toEqual({ name: 'foo' });
154+
});
147155
});
148156
});

src/Single.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import cloneDeep from 'lodash/cloneDeep.js';
12
import type { Database } from './Database.ts';
23
import type { CollectionItem, Embed, Query } from './types.ts';
34

@@ -12,7 +13,7 @@ export class Single<T extends CollectionItem = CollectionItem> {
1213
"Can't initialize a Single with anything except an object",
1314
);
1415
}
15-
this.obj = obj;
16+
this.obj = cloneDeep(obj);
1617
}
1718

1819
/**

0 commit comments

Comments
 (0)