From e04f3c0746bedb32d3738194f613f33460a77968 Mon Sep 17 00:00:00 2001 From: michael1011 Date: Mon, 6 Jan 2025 12:58:34 +0100 Subject: [PATCH] refactor: handle duplicate transaction labels (#770) --- lib/db/Database.ts | 3 ++ .../TransactionLabelRepository.ts | 38 +++++++++++++++--- .../TransactionLabelRepository.spec.ts | 39 ++++++++++++++----- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/lib/db/Database.ts b/lib/db/Database.ts index b3f6531c..11698784 100644 --- a/lib/db/Database.ts +++ b/lib/db/Database.ts @@ -21,6 +21,7 @@ import ReverseRoutingHint from './models/ReverseRoutingHint'; import ReverseSwap from './models/ReverseSwap'; import Swap from './models/Swap'; import TransactionLabel from './models/TransactionLabel'; +import TransactionLabelRepository from './repositories/TransactionLabelRepository'; // To make sure that PostgreSQL types are parsed correctly types.setTypeParser(types.builtins.INT8, parseInt); @@ -145,6 +146,8 @@ class Database { PendingLockupTransaction.load(Database.sequelize); PendingEthereumTransaction.load(Database.sequelize); Rebroadcast.load(Database.sequelize); + + TransactionLabelRepository.setLogger(this.logger); }; } diff --git a/lib/db/repositories/TransactionLabelRepository.ts b/lib/db/repositories/TransactionLabelRepository.ts index 86700a42..8d4157eb 100644 --- a/lib/db/repositories/TransactionLabelRepository.ts +++ b/lib/db/repositories/TransactionLabelRepository.ts @@ -1,14 +1,40 @@ +import Logger from '../../Logger'; import { SwapType, swapTypeToPrettyString } from '../../consts/Enums'; import { AnySwap } from '../../consts/Types'; import TransactionLabel from '../models/TransactionLabel'; class TransactionLabelRepository { - public static addLabel = async (id: string, symbol: string, label: string) => - TransactionLabel.create({ - id, - label, - symbol, - }); + public static logger?: Logger; + + public static setLogger = (logger: Logger) => { + this.logger = logger; + }; + + public static addLabel = async ( + id: string, + symbol: string, + label: string, + ) => { + try { + return await TransactionLabel.create({ + id, + label, + symbol, + }); + } catch (error) { + if ((error as any).name === 'SequelizeUniqueConstraintError') { + const existingLabel = await TransactionLabel.findOne({ where: { id } }); + if (existingLabel) { + this.logger?.warn( + `Updating existing label for ${id} from "${existingLabel.label}" to "${label}"`, + ); + return await existingLabel.update({ label }); + } + } + + throw error; + } + }; public static getLabel = (id: string) => TransactionLabel.findOne({ diff --git a/test/integration/db/repositories/TransactionLabelRepository.spec.ts b/test/integration/db/repositories/TransactionLabelRepository.spec.ts index 068953cb..b450fe28 100644 --- a/test/integration/db/repositories/TransactionLabelRepository.spec.ts +++ b/test/integration/db/repositories/TransactionLabelRepository.spec.ts @@ -21,18 +21,37 @@ describe('TransactionLabelRepository', () => { await database.close(); }); - test('should add labels', async () => { - const txId = 'id'; - const symbol = 'BTC'; - const label = 'important info'; + describe('addLabel', () => { + test('should add labels', async () => { + const txId = 'id'; + const symbol = 'BTC'; + const label = 'important info'; - await TransactionLabelRepository.addLabel(txId, symbol, label); + await TransactionLabelRepository.addLabel(txId, symbol, label); - const entry = await TransactionLabelRepository.getLabel(txId); + const entry = await TransactionLabelRepository.getLabel(txId); - expect(entry).not.toBeNull(); - expect(entry!.id).toEqual(txId); - expect(entry!.symbol).toEqual(symbol); - expect(entry!.label).toEqual(label); + expect(entry).not.toBeNull(); + expect(entry!.id).toEqual(txId); + expect(entry!.symbol).toEqual(symbol); + expect(entry!.label).toEqual(label); + }); + + test('should update existing labels', async () => { + const txId = 'id'; + const symbol = 'BTC'; + const originalLabel = 'original label'; + const newLabel = 'updated label'; + + await TransactionLabelRepository.addLabel(txId, symbol, originalLabel); + await TransactionLabelRepository.addLabel(txId, symbol, newLabel); + + const entry = await TransactionLabelRepository.getLabel(txId); + + expect(entry).not.toBeNull(); + expect(entry!.id).toEqual(txId); + expect(entry!.symbol).toEqual(symbol); + expect(entry!.label).toEqual(newLabel); + }); }); });