commit 0c0a4092043ca8cd4660b541d26e112bc6741b3c
parent a5a96dd347c95adce76ee2180c57f52fe0c406a6
Author: Antoine A <>
Date: Wed, 23 Apr 2025 17:04:09 +0200
wallet-core: clean some type magic
Diffstat:
2 files changed, 46 insertions(+), 71 deletions(-)
diff --git a/packages/taler-wallet-core/src/observable-wrappers.ts b/packages/taler-wallet-core/src/observable-wrappers.ts
@@ -1,6 +1,6 @@
/*
This file is part of GNU Taler
- (C) 2024 Taler Systems SA
+ (C) 2024-2025 Taler Systems SA
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
@@ -33,6 +33,7 @@ import {
DbAccess,
DbReadOnlyTransaction,
DbReadWriteTransaction,
+ StoreMap,
StoreNames,
} from "./query.js";
import { TaskScheduler } from "./shepherd.js";
@@ -44,7 +45,7 @@ export class ObservableTaskScheduler implements TaskScheduler {
constructor(
private impl: TaskScheduler,
private oc: ObservabilityContext,
- ) {}
+ ) { }
private taskDepCache = new Set<string>();
@@ -126,11 +127,11 @@ export function getCallerInfo(up: number = 2): string {
return identifies.slice(up, up + 2).join("/");
}
-export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
+export class ObservableDbAccess<Stores extends StoreMap> implements DbAccess<Stores> {
constructor(
- private impl: DbAccess<StoreMap>,
+ private impl: DbAccess<Stores>,
private oc: ObservabilityContext,
- ) {}
+ ) { }
idbHandle(): IDBDatabase {
return this.impl.idbHandle();
}
@@ -140,7 +141,7 @@ export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
label?: string;
},
txf: (
- tx: DbReadWriteTransaction<StoreMap, StoreNames<StoreMap>[]>,
+ tx: DbReadWriteTransaction<Stores, StoreNames<Stores>[]>,
) => Promise<T>,
): Promise<T> {
const location = getCallerInfo();
@@ -173,7 +174,7 @@ export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
label?: string;
},
txf: (
- tx: DbReadOnlyTransaction<StoreMap, StoreNames<StoreMap>[]>,
+ tx: DbReadOnlyTransaction<Stores, StoreNames<Stores>[]>,
) => Promise<T>,
): Promise<T> {
const location = getCallerInfo();
@@ -201,12 +202,12 @@ export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
}
}
- async runReadWriteTx<T, StoreNameArray extends StoreNames<StoreMap>[]>(
+ async runReadWriteTx<T, StoreNameArray extends StoreNames<Stores>[]>(
opts: {
storeNames: StoreNameArray;
label?: string;
},
- txf: (tx: DbReadWriteTransaction<StoreMap, StoreNameArray>) => Promise<T>,
+ txf: (tx: DbReadWriteTransaction<Stores, StoreNameArray>) => Promise<T>,
): Promise<T> {
const location = getCallerInfo();
this.oc.observe({
@@ -233,12 +234,12 @@ export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> {
}
}
- async runReadOnlyTx<T, StoreNameArray extends StoreNames<StoreMap>[]>(
+ async runReadOnlyTx<T, StoreNameArray extends StoreNames<Stores>[]>(
opts: {
storeNames: StoreNameArray;
label?: string;
},
- txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>,
+ txf: (tx: DbReadOnlyTransaction<Stores, StoreNameArray>) => Promise<T>,
): Promise<T> {
const location = getCallerInfo();
try {
diff --git a/packages/taler-wallet-core/src/query.ts b/packages/taler-wallet-core/src/query.ts
@@ -1,6 +1,7 @@
/*
This file is part of TALER
(C) 2016 GNUnet e.V.
+ (C) 2025 Taler Systems S.A.
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
@@ -344,7 +345,7 @@ export interface IndexDescriptor {
}
export interface StoreDescriptor<RecordType> {
- _dummy: undefined & RecordType;
+ _dummy: RecordType;
keyPath?: IDBKeyPath | IDBKeyPath[];
autoIncrement?: boolean;
/**
@@ -525,8 +526,8 @@ type DerefKeyPath<T, P> = P extends `${infer PX extends keyof T &
KeyPathComponents}`
? T[PX]
: P extends `${infer P0 extends keyof T & KeyPathComponents}.${infer Rest}`
- ? DerefKeyPath<T[P0], Rest>
- : unknown;
+ ? DerefKeyPath<T[P0], Rest>
+ : unknown;
/**
* Return a path if it is a valid dot-separate path to an object.
@@ -536,8 +537,8 @@ type ValidateKeyPath<T, P> = P extends `${infer PX extends keyof T &
KeyPathComponents}`
? PX
: P extends `${infer P0 extends keyof T & KeyPathComponents}.${infer Rest}`
- ? `${P0}.${ValidateKeyPath<T[P0], Rest>}`
- : never;
+ ? `${P0}.${ValidateKeyPath<T[P0], Rest>}`
+ : never;
// function foo<T, P>(
// x: T,
@@ -546,47 +547,20 @@ type ValidateKeyPath<T, P> = P extends `${infer PX extends keyof T &
// foo({x: [0,1,2]}, "x.0");
-export type StoreNames<StoreMap> = StoreMap extends {
- [P in keyof StoreMap]: StoreWithIndexes<infer SN1, infer SD1, infer IM1>;
-}
- ? keyof StoreMap
- : unknown;
-
+export type StoreMap = { [P in string]: StoreWithIndexes<any, any, any> }
+export type StoreNames<Stores extends StoreMap> = keyof Stores
export type DbReadWriteTransaction<
- StoreMap,
- StoresArr extends Array<StoreNames<StoreMap>>,
-> = StoreMap extends {
- [P in string]: StoreWithIndexes<infer _SN1, infer _SD1, infer _IM1>;
-}
- ? {
- [X in StoresArr[number] &
- keyof StoreMap]: StoreMap[X] extends StoreWithIndexes<
- infer _StoreName,
- infer RecordType,
- infer IndexMap
- >
- ? StoreReadWriteAccessor<RecordType, IndexMap>
- : unknown;
- }
- : never;
-
+ Stores extends StoreMap,
+ StoresArr extends Array<StoreNames<Stores>>,
+> = {
+ [X in StoresArr[number]]: StoreReadWriteAccessor<Stores[X]['store']['_dummy'], Stores[X]['indexMap']>
+ }
export type DbReadOnlyTransaction<
- StoreMap,
- StoresArr extends Array<StoreNames<StoreMap>>,
-> = StoreMap extends {
- [P in string]: StoreWithIndexes<infer _SN1, infer _SD1, infer _IM1>;
-}
- ? {
- [X in StoresArr[number] &
- keyof StoreMap]: StoreMap[X] extends StoreWithIndexes<
- infer _StoreName,
- infer RecordType,
- infer IndexMap
- >
- ? StoreReadOnlyAccessor<RecordType, IndexMap>
- : unknown;
- }
- : never;
+ Stores extends StoreMap,
+ StoresArr extends Array<StoreNames<Stores>>,
+> = {
+ [X in StoresArr[number]]: StoreReadOnlyAccessor<Stores[X]['store']['_dummy'], Stores[X]['indexMap']>
+ }
/**
* Convert the type of an array to a union of the contents.
@@ -847,7 +821,7 @@ function makeTxContext(
/**
* Handle for typed access to a database.
*/
-export interface DbAccess<StoreMap> {
+export interface DbAccess<Stores extends StoreMap> {
/**
* The underlying IndexedDB database handle.
*
@@ -869,7 +843,7 @@ export interface DbAccess<StoreMap> {
label?: string;
},
txf: (
- tx: DbReadWriteTransaction<StoreMap, Array<StoreNames<StoreMap>>>,
+ tx: DbReadWriteTransaction<Stores, Array<StoreNames<Stores>>>,
) => Promise<T>,
): Promise<T>;
@@ -886,7 +860,7 @@ export interface DbAccess<StoreMap> {
label?: string;
},
txf: (
- tx: DbReadOnlyTransaction<StoreMap, Array<StoreNames<StoreMap>>>,
+ tx: DbReadOnlyTransaction<Stores, Array<StoreNames<Stores>>>,
) => Promise<T>,
): Promise<T>;
@@ -898,12 +872,12 @@ export interface DbAccess<StoreMap> {
* Waiting for macrotasks results in an autocommit and
* a subsequent exception thrown by this function.
*/
- runReadWriteTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
+ runReadWriteTx<T, StoreNameArray extends Array<StoreNames<Stores>>>(
opts: {
storeNames: StoreNameArray;
label?: string;
},
- txf: (tx: DbReadWriteTransaction<StoreMap, StoreNameArray>) => Promise<T>,
+ txf: (tx: DbReadWriteTransaction<Stores, StoreNameArray>) => Promise<T>,
): Promise<T>;
/**
@@ -914,12 +888,12 @@ export interface DbAccess<StoreMap> {
* Waiting for macrotasks results in an autocommit and
* a subsequent exception thrown by this function.
*/
- runReadOnlyTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
+ runReadOnlyTx<T, StoreNameArray extends Array<StoreNames<Stores>>>(
opts: {
storeNames: StoreNameArray;
label?: string;
},
- txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>,
+ txf: (tx: DbReadOnlyTransaction<Stores, StoreNameArray>) => Promise<T>,
): Promise<T>;
}
@@ -987,13 +961,13 @@ class InternalTransactionContext {
*
* A store map is the metadata that describes the store.
*/
-export class DbAccessImpl<StoreMap> implements DbAccess<StoreMap> {
+export class DbAccessImpl<Stores extends StoreMap> implements DbAccess<Stores> {
constructor(
private db: IDBDatabase,
- private stores: StoreMap,
+ private stores: Stores,
private triggers: TriggerSpec = {},
private cancellationToken: CancellationToken,
- ) {}
+ ) { }
idbHandle(): IDBDatabase {
return this.db;
@@ -1004,7 +978,7 @@ export class DbAccessImpl<StoreMap> implements DbAccess<StoreMap> {
label?: string;
},
txf: (
- tx: DbReadWriteTransaction<StoreMap, Array<StoreNames<StoreMap>>>,
+ tx: DbReadWriteTransaction<Stores, Array<StoreNames<Stores>>>,
) => Promise<T>,
): Promise<T> {
this.cancellationToken.throwIfCancelled();
@@ -1033,7 +1007,7 @@ export class DbAccessImpl<StoreMap> implements DbAccess<StoreMap> {
label?: string;
},
txf: (
- tx: DbReadOnlyTransaction<StoreMap, Array<StoreNames<StoreMap>>>,
+ tx: DbReadOnlyTransaction<Stores, Array<StoreNames<Stores>>>,
) => Promise<T>,
): Promise<T> {
this.cancellationToken.throwIfCancelled();
@@ -1058,11 +1032,11 @@ export class DbAccessImpl<StoreMap> implements DbAccess<StoreMap> {
return res;
}
- async runReadWriteTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
+ async runReadWriteTx<T, StoreNameArray extends Array<StoreNames<Stores>>>(
opts: {
storeNames: StoreNameArray;
},
- txf: (tx: DbReadWriteTransaction<StoreMap, StoreNameArray>) => Promise<T>,
+ txf: (tx: DbReadWriteTransaction<Stores, StoreNameArray>) => Promise<T>,
): Promise<T> {
this.cancellationToken.throwIfCancelled();
const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
@@ -1086,11 +1060,11 @@ export class DbAccessImpl<StoreMap> implements DbAccess<StoreMap> {
return res;
}
- async runReadOnlyTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>(
+ async runReadOnlyTx<T, StoreNameArray extends Array<StoreNames<Stores>>>(
opts: {
storeNames: StoreNameArray;
},
- txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>,
+ txf: (tx: DbReadOnlyTransaction<Stores, StoreNameArray>) => Promise<T>,
): Promise<T> {
this.cancellationToken.throwIfCancelled();
const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =