Skip to content

Commit b8ca322

Browse files
authored
Merge pull request #153 from Kashoo/issue-152-fix-immutable-nested-properties
Issue 152: Allow objects with immutable properties to be added to an array
2 parents 3cc9d56 + 9315673 commit b8ca322

4 files changed

Lines changed: 445 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [Unreleased]
6+
### Fixed
7+
- [#152](https://github.com/Kashoo/synctos/issues/152): Cannot append a new object with immutable properties to an array
8+
59
## [1.9.2] - 2017-10-02
610
### Fixed
711
- [#149](https://github.com/Kashoo/synctos/issues/149): Permissions for add operations sometimes applied to other operation types

etc/sync-function-validation-module.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -438,11 +438,8 @@ function() {
438438
for (var elementIndex = 0; elementIndex < itemValue.length; elementIndex++) {
439439
var elementName = '[' + elementIndex + ']';
440440
var elementValue = itemValue[elementIndex];
441-
442-
var oldElementValue;
443-
if (!isValueNullOrUndefined(oldItemValue) && elementIndex < oldItemValue.length) {
444-
oldElementValue = oldItemValue[elementIndex];
445-
}
441+
var oldElementValue =
442+
(!isValueNullOrUndefined(oldItemValue) && elementIndex < oldItemValue.length) ? oldItemValue[elementIndex] : null;
446443

447444
itemStack.push({
448445
itemName: elementName,
Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
var testHelper = require('../etc/test-helper.js');
2+
var errorFormatter = testHelper.validationErrorFormatter;
3+
4+
describe('Immutable nested properties:', function() {
5+
beforeEach(function() {
6+
testHelper.initSyncFunction('build/sync-functions/test-immutable-nested-properties-sync-function.js');
7+
});
8+
9+
describe('when an object with an immutable property is nested in an array', function() {
10+
it('prevent modification of immutable properties for objects that already exist', function() {
11+
var doc = {
12+
_id: 'myDoc',
13+
type: 'objectNestedInArrayDoc',
14+
elementList: [
15+
{ id: 'my-element-1', content: 'new-content-1' }, // This element has not changed
16+
{ id: 'my-element-3', content: 'new-content-3' }, // This element was originally at index 2 of the array
17+
{ id: 'my-element-2', content: 'new-content-2' }, // This element was originally at index 1 of the array
18+
{ id: 'new-element-4', content: 'new-content-4' } // Brand new element
19+
]
20+
};
21+
22+
var oldDoc = {
23+
_id: 'myDoc',
24+
type: 'objectNestedInArrayDoc',
25+
elementList: [
26+
{ id: 'my-element-1', content: 'old-content-1' },
27+
{ id: 'my-element-2', content: 'old-content-2' },
28+
{ id: 'my-element-3', content: 'old-content-3' }
29+
]
30+
};
31+
32+
testHelper.verifyDocumentNotReplaced(
33+
doc,
34+
oldDoc,
35+
'objectNestedInArrayDoc',
36+
[ errorFormatter.immutableItemViolation('elementList[1].id'), errorFormatter.immutableItemViolation('elementList[2].id') ]);
37+
});
38+
39+
it('allow modification as long as immutable properties do not change', function() {
40+
var doc = {
41+
_id: 'myDoc',
42+
type: 'objectNestedInArrayDoc',
43+
elementList: [
44+
{ id: 'my-element-1', content: 'new-content-1' },
45+
{ id: 'my-element-2', content: 'new-content-2' },
46+
{ id: 'new-element-3', content: 'new-content-3' } // Brand new element
47+
]
48+
};
49+
50+
var oldDoc = {
51+
_id: 'myDoc',
52+
type: 'objectNestedInArrayDoc',
53+
elementList: [
54+
{ id: 'my-element-1', content: 'old-content-1' },
55+
{ id: 'my-element-2', content: 'old-content-2' }
56+
]
57+
};
58+
59+
testHelper.verifyDocumentReplaced(doc, oldDoc);
60+
});
61+
});
62+
63+
describe('when an object with an immutable property is nested in a hashtable', function() {
64+
it('prevent modification of immutable properties for objects that already exist', function() {
65+
var doc = {
66+
_id: 'myDoc',
67+
type: 'objectNestedInHashtableDoc',
68+
hash: {
69+
one: { id: 'my-element-3', content: 'new-content-3' }, // This element was originally for key "three"
70+
two: { id: 'my-element-2', content: 'new-content-2' }, // This element has not changed
71+
three: { id: 'my-element-1', content: 'new-content-1' }, // This element was originally for key "one"
72+
four: { id: 'new-element-4', content: 'new-content-4' } // Brand new element
73+
}
74+
};
75+
76+
var oldDoc = {
77+
_id: 'myDoc',
78+
type: 'objectNestedInHashtableDoc',
79+
hash: {
80+
one: { id: 'my-element-1', content: 'old-content-1' },
81+
two: { id: 'my-element-2', content: 'old-content-2' },
82+
three: { id: 'my-element-3', content: 'old-content-3' }
83+
}
84+
};
85+
86+
testHelper.verifyDocumentNotReplaced(
87+
doc,
88+
oldDoc,
89+
'objectNestedInHashtableDoc',
90+
[ errorFormatter.immutableItemViolation('hash[one].id'), errorFormatter.immutableItemViolation('hash[three].id') ]);
91+
});
92+
93+
it('allow modification as long as immutable properties do not change', function() {
94+
var doc = {
95+
_id: 'myDoc',
96+
type: 'objectNestedInHashtableDoc',
97+
hash: {
98+
one: { id: 'my-element-1', content: 'new-content-1' },
99+
two: { id: 'my-element-2', content: 'new-content-2' },
100+
three: { id: 'new-element-3', content: 'new-content-3' } // Brand new element
101+
}
102+
};
103+
104+
var oldDoc = {
105+
_id: 'myDoc',
106+
type: 'objectNestedInHashtableDoc',
107+
hash: {
108+
one: { id: 'my-element-1', content: 'old-content-1' },
109+
two: { id: 'my-element-2', content: 'old-content-2' }
110+
}
111+
};
112+
113+
testHelper.verifyDocumentReplaced(doc, oldDoc);
114+
});
115+
});
116+
117+
describe('when an object with an immutable property is nested in an object', function() {
118+
it('prevent modification of immutable properties for objects that already exist', function() {
119+
var doc = {
120+
_id: 'myDoc',
121+
type: 'objectNestedInObjectDoc',
122+
object: {
123+
value: { id: 'new-element', content: 'new-content' }
124+
}
125+
};
126+
127+
var oldDoc = {
128+
_id: 'myDoc',
129+
type: 'objectNestedInObjectDoc',
130+
object: {
131+
value: { id: 'old-element', content: 'old-content' }
132+
}
133+
};
134+
135+
testHelper.verifyDocumentNotReplaced(
136+
doc,
137+
oldDoc,
138+
'objectNestedInObjectDoc',
139+
errorFormatter.immutableItemViolation('object.value.id'));
140+
});
141+
142+
it('allow modification as long as immutable properties do not change', function() {
143+
var doc = {
144+
_id: 'myDoc',
145+
type: 'objectNestedInObjectDoc',
146+
object: {
147+
value: { id: 'my-element', content: 'new-content' }
148+
}
149+
};
150+
151+
var oldDoc = {
152+
_id: 'myDoc',
153+
type: 'objectNestedInObjectDoc',
154+
object: {
155+
value: { id: 'my-element', content: 'new-content' }
156+
}
157+
};
158+
159+
testHelper.verifyDocumentReplaced(doc, oldDoc);
160+
});
161+
});
162+
163+
describe('when a hashtable with immutable values is nested in an array', function() {
164+
it('prevent modification of immutable values for hashtables that already exist', function() {
165+
var doc = {
166+
_id: 'myDoc',
167+
type: 'hashtableNestedInArrayDoc',
168+
elementList: [
169+
{ value: 2 }, // This element was originally at index 1 of the array
170+
{ value: 1 }, // This element was originally at index 0 of the array
171+
{ value: 3 }, // This element has not changed
172+
{ value: 4 } // Brand new element
173+
]
174+
};
175+
176+
var oldDoc = {
177+
_id: 'myDoc',
178+
type: 'hashtableNestedInArrayDoc',
179+
elementList: [
180+
{ value: 1 },
181+
{ value: 2 },
182+
{ value: 3 }
183+
]
184+
};
185+
186+
testHelper.verifyDocumentNotReplaced(
187+
doc,
188+
oldDoc,
189+
'hashtableNestedInArrayDoc',
190+
[
191+
errorFormatter.immutableItemViolation('elementList[1][value]'),
192+
errorFormatter.immutableItemViolation('elementList[0][value]')
193+
]);
194+
});
195+
196+
it('allow modification as long as immutable values do not change', function() {
197+
var doc = {
198+
_id: 'myDoc',
199+
type: 'hashtableNestedInArrayDoc',
200+
elementList: [
201+
{ value: 1 },
202+
{ value: 2 },
203+
{ value: 3 } // Brand new element
204+
]
205+
};
206+
207+
var oldDoc = {
208+
_id: 'myDoc',
209+
type: 'hashtableNestedInArrayDoc',
210+
elementList: [
211+
{ value: 1 },
212+
{ value: 2 }
213+
]
214+
};
215+
216+
testHelper.verifyDocumentReplaced(doc, oldDoc);
217+
});
218+
});
219+
220+
describe('when a hashtable with immutable values is nested in an object', function() {
221+
it('prevent modification of immutable values for hashtables that already exist', function() {
222+
var doc = {
223+
_id: 'myDoc',
224+
type: 'hashtableNestedInObjectDoc',
225+
object: {
226+
hash: { value: 2 }
227+
}
228+
};
229+
230+
var oldDoc = {
231+
_id: 'myDoc',
232+
type: 'hashtableNestedInObjectDoc',
233+
object: {
234+
hash: { value: 1 }
235+
}
236+
};
237+
238+
testHelper.verifyDocumentNotReplaced(
239+
doc,
240+
oldDoc,
241+
'hashtableNestedInObjectDoc',
242+
errorFormatter.immutableItemViolation('object.hash[value]'));
243+
});
244+
245+
it('allow modification as long as immutable values do not change', function() {
246+
var doc = {
247+
_id: 'myDoc',
248+
type: 'hashtableNestedInObjectDoc',
249+
object: {
250+
hash: { value: 1 }
251+
}
252+
};
253+
254+
var oldDoc = {
255+
_id: 'myDoc',
256+
type: 'hashtableNestedInObjectDoc',
257+
object: {
258+
hash: { value: 1 }
259+
}
260+
};
261+
262+
testHelper.verifyDocumentReplaced(doc, oldDoc);
263+
});
264+
});
265+
266+
describe('when a hashtable with immutable values is nested in a hashtable', function() {
267+
it('prevent modification of immutable values for hashtables that already exist', function() {
268+
var doc = {
269+
_id: 'myDoc',
270+
type: 'hashtableNestedInHashtableDoc',
271+
hash: {
272+
one: { value: 2 }, // This element was originally for key "two"
273+
two: { value: 1 }, // This element was originally for key "one"
274+
three: { value: 3 }, // This element has not changed
275+
four: { value: 4 } // Brand new element
276+
}
277+
};
278+
279+
var oldDoc = {
280+
_id: 'myDoc',
281+
type: 'hashtableNestedInHashtableDoc',
282+
hash: {
283+
one: { value: 1 },
284+
two: { value: 2 },
285+
three: { value: 3 }
286+
}
287+
};
288+
289+
testHelper.verifyDocumentNotReplaced(
290+
doc,
291+
oldDoc,
292+
'hashtableNestedInHashtableDoc',
293+
[
294+
errorFormatter.immutableItemViolation('hash[one][value]'),
295+
errorFormatter.immutableItemViolation('hash[two][value]')
296+
]);
297+
});
298+
299+
it('allow modification as long as immutable values do not change', function() {
300+
var doc = {
301+
_id: 'myDoc',
302+
type: 'hashtableNestedInHashtableDoc',
303+
hash: {
304+
one: { value: 1 },
305+
two: { value: 2 },
306+
three: { value: 3 } // Brand new element
307+
}
308+
};
309+
310+
var oldDoc = {
311+
_id: 'myDoc',
312+
type: 'hashtableNestedInHashtableDoc',
313+
hash: {
314+
one: { value: 1 },
315+
two: { value: 2 }
316+
}
317+
};
318+
319+
testHelper.verifyDocumentReplaced(doc, oldDoc);
320+
});
321+
});
322+
});

0 commit comments

Comments
 (0)