prepare for schema migrations
This commit is contained in:
parent
20ebc44420
commit
49e3b3e5b9
37
src/db.ts
37
src/db.ts
@ -1,7 +1,7 @@
|
||||
import { Stores } from "./types/dbTypes";
|
||||
import { openDatabase, Database } from "./util/query";
|
||||
import { openDatabase, Database, Store, Index } from "./util/query";
|
||||
|
||||
const TALER_DB_NAME = "taler";
|
||||
const TALER_DB_NAME = "taler-wallet";
|
||||
|
||||
/**
|
||||
* Current database version, should be incremented
|
||||
@ -9,7 +9,7 @@ const TALER_DB_NAME = "taler";
|
||||
* In the future we might consider adding migration functions for
|
||||
* each version increment.
|
||||
*/
|
||||
export const WALLET_DB_VERSION = 28;
|
||||
export const WALLET_DB_VERSION = 1;
|
||||
|
||||
/**
|
||||
* Return a promise that resolves
|
||||
@ -18,18 +18,41 @@ export const WALLET_DB_VERSION = 28;
|
||||
export function openTalerDatabase(
|
||||
idbFactory: IDBFactory,
|
||||
onVersionChange: () => void,
|
||||
onUpgradeUnsupported: (oldVersion: number, newVersion: number) => void,
|
||||
): Promise<IDBDatabase> {
|
||||
const onUpgradeNeeded = (
|
||||
db: IDBDatabase,
|
||||
oldVersion: number,
|
||||
newVersion: number,
|
||||
) => {
|
||||
switch (oldVersion) {
|
||||
case 0: // DB does not exist yet
|
||||
for (const n in Stores) {
|
||||
if ((Stores as any)[n] instanceof Store) {
|
||||
const si: Store<any> = (Stores as any)[n];
|
||||
const s = db.createObjectStore(si.name, si.storeParams);
|
||||
for (const indexName in si as any) {
|
||||
if ((si as any)[indexName] instanceof Index) {
|
||||
const ii: Index<any, any> = (si as any)[indexName];
|
||||
s.createIndex(ii.indexName, ii.keyPath, ii.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw Error("unsupported existig DB version");
|
||||
}
|
||||
};
|
||||
|
||||
return openDatabase(
|
||||
idbFactory,
|
||||
TALER_DB_NAME,
|
||||
WALLET_DB_VERSION,
|
||||
Stores,
|
||||
onVersionChange,
|
||||
onUpgradeUnsupported,
|
||||
onUpgradeNeeded,
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteTalerDatabase(idbFactory: IDBFactory) {
|
||||
Database.deleteDatabase(idbFactory, TALER_DB_NAME);
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,7 @@
|
||||
import { Wallet } from "../wallet";
|
||||
import { MemoryBackend, BridgeIDBFactory, shimIndexedDB } from "idb-bridge";
|
||||
import { openTalerDatabase } from "../db";
|
||||
import {
|
||||
HttpRequestLibrary,
|
||||
} from "../util/http";
|
||||
import { HttpRequestLibrary } from "../util/http";
|
||||
import * as amounts from "../util/amounts";
|
||||
import { Bank } from "./bank";
|
||||
import fs = require("fs");
|
||||
@ -39,7 +37,6 @@ import { Logger } from "../util/logging";
|
||||
|
||||
const logger = new Logger("helpers.ts");
|
||||
|
||||
|
||||
export interface DefaultNodeWalletArgs {
|
||||
/**
|
||||
* Location of the wallet database.
|
||||
@ -112,18 +109,9 @@ export async function getDefaultNodeWallet(
|
||||
throw Error();
|
||||
};
|
||||
|
||||
const myUnsupportedUpgrade = () => {
|
||||
console.error("unsupported database migration");
|
||||
throw Error();
|
||||
};
|
||||
|
||||
shimIndexedDB(myBridgeIdbFactory);
|
||||
|
||||
const myDb = await openTalerDatabase(
|
||||
myIdbFactory,
|
||||
myVersionChange,
|
||||
myUnsupportedUpgrade,
|
||||
);
|
||||
const myDb = await openTalerDatabase(myIdbFactory, myVersionChange);
|
||||
|
||||
//const worker = new SynchronousCryptoWorkerFactory();
|
||||
//const worker = new NodeCryptoWorkerFactory();
|
||||
|
@ -1366,6 +1366,34 @@ export interface BankWithdrawUriRecord {
|
||||
reservePub: string;
|
||||
}
|
||||
|
||||
export const enum ImportPayloadType {
|
||||
CoreSchema = "core-schema",
|
||||
}
|
||||
|
||||
/**
|
||||
* Record to keep track of data imported into the wallet.
|
||||
*/
|
||||
export class WalletImportRecord {
|
||||
/**
|
||||
* Unique ID to reference this import record.
|
||||
*/
|
||||
walletImportId: string;
|
||||
|
||||
/**
|
||||
* When was the data imported?
|
||||
*/
|
||||
timestampImportStarted: Timestamp;
|
||||
|
||||
timestampImportFinished: Timestamp | undefined;
|
||||
|
||||
payloadType: ImportPayloadType;
|
||||
|
||||
/**
|
||||
* The actual data to import.
|
||||
*/
|
||||
payload: any;
|
||||
}
|
||||
|
||||
/* tslint:disable:completed-docs */
|
||||
|
||||
/**
|
||||
@ -1517,6 +1545,12 @@ export namespace Stores {
|
||||
}
|
||||
}
|
||||
|
||||
class WalletImportsStore extends Store<WalletImportRecord> {
|
||||
constructor() {
|
||||
super("walletImports", { keyPath: "walletImportId" });
|
||||
}
|
||||
}
|
||||
|
||||
export const coins = new CoinsStore();
|
||||
export const coinsReturns = new Store<CoinsReturnRecord>("coinsReturns", {
|
||||
keyPath: "contractTermsHash",
|
||||
@ -1539,6 +1573,7 @@ export namespace Stores {
|
||||
export const payEvents = new PayEventsStore();
|
||||
export const reserveUpdatedEvents = new ReserveUpdatedEventsStore();
|
||||
export const exchangeUpdatedEvents = new ExchangeUpdatedEventsStore();
|
||||
export const walletImports = new WalletImportsStore();
|
||||
}
|
||||
|
||||
/* tslint:enable:completed-docs */
|
||||
|
58
src/types/schemacore.ts
Normal file
58
src/types/schemacore.ts
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2019 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/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core of the wallet's schema, used for painless export, import
|
||||
* and schema migration.
|
||||
*
|
||||
* If this schema is extended, it must be extended in a completely
|
||||
* backwards-compatible way.
|
||||
*/
|
||||
|
||||
interface CoreCoin {
|
||||
exchangeBaseUrl: string;
|
||||
coinPub: string;
|
||||
coinPriv: string;
|
||||
amountRemaining: string;
|
||||
}
|
||||
|
||||
interface CorePurchase {
|
||||
noncePub: string;
|
||||
noncePriv: string;
|
||||
paySig: string;
|
||||
contractTerms: any;
|
||||
}
|
||||
|
||||
interface CoreReserve {
|
||||
reservePub: string;
|
||||
reservePriv: string;
|
||||
exchangeBaseUrl: string;
|
||||
}
|
||||
|
||||
interface SchemaCore {
|
||||
coins: CoreCoin[];
|
||||
purchases: CorePurchase[];
|
||||
|
||||
/**
|
||||
* Schema version (of full schema) of wallet that exported the core schema.
|
||||
*/
|
||||
versionExporter: number;
|
||||
|
||||
/**
|
||||
* Schema version of the database that has been exported to the core schema
|
||||
*/
|
||||
versionSourceDatabase: number;
|
||||
}
|
@ -383,9 +383,8 @@ export function openDatabase(
|
||||
idbFactory: IDBFactory,
|
||||
databaseName: string,
|
||||
databaseVersion: number,
|
||||
schema: any,
|
||||
onVersionChange: () => void,
|
||||
onUpgradeUnsupported: (oldVersion: number, newVersion: number) => void,
|
||||
onUpgradeNeeded: (db: IDBDatabase, oldVersion: number, newVersion: number) => void,
|
||||
): Promise<IDBDatabase> {
|
||||
return new Promise<IDBDatabase>((resolve, reject) => {
|
||||
const req = idbFactory.open(databaseName, databaseVersion);
|
||||
@ -405,31 +404,10 @@ export function openDatabase(
|
||||
};
|
||||
req.onupgradeneeded = e => {
|
||||
const db = req.result;
|
||||
onUpgradeNeeded(db, e.oldVersion, e.newVersion!);
|
||||
console.log(
|
||||
`DB: upgrade needed: oldVersion=${e.oldVersion}, newVersion=${e.newVersion}`,
|
||||
);
|
||||
switch (e.oldVersion) {
|
||||
case 0: // DB does not exist yet
|
||||
for (const n in schema) {
|
||||
if (schema[n] instanceof Store) {
|
||||
const si: Store<any> = schema[n];
|
||||
const s = db.createObjectStore(si.name, si.storeParams);
|
||||
for (const indexName in si as any) {
|
||||
if ((si as any)[indexName] instanceof Index) {
|
||||
const ii: Index<any, any> = (si as any)[indexName];
|
||||
s.createIndex(ii.indexName, ii.keyPath, ii.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (e.oldVersion !== databaseVersion) {
|
||||
onUpgradeUnsupported(e.oldVersion, databaseVersion);
|
||||
throw Error("incompatible DB");
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -390,16 +390,6 @@ let outdatedDbVersion: number | undefined;
|
||||
|
||||
let walletInit: OpenedPromise<void> = openPromise<void>();
|
||||
|
||||
function handleUpgradeUnsupported(oldDbVersion: number, newDbVersion: number) {
|
||||
console.log("DB migration not supported");
|
||||
outdatedDbVersion = oldDbVersion;
|
||||
chrome.tabs.create({
|
||||
url: chrome.extension.getURL("/src/webex/pages/reset-required.html"),
|
||||
});
|
||||
setBadgeText({ text: "err" });
|
||||
chrome.browserAction.setBadgeBackgroundColor({ color: "#F00" });
|
||||
}
|
||||
|
||||
async function reinitWallet() {
|
||||
if (currentWallet) {
|
||||
currentWallet.stop();
|
||||
@ -412,7 +402,6 @@ async function reinitWallet() {
|
||||
currentDatabase = await openTalerDatabase(
|
||||
indexedDB,
|
||||
reinitWallet,
|
||||
handleUpgradeUnsupported,
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("could not open database", e);
|
||||
|
@ -67,6 +67,7 @@
|
||||
"src/types/history.ts",
|
||||
"src/types/notifications.ts",
|
||||
"src/types/pending.ts",
|
||||
"src/types/schemacore.ts",
|
||||
"src/types/talerTypes.ts",
|
||||
"src/types/types-test.ts",
|
||||
"src/types/walletTypes.ts",
|
||||
|
Loading…
Reference in New Issue
Block a user