LocalDatastore.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
  4. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  5. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  6. var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
  7. var _CoreManager = _interopRequireDefault(require("./CoreManager"));
  8. var _ParseQuery = _interopRequireDefault(require("./ParseQuery"));
  9. var _LocalDatastoreUtils = require("./LocalDatastoreUtils");
  10. /**
  11. * Copyright (c) 2015-present, Parse, LLC.
  12. * All rights reserved.
  13. *
  14. * This source code is licensed under the BSD-style license found in the
  15. * LICENSE file in the root directory of this source tree. An additional grant
  16. * of patent rights can be found in the PATENTS file in the same directory.
  17. *
  18. * @flow
  19. */
  20. /**
  21. * Provides a local datastore which can be used to store and retrieve <code>Parse.Object</code>. <br />
  22. * To enable this functionality, call <code>Parse.enableLocalDatastore()</code>.
  23. *
  24. * Pin object to add to local datastore
  25. *
  26. * <pre>await object.pin();</pre>
  27. * <pre>await object.pinWithName('pinName');</pre>
  28. *
  29. * Query pinned objects
  30. *
  31. * <pre>query.fromLocalDatastore();</pre>
  32. * <pre>query.fromPin();</pre>
  33. * <pre>query.fromPinWithName();</pre>
  34. *
  35. * <pre>const localObjects = await query.find();</pre>
  36. *
  37. * @class Parse.LocalDatastore
  38. * @static
  39. */
  40. var LocalDatastore = {
  41. isEnabled: false,
  42. isSyncing: false,
  43. fromPinWithName: function (name
  44. /*: string*/
  45. )
  46. /*: Promise<Array<Object>>*/
  47. {
  48. var controller = _CoreManager.default.getLocalDatastoreController();
  49. return controller.fromPinWithName(name);
  50. },
  51. pinWithName: function (name
  52. /*: string*/
  53. , value
  54. /*: any*/
  55. )
  56. /*: Promise<void>*/
  57. {
  58. var controller = _CoreManager.default.getLocalDatastoreController();
  59. return controller.pinWithName(name, value);
  60. },
  61. unPinWithName: function (name
  62. /*: string*/
  63. )
  64. /*: Promise<void>*/
  65. {
  66. var controller = _CoreManager.default.getLocalDatastoreController();
  67. return controller.unPinWithName(name);
  68. },
  69. _getAllContents: function ()
  70. /*: Promise<Object>*/
  71. {
  72. var controller = _CoreManager.default.getLocalDatastoreController();
  73. return controller.getAllContents();
  74. },
  75. // Use for testing
  76. _getRawStorage: function ()
  77. /*: Promise<Object>*/
  78. {
  79. var controller = _CoreManager.default.getLocalDatastoreController();
  80. return controller.getRawStorage();
  81. },
  82. _clear: function ()
  83. /*: Promise<void>*/
  84. {
  85. var controller = _CoreManager.default.getLocalDatastoreController();
  86. return controller.clear();
  87. },
  88. // Pin the object and children recursively
  89. // Saves the object and children key to Pin Name
  90. _handlePinAllWithName: function () {
  91. var _handlePinAllWithName2 = (0, _asyncToGenerator2.default)(
  92. /*#__PURE__*/
  93. _regenerator.default.mark(function _callee(name
  94. /*: string*/
  95. , objects
  96. /*: Array<ParseObject>*/
  97. ) {
  98. var pinName, toPinPromises, objectKeys, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, parent, children, parentKey, json, objectKey, fromPinPromise, _ref, _ref2, pinned, toPin;
  99. return _regenerator.default.wrap(function (_context) {
  100. while (1) {
  101. switch (_context.prev = _context.next) {
  102. case 0:
  103. pinName = this.getPinName(name);
  104. toPinPromises = [];
  105. objectKeys = [];
  106. _iteratorNormalCompletion = true;
  107. _didIteratorError = false;
  108. _iteratorError = undefined;
  109. _context.prev = 6;
  110. for (_iterator = objects[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
  111. parent = _step.value;
  112. children = this._getChildren(parent);
  113. parentKey = this.getKeyForObject(parent);
  114. json = parent._toFullJSON();
  115. if (parent._localId) {
  116. json._localId = parent._localId;
  117. }
  118. children[parentKey] = json;
  119. for (objectKey in children) {
  120. objectKeys.push(objectKey);
  121. toPinPromises.push(this.pinWithName(objectKey, [children[objectKey]]));
  122. }
  123. }
  124. _context.next = 14;
  125. break;
  126. case 10:
  127. _context.prev = 10;
  128. _context.t0 = _context["catch"](6);
  129. _didIteratorError = true;
  130. _iteratorError = _context.t0;
  131. case 14:
  132. _context.prev = 14;
  133. _context.prev = 15;
  134. if (!_iteratorNormalCompletion && _iterator.return != null) {
  135. _iterator.return();
  136. }
  137. case 17:
  138. _context.prev = 17;
  139. if (!_didIteratorError) {
  140. _context.next = 20;
  141. break;
  142. }
  143. throw _iteratorError;
  144. case 20:
  145. return _context.finish(17);
  146. case 21:
  147. return _context.finish(14);
  148. case 22:
  149. fromPinPromise = this.fromPinWithName(pinName);
  150. _context.next = 25;
  151. return Promise.all([fromPinPromise, toPinPromises]);
  152. case 25:
  153. _ref = _context.sent;
  154. _ref2 = (0, _slicedToArray2.default)(_ref, 1);
  155. pinned = _ref2[0];
  156. toPin = (0, _toConsumableArray2.default)(new Set([].concat((0, _toConsumableArray2.default)(pinned || []), objectKeys)));
  157. return _context.abrupt("return", this.pinWithName(pinName, toPin));
  158. case 30:
  159. case "end":
  160. return _context.stop();
  161. }
  162. }
  163. }, _callee, this, [[6, 10, 14, 22], [15,, 17, 21]]);
  164. }));
  165. return function () {
  166. return _handlePinAllWithName2.apply(this, arguments);
  167. };
  168. }(),
  169. // Removes object and children keys from pin name
  170. // Keeps the object and children pinned
  171. _handleUnPinAllWithName: function () {
  172. var _handleUnPinAllWithName2 = (0, _asyncToGenerator2.default)(
  173. /*#__PURE__*/
  174. _regenerator.default.mark(function _callee2(name
  175. /*: string*/
  176. , objects
  177. /*: Array<ParseObject>*/
  178. ) {
  179. var localDatastore, pinName, promises, objectKeys, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _objectKeys, parent, children, parentKey, pinned, _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, objectKey, hasReference, key, pinnedObjects;
  180. return _regenerator.default.wrap(function (_context2) {
  181. while (1) {
  182. switch (_context2.prev = _context2.next) {
  183. case 0:
  184. _context2.next = 2;
  185. return this._getAllContents();
  186. case 2:
  187. localDatastore = _context2.sent;
  188. pinName = this.getPinName(name);
  189. promises = [];
  190. objectKeys = [];
  191. _iteratorNormalCompletion2 = true;
  192. _didIteratorError2 = false;
  193. _iteratorError2 = undefined;
  194. _context2.prev = 9;
  195. for (_iterator2 = objects[Symbol.iterator](); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
  196. parent = _step2.value;
  197. children = this._getChildren(parent);
  198. parentKey = this.getKeyForObject(parent);
  199. (_objectKeys = objectKeys).push.apply(_objectKeys, [parentKey].concat((0, _toConsumableArray2.default)(Object.keys(children))));
  200. }
  201. _context2.next = 17;
  202. break;
  203. case 13:
  204. _context2.prev = 13;
  205. _context2.t0 = _context2["catch"](9);
  206. _didIteratorError2 = true;
  207. _iteratorError2 = _context2.t0;
  208. case 17:
  209. _context2.prev = 17;
  210. _context2.prev = 18;
  211. if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
  212. _iterator2.return();
  213. }
  214. case 20:
  215. _context2.prev = 20;
  216. if (!_didIteratorError2) {
  217. _context2.next = 23;
  218. break;
  219. }
  220. throw _iteratorError2;
  221. case 23:
  222. return _context2.finish(20);
  223. case 24:
  224. return _context2.finish(17);
  225. case 25:
  226. objectKeys = (0, _toConsumableArray2.default)(new Set(objectKeys));
  227. pinned = localDatastore[pinName] || [];
  228. pinned = pinned.filter(function (item) {
  229. return !objectKeys.includes(item);
  230. });
  231. if (pinned.length == 0) {
  232. promises.push(this.unPinWithName(pinName));
  233. delete localDatastore[pinName];
  234. } else {
  235. promises.push(this.pinWithName(pinName, pinned));
  236. localDatastore[pinName] = pinned;
  237. }
  238. _iteratorNormalCompletion3 = true;
  239. _didIteratorError3 = false;
  240. _iteratorError3 = undefined;
  241. _context2.prev = 32;
  242. _iterator3 = objectKeys[Symbol.iterator]();
  243. case 34:
  244. if (_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done) {
  245. _context2.next = 51;
  246. break;
  247. }
  248. objectKey = _step3.value;
  249. hasReference = false;
  250. _context2.t1 = _regenerator.default.keys(localDatastore);
  251. case 38:
  252. if ((_context2.t2 = _context2.t1()).done) {
  253. _context2.next = 47;
  254. break;
  255. }
  256. key = _context2.t2.value;
  257. if (!(key === _LocalDatastoreUtils.DEFAULT_PIN || key.startsWith(_LocalDatastoreUtils.PIN_PREFIX))) {
  258. _context2.next = 45;
  259. break;
  260. }
  261. pinnedObjects = localDatastore[key] || [];
  262. if (!pinnedObjects.includes(objectKey)) {
  263. _context2.next = 45;
  264. break;
  265. }
  266. hasReference = true;
  267. return _context2.abrupt("break", 47);
  268. case 45:
  269. _context2.next = 38;
  270. break;
  271. case 47:
  272. if (!hasReference) {
  273. promises.push(this.unPinWithName(objectKey));
  274. }
  275. case 48:
  276. _iteratorNormalCompletion3 = true;
  277. _context2.next = 34;
  278. break;
  279. case 51:
  280. _context2.next = 57;
  281. break;
  282. case 53:
  283. _context2.prev = 53;
  284. _context2.t3 = _context2["catch"](32);
  285. _didIteratorError3 = true;
  286. _iteratorError3 = _context2.t3;
  287. case 57:
  288. _context2.prev = 57;
  289. _context2.prev = 58;
  290. if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
  291. _iterator3.return();
  292. }
  293. case 60:
  294. _context2.prev = 60;
  295. if (!_didIteratorError3) {
  296. _context2.next = 63;
  297. break;
  298. }
  299. throw _iteratorError3;
  300. case 63:
  301. return _context2.finish(60);
  302. case 64:
  303. return _context2.finish(57);
  304. case 65:
  305. return _context2.abrupt("return", Promise.all(promises));
  306. case 66:
  307. case "end":
  308. return _context2.stop();
  309. }
  310. }
  311. }, _callee2, this, [[9, 13, 17, 25], [18,, 20, 24], [32, 53, 57, 65], [58,, 60, 64]]);
  312. }));
  313. return function () {
  314. return _handleUnPinAllWithName2.apply(this, arguments);
  315. };
  316. }(),
  317. // Retrieve all pointer fields from object recursively
  318. _getChildren: function (object
  319. /*: ParseObject*/
  320. ) {
  321. var encountered = {};
  322. var json = object._toFullJSON();
  323. for (var key in json) {
  324. if (json[key] && json[key].__type && json[key].__type === 'Object') {
  325. this._traverse(json[key], encountered);
  326. }
  327. }
  328. return encountered;
  329. },
  330. _traverse: function (object
  331. /*: any*/
  332. , encountered
  333. /*: any*/
  334. ) {
  335. if (!object.objectId) {
  336. return;
  337. } else {
  338. var objectKey = this.getKeyForObject(object);
  339. if (encountered[objectKey]) {
  340. return;
  341. }
  342. encountered[objectKey] = object;
  343. }
  344. for (var key in object) {
  345. var json = object[key];
  346. if (!object[key]) {
  347. json = object;
  348. }
  349. if (json.__type && json.__type === 'Object') {
  350. this._traverse(json, encountered);
  351. }
  352. }
  353. },
  354. // Transform keys in pin name to objects
  355. _serializeObjectsFromPinName: function () {
  356. var _serializeObjectsFromPinName2 = (0, _asyncToGenerator2.default)(
  357. /*#__PURE__*/
  358. _regenerator.default.mark(function _callee3(name
  359. /*: string*/
  360. ) {
  361. var _this = this,
  362. _ref3;
  363. var localDatastore, allObjects, key, pinName, pinned, promises, objects;
  364. return _regenerator.default.wrap(function (_context3) {
  365. while (1) {
  366. switch (_context3.prev = _context3.next) {
  367. case 0:
  368. _context3.next = 2;
  369. return this._getAllContents();
  370. case 2:
  371. localDatastore = _context3.sent;
  372. allObjects = [];
  373. for (key in localDatastore) {
  374. if (key.startsWith(_LocalDatastoreUtils.OBJECT_PREFIX)) {
  375. allObjects.push(localDatastore[key][0]);
  376. }
  377. }
  378. if (name) {
  379. _context3.next = 7;
  380. break;
  381. }
  382. return _context3.abrupt("return", allObjects);
  383. case 7:
  384. pinName = this.getPinName(name);
  385. pinned = localDatastore[pinName];
  386. if (Array.isArray(pinned)) {
  387. _context3.next = 11;
  388. break;
  389. }
  390. return _context3.abrupt("return", []);
  391. case 11:
  392. promises = pinned.map(function (objectKey) {
  393. return _this.fromPinWithName(objectKey);
  394. });
  395. _context3.next = 14;
  396. return Promise.all(promises);
  397. case 14:
  398. objects = _context3.sent;
  399. objects = (_ref3 = []).concat.apply(_ref3, (0, _toConsumableArray2.default)(objects));
  400. return _context3.abrupt("return", objects.filter(function (object) {
  401. return object != null;
  402. }));
  403. case 17:
  404. case "end":
  405. return _context3.stop();
  406. }
  407. }
  408. }, _callee3, this);
  409. }));
  410. return function () {
  411. return _serializeObjectsFromPinName2.apply(this, arguments);
  412. };
  413. }(),
  414. // Replaces object pointers with pinned pointers
  415. // The object pointers may contain old data
  416. // Uses Breadth First Search Algorithm
  417. _serializeObject: function () {
  418. var _serializeObject2 = (0, _asyncToGenerator2.default)(
  419. /*#__PURE__*/
  420. _regenerator.default.mark(function _callee4(objectKey
  421. /*: string*/
  422. , localDatastore
  423. /*: any*/
  424. ) {
  425. var LDS, root, queue, meta, uniqueId, nodeId, subTreeRoot, field, value, key, pointer;
  426. return _regenerator.default.wrap(function (_context4) {
  427. while (1) {
  428. switch (_context4.prev = _context4.next) {
  429. case 0:
  430. LDS = localDatastore;
  431. if (LDS) {
  432. _context4.next = 5;
  433. break;
  434. }
  435. _context4.next = 4;
  436. return this._getAllContents();
  437. case 4:
  438. LDS = _context4.sent;
  439. case 5:
  440. if (!(!LDS[objectKey] || LDS[objectKey].length === 0)) {
  441. _context4.next = 7;
  442. break;
  443. }
  444. return _context4.abrupt("return", null);
  445. case 7:
  446. root = LDS[objectKey][0];
  447. queue = [];
  448. meta = {};
  449. uniqueId = 0;
  450. meta[uniqueId] = root;
  451. queue.push(uniqueId);
  452. while (queue.length !== 0) {
  453. nodeId = queue.shift();
  454. subTreeRoot = meta[nodeId];
  455. for (field in subTreeRoot) {
  456. value = subTreeRoot[field];
  457. if (value.__type && value.__type === 'Object') {
  458. key = this.getKeyForObject(value);
  459. if (LDS[key] && LDS[key].length > 0) {
  460. pointer = LDS[key][0];
  461. uniqueId++;
  462. meta[uniqueId] = pointer;
  463. subTreeRoot[field] = pointer;
  464. queue.push(uniqueId);
  465. }
  466. }
  467. }
  468. }
  469. return _context4.abrupt("return", root);
  470. case 15:
  471. case "end":
  472. return _context4.stop();
  473. }
  474. }
  475. }, _callee4, this);
  476. }));
  477. return function () {
  478. return _serializeObject2.apply(this, arguments);
  479. };
  480. }(),
  481. // Called when an object is save / fetched
  482. // Update object pin value
  483. _updateObjectIfPinned: function () {
  484. var _updateObjectIfPinned2 = (0, _asyncToGenerator2.default)(
  485. /*#__PURE__*/
  486. _regenerator.default.mark(function _callee5(object
  487. /*: ParseObject*/
  488. ) {
  489. var objectKey, pinned;
  490. return _regenerator.default.wrap(function (_context5) {
  491. while (1) {
  492. switch (_context5.prev = _context5.next) {
  493. case 0:
  494. if (this.isEnabled) {
  495. _context5.next = 2;
  496. break;
  497. }
  498. return _context5.abrupt("return");
  499. case 2:
  500. objectKey = this.getKeyForObject(object);
  501. _context5.next = 5;
  502. return this.fromPinWithName(objectKey);
  503. case 5:
  504. pinned = _context5.sent;
  505. if (!(!pinned || pinned.length === 0)) {
  506. _context5.next = 8;
  507. break;
  508. }
  509. return _context5.abrupt("return");
  510. case 8:
  511. return _context5.abrupt("return", this.pinWithName(objectKey, [object._toFullJSON()]));
  512. case 9:
  513. case "end":
  514. return _context5.stop();
  515. }
  516. }
  517. }, _callee5, this);
  518. }));
  519. return function () {
  520. return _updateObjectIfPinned2.apply(this, arguments);
  521. };
  522. }(),
  523. // Called when object is destroyed
  524. // Unpin object and remove all references from pin names
  525. // TODO: Destroy children?
  526. _destroyObjectIfPinned: function () {
  527. var _destroyObjectIfPinned2 = (0, _asyncToGenerator2.default)(
  528. /*#__PURE__*/
  529. _regenerator.default.mark(function _callee6(object
  530. /*: ParseObject*/
  531. ) {
  532. var localDatastore, objectKey, pin, promises, key, pinned;
  533. return _regenerator.default.wrap(function (_context6) {
  534. while (1) {
  535. switch (_context6.prev = _context6.next) {
  536. case 0:
  537. if (this.isEnabled) {
  538. _context6.next = 2;
  539. break;
  540. }
  541. return _context6.abrupt("return");
  542. case 2:
  543. _context6.next = 4;
  544. return this._getAllContents();
  545. case 4:
  546. localDatastore = _context6.sent;
  547. objectKey = this.getKeyForObject(object);
  548. pin = localDatastore[objectKey];
  549. if (pin) {
  550. _context6.next = 9;
  551. break;
  552. }
  553. return _context6.abrupt("return");
  554. case 9:
  555. promises = [this.unPinWithName(objectKey)];
  556. delete localDatastore[objectKey];
  557. for (key in localDatastore) {
  558. if (key === _LocalDatastoreUtils.DEFAULT_PIN || key.startsWith(_LocalDatastoreUtils.PIN_PREFIX)) {
  559. pinned = localDatastore[key] || [];
  560. if (pinned.includes(objectKey)) {
  561. pinned = pinned.filter(function (item) {
  562. return item !== objectKey;
  563. });
  564. if (pinned.length == 0) {
  565. promises.push(this.unPinWithName(key));
  566. delete localDatastore[key];
  567. } else {
  568. promises.push(this.pinWithName(key, pinned));
  569. localDatastore[key] = pinned;
  570. }
  571. }
  572. }
  573. }
  574. return _context6.abrupt("return", Promise.all(promises));
  575. case 13:
  576. case "end":
  577. return _context6.stop();
  578. }
  579. }
  580. }, _callee6, this);
  581. }));
  582. return function () {
  583. return _destroyObjectIfPinned2.apply(this, arguments);
  584. };
  585. }(),
  586. // Update pin and references of the unsaved object
  587. _updateLocalIdForObject: function () {
  588. var _updateLocalIdForObject2 = (0, _asyncToGenerator2.default)(
  589. /*#__PURE__*/
  590. _regenerator.default.mark(function _callee7(localId
  591. /*: string*/
  592. , object
  593. /*: ParseObject*/
  594. ) {
  595. var localKey, objectKey, unsaved, promises, localDatastore, key, pinned;
  596. return _regenerator.default.wrap(function (_context7) {
  597. while (1) {
  598. switch (_context7.prev = _context7.next) {
  599. case 0:
  600. if (this.isEnabled) {
  601. _context7.next = 2;
  602. break;
  603. }
  604. return _context7.abrupt("return");
  605. case 2:
  606. localKey = "".concat(_LocalDatastoreUtils.OBJECT_PREFIX).concat(object.className, "_").concat(localId);
  607. objectKey = this.getKeyForObject(object);
  608. _context7.next = 6;
  609. return this.fromPinWithName(localKey);
  610. case 6:
  611. unsaved = _context7.sent;
  612. if (!(!unsaved || unsaved.length === 0)) {
  613. _context7.next = 9;
  614. break;
  615. }
  616. return _context7.abrupt("return");
  617. case 9:
  618. promises = [this.unPinWithName(localKey), this.pinWithName(objectKey, unsaved)];
  619. _context7.next = 12;
  620. return this._getAllContents();
  621. case 12:
  622. localDatastore = _context7.sent;
  623. for (key in localDatastore) {
  624. if (key === _LocalDatastoreUtils.DEFAULT_PIN || key.startsWith(_LocalDatastoreUtils.PIN_PREFIX)) {
  625. pinned = localDatastore[key] || [];
  626. if (pinned.includes(localKey)) {
  627. pinned = pinned.filter(function (item) {
  628. return item !== localKey;
  629. });
  630. pinned.push(objectKey);
  631. promises.push(this.pinWithName(key, pinned));
  632. localDatastore[key] = pinned;
  633. }
  634. }
  635. }
  636. return _context7.abrupt("return", Promise.all(promises));
  637. case 15:
  638. case "end":
  639. return _context7.stop();
  640. }
  641. }
  642. }, _callee7, this);
  643. }));
  644. return function () {
  645. return _updateLocalIdForObject2.apply(this, arguments);
  646. };
  647. }(),
  648. /**
  649. * Updates Local Datastore from Server
  650. *
  651. * <pre>
  652. * await Parse.LocalDatastore.updateFromServer();
  653. * </pre>
  654. * @method updateFromServer
  655. * @name Parse.LocalDatastore.updateFromServer
  656. * @static
  657. */
  658. updateFromServer: function () {
  659. var _updateFromServer = (0, _asyncToGenerator2.default)(
  660. /*#__PURE__*/
  661. _regenerator.default.mark(function _callee8() {
  662. var _this2 = this;
  663. var localDatastore, keys, key, pointersHash, _i, _keys, _key, _key$split, _key$split2, className, objectId, queryPromises, responses, objects, pinPromises;
  664. return _regenerator.default.wrap(function (_context8) {
  665. while (1) {
  666. switch (_context8.prev = _context8.next) {
  667. case 0:
  668. if (!(!this.checkIfEnabled() || this.isSyncing)) {
  669. _context8.next = 2;
  670. break;
  671. }
  672. return _context8.abrupt("return");
  673. case 2:
  674. _context8.next = 4;
  675. return this._getAllContents();
  676. case 4:
  677. localDatastore = _context8.sent;
  678. keys = [];
  679. for (key in localDatastore) {
  680. if (key.startsWith(_LocalDatastoreUtils.OBJECT_PREFIX)) {
  681. keys.push(key);
  682. }
  683. }
  684. if (!(keys.length === 0)) {
  685. _context8.next = 9;
  686. break;
  687. }
  688. return _context8.abrupt("return");
  689. case 9:
  690. this.isSyncing = true;
  691. pointersHash = {};
  692. _i = 0, _keys = keys;
  693. case 12:
  694. if (!(_i < _keys.length)) {
  695. _context8.next = 23;
  696. break;
  697. }
  698. _key = _keys[_i]; // Ignore the OBJECT_PREFIX
  699. _key$split = _key.split('_'), _key$split2 = (0, _slicedToArray2.default)(_key$split, 4), className = _key$split2[2], objectId = _key$split2[3]; // User key is split into [ 'Parse', 'LDS', '', 'User', 'objectId' ]
  700. if (_key.split('_').length === 5 && _key.split('_')[3] === 'User') {
  701. className = '_User';
  702. objectId = _key.split('_')[4];
  703. }
  704. if (!objectId.startsWith('local')) {
  705. _context8.next = 18;
  706. break;
  707. }
  708. return _context8.abrupt("continue", 20);
  709. case 18:
  710. if (!(className in pointersHash)) {
  711. pointersHash[className] = new Set();
  712. }
  713. pointersHash[className].add(objectId);
  714. case 20:
  715. _i++;
  716. _context8.next = 12;
  717. break;
  718. case 23:
  719. queryPromises = Object.keys(pointersHash).map(function (className) {
  720. var objectIds = Array.from(pointersHash[className]);
  721. var query = new _ParseQuery.default(className);
  722. query.limit(objectIds.length);
  723. if (objectIds.length === 1) {
  724. query.equalTo('objectId', objectIds[0]);
  725. } else {
  726. query.containedIn('objectId', objectIds);
  727. }
  728. return query.find();
  729. });
  730. _context8.prev = 24;
  731. _context8.next = 27;
  732. return Promise.all(queryPromises);
  733. case 27:
  734. responses = _context8.sent;
  735. objects = [].concat.apply([], responses);
  736. pinPromises = objects.map(function (object) {
  737. var objectKey = _this2.getKeyForObject(object);
  738. return _this2.pinWithName(objectKey, object._toFullJSON());
  739. });
  740. _context8.next = 32;
  741. return Promise.all(pinPromises);
  742. case 32:
  743. this.isSyncing = false;
  744. _context8.next = 39;
  745. break;
  746. case 35:
  747. _context8.prev = 35;
  748. _context8.t0 = _context8["catch"](24);
  749. console.error('Error syncing LocalDatastore: ', _context8.t0);
  750. this.isSyncing = false;
  751. case 39:
  752. case "end":
  753. return _context8.stop();
  754. }
  755. }
  756. }, _callee8, this, [[24, 35]]);
  757. }));
  758. return function () {
  759. return _updateFromServer.apply(this, arguments);
  760. };
  761. }(),
  762. getKeyForObject: function (object
  763. /*: any*/
  764. ) {
  765. var objectId = object.objectId || object._getId();
  766. return "".concat(_LocalDatastoreUtils.OBJECT_PREFIX).concat(object.className, "_").concat(objectId);
  767. },
  768. getPinName: function (pinName
  769. /*: ?string*/
  770. ) {
  771. if (!pinName || pinName === _LocalDatastoreUtils.DEFAULT_PIN) {
  772. return _LocalDatastoreUtils.DEFAULT_PIN;
  773. }
  774. return _LocalDatastoreUtils.PIN_PREFIX + pinName;
  775. },
  776. checkIfEnabled: function () {
  777. if (!this.isEnabled) {
  778. console.error('Parse.enableLocalDatastore() must be called first');
  779. }
  780. return this.isEnabled;
  781. }
  782. };
  783. module.exports = LocalDatastore;
  784. _CoreManager.default.setLocalDatastoreController(require('./LocalDatastoreController.browser'));
  785. _CoreManager.default.setLocalDatastore(LocalDatastore);