react-native-firebase-compiled
Version:
A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Admob, Analytics, Auth, Crash Reporting, Cloud Firestore, Database, Dynamic Links, Functions, Messaging (FCM), Remote Config, Sto
243 lines (184 loc) • 7.05 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _events = require("../../utils/events");
var _native = require("../../utils/native");
var _Transaction = _interopRequireDefault(require("./Transaction"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
let transactionId = 0;
/**
* Uses the push id generator to create a transaction id
* @returns {number}
* @private
*/
const generateTransactionId = () => transactionId++;
/**
* @class TransactionHandler
*/
class TransactionHandler {
constructor(firestore) {
_defineProperty(this, "_firestore", void 0);
_defineProperty(this, "_pending", void 0);
this._pending = {};
this._firestore = firestore;
_events.SharedEventEmitter.addListener((0, _events.getAppEventName)(this._firestore, 'firestore_transaction_event'), this._handleTransactionEvent.bind(this));
}
/**
* -------------
* INTERNAL API
* -------------
*/
/**
* Add a new transaction and start it natively.
* @param updateFunction
*/
_add(updateFunction) {
const id = generateTransactionId(); // $FlowExpectedError: Transaction has to be populated
const meta = {
id,
updateFunction,
stack: new Error().stack.split('\n').slice(2).join('\n')
};
this._pending[id] = {
meta,
transaction: new _Transaction.default(this._firestore, meta)
}; // deferred promise
return new Promise((resolve, reject) => {
(0, _native.getNativeModule)(this._firestore).transactionBegin(id);
meta.resolve = r => {
resolve(r);
this._remove(id);
};
meta.reject = e => {
reject(e);
this._remove(id);
};
});
}
/**
* Destroys a local instance of a transaction meta
*
* @param id
* @private
*/
_remove(id) {
(0, _native.getNativeModule)(this._firestore).transactionDispose(id);
delete this._pending[id];
}
/**
* -------------
* EVENTS
* -------------
*/
/**
* Handles incoming native transaction events and distributes to correct
* internal handler by event.type
*
* @param event
* @returns {*}
* @private
*/
_handleTransactionEvent(event) {
// eslint-disable-next-line default-case
switch (event.type) {
case 'update':
this._handleUpdate(event);
break;
case 'error':
this._handleError(event);
break;
case 'complete':
this._handleComplete(event);
break;
}
}
/**
* Handles incoming native transaction update events
*
* @param event
* @private
*/
_handleUpdate(event) {
var _this = this;
return _asyncToGenerator(function* () {
const id = event.id; // abort if no longer exists js side
if (!_this._pending[id]) return _this._remove(id);
const _this$_pending$id = _this._pending[id],
meta = _this$_pending$id.meta,
transaction = _this$_pending$id.transaction;
const updateFunction = meta.updateFunction,
reject = meta.reject; // clear any saved state from previous transaction runs
transaction._prepare();
let finalError;
let updateFailed;
let pendingResult; // run the users custom update functionality
try {
const possiblePromise = updateFunction(transaction); // validate user has returned a promise in their update function
// TODO must it actually return a promise? Can't find any usages of it without one...
if (!possiblePromise || !possiblePromise.then) {
finalError = new Error('Update function for `firestore.runTransaction(updateFunction)` must return a Promise.');
} else {
pendingResult = yield possiblePromise;
}
} catch (exception) {
// exception can still be falsey if user `Promise.reject();` 's with no args
// so we track the exception with a updateFailed boolean to ensure no fall-through
updateFailed = true;
finalError = exception;
} // reject the final promise and remove from native
// update is failed when either the users updateFunction
// throws an error or rejects a promise
if (updateFailed || finalError) {
// $FlowExpectedError: Reject will always be present
return reject(finalError);
} // capture the resolved result as we'll need this
// to resolve the runTransaction() promise when
// native emits that the transaction is final
transaction._pendingResult = pendingResult; // send the buffered update/set/delete commands for native to process
return (0, _native.getNativeModule)(_this._firestore).transactionApplyBuffer(id, transaction._commandBuffer);
})();
}
/**
* Handles incoming native transaction error events
*
* @param event
* @private
*/
_handleError(event) {
const id = event.id,
error = event.error;
const meta = this._pending[id].meta;
if (meta && error) {
const code = error.code,
message = error.message; // build a JS error and replace its stack
// with the captured one at start of transaction
// so it's actually relevant to the user
const errorWithStack = new Error(message); // $FlowExpectedError: code is needed for Firebase errors
errorWithStack.code = code; // $FlowExpectedError: stack should be a stack trace
errorWithStack.stack = `Error: ${message}\n${meta.stack}`; // $FlowExpectedError: Reject will always be present
meta.reject(errorWithStack);
}
}
/**
* Handles incoming native transaction complete events
*
* @param event
* @private
*/
_handleComplete(event) {
const id = event.id;
const _this$_pending$id2 = this._pending[id],
meta = _this$_pending$id2.meta,
transaction = _this$_pending$id2.transaction;
if (meta) {
const pendingResult = transaction._pendingResult; // $FlowExpectedError: Resolve will always be present
meta.resolve(pendingResult);
}
}
}
exports.default = TransactionHandler;
;