wallet-core: implement database fixups
This commit is contained in:
parent
a82d8fab69
commit
668d7a213e
@ -1,236 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of GNU Taler
|
|
||||||
(C) 2021 Taler Systems S.A.
|
|
||||||
|
|
||||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
|
||||||
|
|
||||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Imports.
|
|
||||||
*/
|
|
||||||
import { IDBDatabase, IDBFactory, IDBTransaction } from "@gnu-taler/idb-bridge";
|
|
||||||
import { Logger } from "@gnu-taler/taler-util";
|
|
||||||
import {
|
|
||||||
CURRENT_DB_CONFIG_KEY,
|
|
||||||
TALER_DB_NAME,
|
|
||||||
TALER_META_DB_NAME,
|
|
||||||
walletMetadataStore,
|
|
||||||
WalletStoresV1,
|
|
||||||
WALLET_DB_MINOR_VERSION,
|
|
||||||
} from "./db.js";
|
|
||||||
import {
|
|
||||||
DbAccess,
|
|
||||||
IndexDescriptor,
|
|
||||||
openDatabase,
|
|
||||||
StoreDescriptor,
|
|
||||||
StoreWithIndexes,
|
|
||||||
} from "./util/query.js";
|
|
||||||
|
|
||||||
const logger = new Logger("db-utils.ts");
|
|
||||||
|
|
||||||
function upgradeFromStoreMap(
|
|
||||||
storeMap: any,
|
|
||||||
db: IDBDatabase,
|
|
||||||
oldVersion: number,
|
|
||||||
newVersion: number,
|
|
||||||
upgradeTransaction: IDBTransaction,
|
|
||||||
): void {
|
|
||||||
if (oldVersion === 0) {
|
|
||||||
for (const n in storeMap) {
|
|
||||||
const swi: StoreWithIndexes<
|
|
||||||
any,
|
|
||||||
StoreDescriptor<unknown>,
|
|
||||||
any
|
|
||||||
> = storeMap[n];
|
|
||||||
const storeDesc: StoreDescriptor<unknown> = swi.store;
|
|
||||||
const s = db.createObjectStore(swi.storeName, {
|
|
||||||
autoIncrement: storeDesc.autoIncrement,
|
|
||||||
keyPath: storeDesc.keyPath,
|
|
||||||
});
|
|
||||||
for (const indexName in swi.indexMap as any) {
|
|
||||||
const indexDesc: IndexDescriptor = swi.indexMap[indexName];
|
|
||||||
s.createIndex(indexDesc.name, indexDesc.keyPath, {
|
|
||||||
multiEntry: indexDesc.multiEntry,
|
|
||||||
unique: indexDesc.unique,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (oldVersion === newVersion) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger.info(`upgrading database from ${oldVersion} to ${newVersion}`);
|
|
||||||
for (const n in storeMap) {
|
|
||||||
const swi: StoreWithIndexes<any, StoreDescriptor<unknown>, any> = storeMap[
|
|
||||||
n
|
|
||||||
];
|
|
||||||
const storeDesc: StoreDescriptor<unknown> = swi.store;
|
|
||||||
const storeAddedVersion = storeDesc.versionAdded ?? 0;
|
|
||||||
if (storeAddedVersion <= oldVersion) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const s = db.createObjectStore(swi.storeName, {
|
|
||||||
autoIncrement: storeDesc.autoIncrement,
|
|
||||||
keyPath: storeDesc.keyPath,
|
|
||||||
});
|
|
||||||
for (const indexName in swi.indexMap as any) {
|
|
||||||
const indexDesc: IndexDescriptor = swi.indexMap[indexName];
|
|
||||||
const indexAddedVersion = indexDesc.versionAdded ?? 0;
|
|
||||||
if (indexAddedVersion <= oldVersion) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
s.createIndex(indexDesc.name, indexDesc.keyPath, {
|
|
||||||
multiEntry: indexDesc.multiEntry,
|
|
||||||
unique: indexDesc.unique,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function promiseFromTransaction(transaction: IDBTransaction): Promise<void> {
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
transaction.oncomplete = () => {
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
transaction.onerror = () => {
|
|
||||||
reject();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Purge all data in the given database.
|
|
||||||
*/
|
|
||||||
export function clearDatabase(db: IDBDatabase): Promise<void> {
|
|
||||||
// db.objectStoreNames is a DOMStringList, so we need to convert
|
|
||||||
let stores: string[] = [];
|
|
||||||
for (let i = 0; i < db.objectStoreNames.length; i++) {
|
|
||||||
stores.push(db.objectStoreNames[i]);
|
|
||||||
}
|
|
||||||
const tx = db.transaction(stores, "readwrite");
|
|
||||||
for (const store of stores) {
|
|
||||||
tx.objectStore(store).clear();
|
|
||||||
}
|
|
||||||
return promiseFromTransaction(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onTalerDbUpgradeNeeded(
|
|
||||||
db: IDBDatabase,
|
|
||||||
oldVersion: number,
|
|
||||||
newVersion: number,
|
|
||||||
upgradeTransaction: IDBTransaction,
|
|
||||||
) {
|
|
||||||
upgradeFromStoreMap(
|
|
||||||
WalletStoresV1,
|
|
||||||
db,
|
|
||||||
oldVersion,
|
|
||||||
newVersion,
|
|
||||||
upgradeTransaction,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onMetaDbUpgradeNeeded(
|
|
||||||
db: IDBDatabase,
|
|
||||||
oldVersion: number,
|
|
||||||
newVersion: number,
|
|
||||||
upgradeTransaction: IDBTransaction,
|
|
||||||
) {
|
|
||||||
upgradeFromStoreMap(
|
|
||||||
walletMetadataStore,
|
|
||||||
db,
|
|
||||||
oldVersion,
|
|
||||||
newVersion,
|
|
||||||
upgradeTransaction,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a promise that resolves
|
|
||||||
* to the taler wallet db.
|
|
||||||
*/
|
|
||||||
export async function openTalerDatabase(
|
|
||||||
idbFactory: IDBFactory,
|
|
||||||
onVersionChange: () => void,
|
|
||||||
): Promise<DbAccess<typeof WalletStoresV1>> {
|
|
||||||
const metaDbHandle = await openDatabase(
|
|
||||||
idbFactory,
|
|
||||||
TALER_META_DB_NAME,
|
|
||||||
1,
|
|
||||||
() => {},
|
|
||||||
onMetaDbUpgradeNeeded,
|
|
||||||
);
|
|
||||||
|
|
||||||
const metaDb = new DbAccess(metaDbHandle, walletMetadataStore);
|
|
||||||
let currentMainVersion: string | undefined;
|
|
||||||
await metaDb
|
|
||||||
.mktx((stores) => [stores.metaConfig])
|
|
||||||
.runReadWrite(async (tx) => {
|
|
||||||
const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY);
|
|
||||||
if (!dbVersionRecord) {
|
|
||||||
currentMainVersion = TALER_DB_NAME;
|
|
||||||
await tx.metaConfig.put({
|
|
||||||
key: CURRENT_DB_CONFIG_KEY,
|
|
||||||
value: TALER_DB_NAME,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
currentMainVersion = dbVersionRecord.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (currentMainVersion !== TALER_DB_NAME) {
|
|
||||||
switch (currentMainVersion) {
|
|
||||||
case "taler-wallet-main-v2":
|
|
||||||
case "taler-wallet-main-v3":
|
|
||||||
case "taler-wallet-main-v4": // temporary, we might migrate v4 later
|
|
||||||
case "taler-wallet-main-v5":
|
|
||||||
case "taler-wallet-main-v6":
|
|
||||||
case "taler-wallet-main-v7":
|
|
||||||
case "taler-wallet-main-v8":
|
|
||||||
// We consider this a pre-release
|
|
||||||
// development version, no migration is done.
|
|
||||||
await metaDb
|
|
||||||
.mktx((stores) => [stores.metaConfig])
|
|
||||||
.runReadWrite(async (tx) => {
|
|
||||||
await tx.metaConfig.put({
|
|
||||||
key: CURRENT_DB_CONFIG_KEY,
|
|
||||||
value: TALER_DB_NAME,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Error(
|
|
||||||
`migration from database ${currentMainVersion} not supported`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainDbHandle = await openDatabase(
|
|
||||||
idbFactory,
|
|
||||||
TALER_DB_NAME,
|
|
||||||
WALLET_DB_MINOR_VERSION,
|
|
||||||
onVersionChange,
|
|
||||||
onTalerDbUpgradeNeeded,
|
|
||||||
);
|
|
||||||
|
|
||||||
return new DbAccess(mainDbHandle, WalletStoresV1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteTalerDatabase(
|
|
||||||
idbFactory: IDBFactory,
|
|
||||||
): Promise<void> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const req = idbFactory.deleteDatabase(TALER_DB_NAME);
|
|
||||||
req.onerror = () => reject(req.error);
|
|
||||||
req.onsuccess = () => resolve();
|
|
||||||
});
|
|
||||||
}
|
|
@ -17,7 +17,12 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
|
import {
|
||||||
|
Event,
|
||||||
|
IDBDatabase,
|
||||||
|
IDBFactory,
|
||||||
|
IDBTransaction,
|
||||||
|
} from "@gnu-taler/idb-bridge";
|
||||||
import {
|
import {
|
||||||
AgeCommitmentProof,
|
AgeCommitmentProof,
|
||||||
AmountJson,
|
AmountJson,
|
||||||
@ -51,13 +56,21 @@ import {
|
|||||||
AttentionPriority,
|
AttentionPriority,
|
||||||
AttentionInfo,
|
AttentionInfo,
|
||||||
AbsoluteTime,
|
AbsoluteTime,
|
||||||
|
Logger,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import {
|
import {
|
||||||
|
DbAccess,
|
||||||
describeContents,
|
describeContents,
|
||||||
describeIndex,
|
describeIndex,
|
||||||
describeStore,
|
describeStore,
|
||||||
|
GetReadWriteAccess,
|
||||||
|
IndexDescriptor,
|
||||||
|
openDatabase,
|
||||||
|
StoreDescriptor,
|
||||||
|
StoreWithIndexes,
|
||||||
} from "./util/query.js";
|
} from "./util/query.js";
|
||||||
import { RetryInfo, RetryTags } from "./util/retries.js";
|
import { RetryInfo, RetryTags } from "./util/retries.js";
|
||||||
|
import { Wallet } from "./wallet.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file contains the database schema of the Taler wallet together
|
* This file contains the database schema of the Taler wallet together
|
||||||
@ -106,7 +119,7 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
|
|||||||
* backwards-compatible way or object stores and indices
|
* backwards-compatible way or object stores and indices
|
||||||
* are added.
|
* are added.
|
||||||
*/
|
*/
|
||||||
export const WALLET_DB_MINOR_VERSION = 1;
|
export const WALLET_DB_MINOR_VERSION = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ranges for operation status fields.
|
* Ranges for operation status fields.
|
||||||
@ -1327,7 +1340,6 @@ export type WgInfo =
|
|||||||
| WgInfoBankPeerPush
|
| WgInfoBankPeerPush
|
||||||
| WgInfoBankRecoup;
|
| WgInfoBankRecoup;
|
||||||
|
|
||||||
|
|
||||||
export interface WithdrawalKycPendingInfo {
|
export interface WithdrawalKycPendingInfo {
|
||||||
paytoHash: string;
|
paytoHash: string;
|
||||||
requirementRow: number;
|
requirementRow: number;
|
||||||
@ -2183,11 +2195,27 @@ export const WalletStoresV1 = {
|
|||||||
"userAttention",
|
"userAttention",
|
||||||
describeContents<UserAttentionRecord>({
|
describeContents<UserAttentionRecord>({
|
||||||
keyPath: ["entityId", "info.type"],
|
keyPath: ["entityId", "info.type"],
|
||||||
|
versionAdded: 2,
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
fixups: describeStore(
|
||||||
|
"fixups",
|
||||||
|
describeContents<FixupRecord>({
|
||||||
|
keyPath: "fixupName",
|
||||||
|
versionAdded: 2,
|
||||||
}),
|
}),
|
||||||
{},
|
{},
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An applied migration.
|
||||||
|
*/
|
||||||
|
export interface FixupRecord {
|
||||||
|
fixupName: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User accounts
|
* User accounts
|
||||||
*/
|
*/
|
||||||
@ -2320,3 +2348,250 @@ export async function importDb(db: IDBDatabase, object: any): Promise<void> {
|
|||||||
}
|
}
|
||||||
throw Error("could not import database");
|
throw Error("could not import database");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FixupDescription {
|
||||||
|
name: string;
|
||||||
|
fn(tx: GetReadWriteAccess<typeof WalletStoresV1>): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manual migrations between minor versions of the DB schema.
|
||||||
|
*/
|
||||||
|
export const walletDbFixups: FixupDescription[] = [
|
||||||
|
{
|
||||||
|
name: "RefreshGroupRecord_currency",
|
||||||
|
async fn(tx): Promise<void> {
|
||||||
|
await tx.refreshGroups.iter().forEachAsync(async (rg) => {
|
||||||
|
if (rg.currency) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Empty refresh group without input coin, delete it!
|
||||||
|
if (rg.inputPerCoin.length === 0) {
|
||||||
|
await tx.refreshGroups.delete(rg.refreshGroupId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rg.currency = Amounts.parseOrThrow(rg.inputPerCoin[0]).currency;
|
||||||
|
await tx.refreshGroups.put(rg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const logger = new Logger("db.ts");
|
||||||
|
|
||||||
|
export async function applyFixups(
|
||||||
|
db: DbAccess<typeof WalletStoresV1>,
|
||||||
|
): Promise<void> {
|
||||||
|
await db.mktxAll().runReadWrite(async (tx) => {
|
||||||
|
for (const fixupInstruction of walletDbFixups) {
|
||||||
|
const fixupRecord = await tx.fixups.get(fixupInstruction.name);
|
||||||
|
if (fixupRecord) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info(`applying DB fixup ${fixupInstruction.name}`);
|
||||||
|
await fixupInstruction.fn(tx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgradeFromStoreMap(
|
||||||
|
storeMap: any,
|
||||||
|
db: IDBDatabase,
|
||||||
|
oldVersion: number,
|
||||||
|
newVersion: number,
|
||||||
|
upgradeTransaction: IDBTransaction,
|
||||||
|
): void {
|
||||||
|
if (oldVersion === 0) {
|
||||||
|
for (const n in storeMap) {
|
||||||
|
const swi: StoreWithIndexes<
|
||||||
|
any,
|
||||||
|
StoreDescriptor<unknown>,
|
||||||
|
any
|
||||||
|
> = storeMap[n];
|
||||||
|
const storeDesc: StoreDescriptor<unknown> = swi.store;
|
||||||
|
const s = db.createObjectStore(swi.storeName, {
|
||||||
|
autoIncrement: storeDesc.autoIncrement,
|
||||||
|
keyPath: storeDesc.keyPath,
|
||||||
|
});
|
||||||
|
for (const indexName in swi.indexMap as any) {
|
||||||
|
const indexDesc: IndexDescriptor = swi.indexMap[indexName];
|
||||||
|
s.createIndex(indexDesc.name, indexDesc.keyPath, {
|
||||||
|
multiEntry: indexDesc.multiEntry,
|
||||||
|
unique: indexDesc.unique,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (oldVersion === newVersion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info(`upgrading database from ${oldVersion} to ${newVersion}`);
|
||||||
|
for (const n in storeMap) {
|
||||||
|
const swi: StoreWithIndexes<any, StoreDescriptor<unknown>, any> = storeMap[
|
||||||
|
n
|
||||||
|
];
|
||||||
|
const storeDesc: StoreDescriptor<unknown> = swi.store;
|
||||||
|
const storeAddedVersion = storeDesc.versionAdded ?? 0;
|
||||||
|
if (storeAddedVersion <= oldVersion) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const s = db.createObjectStore(swi.storeName, {
|
||||||
|
autoIncrement: storeDesc.autoIncrement,
|
||||||
|
keyPath: storeDesc.keyPath,
|
||||||
|
});
|
||||||
|
for (const indexName in swi.indexMap as any) {
|
||||||
|
const indexDesc: IndexDescriptor = swi.indexMap[indexName];
|
||||||
|
const indexAddedVersion = indexDesc.versionAdded ?? 0;
|
||||||
|
if (indexAddedVersion <= oldVersion) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
s.createIndex(indexDesc.name, indexDesc.keyPath, {
|
||||||
|
multiEntry: indexDesc.multiEntry,
|
||||||
|
unique: indexDesc.unique,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function promiseFromTransaction(transaction: IDBTransaction): Promise<void> {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
transaction.oncomplete = () => {
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
transaction.onerror = () => {
|
||||||
|
reject();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purge all data in the given database.
|
||||||
|
*/
|
||||||
|
export function clearDatabase(db: IDBDatabase): Promise<void> {
|
||||||
|
// db.objectStoreNames is a DOMStringList, so we need to convert
|
||||||
|
let stores: string[] = [];
|
||||||
|
for (let i = 0; i < db.objectStoreNames.length; i++) {
|
||||||
|
stores.push(db.objectStoreNames[i]);
|
||||||
|
}
|
||||||
|
const tx = db.transaction(stores, "readwrite");
|
||||||
|
for (const store of stores) {
|
||||||
|
tx.objectStore(store).clear();
|
||||||
|
}
|
||||||
|
return promiseFromTransaction(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTalerDbUpgradeNeeded(
|
||||||
|
db: IDBDatabase,
|
||||||
|
oldVersion: number,
|
||||||
|
newVersion: number,
|
||||||
|
upgradeTransaction: IDBTransaction,
|
||||||
|
) {
|
||||||
|
upgradeFromStoreMap(
|
||||||
|
WalletStoresV1,
|
||||||
|
db,
|
||||||
|
oldVersion,
|
||||||
|
newVersion,
|
||||||
|
upgradeTransaction,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMetaDbUpgradeNeeded(
|
||||||
|
db: IDBDatabase,
|
||||||
|
oldVersion: number,
|
||||||
|
newVersion: number,
|
||||||
|
upgradeTransaction: IDBTransaction,
|
||||||
|
) {
|
||||||
|
upgradeFromStoreMap(
|
||||||
|
walletMetadataStore,
|
||||||
|
db,
|
||||||
|
oldVersion,
|
||||||
|
newVersion,
|
||||||
|
upgradeTransaction,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a promise that resolves
|
||||||
|
* to the taler wallet db.
|
||||||
|
*/
|
||||||
|
export async function openTalerDatabase(
|
||||||
|
idbFactory: IDBFactory,
|
||||||
|
onVersionChange: () => void,
|
||||||
|
): Promise<DbAccess<typeof WalletStoresV1>> {
|
||||||
|
const metaDbHandle = await openDatabase(
|
||||||
|
idbFactory,
|
||||||
|
TALER_META_DB_NAME,
|
||||||
|
1,
|
||||||
|
() => {},
|
||||||
|
onMetaDbUpgradeNeeded,
|
||||||
|
);
|
||||||
|
|
||||||
|
const metaDb = new DbAccess(metaDbHandle, walletMetadataStore);
|
||||||
|
let currentMainVersion: string | undefined;
|
||||||
|
await metaDb
|
||||||
|
.mktx((stores) => [stores.metaConfig])
|
||||||
|
.runReadWrite(async (tx) => {
|
||||||
|
const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY);
|
||||||
|
if (!dbVersionRecord) {
|
||||||
|
currentMainVersion = TALER_DB_NAME;
|
||||||
|
await tx.metaConfig.put({
|
||||||
|
key: CURRENT_DB_CONFIG_KEY,
|
||||||
|
value: TALER_DB_NAME,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
currentMainVersion = dbVersionRecord.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (currentMainVersion !== TALER_DB_NAME) {
|
||||||
|
switch (currentMainVersion) {
|
||||||
|
case "taler-wallet-main-v2":
|
||||||
|
case "taler-wallet-main-v3":
|
||||||
|
case "taler-wallet-main-v4": // temporary, we might migrate v4 later
|
||||||
|
case "taler-wallet-main-v5":
|
||||||
|
case "taler-wallet-main-v6":
|
||||||
|
case "taler-wallet-main-v7":
|
||||||
|
case "taler-wallet-main-v8":
|
||||||
|
// We consider this a pre-release
|
||||||
|
// development version, no migration is done.
|
||||||
|
await metaDb
|
||||||
|
.mktx((stores) => [stores.metaConfig])
|
||||||
|
.runReadWrite(async (tx) => {
|
||||||
|
await tx.metaConfig.put({
|
||||||
|
key: CURRENT_DB_CONFIG_KEY,
|
||||||
|
value: TALER_DB_NAME,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Error(
|
||||||
|
`major migration from database major=${currentMainVersion} not supported`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainDbHandle = await openDatabase(
|
||||||
|
idbFactory,
|
||||||
|
TALER_DB_NAME,
|
||||||
|
WALLET_DB_MINOR_VERSION,
|
||||||
|
onVersionChange,
|
||||||
|
onTalerDbUpgradeNeeded,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handle = new DbAccess(mainDbHandle, WalletStoresV1);
|
||||||
|
|
||||||
|
await applyFixups(handle);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteTalerDatabase(
|
||||||
|
idbFactory: IDBFactory,
|
||||||
|
): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const req = idbFactory.deleteDatabase(TALER_DB_NAME);
|
||||||
|
req.onerror = () => reject(req.error);
|
||||||
|
req.onsuccess = () => resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -34,7 +34,7 @@ import { Logger, WalletNotification } from "@gnu-taler/taler-util";
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { NodeThreadCryptoWorkerFactory } from "../crypto/workers/nodeThreadWorker.js";
|
import { NodeThreadCryptoWorkerFactory } from "../crypto/workers/nodeThreadWorker.js";
|
||||||
import { SynchronousCryptoWorkerFactoryNode } from "../crypto/workers/synchronousWorkerFactoryNode.js";
|
import { SynchronousCryptoWorkerFactoryNode } from "../crypto/workers/synchronousWorkerFactoryNode.js";
|
||||||
import { openTalerDatabase } from "../db-utils.js";
|
import { openTalerDatabase } from "../index.js";
|
||||||
import { HttpRequestLibrary } from "../util/http.js";
|
import { HttpRequestLibrary } from "../util/http.js";
|
||||||
import { SetTimeoutTimerAPI } from "../util/timer.js";
|
import { SetTimeoutTimerAPI } from "../util/timer.js";
|
||||||
import { Wallet } from "../wallet.js";
|
import { Wallet } from "../wallet.js";
|
||||||
|
@ -29,7 +29,6 @@ export * from "./util/http.js";
|
|||||||
export * from "./versions.js";
|
export * from "./versions.js";
|
||||||
|
|
||||||
export * from "./db.js";
|
export * from "./db.js";
|
||||||
export * from "./db-utils.js";
|
|
||||||
|
|
||||||
// Crypto and crypto workers
|
// Crypto and crypto workers
|
||||||
// export * from "./crypto/workers/nodeThreadWorker.js";
|
// export * from "./crypto/workers/nodeThreadWorker.js";
|
||||||
|
@ -303,7 +303,7 @@ export interface StoreOptions {
|
|||||||
autoIncrement?: boolean;
|
autoIncrement?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database version that this store was added in, or
|
* First minor database version that this store was added in, or
|
||||||
* undefined if added in the first version.
|
* undefined if added in the first version.
|
||||||
*/
|
*/
|
||||||
versionAdded?: number;
|
versionAdded?: number;
|
||||||
|
@ -55,7 +55,6 @@ import {
|
|||||||
codecForInitiatePeerPushPaymentRequest,
|
codecForInitiatePeerPushPaymentRequest,
|
||||||
codecForIntegrationTestArgs,
|
codecForIntegrationTestArgs,
|
||||||
codecForListKnownBankAccounts,
|
codecForListKnownBankAccounts,
|
||||||
codecForUserAttentionsRequest,
|
|
||||||
codecForPrepareDepositRequest,
|
codecForPrepareDepositRequest,
|
||||||
codecForPreparePayRequest,
|
codecForPreparePayRequest,
|
||||||
codecForPreparePeerPullPaymentRequest,
|
codecForPreparePeerPullPaymentRequest,
|
||||||
@ -70,6 +69,8 @@ import {
|
|||||||
codecForTrackDepositGroupRequest,
|
codecForTrackDepositGroupRequest,
|
||||||
codecForTransactionByIdRequest,
|
codecForTransactionByIdRequest,
|
||||||
codecForTransactionsRequest,
|
codecForTransactionsRequest,
|
||||||
|
codecForUserAttentionByIdRequest,
|
||||||
|
codecForUserAttentionsRequest,
|
||||||
codecForWithdrawFakebankRequest,
|
codecForWithdrawFakebankRequest,
|
||||||
codecForWithdrawTestBalance,
|
codecForWithdrawTestBalance,
|
||||||
CoinDumpJson,
|
CoinDumpJson,
|
||||||
@ -92,6 +93,7 @@ import {
|
|||||||
KnownBankAccounts,
|
KnownBankAccounts,
|
||||||
KnownBankAccountsInfo,
|
KnownBankAccountsInfo,
|
||||||
Logger,
|
Logger,
|
||||||
|
ManualWithdrawalDetails,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
RefreshReason,
|
RefreshReason,
|
||||||
@ -99,17 +101,15 @@ import {
|
|||||||
URL,
|
URL,
|
||||||
WalletCoreVersion,
|
WalletCoreVersion,
|
||||||
WalletNotification,
|
WalletNotification,
|
||||||
codecForUserAttentionByIdRequest,
|
|
||||||
ManualWithdrawalDetails,
|
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
|
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
|
||||||
import {
|
import {
|
||||||
CryptoDispatcher,
|
CryptoDispatcher,
|
||||||
CryptoWorkerFactory,
|
CryptoWorkerFactory,
|
||||||
} from "./crypto/workers/crypto-dispatcher.js";
|
} from "./crypto/workers/crypto-dispatcher.js";
|
||||||
import { clearDatabase } from "./db-utils.js";
|
|
||||||
import {
|
import {
|
||||||
AuditorTrustRecord,
|
AuditorTrustRecord,
|
||||||
|
clearDatabase,
|
||||||
CoinSourceType,
|
CoinSourceType,
|
||||||
ConfigRecordKey,
|
ConfigRecordKey,
|
||||||
DenominationRecord,
|
DenominationRecord,
|
||||||
@ -134,6 +134,11 @@ import {
|
|||||||
RecoupOperations,
|
RecoupOperations,
|
||||||
RefreshOperations,
|
RefreshOperations,
|
||||||
} from "./internal-wallet-state.js";
|
} from "./internal-wallet-state.js";
|
||||||
|
import {
|
||||||
|
getUserAttentions,
|
||||||
|
getUserAttentionsUnreadCount,
|
||||||
|
markAttentionRequestAsRead,
|
||||||
|
} from "./operations/attention.js";
|
||||||
import { exportBackup } from "./operations/backup/export.js";
|
import { exportBackup } from "./operations/backup/export.js";
|
||||||
import {
|
import {
|
||||||
addBackupProvider,
|
addBackupProvider,
|
||||||
@ -150,11 +155,6 @@ import {
|
|||||||
} from "./operations/backup/index.js";
|
} from "./operations/backup/index.js";
|
||||||
import { setWalletDeviceId } from "./operations/backup/state.js";
|
import { setWalletDeviceId } from "./operations/backup/state.js";
|
||||||
import { getBalances } from "./operations/balance.js";
|
import { getBalances } from "./operations/balance.js";
|
||||||
import {
|
|
||||||
getUserAttentions,
|
|
||||||
getUserAttentionsUnreadCount,
|
|
||||||
markAttentionRequestAsRead,
|
|
||||||
} from "./operations/attention.js";
|
|
||||||
import {
|
import {
|
||||||
getExchangeTosStatus,
|
getExchangeTosStatus,
|
||||||
makeExchangeListItem,
|
makeExchangeListItem,
|
||||||
|
Loading…
Reference in New Issue
Block a user