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) {
for (const n in Stores) {
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);
for (const indexName in si as any) {
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);
}
}
@ -57,7 +57,7 @@ export function openTalerDatabase(
logger.info(`upgrading database from ${oldVersion} to ${newVersion}`);
for (const n in Stores) {
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;
if ((si.storeParams?.versionAdded ?? 1) > oldVersion) {
s = db.createObjectStore(si.name, si.storeParams);
@ -66,7 +66,7 @@ export function openTalerDatabase(
}
for (const indexName in si as any) {
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) {
s.createIndex(ii.indexName, ii.keyPath, ii.options);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -81,7 +81,11 @@ import {
} from "../util/http";
import { codecForAny } from "../util/codec";
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");
@ -523,7 +527,8 @@ async function updateReserve(
if (result.isError) {
if (
resp.status === 404 &&
result.talerErrorResponse.code === TalerErrorCode.EXCHANGE_RESERVES_GET_STATUS_UNKNOWN
result.talerErrorResponse.code ===
TalerErrorCode.EXCHANGE_RESERVES_GET_STATUS_UNKNOWN
) {
ws.notify({
type: NotificationType.ReserveNotYetFound,
@ -863,7 +868,7 @@ export async function createTalerWithdrawReserve(
* Get payto URIs needed to fund a reserve.
*/
export async function getFundingPaytoUris(
tx: TransactionHandle,
tx: TransactionHandle<typeof Stores.reserves | typeof Stores.exchanges>,
reservePub: string,
): Promise<string[]> {
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 StoreContent<S> = S extends Store<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) {}
put<S extends StoreTypes>(
@ -306,14 +314,9 @@ export class TransactionHandle<StoreTypes extends Store<string, {}>> {
}
getIndexed<
StoreName extends StrKey<StoreTypes>,
IndexName extends string,
S extends IDBValidKey,
T
>(
index: Index<StoreName, IndexName, S, T>,
key: any,
): Promise<T | undefined> {
St extends StoreTypes,
Ind extends Index<StoreName<St>, string, any, any>
>(index: InferIndex<Ind>, key: any): Promise<IndexRecord<Ind> | undefined> {
const req = this.tx
.objectStore(index.storeName)
.index(index.indexName)
@ -321,39 +324,37 @@ export class TransactionHandle<StoreTypes extends Store<string, {}>> {
return requestToPromise(req);
}
iter<N extends StrKey<StoreTypes>, T extends StoreTypes[N]>(
store: Store<N, T>,
iter<St extends InferStore<StoreTypes>>(
store: St,
key?: any,
): ResultStream<T> {
): ResultStream<StoreContent<St>> {
const req = this.tx.objectStore(store.name).openCursor(key);
return new ResultStream<T>(req);
return new ResultStream<StoreContent<St>>(req);
}
iterIndexed<
StoreName extends StrKey<StoreTypes>,
IndexName extends string,
S extends IDBValidKey,
T
>(index: Index<StoreName, IndexName, S, T>, key?: any): ResultStream<T> {
St extends InferStore<StoreTypes>,
Ind extends InferIndex<Index<StoreName<St>, string, any, any>>
>(index: Ind, key?: any): ResultStream<IndexRecord<Ind>> {
const req = this.tx
.objectStore(index.storeName)
.index(index.indexName)
.openCursor(key);
return new ResultStream<T>(req);
return new ResultStream<IndexRecord<Ind>>(req);
}
delete<N extends StrKey<StoreTypes>, T extends StoreTypes[N]>(
store: Store<N, T>,
delete<St extends StoreTypes>(
store: InferStore<St>,
key: any,
): Promise<void> {
const req = this.tx.objectStore(store.name).delete(key);
return requestToPromise(req);
}
mutate<N extends StrKey<StoreTypes>, T extends StoreTypes[N]>(
store: Store<N, T>,
mutate<St extends StoreTypes>(
store: InferStore<St>,
key: any,
f: (x: T) => T | undefined,
f: (x: StoreContent<St>) => StoreContent<St> | undefined,
): Promise<void> {
const req = this.tx.objectStore(store.name).openCursor(key);
return applyMutation(req, f);
@ -583,9 +584,7 @@ export class Database {
}
async getIndexed<Ind extends Index<string, string, any, any>>(
index: Ind extends Index<infer IndN, infer StN, any, infer R>
? Index<IndN, StN, any, R>
: never,
index: InferIndex<Ind>,
key: any,
): Promise<IndexRecord<Ind> | undefined> {
const tx = this.db.transaction([index.storeName], "readonly");
@ -624,16 +623,16 @@ export class Database {
return new ResultStream<T>(req);
}
iterIndex<N extends string, I extends string, S extends IDBValidKey, T>(
index: Index<N, I, S, T>,
iterIndex<Ind extends Index<string, string, any, any>>(
index: InferIndex<Ind>,
query?: any,
): ResultStream<T> {
): ResultStream<IndexRecord<Ind>> {
const tx = this.db.transaction([index.storeName], "readonly");
const req = tx
.objectStore(index.storeName)
.index(index.indexName)
.openCursor(query);
return new ResultStream<T>(req);
return new ResultStream<IndexRecord<Ind>>(req);
}
async runWithReadTransaction<T, StoreTypes extends Store<string, any>>(