taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit af6c5877c41937eb580b2090ddedfde4212302b2
parent 34b2d212ca47409358764bfc12bf2045523ad66f
Author: Florian Dold <dold@taler.net>
Date:   Sun, 19 Jul 2026 00:06:09 +0200

db: move the exchange purge cascade behind the DAL

Diffstat:
Mpackages/taler-wallet-core/src/dbtx-indexeddb.ts | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-wallet-core/src/dbtx.ts | 46++++++++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-wallet-core/src/exchanges.ts | 46+++++++++++++++++++++++++---------------------
3 files changed, 153 insertions(+), 21 deletions(-)

diff --git a/packages/taler-wallet-core/src/dbtx-indexeddb.ts b/packages/taler-wallet-core/src/dbtx-indexeddb.ts @@ -354,6 +354,88 @@ export class IdbWalletTransaction implements WalletDbTransaction { }); } + async getCoinsByExchange(exchangeBaseUrl: string): Promise<WalletCoin[]> { + const tx = this.tx; + return await tx.coins.indexes.byBaseUrl.getAll(exchangeBaseUrl); + } + + async countCoinsByExchange(exchangeBaseUrl: string): Promise<number> { + const tx = this.tx; + return await tx.coins.indexes.byBaseUrl.count(exchangeBaseUrl); + } + + async getCoinsByDenomPubHash(denomPubHash: string): Promise<WalletCoin[]> { + const tx = this.tx; + return await tx.coins.indexes.byDenomPubHash.getAll(denomPubHash); + } + + async deleteCoin(coinPub: string): Promise<void> { + const tx = this.tx; + await tx.coins.delete(coinPub); + } + + async deleteCoinHistory(coinPub: string): Promise<void> { + const tx = this.tx; + await tx.coinHistory.delete(coinPub); + } + + async getCoinAvailabilityByExchange( + exchangeBaseUrl: string, + ): Promise<WalletCoinAvailability[]> { + const tx = this.tx; + return await tx.coinAvailability.indexes.byExchangeBaseUrl.getAll( + exchangeBaseUrl, + ); + } + + async deleteCoinAvailability( + exchangeBaseUrl: string, + denomPubHash: string, + maxAge: number, + ): Promise<void> { + const tx = this.tx; + await tx.coinAvailability.delete([exchangeBaseUrl, denomPubHash, maxAge]); + } + + async getRecoupGroupsByExchange( + exchangeBaseUrl: string, + ): Promise<WalletRecoupGroup[]> { + const tx = this.tx; + return await tx.recoupGroups.indexes.byExchangeBaseUrl.getAll( + exchangeBaseUrl, + ); + } + + async listAllRefreshGroups(): Promise<WalletRefreshGroup[]> { + const tx = this.tx; + return await tx.refreshGroups.iter().toArray(); + } + + async listAllDepositGroups(): Promise<WalletDepositGroup[]> { + const tx = this.tx; + return await tx.depositGroups.iter().toArray(); + } + + async listAllPeerPullCredits(): Promise<WalletPeerPullCredit[]> { + const tx = this.tx; + return await tx.peerPullCredit.iter().toArray(); + } + + async listAllPeerPullDebits(): Promise<WalletPeerPullDebit[]> { + const tx = this.tx; + return await tx.peerPullDebit.iter().toArray(); + } + + async listAllPeerPushCredits(): Promise<WalletPeerPushCredit[]> { + const tx = this.tx; + return await tx.peerPushCredit.iter().toArray(); + } + + async listAllPeerPushDebits(): Promise<WalletPeerPushDebit[]> { + const tx = this.tx; + return await tx.peerPushDebit.iter().toArray(); + } + async getDenominationFamilyByParams( params: WalletDenomFamilyParams, ): Promise<WalletDenominationFamily | undefined> { diff --git a/packages/taler-wallet-core/src/dbtx.ts b/packages/taler-wallet-core/src/dbtx.ts @@ -251,6 +251,52 @@ export interface WalletDbTransaction { /** * Look up a denomination family by its parameters. */ + getCoinsByExchange(exchangeBaseUrl: string): Promise<WalletCoin[]>; + + countCoinsByExchange(exchangeBaseUrl: string): Promise<number>; + + getCoinsByDenomPubHash(denomPubHash: string): Promise<WalletCoin[]>; + + deleteCoin(coinPub: string): Promise<void>; + + deleteCoinHistory(coinPub: string): Promise<void>; + + getCoinAvailabilityByExchange( + exchangeBaseUrl: string, + ): Promise<WalletCoinAvailability[]>; + + deleteCoinAvailability( + exchangeBaseUrl: string, + denomPubHash: string, + maxAge: number, + ): Promise<void>; + + getRecoupGroupsByExchange( + exchangeBaseUrl: string, + ): Promise<WalletRecoupGroup[]>; + + /** + * List every refresh group, in any state. + * + * Used by exchange purge and base-URL migration, which filter on + * infoPerExchange -- a field with no index. + */ + listAllRefreshGroups(): Promise<WalletRefreshGroup[]>; + + /** + * List every deposit group, in any state. As above, filtered on + * infoPerExchange by the caller. + */ + listAllDepositGroups(): Promise<WalletDepositGroup[]>; + + listAllPeerPullCredits(): Promise<WalletPeerPullCredit[]>; + + listAllPeerPullDebits(): Promise<WalletPeerPullDebit[]>; + + listAllPeerPushCredits(): Promise<WalletPeerPushCredit[]>; + + listAllPeerPushDebits(): Promise<WalletPeerPushDebit[]>; + getDenominationFamilyByParams( params: WalletDenomFamilyParams, ): Promise<WalletDenominationFamily | undefined>; diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts @@ -3181,23 +3181,21 @@ async function purgeExchange( { const coinAvailabilityRecs = - await tx.coinAvailability.indexes.byExchangeBaseUrl.getAll( - exchangeBaseUrl, - ); + await tx.wtx.getCoinAvailabilityByExchange(exchangeBaseUrl); for (const rec of coinAvailabilityRecs) { - await tx.coinAvailability.delete([ + await tx.wtx.deleteCoinAvailability( exchangeBaseUrl, rec.denomPubHash, rec.maxAge, - ]); + ); } } { - const coinRecs = await tx.coins.indexes.byBaseUrl.getAll(exchangeBaseUrl); + const coinRecs = await tx.wtx.getCoinsByExchange(exchangeBaseUrl); for (const rec of coinRecs) { - await tx.coins.delete(rec.coinPub); - await tx.coinHistory.delete(rec.coinPub); + await tx.wtx.deleteCoin(rec.coinPub); + await tx.wtx.deleteCoinHistory(rec.coinPub); } } @@ -3239,17 +3237,18 @@ async function purgeExchange( if (purgeTransactions) { // Remove from refreshGroups and refreshSessions { - await tx.refreshGroups.iter().forEachAsync(async (rg) => { + const refreshGroups = await tx.wtx.listAllRefreshGroups(); + for (const rg of refreshGroups) { if (rg.infoPerExchange && rg.infoPerExchange[exchangeBaseUrl] != null) { const ctx = new RefreshTransactionContext(wex, rg.refreshGroupId); await ctx.deleteTransactionInTx(tx); } - }); + } } // Remove from recoupGroups { const recoupGroups = - await tx.recoupGroups.indexes.byExchangeBaseUrl.getAll(exchangeBaseUrl); + await tx.wtx.getRecoupGroupsByExchange(exchangeBaseUrl); for (const rg of recoupGroups) { const ctx = new RecoupTransactionContext(wex, rg.recoupGroupId); await ctx.deleteTransactionInTx(tx); @@ -3258,12 +3257,13 @@ async function purgeExchange( // Remove from deposits { // FIXME: Index would be useful here - await tx.depositGroups.iter().forEachAsync(async (dg) => { + const depositGroups = await tx.wtx.listAllDepositGroups(); + for (const dg of depositGroups) { if (dg.infoPerExchange && dg.infoPerExchange[exchangeBaseUrl]) { const ctx = new DepositTransactionContext(wex, dg.depositGroupId); await ctx.deleteTransactionInTx(tx); } - }); + } } // Remove from purchases, refundGroups, refundItems { @@ -3283,16 +3283,18 @@ async function purgeExchange( } // Remove from peerPullCredit { - await tx.peerPullCredit.iter().forEachAsync(async (rec) => { + const recs = await tx.wtx.listAllPeerPullCredits(); + for (const rec of recs) { if (rec.exchangeBaseUrl === exchangeBaseUrl) { const ctx = new PeerPullCreditTransactionContext(wex, rec.pursePub); await ctx.deleteTransactionInTx(tx); } - }); + } } // Remove from peerPullDebit { - await tx.peerPullDebit.iter().forEachAsync(async (rec) => { + const recs = await tx.wtx.listAllPeerPullDebits(); + for (const rec of recs) { if (rec.exchangeBaseUrl === exchangeBaseUrl) { const ctx = new PeerPullDebitTransactionContext( wex, @@ -3300,11 +3302,12 @@ async function purgeExchange( ); await ctx.deleteTransactionInTx(tx); } - }); + } } // Remove from peerPushCredit { - await tx.peerPushCredit.iter().forEachAsync(async (rec) => { + const recs = await tx.wtx.listAllPeerPushCredits(); + for (const rec of recs) { if (rec.exchangeBaseUrl === exchangeBaseUrl) { const ctx = new PeerPushCreditTransactionContext( wex, @@ -3312,16 +3315,17 @@ async function purgeExchange( ); await ctx.deleteTransactionInTx(tx); } - }); + } } // Remove from peerPushDebit { - await tx.peerPushDebit.iter().forEachAsync(async (rec) => { + const recs = await tx.wtx.listAllPeerPushDebits(); + for (const rec of recs) { if (rec.exchangeBaseUrl === exchangeBaseUrl) { const ctx = new PeerPushDebitTransactionContext(wex, rec.pursePub); await ctx.deleteTransactionInTx(tx); } - }); + } } }