aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-09-21 21:47:00 +0200
committerFlorian Dold <florian@dold.me>2022-09-21 22:50:42 +0200
commit4649469b58b9a4068fa94de07f415f1bbc58794c (patch)
treed9db9126ddf51c496e6660acacc7561a71e9252a
parenta398959670d56f5ecd3ef58abc85f14c55c8a427 (diff)
wallet-core: DB improvements
-rw-r--r--packages/idb-bridge/src/bridge-idb.ts37
-rw-r--r--packages/taler-wallet-core/src/db-utils.ts1
-rw-r--r--packages/taler-wallet-core/src/db.ts23
-rw-r--r--packages/taler-wallet-core/src/operations/recoup.ts4
-rw-r--r--packages/taler-wallet-core/src/util/query.ts40
5 files changed, 72 insertions, 33 deletions
diff --git a/packages/idb-bridge/src/bridge-idb.ts b/packages/idb-bridge/src/bridge-idb.ts
index 35cedb1db..128a6900d 100644
--- a/packages/idb-bridge/src/bridge-idb.ts
+++ b/packages/idb-bridge/src/bridge-idb.ts
@@ -57,16 +57,17 @@ import {
TransactionInactiveError,
VersionError,
} from "./util/errors.js";
-import { FakeDOMStringList, fakeDOMStringList } from "./util/fakeDOMStringList.js";
+import {
+ FakeDOMStringList,
+ fakeDOMStringList,
+} from "./util/fakeDOMStringList.js";
import FakeEvent from "./util/FakeEvent.js";
import FakeEventTarget from "./util/FakeEventTarget.js";
import { makeStoreKeyValue } from "./util/makeStoreKeyValue.js";
import { normalizeKeyPath } from "./util/normalizeKeyPath.js";
import { openPromise } from "./util/openPromise.js";
import queueTask from "./util/queueTask.js";
-import {
- checkStructuredCloneOrThrow,
-} from "./util/structuredClone.js";
+import { checkStructuredCloneOrThrow } from "./util/structuredClone.js";
import { validateKeyPath } from "./util/validateKeyPath.js";
import { valueToKey } from "./util/valueToKey.js";
@@ -933,9 +934,8 @@ export class BridgeIDBFactory {
);
// We need to expose the new version number to the upgrade transaction.
- db._schema = this.backend.getCurrentTransactionSchema(
- backendTransaction,
- );
+ db._schema =
+ this.backend.getCurrentTransactionSchema(backendTransaction);
const transaction = db._internalTransaction(
[],
@@ -1110,9 +1110,8 @@ export class BridgeIDBIndex implements IDBIndex {
this._backend.renameIndex(btx, this._objectStore.name, oldName, newName);
- this._objectStore._transaction._db._schema = this._backend.getCurrentTransactionSchema(
- btx,
- );
+ this._objectStore._transaction._db._schema =
+ this._backend.getCurrentTransactionSchema(btx);
this._objectStore._indexesCache.delete(oldName);
this._objectStore._indexesCache.set(newName, this);
@@ -1629,9 +1628,8 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
}
this._backend.renameObjectStore(btx, oldName, newName);
- this._transaction._db._schema = this._backend.getCurrentTransactionSchema(
- btx,
- );
+ this._transaction._db._schema =
+ this._backend.getCurrentTransactionSchema(btx);
// We don't modify scope, as the scope of the transaction
// doesn't matter if we're in an upgrade transaction.
@@ -2235,11 +2233,8 @@ export class BridgeIDBRequest extends FakeEventTarget implements IDBRequest {
}
return this._source;
}
- _source:
- | BridgeIDBCursor
- | BridgeIDBIndex
- | BridgeIDBObjectStore
- | null = null;
+ _source: BridgeIDBCursor | BridgeIDBIndex | BridgeIDBObjectStore | null =
+ null;
transaction: BridgeIDBTransaction | null = null;
readyState: "done" | "pending" = "pending";
onsuccess: EventListener | null = null;
@@ -2302,7 +2297,8 @@ export class BridgeIDBRequest extends FakeEventTarget implements IDBRequest {
/** @public */
export class BridgeIDBOpenDBRequest
extends BridgeIDBRequest
- implements IDBOpenDBRequest {
+ implements IDBOpenDBRequest
+{
public onupgradeneeded: EventListener | null = null;
public onblocked: EventListener | null = null;
@@ -2350,7 +2346,8 @@ function waitMacroQueue(): Promise<void> {
/** @public */
export class BridgeIDBTransaction
extends FakeEventTarget
- implements IDBTransaction {
+ implements IDBTransaction
+{
_committed: boolean = false;
/**
* A transaction is active as long as new operations can be
diff --git a/packages/taler-wallet-core/src/db-utils.ts b/packages/taler-wallet-core/src/db-utils.ts
index b32b3d585..7f4b0de45 100644
--- a/packages/taler-wallet-core/src/db-utils.ts
+++ b/packages/taler-wallet-core/src/db-utils.ts
@@ -60,6 +60,7 @@ function upgradeFromStoreMap(
const indexDesc: IndexDescriptor = swi.indexMap[indexName];
s.createIndex(indexDesc.name, indexDesc.keyPath, {
multiEntry: indexDesc.multiEntry,
+ unique: indexDesc.unique,
});
}
}
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 493f1a1d0..8b96dd5be 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -527,6 +527,8 @@ export interface ExchangeRecord {
/**
* Public key of the reserve that we're currently using for
* receiving P2P payments.
+ *
+ * FIXME: Make this a rowId of reserves!
*/
currentMergeReserveInfo?: MergeReserveInfo;
}
@@ -569,6 +571,8 @@ export interface PlanchetRecord {
*
* Can be the empty string (non-null/undefined for DB indexing)
* if this is a tipping reserve.
+ *
+ * FIXME: Where is this used?
*/
reservePub: string;
@@ -763,6 +767,8 @@ export interface ProposalDownload {
/**
* Extracted / parsed data from the contract terms.
+ *
+ * FIXME: Do we need to store *all* that data in duplicate?
*/
contractData: WalletContractData;
}
@@ -1762,9 +1768,14 @@ export interface PeerPullPaymentIncomingRecord {
contractPriv: string;
}
-// FIXME: give this some smaller "row ID" to
-// reference in other records?
+/**
+ * Store for extra information about a reserve.
+ *
+ * Mostly used to store the private key for a reserve and to allow
+ * other records to reference the reserve key pair via a small row ID.
+ */
export interface ReserveRecord {
+ rowId?: number;
reservePub: string;
reservePriv: string;
}
@@ -1844,9 +1855,12 @@ export const WalletStoresV1 = {
reserves: describeStore(
"reserves",
describeContents<ReserveRecord>({
- keyPath: "reservePub",
+ keyPath: "rowId",
+ autoIncrement: true,
}),
- {},
+ {
+ byReservePub: describeIndex("byReservePub", "reservePub", {}),
+ },
),
config: describeStore(
"config",
@@ -1956,7 +1970,6 @@ export const WalletStoresV1 = {
keyPath: "withdrawalGroupId",
}),
{
- byReservePub: describeIndex("byReservePub", "reservePub"),
byStatus: describeIndex("byStatus", "status"),
byTalerWithdrawUri: describeIndex(
"byTalerWithdrawUri",
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts
index 6d899b947..2d92ff8ba 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -356,7 +356,9 @@ export async function processRecoupGroupHandler(
throw Error(`Coin ${coinPub} not found, can't request recoup`);
}
if (coin.coinSource.type === CoinSourceType.Withdraw) {
- const reserve = await tx.reserves.get(coin.coinSource.reservePub);
+ const reserve = await tx.reserves.indexes.byReservePub.get(
+ coin.coinSource.reservePub,
+ );
if (!reserve) {
return;
}
diff --git a/packages/taler-wallet-core/src/util/query.ts b/packages/taler-wallet-core/src/util/query.ts
index 3d4ff79cb..71d7b9783 100644
--- a/packages/taler-wallet-core/src/util/query.ts
+++ b/packages/taler-wallet-core/src/util/query.ts
@@ -61,6 +61,13 @@ export interface IndexOptions {
* undefined if added in the first version.
*/
versionAdded?: number;
+
+ /**
+ * Does this index enforce unique keys?
+ *
+ * Defaults to false.
+ */
+ unique?: boolean;
}
function requestToPromise(req: IDBRequest): Promise<any> {
@@ -276,6 +283,7 @@ export interface IndexDescriptor {
name: string;
keyPath: IDBKeyPath | IDBKeyPath[];
multiEntry?: boolean;
+ unique?: boolean;
}
export interface StoreDescriptor<RecordType> {
@@ -292,7 +300,11 @@ export interface StoreOptions {
export function describeContents<RecordType = never>(
options: StoreOptions,
): StoreDescriptor<RecordType> {
- return { keyPath: options.keyPath, _dummy: undefined as any };
+ return {
+ keyPath: options.keyPath,
+ _dummy: undefined as any,
+ autoIncrement: options.autoIncrement,
+ };
}
export function describeIndex(
@@ -304,6 +316,7 @@ export function describeIndex(
keyPath,
name,
multiEntry: options.multiEntry,
+ unique: options.unique,
};
}
@@ -339,11 +352,18 @@ export interface StoreReadOnlyAccessor<RecordType, IndexMap> {
indexes: GetIndexReadOnlyAccess<RecordType, IndexMap>;
}
+export interface InsertResponse {
+ /**
+ * Key of the newly inserted (via put/add) record.
+ */
+ key: IDBValidKey;
+}
+
export interface StoreReadWriteAccessor<RecordType, IndexMap> {
get(key: IDBValidKey): Promise<RecordType | undefined>;
iter(query?: IDBValidKey): ResultStream<RecordType>;
- put(r: RecordType): Promise<void>;
- add(r: RecordType): Promise<void>;
+ put(r: RecordType): Promise<InsertResponse>;
+ add(r: RecordType): Promise<InsertResponse>;
delete(key: IDBValidKey): Promise<void>;
indexes: GetIndexReadWriteAccess<RecordType, IndexMap>;
}
@@ -577,13 +597,19 @@ function makeWriteContext(
const req = tx.objectStore(storeName).openCursor(query);
return new ResultStream<any>(req);
},
- add(r) {
+ async add(r) {
const req = tx.objectStore(storeName).add(r);
- return requestToPromise(req);
+ const key = await requestToPromise(req);
+ return {
+ key: key,
+ };
},
- put(r) {
+ async put(r) {
const req = tx.objectStore(storeName).put(r);
- return requestToPromise(req);
+ const key = await requestToPromise(req);
+ return {
+ key: key,
+ };
},
delete(k) {
const req = tx.objectStore(storeName).delete(k);