parse
Version:
Parse JavaScript SDK
355 lines (353 loc) • 11 kB
JavaScript
;
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify"));
var _splice = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/splice"));
var _findIndex = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/find-index"));
var _setInterval2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/set-interval"));
var _find = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/find"));
var _CoreManager = _interopRequireDefault(require("./CoreManager"));
var _ParseError = _interopRequireDefault(require("./ParseError"));
var _ParseObject = _interopRequireDefault(require("./ParseObject"));
var _ParseQuery = _interopRequireDefault(require("./ParseQuery"));
var _Storage = _interopRequireDefault(require("./Storage"));
const QUEUE_KEY = 'Parse/Eventually/Queue';
let queueCache = [];
let dirtyCache = true;
let polling = undefined;
/**
* Provides utility functions to queue objects that will be
* saved to the server at a later date.
*
* @class Parse.EventuallyQueue
* @static
*/
const EventuallyQueue = {
/**
* Add object to queue with save operation.
*
* @function save
* @name Parse.EventuallyQueue.save
* @param {ParseObject} object Parse.Object to be saved eventually
* @param {object} [serverOptions] See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Object.html#save Parse.Object.save} options.
* @returns {Promise} A promise that is fulfilled if object is added to queue.
* @static
* @see Parse.Object#saveEventually
*/
save(object, serverOptions) {
return this.enqueue('save', object, serverOptions);
},
/**
* Add object to queue with save operation.
*
* @function destroy
* @name Parse.EventuallyQueue.destroy
* @param {ParseObject} object Parse.Object to be destroyed eventually
* @param {object} [serverOptions] See {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Object.html#destroy Parse.Object.destroy} options
* @returns {Promise} A promise that is fulfilled if object is added to queue.
* @static
* @see Parse.Object#destroyEventually
*/
destroy(object, serverOptions) {
return this.enqueue('destroy', object, serverOptions);
},
/**
* Generate unique identifier to avoid duplicates and maintain previous state.
*
* @param {string} action save / destroy
* @param {object} object Parse.Object to be queued
* @returns {string}
* @static
* @ignore
*/
generateQueueId(action, object) {
object._getId();
const {
className,
id,
_localId
} = object;
const uniqueId = object.get('hash') || _localId;
return [action, className, id, uniqueId].join('_');
},
/**
* Build queue object and add to queue.
*
* @param {string} action save / destroy
* @param {object} object Parse.Object to be queued
* @param {object} [serverOptions]
* @returns {Promise} A promise that is fulfilled if object is added to queue.
* @static
* @ignore
*/
async enqueue(action, object, serverOptions) {
const queueData = await this.getQueue();
const queueId = this.generateQueueId(action, object);
let index = this.queueItemExists(queueData, queueId);
if (index > -1) {
// Add cached values to new object if they don't exist
for (const prop in queueData[index].object) {
if (typeof object.get(prop) === 'undefined') {
object.set(prop, queueData[index].object[prop]);
}
}
} else {
index = queueData.length;
}
queueData[index] = {
queueId,
action,
object: object.toJSON(),
serverOptions: serverOptions || {},
id: object.id,
className: object.className,
hash: object.get('hash'),
createdAt: new Date()
};
return this.setQueue(queueData);
},
store(data) {
return _Storage.default.setItemAsync(QUEUE_KEY, (0, _stringify.default)(data));
},
load() {
return _Storage.default.getItemAsync(QUEUE_KEY);
},
/**
* Sets the in-memory queue from local storage and returns.
*
* @function getQueue
* @name Parse.EventuallyQueue.getQueue
* @returns {Promise<Queue>}
* @static
*/
async getQueue() {
if (dirtyCache) {
queueCache = JSON.parse((await this.load()) || '[]');
dirtyCache = false;
}
return queueCache;
},
/**
* Saves the queue to local storage
*
* @param {Queue} queue Queue containing Parse.Object data.
* @returns {Promise} A promise that is fulfilled when queue is stored.
* @static
* @ignore
*/
setQueue(queue) {
queueCache = queue;
return this.store(queueCache);
},
/**
* Removes Parse.Object data from queue.
*
* @param {string} queueId Unique identifier for Parse.Object data.
* @returns {Promise} A promise that is fulfilled when queue is stored.
* @static
* @ignore
*/
async remove(queueId) {
const queueData = await this.getQueue();
const index = this.queueItemExists(queueData, queueId);
if (index > -1) {
(0, _splice.default)(queueData).call(queueData, index, 1);
await this.setQueue(queueData);
}
},
/**
* Removes all objects from queue.
*
* @function clear
* @name Parse.EventuallyQueue.clear
* @returns {Promise} A promise that is fulfilled when queue is cleared.
* @static
*/
clear() {
queueCache = [];
return this.store([]);
},
/**
* Return the index of a queueId in the queue. Returns -1 if not found.
*
* @param {Queue} queue Queue containing Parse.Object data.
* @param {string} queueId Unique identifier for Parse.Object data.
* @returns {number}
* @static
* @ignore
*/
queueItemExists(queue, queueId) {
return (0, _findIndex.default)(queue).call(queue, data => data.queueId === queueId);
},
/**
* Return the number of objects in the queue.
*
* @function length
* @name Parse.EventuallyQueue.length
* @returns {Promise<number>}
* @static
*/
async length() {
const queueData = await this.getQueue();
return queueData.length;
},
/**
* Sends the queue to the server.
*
* @function sendQueue
* @name Parse.EventuallyQueue.sendQueue
* @returns {Promise<boolean>} Returns true if queue was sent successfully.
* @static
*/
async sendQueue() {
const queue = await this.getQueue();
const queueData = [...queue];
if (queueData.length === 0) {
return false;
}
for (let i = 0; i < queueData.length; i += 1) {
const queueObject = queueData[i];
const {
id,
hash,
className
} = queueObject;
const ObjectType = _ParseObject.default.extend(className);
if (id) {
await this.process.byId(ObjectType, queueObject);
} else if (hash) {
await this.process.byHash(ObjectType, queueObject);
} else {
await this.process.create(ObjectType, queueObject);
}
}
return true;
},
/**
* Build queue object and add to queue.
*
* @param {ParseObject} object Parse.Object to be processed
* @param {QueueObject} queueObject Parse.Object data from the queue
* @returns {Promise} A promise that is fulfilled when operation is performed.
* @static
* @ignore
*/
async sendQueueCallback(object, queueObject) {
if (!object) {
return this.remove(queueObject.queueId);
}
switch (queueObject.action) {
case 'save':
// Queued update was overwritten by other request. Do not save
if (typeof object.updatedAt !== 'undefined' && object.updatedAt > new Date(queueObject.object.createdAt)) {
return this.remove(queueObject.queueId);
}
try {
await object.save(queueObject.object, queueObject.serverOptions);
await this.remove(queueObject.queueId);
} catch (e) {
if (e.code !== _ParseError.default.CONNECTION_FAILED) {
await this.remove(queueObject.queueId);
}
}
break;
case 'destroy':
try {
await object.destroy(queueObject.serverOptions);
await this.remove(queueObject.queueId);
} catch (e) {
if (e.code !== _ParseError.default.CONNECTION_FAILED) {
await this.remove(queueObject.queueId);
}
}
break;
}
},
/**
* Start polling server for network connection.
* Will send queue if connection is established.
*
* @function poll
* @name Parse.EventuallyQueue.poll
* @param [ms] Milliseconds to ping the server. Default 2000ms
* @static
*/
poll(ms) {
if (polling) {
return;
}
polling = (0, _setInterval2.default)(() => {
const RESTController = _CoreManager.default.getRESTController();
RESTController.request('GET', 'health').then(_ref => {
let {
status
} = _ref;
if (status === 'ok') {
this.stopPoll();
return this.sendQueue();
}
}).catch(e => e);
}, ms || 2000);
},
/**
* Turns off polling.
*
* @function stopPoll
* @name Parse.EventuallyQueue.stopPoll
* @static
*/
stopPoll() {
clearInterval(polling);
polling = undefined;
},
/**
* Return true if pinging the server.
*
* @function isPolling
* @name Parse.EventuallyQueue.isPolling
* @returns {boolean}
* @static
*/
isPolling() {
return !!polling;
},
_setPolling(flag) {
polling = flag;
},
process: {
create(ObjectType, queueObject) {
const object = new ObjectType();
return EventuallyQueue.sendQueueCallback(object, queueObject);
},
async byId(ObjectType, queueObject) {
const {
sessionToken
} = queueObject.serverOptions;
const query = new _ParseQuery.default(ObjectType);
query.equalTo('objectId', queueObject.id);
const results = await (0, _find.default)(query).call(query, {
sessionToken
});
return EventuallyQueue.sendQueueCallback(results[0], queueObject);
},
async byHash(ObjectType, queueObject) {
const {
sessionToken
} = queueObject.serverOptions;
const query = new _ParseQuery.default(ObjectType);
query.equalTo('hash', queueObject.hash);
const results = await (0, _find.default)(query).call(query, {
sessionToken
});
if (results.length > 0) {
return EventuallyQueue.sendQueueCallback(results[0], queueObject);
}
return EventuallyQueue.process.create(ObjectType, queueObject);
}
}
};
var _default = exports.default = EventuallyQueue;