Skip to content

Bug/server 6899/embedded document increment #1219

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

21 changes: 21 additions & 0 deletions integration/test/ParseObjectTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,27 @@ describe('Parse Object', () => {
assert.equal(result.get('objectField').number, 20);
});

it('can increment nested field and retain full object', async () => {
const obj = new TestObject();
obj.set('objectField', { number: 5, letter: 'a' });
assert.equal(obj.get('objectField').number, 5);
assert.equal(obj.get('objectField').letter, 'a');
await obj.save();

obj.increment('objectField.number', 15);
assert.equal(obj.get('objectField').number, 20);
assert.equal(obj.get('objectField').letter, 'a');
await obj.save();

assert.equal(obj.get('objectField').number, 20);
assert.equal(obj.get('objectField').letter, 'a');

const query = new Parse.Query(TestObject);
const result = await query.get(obj.id);
assert.equal(result.get('objectField').number, 20);
assert.equal(result.get('objectField').letter, 'a');
});

it('can increment non existing field', async () => {
const obj = new TestObject();
obj.set('objectField', { number: 5 });
Expand Down
10 changes: 8 additions & 2 deletions src/ParseObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ class ParseObject {
for (attr in pending) {
if (pending[attr] instanceof RelationOp) {
changes[attr] = pending[attr].applyTo(undefined, this, attr);
} else if (!(attr in response)) {
} else if (!(attr in response) && !attr.includes('.')) {
// Only SetOps and UnsetOps should not come back with results
changes[attr] = pending[attr].applyTo(undefined);
}
Expand All @@ -407,7 +407,13 @@ class ParseObject {
} else if (attr === 'ACL') {
changes[attr] = new ParseACL(response[attr]);
} else if (attr !== 'objectId') {
changes[attr] = decode(response[attr]);
const val = decode(response[attr]);
if (val && Object.getPrototypeOf(val) === Object.prototype) {
// Update the object by merging in updates w/ old object
changes[attr] = { ...this.attributes[attr], ...val }
} else {
changes[attr] = val
}
if (changes[attr] instanceof UnsetOp) {
changes[attr] = undefined;
}
Expand Down
8 changes: 5 additions & 3 deletions src/__tests__/ObjectStateMutations-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,19 @@ describe('ObjectStateMutations', () => {
});

it('can estimate attributes for nested documents', () => {
const serverData = { objectField: { counter: 10 } };
const serverData = { objectField: { counter: 10, letter: 'a' } };
let pendingOps = [{ 'objectField.counter': new ParseOps.IncrementOp(2) }];
expect(ObjectStateMutations.estimateAttributes(serverData, pendingOps, 'someClass', 'someId')).toEqual({
objectField: {
counter: 12
counter: 12,
letter: 'a'
},
});
pendingOps = [{ 'objectField.counter': new ParseOps.SetOp(20) }];
expect(ObjectStateMutations.estimateAttributes(serverData, pendingOps, 'someClass', 'someId')).toEqual({
objectField: {
counter: 20
counter: 20,
letter: 'a'
},
});
});
Expand Down
45 changes: 42 additions & 3 deletions src/__tests__/ParseObject-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,20 +610,21 @@ describe('ParseObject', () => {
o._finishFetch({
objectId: 'setNested',
objectField: {
number: 5
number: 5,
letter: 'a'
},
otherField: {},
});

expect(o.attributes).toEqual({
objectField: { number: 5 },
objectField: { number: 5, letter: 'a' },
otherField: {},
});
o.set('otherField', { hello: 'world' });
o.set('objectField.number', 20);

expect(o.attributes).toEqual({
objectField: { number: 20 },
objectField: { number: 20, letter: 'a' },
otherField: { hello: 'world' },
});
expect(o.op('objectField.number') instanceof SetOp).toBe(true);
Expand All @@ -634,6 +635,44 @@ describe('ParseObject', () => {
});
});

it('can increment a nested field', () => {
const o = new ParseObject('Person');
o._finishFetch({
objectId: 'incNested',
objectField: {
number: 5,
letter: 'a'
},
});

expect(o.attributes).toEqual({
objectField: { number: 5, letter: 'a' },
});
o.increment('objectField.number');

expect(o.attributes).toEqual({
objectField: { number: 6, letter: 'a' },
});
expect(o.op('objectField.number') instanceof IncrementOp).toBe(true);
expect(o.dirtyKeys()).toEqual(['objectField.number', 'objectField']);
expect(o._getSaveJSON()).toEqual({
'objectField.number': {
"__op": "Increment",
"amount": 1
},
});

// Nested objects only return values changed
o._handleSaveResponse({
objectId: 'incNested',
objectField: {
number: 6
}
})
expect(o.get('objectField').number).toEqual(6)
expect(o.get('objectField').letter).toEqual('a')
});

it('ignore set nested field on new object', () => {
const o = new ParseObject('Person');
o.set('objectField.number', 20);
Expand Down