Skip to content

Commit 1d30b03

Browse files
authored
LDS: Support Users (#801)
Closes: #796
1 parent 5ab0542 commit 1d30b03

File tree

4 files changed

+150
-2
lines changed

4 files changed

+150
-2
lines changed

integration/cloud/main.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ Parse.Cloud.define('TestFetchFromLocalDatastore', function (request) {
1414
return object.save();
1515
});
1616

17+
Parse.Cloud.define('UpdateUser', function (request) {
18+
const user = new Parse.User();
19+
user.id = request.params.id;
20+
user.set('foo', 'changed');
21+
return user.save(null, { useMasterKey: true });
22+
});
23+
1724
Parse.Cloud.define('CloudFunctionUndefined', function() {
1825
return undefined;
1926
});

integration/test/ParseLocalDatastoreTest.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,46 @@ function runTest(controller) {
150150
}
151151
});
152152

153+
it(`${controller.name} can pin user (unsaved)`, async () => {
154+
const user = new Parse.User();
155+
user.set('field', 'test');
156+
await user.pin();
157+
158+
const json = user._toFullJSON();
159+
json._localId = user._localId;
160+
161+
const localDatastore = await Parse.LocalDatastore._getAllContents();
162+
const cachedObject = localDatastore[LDS_KEY(user)][0];
163+
assert.equal(Object.keys(localDatastore).length, 2);
164+
assert.deepEqual(localDatastore[DEFAULT_PIN], [LDS_KEY(user)]);
165+
assert.deepEqual(localDatastore[LDS_KEY(user)], [json]);
166+
assert.equal(cachedObject.objectId, user.id);
167+
assert.equal(cachedObject.field, 'test');
168+
await Parse.User.logOut();
169+
});
170+
171+
it(`${controller.name} can pin user (saved)`, async () => {
172+
const user = new Parse.User();
173+
user.set('field', 'test');
174+
user.setPassword('asdf');
175+
user.setUsername('zxcv');
176+
await user.signUp()
177+
await user.pin();
178+
179+
const json = user._toFullJSON();
180+
delete json.password;
181+
182+
const localDatastore = await Parse.LocalDatastore._getAllContents();
183+
const cachedObject = localDatastore[LDS_KEY(user)][0];
184+
185+
assert.equal(Object.keys(localDatastore).length, 2);
186+
assert.deepEqual(localDatastore[DEFAULT_PIN], [LDS_KEY(user)]);
187+
assert.deepEqual(localDatastore[LDS_KEY(user)], [json]);
188+
assert.equal(cachedObject.objectId, user.id);
189+
assert.equal(cachedObject.field, 'test');
190+
await Parse.User.logOut();
191+
});
192+
153193
it(`${controller.name} can pin (saved)`, async () => {
154194
const object = new TestObject();
155195
object.set('field', 'test');
@@ -218,6 +258,31 @@ function runTest(controller) {
218258
assert.deepEqual(localDatastore[LDS_KEY(grandchild)], [grandchild._toFullJSON()]);
219259
});
220260

261+
it(`${controller.name} can pin user (recursive)`, async () => {
262+
const parent = new TestObject();
263+
const child = new Parse.User();
264+
child.setUsername('username');
265+
child.setPassword('password');
266+
await child.signUp();
267+
parent.set('field', 'test');
268+
parent.set('child', child);
269+
await parent.save();
270+
await parent.pin();
271+
272+
const parentJSON = parent._toFullJSON();
273+
const childJSON = child._toFullJSON();
274+
delete childJSON.password;
275+
delete parentJSON.child.password;
276+
277+
const localDatastore = await Parse.LocalDatastore._getAllContents();
278+
assert.equal(Object.keys(localDatastore).length, 3);
279+
assert.equal(localDatastore[DEFAULT_PIN].includes(LDS_KEY(parent)), true);
280+
assert.equal(localDatastore[DEFAULT_PIN].includes(LDS_KEY(child)), true);
281+
assert.deepEqual(localDatastore[LDS_KEY(parent)], [parentJSON]);
282+
assert.deepEqual(localDatastore[LDS_KEY(child)], [childJSON]);
283+
await Parse.User.logOut();
284+
});
285+
221286
it(`${controller.name} can pinAll (unsaved)`, async () => {
222287
const obj1 = new TestObject();
223288
const obj2 = new TestObject();
@@ -945,6 +1010,27 @@ function runTest(controller) {
9451010
const itemJSON = updatedLDS[LDS_KEY(item)];
9461011
assert.equal(itemJSON.foo, 'changed');
9471012
});
1013+
1014+
it(`${controller.name} can update Local Datastore User from network`, async () => {
1015+
const user = new Parse.User();
1016+
user.setUsername('asdf');
1017+
user.setPassword('zxcv');
1018+
await user.signUp();
1019+
await user.pin();
1020+
1021+
// Updates user with { foo: 'changed' }
1022+
const params = { id: user.id };
1023+
await Parse.Cloud.run('UpdateUser', params);
1024+
1025+
Parse.LocalDatastore.isSyncing = false;
1026+
1027+
await Parse.LocalDatastore.updateFromServer();
1028+
1029+
const updatedLDS = await Parse.LocalDatastore._getAllContents();
1030+
const userJSON = updatedLDS[LDS_KEY(user)];
1031+
assert.equal(userJSON.foo, 'changed');
1032+
await Parse.User.logOut();
1033+
});
9481034
});
9491035

9501036
describe(`Parse Query Pinning (${controller.name})`, () => {
@@ -1016,6 +1102,19 @@ function runTest(controller) {
10161102
assert.equal(results.length, 3);
10171103
});
10181104

1105+
it(`${controller.name} can query user from pin`, async () => {
1106+
const user = await Parse.User.signUp('asdf', 'zxcv', { foo: 'bar' });
1107+
await user.pin();
1108+
1109+
const query = new Parse.Query(Parse.User);
1110+
query.fromPin();
1111+
const results = await query.find();
1112+
1113+
assert.equal(results.length, 1);
1114+
assert.equal(results[0].getSessionToken(), user.getSessionToken());
1115+
await Parse.User.logOut();
1116+
});
1117+
10191118
it(`${controller.name} can do basic queries`, async () => {
10201119
const baz = new TestObject({ foo: 'baz' });
10211120
const qux = new TestObject({ foo: 'qux' });
@@ -2551,6 +2650,7 @@ describe('Parse LocalDatastore', () => {
25512650
Parse.initialize('integration', null, 'notsosecret');
25522651
Parse.CoreManager.set('SERVER_URL', 'http://localhost:1337/parse');
25532652
Parse.enableLocalDatastore();
2653+
Parse.User.enableUnsafeCurrentUser();
25542654
Parse.Storage._clear();
25552655
clear().then(() => {
25562656
done()

src/LocalDatastore.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ const LocalDatastore = {
141141
const encountered = {};
142142
const json = object._toFullJSON();
143143
for (const key in json) {
144-
if (json[key].__type && json[key].__type === 'Object') {
144+
if (json[key] && json[key].__type && json[key].__type === 'Object') {
145145
this._traverse(json[key], encountered);
146146
}
147147
}
@@ -341,7 +341,13 @@ const LocalDatastore = {
341341
const pointersHash = {};
342342
for (const key of keys) {
343343
// Ignore the OBJECT_PREFIX
344-
const [ , , className, objectId] = key.split('_');
344+
let [ , , className, objectId] = key.split('_');
345+
346+
// User key is split into [ 'Parse', 'LDS', '', 'User', 'objectId' ]
347+
if (key.split('_').length === 5 && key.split('_')[3] === 'User') {
348+
className = '_User';
349+
objectId = key.split('_')[4];
350+
}
345351
if (objectId.startsWith('local')) {
346352
continue;
347353
}

src/__tests__/LocalDatastore-test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ const CoreManager = require('../CoreManager');
9898
const LocalDatastore = require('../LocalDatastore');
9999
const ParseObject = require('../ParseObject');
100100
const ParseQuery = require('../ParseQuery');
101+
const ParseUser = require('../ParseUser').default;
101102
const RNDatastoreController = require('../LocalDatastoreController.react-native');
102103
const BrowserDatastoreController = require('../LocalDatastoreController.browser');
103104
const DefaultDatastoreController = require('../LocalDatastoreController.default');
@@ -647,6 +648,40 @@ describe('LocalDatastore', () => {
647648
expect(mockLocalStorageController.pinWithName).toHaveBeenCalledTimes(1);
648649
});
649650

651+
it('updateFromServer on user', async () => {
652+
LocalDatastore.isEnabled = true;
653+
LocalDatastore.isSyncing = false;
654+
655+
const user = new ParseUser();
656+
user.id = '1234';
657+
user._localId = null;
658+
659+
const USER_KEY = LocalDatastore.getKeyForObject(user);
660+
console.log(USER_KEY);
661+
const LDS = {
662+
[USER_KEY]: [user._toFullJSON()],
663+
[`${PIN_PREFIX}_testPinName`]: [USER_KEY],
664+
[DEFAULT_PIN]: [USER_KEY],
665+
};
666+
667+
mockLocalStorageController
668+
.getAllContents
669+
.mockImplementationOnce(() => LDS);
670+
671+
user.set('updatedField', 'foo');
672+
mockQueryFind.mockImplementationOnce(() => Promise.resolve([user]));
673+
674+
await LocalDatastore.updateFromServer();
675+
676+
expect(mockLocalStorageController.getAllContents).toHaveBeenCalledTimes(1);
677+
expect(ParseQuery).toHaveBeenCalledTimes(1);
678+
const mockQueryInstance = ParseQuery.mock.instances[0];
679+
680+
expect(mockQueryInstance.equalTo.mock.calls.length).toBe(1);
681+
expect(mockQueryFind).toHaveBeenCalledTimes(1);
682+
expect(mockLocalStorageController.pinWithName).toHaveBeenCalledTimes(1);
683+
});
684+
650685
it('updateFromServer ignore unsaved objects', async () => {
651686
LocalDatastore.isEnabled = true;
652687
LocalDatastore.isSyncing = false;

0 commit comments

Comments
 (0)