react-native-firebase/lib/modules/database/transaction.js

166 lines
3.4 KiB
JavaScript
Raw Normal View History

/**
* @flow
2017-10-29 00:27:45 +00:00
* Database Transaction representation wrapper
*/
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
import { getLogger } from '../../utils/log';
import { getNativeModule } from '../../utils/native';
import type Database from './';
let transactionId = 0;
/**
* Uses the push id generator to create a transaction id
* @returns {number}
* @private
*/
2018-01-25 18:25:39 +00:00
const generateTransactionId = (): number => transactionId++;
/**
2017-10-29 00:27:45 +00:00
* @class TransactionHandler
*/
export default class TransactionHandler {
_database: Database;
_transactionListener: Function;
2018-01-25 18:25:39 +00:00
_transactions: { [number]: Object };
constructor(database: Database) {
this._transactions = {};
this._database = database;
this._transactionListener = SharedEventEmitter.addListener(
getAppEventName(this._database, 'database_transaction_event'),
2018-01-25 18:25:39 +00:00
this._handleTransactionEvent.bind(this)
);
}
/**
2017-08-02 09:38:30 +00:00
* Add a new transaction and start it natively.
* @param reference
* @param transactionUpdater
* @param onComplete
* @param applyLocally
*/
2018-01-25 18:25:39 +00:00
add(
reference: Object,
transactionUpdater: Function,
onComplete?: Function,
applyLocally?: boolean = false
) {
const id = generateTransactionId();
this._transactions[id] = {
id,
reference,
transactionUpdater,
onComplete,
applyLocally,
completed: false,
started: true,
};
2018-01-25 18:25:39 +00:00
getNativeModule(this._database).transactionStart(
reference.path,
id,
applyLocally
);
}
/**
* INTERNALS
*/
/**
*
* @param event
* @returns {*}
* @private
*/
_handleTransactionEvent(event: Object = {}) {
switch (event.type) {
case 'update':
return this._handleUpdate(event);
case 'error':
2017-04-04 16:58:47 +00:00
return this._handleError(event);
case 'complete':
return this._handleComplete(event);
default:
2018-01-25 18:25:39 +00:00
getLogger(this._database).warn(
`Unknown transaction event type: '${event.type}'`,
event
);
return undefined;
}
}
/**
*
* @param event
* @private
*/
_handleUpdate(event: Object = {}) {
let newValue;
const { id, value } = event;
try {
const transaction = this._transactions[id];
if (!transaction) return;
newValue = transaction.transactionUpdater(value);
} finally {
let abort = false;
if (newValue === undefined) {
abort = true;
}
2018-01-25 18:25:39 +00:00
getNativeModule(this._database).transactionTryCommit(id, {
value: newValue,
abort,
});
}
}
/**
*
* @param event
* @private
*/
_handleError(event: Object = {}) {
const transaction = this._transactions[event.id];
if (transaction && !transaction.completed) {
transaction.completed = true;
try {
transaction.onComplete(event.error, false, null);
} finally {
setImmediate(() => {
delete this._transactions[event.id];
});
}
}
}
/**
*
* @param event
* @private
*/
_handleComplete(event: Object = {}) {
const transaction = this._transactions[event.id];
if (transaction && !transaction.completed) {
transaction.completed = true;
try {
2018-01-25 18:25:39 +00:00
transaction.onComplete(
null,
event.committed,
Object.assign({}, event.snapshot)
);
} finally {
setImmediate(() => {
delete this._transactions[event.id];
});
}
}
}
}