Skip to content

Commit 48e44f4

Browse files
authored
ArrayStore: Objects in nested array lose their type when array is updated (T1309567) (#31884)
1 parent dd93fba commit 48e44f4

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

packages/devextreme/js/__internal/core/utils/m_object.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ const orderEach = function (map, func) {
4141

4242
const getDeepCopyTarget = (item) => {
4343
if (isObject(item)) {
44-
return Array.isArray(item) ? [] : {};
44+
if (Array.isArray(item)) {
45+
return [];
46+
}
47+
if (!isPlainObject(item)) {
48+
return Object.create(Object.getPrototypeOf(item));
49+
}
50+
return {};
4551
}
4652
return item;
4753
};

packages/devextreme/testing/tests/DevExpress.core/utils.object.tests.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,12 @@ QUnit.test('deepExtendArraySafe copies array into object property deeply', funct
212212
timeArray[0] = 5;
213213
assert.deepEqual(objWithValue.time, [1, complexTime, 3]);
214214
});
215+
216+
QUnit.test('deepExtendArraySafe preserves custom object instances in arrays', function(assert) {
217+
const CustomClass = function(value) { this.value = value; };
218+
const target = { items: [new CustomClass(1), new CustomClass(2)] };
219+
const changes = { items: [new CustomClass(3), new CustomClass(4)] };
220+
const result = objectUtils.deepExtendArraySafe(target, changes, true, false, false, objectUtils.newAssign);
221+
assert.ok(result.items[0] instanceof CustomClass, 'First item preserves custom type');
222+
assert.ok(result.items[1] instanceof CustomClass, 'Second item preserves custom type');
223+
});

packages/devextreme/testing/tests/DevExpress.data/storeArray.tests.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import $ from 'jquery';
22
import ArrayStore from 'common/data/array_store';
3+
import Guid from 'core/guid';
34
import config from 'core/config';
45
import ErrorHandlingHelper from '../../helpers/data.errorHandlingHelper.js';
56

@@ -1115,6 +1116,45 @@ QUnit.test('prevent passing data as non-array', function(assert) {
11151116
});
11161117
});
11171118

1119+
QUnit.module('Push changes');
1120+
1121+
QUnit.test('push update preserves custom object instances inside arrays', function(assert) {
1122+
function createPerson(id, name) {
1123+
return {
1124+
id,
1125+
name,
1126+
guidArray: [new Guid(), new Guid(), new Guid()]
1127+
};
1128+
}
1129+
1130+
const guidPerson1 = new Guid();
1131+
const guidPerson2 = new Guid();
1132+
const person1 = createPerson(guidPerson1, 'Paul');
1133+
const person2 = createPerson(guidPerson2, 'George');
1134+
1135+
const store = new ArrayStore({
1136+
key: 'id',
1137+
data: [person1, person2]
1138+
});
1139+
1140+
const originalGuidArray = store.createQuery().toArray()[0].guidArray;
1141+
assert.ok(originalGuidArray[0] instanceof Guid, 'Guid instance is preserved before push');
1142+
1143+
person1.name = 'Will';
1144+
store.push([{ type: 'update', key: guidPerson1, data: person1 }]);
1145+
1146+
const updatedPerson = store.createQuery().toArray().find(item => item.id === guidPerson1);
1147+
assert.ok(updatedPerson, 'updated person is found');
1148+
const updatedGuidArray = updatedPerson.guidArray;
1149+
1150+
assert.strictEqual(updatedGuidArray.length, originalGuidArray.length, 'array length remains the same');
1151+
updatedGuidArray.forEach((guidInstance, index) => {
1152+
assert.ok(guidInstance instanceof Guid, `item ${index} keeps Guid type after push`);
1153+
assert.strictEqual(guidInstance.toString(), originalGuidArray[index].toString(), 'Guid value is preserved');
1154+
});
1155+
assert.equal(updatedPerson.name, 'Will', 'person data is updated');
1156+
});
1157+
11181158
QUnit.module('Error handling');
11191159

11201160
QUnit.test('error in during query evaluation', function(assert) {

0 commit comments

Comments
 (0)