LocalDatastore.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  2. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  3. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  4. var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
  5. var _CoreManager = _interopRequireDefault(require("./CoreManager"));
  6. var _ParseQuery = _interopRequireDefault(require("./ParseQuery"));
  7. var _LocalDatastoreUtils = require("./LocalDatastoreUtils");
  8. var LocalDatastore = {
  9. isEnabled: false,
  10. isSyncing: false,
  11. fromPinWithName: function (name) {
  12. var controller = _CoreManager.default.getLocalDatastoreController();
  13. return controller.fromPinWithName(name);
  14. },
  15. pinWithName: function (name, value) {
  16. var controller = _CoreManager.default.getLocalDatastoreController();
  17. return controller.pinWithName(name, value);
  18. },
  19. unPinWithName: function (name) {
  20. var controller = _CoreManager.default.getLocalDatastoreController();
  21. return controller.unPinWithName(name);
  22. },
  23. _getAllContents: function () {
  24. var controller = _CoreManager.default.getLocalDatastoreController();
  25. return controller.getAllContents();
  26. },
  27. _getRawStorage: function () {
  28. var controller = _CoreManager.default.getLocalDatastoreController();
  29. return controller.getRawStorage();
  30. },
  31. _clear: function () {
  32. var controller = _CoreManager.default.getLocalDatastoreController();
  33. return controller.clear();
  34. },
  35. _handlePinAllWithName: function () {
  36. var _handlePinAllWithName2 = (0, _asyncToGenerator2.default)(function* (name, objects) {
  37. var pinName = this.getPinName(name);
  38. var toPinPromises = [];
  39. var objectKeys = [];
  40. for (var parent of objects) {
  41. var children = this._getChildren(parent);
  42. var parentKey = this.getKeyForObject(parent);
  43. var json = parent._toFullJSON(undefined, true);
  44. if (parent._localId) {
  45. json._localId = parent._localId;
  46. }
  47. children[parentKey] = json;
  48. for (var objectKey in children) {
  49. objectKeys.push(objectKey);
  50. toPinPromises.push(this.pinWithName(objectKey, [children[objectKey]]));
  51. }
  52. }
  53. var fromPinPromise = this.fromPinWithName(pinName);
  54. var _yield$Promise$all = yield Promise.all([fromPinPromise, toPinPromises]),
  55. _yield$Promise$all2 = (0, _slicedToArray2.default)(_yield$Promise$all, 1),
  56. pinned = _yield$Promise$all2[0];
  57. var toPin = (0, _toConsumableArray2.default)(new Set([].concat((0, _toConsumableArray2.default)(pinned || []), objectKeys)));
  58. return this.pinWithName(pinName, toPin);
  59. });
  60. function _handlePinAllWithName() {
  61. return _handlePinAllWithName2.apply(this, arguments);
  62. }
  63. return _handlePinAllWithName;
  64. }(),
  65. _handleUnPinAllWithName: function () {
  66. var _handleUnPinAllWithName2 = (0, _asyncToGenerator2.default)(function* (name, objects) {
  67. var localDatastore = yield this._getAllContents();
  68. var pinName = this.getPinName(name);
  69. var promises = [];
  70. var objectKeys = [];
  71. for (var parent of objects) {
  72. var _objectKeys;
  73. var children = this._getChildren(parent);
  74. var parentKey = this.getKeyForObject(parent);
  75. (_objectKeys = objectKeys).push.apply(_objectKeys, [parentKey].concat((0, _toConsumableArray2.default)(Object.keys(children))));
  76. }
  77. objectKeys = (0, _toConsumableArray2.default)(new Set(objectKeys));
  78. var pinned = localDatastore[pinName] || [];
  79. pinned = pinned.filter(function (item) {
  80. return !objectKeys.includes(item);
  81. });
  82. if (pinned.length == 0) {
  83. promises.push(this.unPinWithName(pinName));
  84. delete localDatastore[pinName];
  85. } else {
  86. promises.push(this.pinWithName(pinName, pinned));
  87. localDatastore[pinName] = pinned;
  88. }
  89. for (var objectKey of objectKeys) {
  90. var hasReference = false;
  91. for (var key in localDatastore) {
  92. if (key === _LocalDatastoreUtils.DEFAULT_PIN || key.startsWith(_LocalDatastoreUtils.PIN_PREFIX)) {
  93. var pinnedObjects = localDatastore[key] || [];
  94. if (pinnedObjects.includes(objectKey)) {
  95. hasReference = true;
  96. break;
  97. }
  98. }
  99. }
  100. if (!hasReference) {
  101. promises.push(this.unPinWithName(objectKey));
  102. }
  103. }
  104. return Promise.all(promises);
  105. });
  106. function _handleUnPinAllWithName() {
  107. return _handleUnPinAllWithName2.apply(this, arguments);
  108. }
  109. return _handleUnPinAllWithName;
  110. }(),
  111. _getChildren: function (object) {
  112. var encountered = {};
  113. var json = object._toFullJSON(undefined, true);
  114. for (var key in json) {
  115. if (json[key] && json[key].__type && json[key].__type === 'Object') {
  116. this._traverse(json[key], encountered);
  117. }
  118. }
  119. return encountered;
  120. },
  121. _traverse: function (object, encountered) {
  122. if (!object.objectId) {
  123. return;
  124. } else {
  125. var objectKey = this.getKeyForObject(object);
  126. if (encountered[objectKey]) {
  127. return;
  128. }
  129. encountered[objectKey] = object;
  130. }
  131. for (var key in object) {
  132. var json = object[key];
  133. if (!object[key]) {
  134. json = object;
  135. }
  136. if (json.__type && json.__type === 'Object') {
  137. this._traverse(json, encountered);
  138. }
  139. }
  140. },
  141. _serializeObjectsFromPinName: function () {
  142. var _serializeObjectsFromPinName2 = (0, _asyncToGenerator2.default)(function* (name) {
  143. var _this = this,
  144. _ref;
  145. var localDatastore = yield this._getAllContents();
  146. var allObjects = [];
  147. for (var key in localDatastore) {
  148. if (key.startsWith(_LocalDatastoreUtils.OBJECT_PREFIX)) {
  149. allObjects.push(localDatastore[key][0]);
  150. }
  151. }
  152. if (!name) {
  153. return allObjects;
  154. }
  155. var pinName = this.getPinName(name);
  156. var pinned = localDatastore[pinName];
  157. if (!Array.isArray(pinned)) {
  158. return [];
  159. }
  160. var promises = pinned.map(function (objectKey) {
  161. return _this.fromPinWithName(objectKey);
  162. });
  163. var objects = yield Promise.all(promises);
  164. objects = (_ref = []).concat.apply(_ref, (0, _toConsumableArray2.default)(objects));
  165. return objects.filter(function (object) {
  166. return object != null;
  167. });
  168. });
  169. function _serializeObjectsFromPinName() {
  170. return _serializeObjectsFromPinName2.apply(this, arguments);
  171. }
  172. return _serializeObjectsFromPinName;
  173. }(),
  174. _serializeObject: function () {
  175. var _serializeObject2 = (0, _asyncToGenerator2.default)(function* (objectKey, localDatastore) {
  176. var LDS = localDatastore;
  177. if (!LDS) {
  178. LDS = yield this._getAllContents();
  179. }
  180. if (!LDS[objectKey] || LDS[objectKey].length === 0) {
  181. return null;
  182. }
  183. var root = LDS[objectKey][0];
  184. var queue = [];
  185. var meta = {};
  186. var uniqueId = 0;
  187. meta[uniqueId] = root;
  188. queue.push(uniqueId);
  189. while (queue.length !== 0) {
  190. var nodeId = queue.shift();
  191. var subTreeRoot = meta[nodeId];
  192. for (var field in subTreeRoot) {
  193. var value = subTreeRoot[field];
  194. if (value.__type && value.__type === 'Object') {
  195. var key = this.getKeyForObject(value);
  196. if (LDS[key] && LDS[key].length > 0) {
  197. var pointer = LDS[key][0];
  198. uniqueId++;
  199. meta[uniqueId] = pointer;
  200. subTreeRoot[field] = pointer;
  201. queue.push(uniqueId);
  202. }
  203. }
  204. }
  205. }
  206. return root;
  207. });
  208. function _serializeObject() {
  209. return _serializeObject2.apply(this, arguments);
  210. }
  211. return _serializeObject;
  212. }(),
  213. _updateObjectIfPinned: function () {
  214. var _updateObjectIfPinned2 = (0, _asyncToGenerator2.default)(function* (object) {
  215. if (!this.isEnabled) {
  216. return;
  217. }
  218. var objectKey = this.getKeyForObject(object);
  219. var pinned = yield this.fromPinWithName(objectKey);
  220. if (!pinned || pinned.length === 0) {
  221. return;
  222. }
  223. return this.pinWithName(objectKey, [object._toFullJSON()]);
  224. });
  225. function _updateObjectIfPinned() {
  226. return _updateObjectIfPinned2.apply(this, arguments);
  227. }
  228. return _updateObjectIfPinned;
  229. }(),
  230. _destroyObjectIfPinned: function () {
  231. var _destroyObjectIfPinned2 = (0, _asyncToGenerator2.default)(function* (object) {
  232. if (!this.isEnabled) {
  233. return;
  234. }
  235. var localDatastore = yield this._getAllContents();
  236. var objectKey = this.getKeyForObject(object);
  237. var pin = localDatastore[objectKey];
  238. if (!pin) {
  239. return;
  240. }
  241. var promises = [this.unPinWithName(objectKey)];
  242. delete localDatastore[objectKey];
  243. for (var key in localDatastore) {
  244. if (key === _LocalDatastoreUtils.DEFAULT_PIN || key.startsWith(_LocalDatastoreUtils.PIN_PREFIX)) {
  245. var pinned = localDatastore[key] || [];
  246. if (pinned.includes(objectKey)) {
  247. pinned = pinned.filter(function (item) {
  248. return item !== objectKey;
  249. });
  250. if (pinned.length == 0) {
  251. promises.push(this.unPinWithName(key));
  252. delete localDatastore[key];
  253. } else {
  254. promises.push(this.pinWithName(key, pinned));
  255. localDatastore[key] = pinned;
  256. }
  257. }
  258. }
  259. }
  260. return Promise.all(promises);
  261. });
  262. function _destroyObjectIfPinned() {
  263. return _destroyObjectIfPinned2.apply(this, arguments);
  264. }
  265. return _destroyObjectIfPinned;
  266. }(),
  267. _updateLocalIdForObject: function () {
  268. var _updateLocalIdForObject2 = (0, _asyncToGenerator2.default)(function* (localId, object) {
  269. if (!this.isEnabled) {
  270. return;
  271. }
  272. var localKey = `${_LocalDatastoreUtils.OBJECT_PREFIX}${object.className}_${localId}`;
  273. var objectKey = this.getKeyForObject(object);
  274. var unsaved = yield this.fromPinWithName(localKey);
  275. if (!unsaved || unsaved.length === 0) {
  276. return;
  277. }
  278. var promises = [this.unPinWithName(localKey), this.pinWithName(objectKey, unsaved)];
  279. var localDatastore = yield this._getAllContents();
  280. for (var key in localDatastore) {
  281. if (key === _LocalDatastoreUtils.DEFAULT_PIN || key.startsWith(_LocalDatastoreUtils.PIN_PREFIX)) {
  282. var pinned = localDatastore[key] || [];
  283. if (pinned.includes(localKey)) {
  284. pinned = pinned.filter(function (item) {
  285. return item !== localKey;
  286. });
  287. pinned.push(objectKey);
  288. promises.push(this.pinWithName(key, pinned));
  289. localDatastore[key] = pinned;
  290. }
  291. }
  292. }
  293. return Promise.all(promises);
  294. });
  295. function _updateLocalIdForObject() {
  296. return _updateLocalIdForObject2.apply(this, arguments);
  297. }
  298. return _updateLocalIdForObject;
  299. }(),
  300. updateFromServer: function () {
  301. var _updateFromServer = (0, _asyncToGenerator2.default)(function* () {
  302. var _this2 = this;
  303. if (!this.checkIfEnabled() || this.isSyncing) {
  304. return;
  305. }
  306. var localDatastore = yield this._getAllContents();
  307. var keys = [];
  308. for (var key in localDatastore) {
  309. if (key.startsWith(_LocalDatastoreUtils.OBJECT_PREFIX)) {
  310. keys.push(key);
  311. }
  312. }
  313. if (keys.length === 0) {
  314. return;
  315. }
  316. this.isSyncing = true;
  317. var pointersHash = {};
  318. for (var _key of keys) {
  319. var _key$split = _key.split('_'),
  320. _key$split2 = (0, _slicedToArray2.default)(_key$split, 4),
  321. className = _key$split2[2],
  322. objectId = _key$split2[3];
  323. if (_key.split('_').length === 5 && _key.split('_')[3] === 'User') {
  324. className = '_User';
  325. objectId = _key.split('_')[4];
  326. }
  327. if (objectId.startsWith('local')) {
  328. continue;
  329. }
  330. if (!(className in pointersHash)) {
  331. pointersHash[className] = new Set();
  332. }
  333. pointersHash[className].add(objectId);
  334. }
  335. var queryPromises = Object.keys(pointersHash).map(function (className) {
  336. var objectIds = Array.from(pointersHash[className]);
  337. var query = new _ParseQuery.default(className);
  338. query.limit(objectIds.length);
  339. if (objectIds.length === 1) {
  340. query.equalTo('objectId', objectIds[0]);
  341. } else {
  342. query.containedIn('objectId', objectIds);
  343. }
  344. return query.find();
  345. });
  346. try {
  347. var responses = yield Promise.all(queryPromises);
  348. var objects = [].concat.apply([], responses);
  349. var pinPromises = objects.map(function (object) {
  350. var objectKey = _this2.getKeyForObject(object);
  351. return _this2.pinWithName(objectKey, object._toFullJSON());
  352. });
  353. yield Promise.all(pinPromises);
  354. this.isSyncing = false;
  355. } catch (error) {
  356. console.error('Error syncing LocalDatastore: ', error);
  357. this.isSyncing = false;
  358. }
  359. });
  360. function updateFromServer() {
  361. return _updateFromServer.apply(this, arguments);
  362. }
  363. return updateFromServer;
  364. }(),
  365. getKeyForObject: function (object) {
  366. var objectId = object.objectId || object._getId();
  367. return `${_LocalDatastoreUtils.OBJECT_PREFIX}${object.className}_${objectId}`;
  368. },
  369. getPinName: function (pinName) {
  370. if (!pinName || pinName === _LocalDatastoreUtils.DEFAULT_PIN) {
  371. return _LocalDatastoreUtils.DEFAULT_PIN;
  372. }
  373. return _LocalDatastoreUtils.PIN_PREFIX + pinName;
  374. },
  375. checkIfEnabled: function () {
  376. if (!this.isEnabled) {
  377. console.error('Parse.enableLocalDatastore() must be called first');
  378. }
  379. return this.isEnabled;
  380. }
  381. };
  382. module.exports = LocalDatastore;
  383. _CoreManager.default.setLocalDatastoreController(require('./LocalDatastoreController.react-native'));
  384. _CoreManager.default.setLocalDatastore(LocalDatastore);