fix static types

This commit is contained in:
Florian Dold 2020-11-27 11:23:06 +01:00
parent 4e481a51c6
commit 0828e65f88
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
8 changed files with 72 additions and 60 deletions

View File

@ -39,11 +39,11 @@ export function openTalerDatabase(
if (oldVersion === 0) { if (oldVersion === 0) {
for (const n in Stores) { for (const n in Stores) {
if ((Stores as any)[n] instanceof Store) { if ((Stores as any)[n] instanceof Store) {
const si: Store<any> = (Stores as any)[n]; const si: Store<string, any> = (Stores as any)[n];
const s = db.createObjectStore(si.name, si.storeParams); const s = db.createObjectStore(si.name, si.storeParams);
for (const indexName in si as any) { for (const indexName in si as any) {
if ((si as any)[indexName] instanceof Index) { if ((si as any)[indexName] instanceof Index) {
const ii: Index<any, any> = (si as any)[indexName]; const ii: Index<string, string, any, any> = (si as any)[indexName];
s.createIndex(ii.indexName, ii.keyPath, ii.options); s.createIndex(ii.indexName, ii.keyPath, ii.options);
} }
} }
@ -57,7 +57,7 @@ export function openTalerDatabase(
logger.info(`upgrading database from ${oldVersion} to ${newVersion}`); logger.info(`upgrading database from ${oldVersion} to ${newVersion}`);
for (const n in Stores) { for (const n in Stores) {
if ((Stores as any)[n] instanceof Store) { if ((Stores as any)[n] instanceof Store) {
const si: Store<any> = (Stores as any)[n]; const si: Store<string, any> = (Stores as any)[n];
let s: IDBObjectStore; let s: IDBObjectStore;
if ((si.storeParams?.versionAdded ?? 1) > oldVersion) { if ((si.storeParams?.versionAdded ?? 1) > oldVersion) {
s = db.createObjectStore(si.name, si.storeParams); s = db.createObjectStore(si.name, si.storeParams);
@ -66,7 +66,7 @@ export function openTalerDatabase(
} }
for (const indexName in si as any) { for (const indexName in si as any) {
if ((si as any)[indexName] instanceof Index) { if ((si as any)[indexName] instanceof Index) {
const ii: Index<any, any> = (si as any)[indexName]; const ii: Index<string, string, any, any> = (si as any)[indexName];
if ((ii.options?.versionAdded ?? 0) > oldVersion) { if ((ii.options?.versionAdded ?? 0) > oldVersion) {
s.createIndex(ii.indexName, ii.keyPath, ii.options); s.createIndex(ii.indexName, ii.keyPath, ii.options);
} }

View File

@ -38,7 +38,13 @@ interface WalletBalance {
*/ */
export async function getBalancesInsideTransaction( export async function getBalancesInsideTransaction(
ws: InternalWalletState, ws: InternalWalletState,
tx: TransactionHandle, tx: TransactionHandle<
| typeof Stores.reserves
| typeof Stores.coins
| typeof Stores.reserves
| typeof Stores.refreshGroups
| typeof Stores.withdrawalGroups
>,
): Promise<BalancesResponse> { ): Promise<BalancesResponse> {
const balanceStore: Record<string, WalletBalance> = {}; const balanceStore: Record<string, WalletBalance> = {};

View File

@ -37,7 +37,7 @@ import {
getDurationRemaining, getDurationRemaining,
durationMin, durationMin,
} from "../util/time"; } from "../util/time";
import { TransactionHandle } from "../util/query"; import { Store, TransactionHandle } from "../util/query";
import { InternalWalletState } from "./state"; import { InternalWalletState } from "./state";
import { getBalancesInsideTransaction } from "./balance"; import { getBalancesInsideTransaction } from "./balance";
@ -52,7 +52,7 @@ function updateRetryDelay(
} }
async function gatherExchangePending( async function gatherExchangePending(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.exchanges>,
now: Timestamp, now: Timestamp,
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
onlyDue = false, onlyDue = false,
@ -171,7 +171,7 @@ async function gatherExchangePending(
} }
async function gatherReservePending( async function gatherReservePending(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.reserves>,
now: Timestamp, now: Timestamp,
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
onlyDue = false, onlyDue = false,
@ -226,7 +226,7 @@ async function gatherReservePending(
} }
async function gatherRefreshPending( async function gatherRefreshPending(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.refreshGroups>,
now: Timestamp, now: Timestamp,
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
onlyDue = false, onlyDue = false,
@ -255,7 +255,7 @@ async function gatherRefreshPending(
} }
async function gatherWithdrawalPending( async function gatherWithdrawalPending(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.withdrawalGroups>,
now: Timestamp, now: Timestamp,
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
onlyDue = false, onlyDue = false,
@ -295,7 +295,7 @@ async function gatherWithdrawalPending(
} }
async function gatherProposalPending( async function gatherProposalPending(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.proposals>,
now: Timestamp, now: Timestamp,
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
onlyDue = false, onlyDue = false,
@ -346,7 +346,7 @@ async function gatherProposalPending(
} }
async function gatherTipPending( async function gatherTipPending(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.tips>,
now: Timestamp, now: Timestamp,
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
onlyDue = false, onlyDue = false,
@ -376,7 +376,7 @@ async function gatherTipPending(
} }
async function gatherPurchasePending( async function gatherPurchasePending(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.purchases>,
now: Timestamp, now: Timestamp,
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
onlyDue = false, onlyDue = false,
@ -419,7 +419,7 @@ async function gatherPurchasePending(
} }
async function gatherRecoupPending( async function gatherRecoupPending(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.recoupGroups>,
now: Timestamp, now: Timestamp,
resp: PendingOperationsResponse, resp: PendingOperationsResponse,
onlyDue = false, onlyDue = false,

View File

@ -46,7 +46,7 @@ import {
import { Amounts } from "../util/amounts"; import { Amounts } from "../util/amounts";
import { createRefreshGroup, processRefreshGroup } from "./refresh"; import { createRefreshGroup, processRefreshGroup } from "./refresh";
import { RefreshReason, TalerErrorDetails } from "../types/walletTypes"; import { RefreshReason, TalerErrorDetails } from "../types/walletTypes";
import { TransactionHandle } from "../util/query"; import { Store, StoreParams, TransactionHandle } from "../util/query";
import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto"; import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto";
import { getTimestampNow } from "../util/time"; import { getTimestampNow } from "../util/time";
import { guardOperationException } from "./errors"; import { guardOperationException } from "./errors";
@ -82,7 +82,7 @@ async function incrementRecoupRetry(
async function putGroupAsFinished( async function putGroupAsFinished(
ws: InternalWalletState, ws: InternalWalletState,
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.recoupGroups>,
recoupGroup: RecoupGroupRecord, recoupGroup: RecoupGroupRecord,
coinIdx: number, coinIdx: number,
): Promise<void> { ): Promise<void> {
@ -366,7 +366,7 @@ async function processRecoupGroupImpl(
export async function createRecoupGroup( export async function createRecoupGroup(
ws: InternalWalletState, ws: InternalWalletState,
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.recoupGroups | typeof Stores.coins>,
coinPubs: string[], coinPubs: string[],
): Promise<string> { ): Promise<string> {
const recoupGroupId = encodeCrock(getRandomBytes(32)); const recoupGroupId = encodeCrock(getRandomBytes(32));

View File

@ -52,9 +52,7 @@ import {
durationMax, durationMax,
durationMul, durationMul,
} from "../util/time"; } from "../util/time";
import { import { readSuccessResponseJsonOrThrow } from "../util/http";
readSuccessResponseJsonOrThrow,
} from "../util/http";
import { import {
codecForExchangeMeltResponse, codecForExchangeMeltResponse,
codecForExchangeRevealResponse, codecForExchangeRevealResponse,
@ -567,7 +565,11 @@ async function processRefreshSession(
*/ */
export async function createRefreshGroup( export async function createRefreshGroup(
ws: InternalWalletState, ws: InternalWalletState,
tx: TransactionHandle, tx: TransactionHandle<
| typeof Stores.denominations
| typeof Stores.coins
| typeof Stores.refreshGroups
>,
oldCoinPubs: CoinPublicKey[], oldCoinPubs: CoinPublicKey[],
reason: RefreshReason, reason: RefreshReason,
): Promise<RefreshGroupId> { ): Promise<RefreshGroupId> {

View File

@ -103,7 +103,7 @@ function getRefundKey(d: MerchantCoinRefundStatus): string {
} }
async function applySuccessfulRefund( async function applySuccessfulRefund(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.coins | typeof Stores.denominations>,
p: PurchaseRecord, p: PurchaseRecord,
refreshCoinsMap: Record<string, { coinPub: string }>, refreshCoinsMap: Record<string, { coinPub: string }>,
r: MerchantCoinRefundSuccessStatus, r: MerchantCoinRefundSuccessStatus,
@ -162,7 +162,7 @@ async function applySuccessfulRefund(
} }
async function storePendingRefund( async function storePendingRefund(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.denominations | typeof Stores.coins>,
p: PurchaseRecord, p: PurchaseRecord,
r: MerchantCoinRefundFailureStatus, r: MerchantCoinRefundFailureStatus,
): Promise<void> { ): Promise<void> {
@ -212,7 +212,7 @@ async function storePendingRefund(
} }
async function storeFailedRefund( async function storeFailedRefund(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.coins | typeof Stores.denominations>,
p: PurchaseRecord, p: PurchaseRecord,
refreshCoinsMap: Record<string, { coinPub: string }>, refreshCoinsMap: Record<string, { coinPub: string }>,
r: MerchantCoinRefundFailureStatus, r: MerchantCoinRefundFailureStatus,

View File

@ -81,7 +81,11 @@ import {
} from "../util/http"; } from "../util/http";
import { codecForAny } from "../util/codec"; import { codecForAny } from "../util/codec";
import { URL } from "../util/url"; import { URL } from "../util/url";
import { initRetryInfo, getRetryDuration, updateRetryInfoTimeout } from "../util/retries"; import {
initRetryInfo,
getRetryDuration,
updateRetryInfoTimeout,
} from "../util/retries";
const logger = new Logger("reserves.ts"); const logger = new Logger("reserves.ts");
@ -523,7 +527,8 @@ async function updateReserve(
if (result.isError) { if (result.isError) {
if ( if (
resp.status === 404 && resp.status === 404 &&
result.talerErrorResponse.code === TalerErrorCode.EXCHANGE_RESERVES_GET_STATUS_UNKNOWN result.talerErrorResponse.code ===
TalerErrorCode.EXCHANGE_RESERVES_GET_STATUS_UNKNOWN
) { ) {
ws.notify({ ws.notify({
type: NotificationType.ReserveNotYetFound, type: NotificationType.ReserveNotYetFound,
@ -863,7 +868,7 @@ export async function createTalerWithdrawReserve(
* Get payto URIs needed to fund a reserve. * Get payto URIs needed to fund a reserve.
*/ */
export async function getFundingPaytoUris( export async function getFundingPaytoUris(
tx: TransactionHandle, tx: TransactionHandle<typeof Stores.reserves | typeof Stores.exchanges>,
reservePub: string, reservePub: string,
): Promise<string[]> { ): Promise<string[]> {
const r = await tx.get(Stores.reserves, reservePub); const r = await tx.get(Stores.reserves, reservePub);

View File

@ -270,13 +270,21 @@ class ResultStream<T> {
} }
} }
type StrKey<T> = string & keyof T;
type StoreName<S> = S extends Store<infer N, any> ? N : never; type StoreName<S> = S extends Store<infer N, any> ? N : never;
type StoreContent<S> = S extends Store<any, infer R> ? R : never; type StoreContent<S> = S extends Store<any, infer R> ? R : never;
type IndexRecord<Ind> = Ind extends Index<any, any, any, infer R> ? R : never; type IndexRecord<Ind> = Ind extends Index<any, any, any, infer R> ? R : never;
export class TransactionHandle<StoreTypes extends Store<string, {}>> { type InferStore<S> = S extends Store<infer N, infer R> ? Store<N, R> : never;
type InferIndex<Ind> = Ind extends Index<
infer StN,
infer IndN,
infer KT,
infer RT
>
? Index<StN, IndN, KT, RT>
: never;
export class TransactionHandle<StoreTypes extends Store<string, any>> {
constructor(private tx: IDBTransaction) {} constructor(private tx: IDBTransaction) {}
put<S extends StoreTypes>( put<S extends StoreTypes>(
@ -306,14 +314,9 @@ export class TransactionHandle<StoreTypes extends Store<string, {}>> {
} }
getIndexed< getIndexed<
StoreName extends StrKey<StoreTypes>, St extends StoreTypes,
IndexName extends string, Ind extends Index<StoreName<St>, string, any, any>
S extends IDBValidKey, >(index: InferIndex<Ind>, key: any): Promise<IndexRecord<Ind> | undefined> {
T
>(
index: Index<StoreName, IndexName, S, T>,
key: any,
): Promise<T | undefined> {
const req = this.tx const req = this.tx
.objectStore(index.storeName) .objectStore(index.storeName)
.index(index.indexName) .index(index.indexName)
@ -321,39 +324,37 @@ export class TransactionHandle<StoreTypes extends Store<string, {}>> {
return requestToPromise(req); return requestToPromise(req);
} }
iter<N extends StrKey<StoreTypes>, T extends StoreTypes[N]>( iter<St extends InferStore<StoreTypes>>(
store: Store<N, T>, store: St,
key?: any, key?: any,
): ResultStream<T> { ): ResultStream<StoreContent<St>> {
const req = this.tx.objectStore(store.name).openCursor(key); const req = this.tx.objectStore(store.name).openCursor(key);
return new ResultStream<T>(req); return new ResultStream<StoreContent<St>>(req);
} }
iterIndexed< iterIndexed<
StoreName extends StrKey<StoreTypes>, St extends InferStore<StoreTypes>,
IndexName extends string, Ind extends InferIndex<Index<StoreName<St>, string, any, any>>
S extends IDBValidKey, >(index: Ind, key?: any): ResultStream<IndexRecord<Ind>> {
T
>(index: Index<StoreName, IndexName, S, T>, key?: any): ResultStream<T> {
const req = this.tx const req = this.tx
.objectStore(index.storeName) .objectStore(index.storeName)
.index(index.indexName) .index(index.indexName)
.openCursor(key); .openCursor(key);
return new ResultStream<T>(req); return new ResultStream<IndexRecord<Ind>>(req);
} }
delete<N extends StrKey<StoreTypes>, T extends StoreTypes[N]>( delete<St extends StoreTypes>(
store: Store<N, T>, store: InferStore<St>,
key: any, key: any,
): Promise<void> { ): Promise<void> {
const req = this.tx.objectStore(store.name).delete(key); const req = this.tx.objectStore(store.name).delete(key);
return requestToPromise(req); return requestToPromise(req);
} }
mutate<N extends StrKey<StoreTypes>, T extends StoreTypes[N]>( mutate<St extends StoreTypes>(
store: Store<N, T>, store: InferStore<St>,
key: any, key: any,
f: (x: T) => T | undefined, f: (x: StoreContent<St>) => StoreContent<St> | undefined,
): Promise<void> { ): Promise<void> {
const req = this.tx.objectStore(store.name).openCursor(key); const req = this.tx.objectStore(store.name).openCursor(key);
return applyMutation(req, f); return applyMutation(req, f);
@ -583,9 +584,7 @@ export class Database {
} }
async getIndexed<Ind extends Index<string, string, any, any>>( async getIndexed<Ind extends Index<string, string, any, any>>(
index: Ind extends Index<infer IndN, infer StN, any, infer R> index: InferIndex<Ind>,
? Index<IndN, StN, any, R>
: never,
key: any, key: any,
): Promise<IndexRecord<Ind> | undefined> { ): Promise<IndexRecord<Ind> | undefined> {
const tx = this.db.transaction([index.storeName], "readonly"); const tx = this.db.transaction([index.storeName], "readonly");
@ -624,16 +623,16 @@ export class Database {
return new ResultStream<T>(req); return new ResultStream<T>(req);
} }
iterIndex<N extends string, I extends string, S extends IDBValidKey, T>( iterIndex<Ind extends Index<string, string, any, any>>(
index: Index<N, I, S, T>, index: InferIndex<Ind>,
query?: any, query?: any,
): ResultStream<T> { ): ResultStream<IndexRecord<Ind>> {
const tx = this.db.transaction([index.storeName], "readonly"); const tx = this.db.transaction([index.storeName], "readonly");
const req = tx const req = tx
.objectStore(index.storeName) .objectStore(index.storeName)
.index(index.indexName) .index(index.indexName)
.openCursor(query); .openCursor(query);
return new ResultStream<T>(req); return new ResultStream<IndexRecord<Ind>>(req);
} }
async runWithReadTransaction<T, StoreTypes extends Store<string, any>>( async runWithReadTransaction<T, StoreTypes extends Store<string, any>>(