Skip to content

Commit

Permalink
Merge pull request #31280 from Tony-MK/backup-transactions-onyx-migra…
Browse files Browse the repository at this point in the history
…tion

Onyx migration for transactions backups
  • Loading branch information
tgolen authored Nov 21, 2023
2 parents 2fa90eb + 32f725c commit 9da929f
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@ const ONYXKEYS = {
REPORT_USER_IS_LEAVING_ROOM: 'reportUserIsLeavingRoom_',
SECURITY_GROUP: 'securityGroup_',
TRANSACTION: 'transactions_',

// Holds temporary transactions used during the creation and edit flow
TRANSACTION_DRAFT: 'transactionsDraft_',
SPLIT_TRANSACTION_DRAFT: 'splitTransactionDraft_',
PRIVATE_NOTES_DRAFT: 'privateNotesDraft_',
NEXT_STEP: 'reportNextStep_',
Expand Down
4 changes: 2 additions & 2 deletions src/libs/actions/IOU.js
Original file line number Diff line number Diff line change
Expand Up @@ -794,10 +794,10 @@ function editDistanceMoneyRequest(transactionID, transactionThreadReportID, tran
});

if (_.has(transactionChanges, 'waypoints')) {
// Delete the backup transaction when editing waypoints when the server responds successfully and there are no errors
// Delete the draft transaction when editing waypoints when the server responds successfully and there are no errors
successData.push({
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}-backup`,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`,
value: null,
});
}
Expand Down
6 changes: 3 additions & 3 deletions src/libs/actions/TransactionEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ function createBackupTransaction(transaction) {
...transaction,
};
// Use set so that it will always fully overwrite any backup transaction that could have existed before
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}-backup`, newTransaction);
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transaction.transactionID}`, newTransaction);
}

/**
* Removes a transaction from Onyx that was only used temporary in the edit flow
* @param {String} transactionID
*/
function removeBackupTransaction(transactionID) {
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}-backup`, null);
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, null);
}

function restoreOriginalTransactionFromBackup(transactionID) {
const connectionID = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}-backup`,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`,
callback: (backupTransaction) => {
Onyx.disconnect(connectionID);

Expand Down
3 changes: 2 additions & 1 deletion src/libs/migrateOnyx.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import Log from './Log';
import KeyReportActionsDraftByReportActionID from './migrations/KeyReportActionsDraftByReportActionID';
import PersonalDetailsByAccountID from './migrations/PersonalDetailsByAccountID';
import RenameReceiptFilename from './migrations/RenameReceiptFilename';
import TransactionBackupsToCollection from './migrations/TransactionBackupsToCollection';

export default function () {
const startTime = Date.now();
Log.info('[Migrate Onyx] start');

return new Promise((resolve) => {
// Add all migrations to an array so they are executed in order
const migrationPromises = [PersonalDetailsByAccountID, RenameReceiptFilename, KeyReportActionsDraftByReportActionID];
const migrationPromises = [PersonalDetailsByAccountID, RenameReceiptFilename, KeyReportActionsDraftByReportActionID, TransactionBackupsToCollection];

// Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the
// previous promise to finish before moving onto the next one.
Expand Down
58 changes: 58 additions & 0 deletions src/libs/migrations/TransactionBackupsToCollection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Onyx, {OnyxCollection} from 'react-native-onyx';
import Log from '@libs/Log';
import ONYXKEYS from '@src/ONYXKEYS';
import {Transaction} from '@src/types/onyx';

/**
* This migration moves all the transaction backups stored in the transaction collection, ONYXKEYS.COLLECTION.TRANSACTION, to a reserved collection that only
* stores draft transactions, ONYXKEYS.COLLECTION.TRANSACTION_DRAFT. The purpose of the migration is that there is a possibility that transaction backups are
* not filtered by most functions, e.g, getAllReportTransactions (src/libs/TransactionUtils.ts). One problem that arose from storing transaction backups with
* the other transactions is that for every distance request which have their waypoints updated offline, we expect the ReportPreview component to display the
* default image of a pending map. However, due to the presence of the transaction backup, the previous map image will be displayed alongside the pending map.
* The problem was further discussed in this PR. https://github.com/Expensify/App/pull/30232#issuecomment-178110172
*/
export default function (): Promise<void> {
return new Promise<void>((resolve) => {
const connectionID = Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION,
waitForCollectionCallback: true,
callback: (transactions: OnyxCollection<Transaction>) => {
Onyx.disconnect(connectionID);

// Determine whether any transactions were stored
if (!transactions || Object.keys(transactions).length === 0) {
Log.info('[Migrate Onyx] Skipped TransactionBackupsToCollection migration because there are no transactions');
return resolve();
}

const onyxData: OnyxCollection<Transaction> = {};

// Find all the transaction backups available
Object.keys(transactions).forEach((transactionOnyxKey: string) => {
const transaction: Transaction | null = transactions[transactionOnyxKey];

// Determine whether or not the transaction is a backup
if (transactionOnyxKey.endsWith('-backup') && transaction) {
// Create the transaction backup in the draft transaction collection
onyxData[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transaction.transactionID}`] = transaction;

// Delete the transaction backup stored in the transaction collection
onyxData[transactionOnyxKey] = null;
}
});

// Determine whether any transaction backups are found
if (Object.keys(onyxData).length === 0) {
Log.info('[Migrate Onyx] Skipped TransactionBackupsToCollection migration because there are no transaction backups');
return resolve();
}

// Move the transaction backups to the draft transaction collection
Onyx.multiSet(onyxData as Partial<{string: [Transaction | null]}>).then(() => {
Log.info('[Migrate Onyx] TransactionBackupsToCollection migration: Successfully moved all the transaction backups to the draft transaction collection');
resolve();
});
},
});
});
}
2 changes: 1 addition & 1 deletion src/pages/EditRequestDistancePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,6 @@ export default withOnyx({
key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION}${props.transactionID}`,
},
transactionBackup: {
key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION}${props.transactionID}-backup`,
key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${props.transactionID}`,
},
})(EditRequestDistancePage);

0 comments on commit 9da929f

Please sign in to comment.