wallet-core: DB improvements
This commit is contained in:
parent
a398959670
commit
4649469b58
@ -57,16 +57,17 @@ import {
|
|||||||
TransactionInactiveError,
|
TransactionInactiveError,
|
||||||
VersionError,
|
VersionError,
|
||||||
} from "./util/errors.js";
|
} 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 FakeEvent from "./util/FakeEvent.js";
|
||||||
import FakeEventTarget from "./util/FakeEventTarget.js";
|
import FakeEventTarget from "./util/FakeEventTarget.js";
|
||||||
import { makeStoreKeyValue } from "./util/makeStoreKeyValue.js";
|
import { makeStoreKeyValue } from "./util/makeStoreKeyValue.js";
|
||||||
import { normalizeKeyPath } from "./util/normalizeKeyPath.js";
|
import { normalizeKeyPath } from "./util/normalizeKeyPath.js";
|
||||||
import { openPromise } from "./util/openPromise.js";
|
import { openPromise } from "./util/openPromise.js";
|
||||||
import queueTask from "./util/queueTask.js";
|
import queueTask from "./util/queueTask.js";
|
||||||
import {
|
import { checkStructuredCloneOrThrow } from "./util/structuredClone.js";
|
||||||
checkStructuredCloneOrThrow,
|
|
||||||
} from "./util/structuredClone.js";
|
|
||||||
import { validateKeyPath } from "./util/validateKeyPath.js";
|
import { validateKeyPath } from "./util/validateKeyPath.js";
|
||||||
import { valueToKey } from "./util/valueToKey.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.
|
// We need to expose the new version number to the upgrade transaction.
|
||||||
db._schema = this.backend.getCurrentTransactionSchema(
|
db._schema =
|
||||||
backendTransaction,
|
this.backend.getCurrentTransactionSchema(backendTransaction);
|
||||||
);
|
|
||||||
|
|
||||||
const transaction = db._internalTransaction(
|
const transaction = db._internalTransaction(
|
||||||
[],
|
[],
|
||||||
@ -1110,9 +1110,8 @@ export class BridgeIDBIndex implements IDBIndex {
|
|||||||
|
|
||||||
this._backend.renameIndex(btx, this._objectStore.name, oldName, newName);
|
this._backend.renameIndex(btx, this._objectStore.name, oldName, newName);
|
||||||
|
|
||||||
this._objectStore._transaction._db._schema = this._backend.getCurrentTransactionSchema(
|
this._objectStore._transaction._db._schema =
|
||||||
btx,
|
this._backend.getCurrentTransactionSchema(btx);
|
||||||
);
|
|
||||||
|
|
||||||
this._objectStore._indexesCache.delete(oldName);
|
this._objectStore._indexesCache.delete(oldName);
|
||||||
this._objectStore._indexesCache.set(newName, this);
|
this._objectStore._indexesCache.set(newName, this);
|
||||||
@ -1629,9 +1628,8 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._backend.renameObjectStore(btx, oldName, newName);
|
this._backend.renameObjectStore(btx, oldName, newName);
|
||||||
this._transaction._db._schema = this._backend.getCurrentTransactionSchema(
|
this._transaction._db._schema =
|
||||||
btx,
|
this._backend.getCurrentTransactionSchema(btx);
|
||||||
);
|
|
||||||
|
|
||||||
// We don't modify scope, as the scope of the transaction
|
// We don't modify scope, as the scope of the transaction
|
||||||
// doesn't matter if we're in an upgrade 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;
|
return this._source;
|
||||||
}
|
}
|
||||||
_source:
|
_source: BridgeIDBCursor | BridgeIDBIndex | BridgeIDBObjectStore | null =
|
||||||
| BridgeIDBCursor
|
null;
|
||||||
| BridgeIDBIndex
|
|
||||||
| BridgeIDBObjectStore
|
|
||||||
| null = null;
|
|
||||||
transaction: BridgeIDBTransaction | null = null;
|
transaction: BridgeIDBTransaction | null = null;
|
||||||
readyState: "done" | "pending" = "pending";
|
readyState: "done" | "pending" = "pending";
|
||||||
onsuccess: EventListener | null = null;
|
onsuccess: EventListener | null = null;
|
||||||
@ -2302,7 +2297,8 @@ export class BridgeIDBRequest extends FakeEventTarget implements IDBRequest {
|
|||||||
/** @public */
|
/** @public */
|
||||||
export class BridgeIDBOpenDBRequest
|
export class BridgeIDBOpenDBRequest
|
||||||
extends BridgeIDBRequest
|
extends BridgeIDBRequest
|
||||||
implements IDBOpenDBRequest {
|
implements IDBOpenDBRequest
|
||||||
|
{
|
||||||
public onupgradeneeded: EventListener | null = null;
|
public onupgradeneeded: EventListener | null = null;
|
||||||
public onblocked: EventListener | null = null;
|
public onblocked: EventListener | null = null;
|
||||||
|
|
||||||
@ -2350,7 +2346,8 @@ function waitMacroQueue(): Promise<void> {
|
|||||||
/** @public */
|
/** @public */
|
||||||
export class BridgeIDBTransaction
|
export class BridgeIDBTransaction
|
||||||
extends FakeEventTarget
|
extends FakeEventTarget
|
||||||
implements IDBTransaction {
|
implements IDBTransaction
|
||||||
|
{
|
||||||
_committed: boolean = false;
|
_committed: boolean = false;
|
||||||
/**
|
/**
|
||||||
* A transaction is active as long as new operations can be
|
* A transaction is active as long as new operations can be
|
||||||
|
@ -60,6 +60,7 @@ function upgradeFromStoreMap(
|
|||||||
const indexDesc: IndexDescriptor = swi.indexMap[indexName];
|
const indexDesc: IndexDescriptor = swi.indexMap[indexName];
|
||||||
s.createIndex(indexDesc.name, indexDesc.keyPath, {
|
s.createIndex(indexDesc.name, indexDesc.keyPath, {
|
||||||
multiEntry: indexDesc.multiEntry,
|
multiEntry: indexDesc.multiEntry,
|
||||||
|
unique: indexDesc.unique,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,6 +527,8 @@ export interface ExchangeRecord {
|
|||||||
/**
|
/**
|
||||||
* Public key of the reserve that we're currently using for
|
* Public key of the reserve that we're currently using for
|
||||||
* receiving P2P payments.
|
* receiving P2P payments.
|
||||||
|
*
|
||||||
|
* FIXME: Make this a rowId of reserves!
|
||||||
*/
|
*/
|
||||||
currentMergeReserveInfo?: MergeReserveInfo;
|
currentMergeReserveInfo?: MergeReserveInfo;
|
||||||
}
|
}
|
||||||
@ -569,6 +571,8 @@ export interface PlanchetRecord {
|
|||||||
*
|
*
|
||||||
* Can be the empty string (non-null/undefined for DB indexing)
|
* Can be the empty string (non-null/undefined for DB indexing)
|
||||||
* if this is a tipping reserve.
|
* if this is a tipping reserve.
|
||||||
|
*
|
||||||
|
* FIXME: Where is this used?
|
||||||
*/
|
*/
|
||||||
reservePub: string;
|
reservePub: string;
|
||||||
|
|
||||||
@ -763,6 +767,8 @@ export interface ProposalDownload {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracted / parsed data from the contract terms.
|
* Extracted / parsed data from the contract terms.
|
||||||
|
*
|
||||||
|
* FIXME: Do we need to store *all* that data in duplicate?
|
||||||
*/
|
*/
|
||||||
contractData: WalletContractData;
|
contractData: WalletContractData;
|
||||||
}
|
}
|
||||||
@ -1762,9 +1768,14 @@ export interface PeerPullPaymentIncomingRecord {
|
|||||||
contractPriv: string;
|
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 {
|
export interface ReserveRecord {
|
||||||
|
rowId?: number;
|
||||||
reservePub: string;
|
reservePub: string;
|
||||||
reservePriv: string;
|
reservePriv: string;
|
||||||
}
|
}
|
||||||
@ -1844,9 +1855,12 @@ export const WalletStoresV1 = {
|
|||||||
reserves: describeStore(
|
reserves: describeStore(
|
||||||
"reserves",
|
"reserves",
|
||||||
describeContents<ReserveRecord>({
|
describeContents<ReserveRecord>({
|
||||||
keyPath: "reservePub",
|
keyPath: "rowId",
|
||||||
|
autoIncrement: true,
|
||||||
}),
|
}),
|
||||||
{},
|
{
|
||||||
|
byReservePub: describeIndex("byReservePub", "reservePub", {}),
|
||||||
|
},
|
||||||
),
|
),
|
||||||
config: describeStore(
|
config: describeStore(
|
||||||
"config",
|
"config",
|
||||||
@ -1956,7 +1970,6 @@ export const WalletStoresV1 = {
|
|||||||
keyPath: "withdrawalGroupId",
|
keyPath: "withdrawalGroupId",
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
byReservePub: describeIndex("byReservePub", "reservePub"),
|
|
||||||
byStatus: describeIndex("byStatus", "status"),
|
byStatus: describeIndex("byStatus", "status"),
|
||||||
byTalerWithdrawUri: describeIndex(
|
byTalerWithdrawUri: describeIndex(
|
||||||
"byTalerWithdrawUri",
|
"byTalerWithdrawUri",
|
||||||
|
@ -356,7 +356,9 @@ export async function processRecoupGroupHandler(
|
|||||||
throw Error(`Coin ${coinPub} not found, can't request recoup`);
|
throw Error(`Coin ${coinPub} not found, can't request recoup`);
|
||||||
}
|
}
|
||||||
if (coin.coinSource.type === CoinSourceType.Withdraw) {
|
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) {
|
if (!reserve) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,13 @@ export interface IndexOptions {
|
|||||||
* undefined if added in the first version.
|
* undefined if added in the first version.
|
||||||
*/
|
*/
|
||||||
versionAdded?: number;
|
versionAdded?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this index enforce unique keys?
|
||||||
|
*
|
||||||
|
* Defaults to false.
|
||||||
|
*/
|
||||||
|
unique?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestToPromise(req: IDBRequest): Promise<any> {
|
function requestToPromise(req: IDBRequest): Promise<any> {
|
||||||
@ -276,6 +283,7 @@ export interface IndexDescriptor {
|
|||||||
name: string;
|
name: string;
|
||||||
keyPath: IDBKeyPath | IDBKeyPath[];
|
keyPath: IDBKeyPath | IDBKeyPath[];
|
||||||
multiEntry?: boolean;
|
multiEntry?: boolean;
|
||||||
|
unique?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StoreDescriptor<RecordType> {
|
export interface StoreDescriptor<RecordType> {
|
||||||
@ -292,7 +300,11 @@ export interface StoreOptions {
|
|||||||
export function describeContents<RecordType = never>(
|
export function describeContents<RecordType = never>(
|
||||||
options: StoreOptions,
|
options: StoreOptions,
|
||||||
): StoreDescriptor<RecordType> {
|
): StoreDescriptor<RecordType> {
|
||||||
return { keyPath: options.keyPath, _dummy: undefined as any };
|
return {
|
||||||
|
keyPath: options.keyPath,
|
||||||
|
_dummy: undefined as any,
|
||||||
|
autoIncrement: options.autoIncrement,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function describeIndex(
|
export function describeIndex(
|
||||||
@ -304,6 +316,7 @@ export function describeIndex(
|
|||||||
keyPath,
|
keyPath,
|
||||||
name,
|
name,
|
||||||
multiEntry: options.multiEntry,
|
multiEntry: options.multiEntry,
|
||||||
|
unique: options.unique,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,11 +352,18 @@ export interface StoreReadOnlyAccessor<RecordType, IndexMap> {
|
|||||||
indexes: GetIndexReadOnlyAccess<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> {
|
export interface StoreReadWriteAccessor<RecordType, IndexMap> {
|
||||||
get(key: IDBValidKey): Promise<RecordType | undefined>;
|
get(key: IDBValidKey): Promise<RecordType | undefined>;
|
||||||
iter(query?: IDBValidKey): ResultStream<RecordType>;
|
iter(query?: IDBValidKey): ResultStream<RecordType>;
|
||||||
put(r: RecordType): Promise<void>;
|
put(r: RecordType): Promise<InsertResponse>;
|
||||||
add(r: RecordType): Promise<void>;
|
add(r: RecordType): Promise<InsertResponse>;
|
||||||
delete(key: IDBValidKey): Promise<void>;
|
delete(key: IDBValidKey): Promise<void>;
|
||||||
indexes: GetIndexReadWriteAccess<RecordType, IndexMap>;
|
indexes: GetIndexReadWriteAccess<RecordType, IndexMap>;
|
||||||
}
|
}
|
||||||
@ -577,13 +597,19 @@ function makeWriteContext(
|
|||||||
const req = tx.objectStore(storeName).openCursor(query);
|
const req = tx.objectStore(storeName).openCursor(query);
|
||||||
return new ResultStream<any>(req);
|
return new ResultStream<any>(req);
|
||||||
},
|
},
|
||||||
add(r) {
|
async add(r) {
|
||||||
const req = tx.objectStore(storeName).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);
|
const req = tx.objectStore(storeName).put(r);
|
||||||
return requestToPromise(req);
|
const key = await requestToPromise(req);
|
||||||
|
return {
|
||||||
|
key: key,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
delete(k) {
|
delete(k) {
|
||||||
const req = tx.objectStore(storeName).delete(k);
|
const req = tx.objectStore(storeName).delete(k);
|
||||||
|
Loading…
Reference in New Issue
Block a user