Skip to content

Commit bfbae78

Browse files
authored
Merge branch 'master' into master
2 parents 0abaf63 + 6034c04 commit bfbae78

15 files changed

+518
-27
lines changed

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ jobs:
2222
before_script:
2323
- npm install -g mongodb-runner
2424
- mongodb-runner start
25-
script:
25+
script:
2626
- npm run lint
2727
- npm test -- --maxWorkers=4
28+
- npm run build
2829
- npm run integration
2930
after_script: ./node_modules/codecov/bin/codecov -f ./coverage/coverage-final.json && rm -rf ./coverage
3031
# release on github latest branch
@@ -33,7 +34,7 @@ jobs:
3334
-
3435
before_script: skip
3536
after_script: skip
36-
script:
37+
script:
3738
- npm run release_docs
3839
- npm run build
3940
deploy:

CHANGELOG.md

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,40 @@
11
# Parse-SDK-JS
22

3+
## 2.2.0
4+
5+
- Support for Local Datastore ([#612](https://github.com/parse-community/parse-server/pull/612))
6+
- LiveQuery override data on update ([#718](https://github.com/parse-community/parse-server/pull/718)) (Requires Parse-Server 3.1.3+)
7+
- Support setting user from JSON (hydrate) ([#730](https://github.com/parse-community/parse-server/pull/730))
8+
- Improve dot notation for updating nested objects ([#729](https://github.com/parse-community/parse-server/pull/729))
9+
- LiveQuery handle unset operation ([#714](https://github.com/parse-community/parse-server/pull/714)) (Requires Parse-Server 3.1.3+)
10+
- Add original object to LiveQuery events ([#712](https://github.com/parse-community/parse-server/pull/712)) (Requires Parse-Server 3.1.3+)
11+
- Add support for providing file upload progress. ([#373](https://github.com/parse-community/parse-server/pull/373)) (Browser Only)
12+
- Support clone with relation ([#382](https://github.com/parse-community/parse-server/pull/382))
13+
- Add batchSize to saveAll / destroyAll ([#701](https://github.com/parse-community/parse-server/pull/701))
14+
- Add save Method for Parse.Config ([#684](https://github.com/parse-community/parse-server/pull/684))
15+
- Allow specific keys to be reverted in unsaved objects ([#565](https://github.com/parse-community/parse-server/pull/565))
16+
- Handle undefined in Cloud Code ([#682](https://github.com/parse-community/parse-server/pull/682))
17+
- Validate if geopoint values is number ([#671](https://github.com/parse-community/parse-server/pull/671))
18+
- LiveQuery Support for Subclasses ([#662](https://github.com/parse-community/parse-server/pull/662))
19+
320
## 2.1.0
421

5-
- Parse.Error now inherits from Error
22+
- Parse.Error now inherits from Error ([#658](https://github.com/parse-community/parse-server/pull/658))
623

724
## 2.0.2
825

9-
- Fixes issue affecting unsubscribing from liveQueries (#640)
10-
- Adds support for aggregate stages with identical names (#637)
11-
- Adds ability to fetch an object with includes (#631)
12-
- Adds support for $nor operator in queries (#634)
13-
- Adds support for containedBy operator in queries (#633)
14-
- Adds support for includeAll (#632)
26+
- Fixes issue affecting unsubscribing from liveQueries ([#640](https://github.com/parse-community/parse-server/pull/640))
27+
- Adds support for aggregate stages with identical names ([#637](https://github.com/parse-community/parse-server/pull/637))
28+
- Adds ability to fetch an object with includes ([#631](https://github.com/parse-community/parse-server/pull/631))
29+
- Adds support for $nor operator in queries ([#634](https://github.com/parse-community/parse-server/pull/634))
30+
- Adds support for containedBy operator in queries ([#633](https://github.com/parse-community/parse-server/pull/633))
31+
- Adds support for includeAll ([#632](https://github.com/parse-community/parse-server/pull/632))
1532

1633
## 2.0.1
1734

18-
- Ensure we only read the job status id header if present.
35+
- Ensure we only read the job status id header if present. ([#623](https://github.com/parse-community/parse-server/pull/623))
1936

2037
## 2.0.0
2138

22-
- Parse.Promise has been replaced by native Promises
23-
- Backbone style callbacks are removed
39+
- Parse.Promise has been replaced by native Promises ([#620](https://github.com/parse-community/parse-server/pull/620))
40+
- Backbone style callbacks are removed ([#620](https://github.com/parse-community/parse-server/pull/620))

integration/test/ParseLocalDatastoreTest.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ function runTest(controller) {
8181
assert.equal(cachedObject.field, 'new info');
8282
});
8383

84+
it(`${controller.name} can check if pinned`, async () => {
85+
const object = new TestObject();
86+
object.set('field', 'test');
87+
await object.save();
88+
89+
let isPinned = await object.isPinned();
90+
assert.equal(isPinned, false);
91+
92+
await object.pin();
93+
isPinned = await object.isPinned();
94+
assert.equal(isPinned, true);
95+
96+
await object.unPin();
97+
isPinned = await object.isPinned();
98+
assert.equal(isPinned, false);
99+
});
100+
84101
it(`${controller.name} can pin (recursive)`, async () => {
85102
const parent = new TestObject();
86103
const child = new Item();

integration/test/ParseObjectTest.js

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,181 @@ describe('Parse Object', () => {
229229
});
230230
});
231231

232+
it('can increment nested fields', async () => {
233+
const obj = new TestObject();
234+
obj.set('objectField', { number: 5 });
235+
assert.equal(obj.get('objectField').number, 5);
236+
await obj.save();
237+
238+
obj.increment('objectField.number', 15);
239+
assert.equal(obj.get('objectField').number, 20);
240+
await obj.save();
241+
242+
assert.equal(obj.get('objectField').number, 20);
243+
244+
const query = new Parse.Query(TestObject);
245+
const result = await query.get(obj.id);
246+
assert.equal(result.get('objectField').number, 20);
247+
});
248+
249+
it('can increment non existing field', async () => {
250+
const obj = new TestObject();
251+
obj.set('objectField', { number: 5 });
252+
await obj.save();
253+
254+
obj.increment('objectField.unknown', 15);
255+
assert.deepEqual(obj.get('objectField'), {
256+
number: 5,
257+
unknown: 15,
258+
});
259+
await obj.save();
260+
261+
const query = new Parse.Query(TestObject);
262+
const result = await query.get(obj.id);
263+
assert.equal(result.get('objectField').number, 5);
264+
assert.equal(result.get('objectField').unknown, 15);
265+
});
266+
267+
it('can increment nested fields two levels', async () => {
268+
const obj = new TestObject();
269+
obj.set('objectField', { foo: { bar: 5 } });
270+
assert.equal(obj.get('objectField').foo.bar, 5);
271+
await obj.save();
272+
273+
obj.increment('objectField.foo.bar', 15);
274+
assert.equal(obj.get('objectField').foo.bar, 20);
275+
await obj.save();
276+
277+
assert.equal(obj.get('objectField').foo.bar, 20);
278+
279+
const query = new Parse.Query(TestObject);
280+
const result = await query.get(obj.id);
281+
assert.equal(result.get('objectField').foo.bar, 20);
282+
});
283+
284+
it('can increment nested fields without object', async () => {
285+
const obj = new TestObject();
286+
obj.set('hello', 'world');
287+
await obj.save();
288+
289+
obj.increment('hello.dot', 15);
290+
try {
291+
await obj.save();
292+
assert.equal(false, true);
293+
} catch(error) {
294+
assert.equal(error.message, "Cannot create property 'dot' on string 'world'");
295+
}
296+
});
297+
298+
it('can set nested fields', async () => {
299+
const obj = new TestObject({ objectField: { number: 5 } });
300+
assert.equal(obj.get('objectField').number, 5);
301+
await obj.save();
302+
303+
assert.equal(obj.get('objectField').number, 5);
304+
obj.set('objectField.number', 20);
305+
assert.equal(obj.get('objectField').number, 20);
306+
await obj.save();
307+
308+
const query = new Parse.Query(TestObject);
309+
const result = await query.get(obj.id);
310+
assert.equal(result.get('objectField').number, 20);
311+
});
312+
313+
it('can set non existing fields', async () => {
314+
const obj = new TestObject();
315+
obj.set('objectField', { number: 5 });
316+
await obj.save();
317+
318+
obj.set('objectField.unknown', 20);
319+
await obj.save();
320+
const query = new Parse.Query(TestObject);
321+
const result = await query.get(obj.id);
322+
assert.equal(result.get('objectField').number, 5);
323+
assert.equal(result.get('objectField').unknown, 20);
324+
});
325+
326+
it('ignore set nested fields on new object', async () => {
327+
const obj = new TestObject();
328+
obj.set('objectField.number', 5);
329+
assert.deepEqual(obj._getPendingOps()[0], {});
330+
assert.equal(obj.get('objectField'), undefined);
331+
332+
await obj.save();
333+
assert.equal(obj.get('objectField'), undefined);
334+
});
335+
336+
it('can set nested fields two levels', async () => {
337+
const obj = new TestObject({ objectField: { foo: { bar: 5 } } });
338+
assert.equal(obj.get('objectField').foo.bar, 5);
339+
await obj.save();
340+
341+
assert.equal(obj.get('objectField').foo.bar, 5);
342+
obj.set('objectField.foo.bar', 20);
343+
assert.equal(obj.get('objectField').foo.bar, 20);
344+
await obj.save();
345+
346+
const query = new Parse.Query(TestObject);
347+
const result = await query.get(obj.id);
348+
assert.equal(result.get('objectField').foo.bar, 20);
349+
});
350+
351+
it('can unset nested fields', async () => {
352+
const obj = new TestObject({
353+
objectField: {
354+
number: 5,
355+
string: 'hello',
356+
}
357+
});
358+
await obj.save();
359+
360+
obj.unset('objectField.number');
361+
assert.equal(obj.get('objectField').number, undefined);
362+
assert.equal(obj.get('objectField').string, 'hello');
363+
await obj.save();
364+
365+
const query = new Parse.Query(TestObject);
366+
const result = await query.get(obj.id);
367+
assert.equal(result.get('objectField').number, undefined);
368+
assert.equal(result.get('objectField').string, 'hello');
369+
});
370+
371+
it('can unset nested fields two levels', async () => {
372+
const obj = new TestObject({
373+
objectField: {
374+
foo: {
375+
bar: 5,
376+
},
377+
string: 'hello',
378+
}
379+
});
380+
await obj.save();
381+
382+
obj.unset('objectField.foo.bar');
383+
assert.equal(obj.get('objectField').foo.bar, undefined);
384+
assert.equal(obj.get('objectField').string, 'hello');
385+
await obj.save();
386+
387+
const query = new Parse.Query(TestObject);
388+
const result = await query.get(obj.id);
389+
assert.equal(result.get('objectField').foo.bar, undefined);
390+
assert.equal(result.get('objectField').string, 'hello');
391+
});
392+
393+
it('can unset non existing fields', async () => {
394+
const obj = new TestObject();
395+
obj.set('objectField', { number: 5 });
396+
await obj.save();
397+
398+
obj.unset('objectField.unknown');
399+
await obj.save();
400+
401+
const query = new Parse.Query(TestObject);
402+
const result = await query.get(obj.id);
403+
assert.equal(result.get('objectField').number, 5);
404+
assert.equal(result.get('objectField').unknown, undefined);
405+
});
406+
232407
it('can set keys to null', (done) => {
233408
const obj = new TestObject();
234409
obj.set('foo', null);

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "parse",
3-
"version": "2.1.0",
3+
"version": "2.2.0",
44
"description": "The Parse JavaScript SDK",
55
"homepage": "https://www.parse.com",
66
"keywords": [
@@ -29,7 +29,7 @@
2929
},
3030
"dependencies": {
3131
"@babel/runtime": "^7.3.1",
32-
"ws": "6.1.2",
32+
"ws": "6.1.4",
3333
"xmlhttprequest": "1.8.0"
3434
},
3535
"devDependencies": {
@@ -74,7 +74,6 @@
7474
"test": "PARSE_BUILD=node jest",
7575
"lint": "eslint --cache src/ integration/",
7676
"lint:fix": "eslint --fix --cache src/ integration/",
77-
"preintegration": "npm run build",
7877
"watch": "PARSE_BUILD=${PARSE_BUILD:=node} gulp watch",
7978
"integration": "TESTING=1 jasmine --config=jasmine.json",
8079
"docs": "jsdoc -c ./jsdoc-conf.json ./src",

src/CoreManager.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ type UserController = {
122122
signUp: (user: ParseUser, attrs: AttributeMap, options: RequestOptions) => Promise;
123123
logIn: (user: ParseUser, options: RequestOptions) => Promise;
124124
become: (options: RequestOptions) => Promise;
125+
hydrate: (userJSON: AttributeMap) => Promise;
125126
logOut: () => Promise;
126127
requestPasswordReset: (email: string, options: RequestOptions) => Promise;
127128
updateUserOnDisk: (user: ParseUser) => Promise;

src/LiveQueryClient.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
/* global WebSocket */
1111

12+
import CoreManager from './CoreManager';
1213
import EventEmitter from './EventEmitter';
1314
import ParseObject from './ParseObject';
1415
import LiveQuerySubscription from './LiveQuerySubscription';
@@ -392,7 +393,9 @@ class LiveQueryClient extends EventEmitter {
392393
if (!subscription) {
393394
break;
394395
}
396+
let override = false;
395397
if (data.original) {
398+
override = true;
396399
delete data.original.__type;
397400
// Check for removed fields
398401
for (const field in data.original) {
@@ -403,9 +406,14 @@ class LiveQueryClient extends EventEmitter {
403406
data.original = ParseObject.fromJSON(data.original, false);
404407
}
405408
delete data.object.__type;
406-
const parseObject = ParseObject.fromJSON(data.object, false);
409+
const parseObject = ParseObject.fromJSON(data.object, override);
407410

408411
subscription.emit(data.op, parseObject, data.original);
412+
413+
const localDatastore = CoreManager.getLocalDatastore();
414+
if (override && localDatastore.isEnabled) {
415+
localDatastore._updateObjectIfPinned(parseObject).then(() => {});
416+
}
409417
}
410418
}
411419
}

src/ObjectStateMutations.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,18 @@ export function estimateAttributes(serverData: AttributeMap, pendingOps: Array<O
123123
);
124124
}
125125
} else {
126-
data[attr] = pendingOps[i][attr].applyTo(data[attr]);
126+
if (attr.includes('.')) {
127+
// convert a.b.c into { a: { b: { c: value } } }
128+
const fields = attr.split('.');
129+
const last = fields[fields.length - 1];
130+
let object = Object.assign({}, data);
131+
for (let i = 0; i < fields.length - 1; i++) {
132+
object = object[fields[i]];
133+
}
134+
object[last] = pendingOps[i][attr].applyTo(object[last]);
135+
} else {
136+
data[attr] = pendingOps[i][attr].applyTo(data[attr]);
137+
}
127138
}
128139
}
129140
}

0 commit comments

Comments
 (0)