be even more safe in db
This commit is contained in:
parent
89c3c2d58d
commit
700eb32f5a
@ -34,14 +34,23 @@ export class Store<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Index<S,T> {
|
||||||
|
indexName: string;
|
||||||
|
storeName: string;
|
||||||
|
|
||||||
|
constructor(s: Store<T>, indexName: string) {
|
||||||
|
this.storeName = s.name;
|
||||||
|
this.indexName = indexName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream that can be filtered, reduced or joined
|
* Stream that can be filtered, reduced or joined
|
||||||
* with indices.
|
* with indices.
|
||||||
*/
|
*/
|
||||||
export interface QueryStream<T> {
|
export interface QueryStream<T> {
|
||||||
indexJoin<S>(storeName: string,
|
indexJoin<S,I>(index: Index<I,S>,
|
||||||
indexName: string,
|
keyFn: (obj: T) => I): QueryStream<[T, S]>;
|
||||||
keyFn: (obj: any) => any): QueryStream<[T, S]>;
|
|
||||||
filter(f: (x: any) => boolean): QueryStream<T>;
|
filter(f: (x: any) => boolean): QueryStream<T>;
|
||||||
reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>;
|
reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>;
|
||||||
flatMap(f: (x: T) => T[]): QueryStream<T>;
|
flatMap(f: (x: T) => T[]): QueryStream<T>;
|
||||||
@ -64,14 +73,14 @@ function openPromise<T>() {
|
|||||||
// Never happens, unless JS implementation is broken
|
// Never happens, unless JS implementation is broken
|
||||||
throw Error();
|
throw Error();
|
||||||
}
|
}
|
||||||
return { resolve, reject, promise };
|
return {resolve, reject, promise};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
abstract class QueryStreamBase<T> implements QueryStream<T> {
|
abstract class QueryStreamBase<T> implements QueryStream<T> {
|
||||||
abstract subscribe(f: (isDone: boolean,
|
abstract subscribe(f: (isDone: boolean,
|
||||||
value: any,
|
value: any,
|
||||||
tx: IDBTransaction) => void): void;
|
tx: IDBTransaction) => void): void;
|
||||||
|
|
||||||
root: QueryRoot;
|
root: QueryRoot;
|
||||||
|
|
||||||
@ -83,11 +92,10 @@ abstract class QueryStreamBase<T> implements QueryStream<T> {
|
|||||||
return new QueryStreamFlatMap(this, f);
|
return new QueryStreamFlatMap(this, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
indexJoin<S>(storeName: string,
|
indexJoin<S,I>(index: Index<I,S>,
|
||||||
indexName: string,
|
keyFn: (obj: T) => I): QueryStream<[T, S]> {
|
||||||
key: any): QueryStream<[T, S]> {
|
this.root.addStoreAccess(index.storeName, false);
|
||||||
this.root.addStoreAccess(storeName, false);
|
return new QueryStreamIndexJoin(this, index.storeName, index.indexName, keyFn);
|
||||||
return new QueryStreamIndexJoin(this, storeName, indexName, key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filter(f: (x: any) => boolean): QueryStream<T> {
|
filter(f: (x: any) => boolean): QueryStream<T> {
|
||||||
@ -107,8 +115,8 @@ abstract class QueryStreamBase<T> implements QueryStream<T> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.root.finish())
|
.then(() => this.root.finish())
|
||||||
.then(() => promise);
|
.then(() => promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
reduce<A>(f: (x: any, acc?: A) => A, init?: A): Promise<any> {
|
reduce<A>(f: (x: any, acc?: A) => A, init?: A): Promise<any> {
|
||||||
@ -124,8 +132,8 @@ abstract class QueryStreamBase<T> implements QueryStream<T> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.root.finish())
|
.then(() => this.root.finish())
|
||||||
.then(() => promise);
|
.then(() => promise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +199,8 @@ class QueryStreamIndexJoin<T, S> extends QueryStreamBase<[T, S]> {
|
|||||||
key: any;
|
key: any;
|
||||||
indexName: string;
|
indexName: string;
|
||||||
|
|
||||||
constructor(s: QueryStreamBase<T>, storeName: string, indexName: string, key: any) {
|
constructor(s: QueryStreamBase<T>, storeName: string, indexName: string,
|
||||||
|
key: any) {
|
||||||
super(s.root);
|
super(s.root);
|
||||||
this.s = s;
|
this.s = s;
|
||||||
this.storeName = storeName;
|
this.storeName = storeName;
|
||||||
@ -238,7 +247,7 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
|
|||||||
let s: any;
|
let s: any;
|
||||||
if (indexName !== void 0) {
|
if (indexName !== void 0) {
|
||||||
s = tx.objectStore(this.storeName)
|
s = tx.objectStore(this.storeName)
|
||||||
.index(this.options.indexName);
|
.index(this.options.indexName);
|
||||||
} else {
|
} else {
|
||||||
s = tx.objectStore(this.storeName);
|
s = tx.objectStore(this.storeName);
|
||||||
}
|
}
|
||||||
@ -287,10 +296,17 @@ export class QueryRoot {
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
iter<T>(store: Store<T>,
|
iter<T>(store: Store<T>): QueryStream<T> {
|
||||||
{only = <string | undefined>undefined, indexName = <string | undefined>undefined} = {}): QueryStream<T> {
|
|
||||||
this.stores.add(store.name);
|
this.stores.add(store.name);
|
||||||
return new IterQueryStream(this, store.name, { only, indexName });
|
return new IterQueryStream(this, store.name, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
iterIndex<S,T>(index: Index<S,T>, only?: S): QueryStream<T> {
|
||||||
|
this.stores.add(index.storeName);
|
||||||
|
return new IterQueryStream(this, index.storeName, {
|
||||||
|
only,
|
||||||
|
indexName: index.indexName
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -354,8 +370,8 @@ export class QueryRoot {
|
|||||||
|
|
||||||
this.addWork(doGet, store.name, false);
|
this.addWork(doGet, store.name, false);
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.finish())
|
.then(() => this.finish())
|
||||||
.then(() => promise);
|
.then(() => promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -377,8 +393,8 @@ export class QueryRoot {
|
|||||||
|
|
||||||
this.addWork(doGetIndexed, storeName, false);
|
this.addWork(doGetIndexed, storeName, false);
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.finish())
|
.then(() => this.finish())
|
||||||
.then(() => promise);
|
.then(() => promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -420,8 +436,8 @@ export class QueryRoot {
|
|||||||
* Low-level function to add a task to the internal work queue.
|
* Low-level function to add a task to the internal work queue.
|
||||||
*/
|
*/
|
||||||
addWork(workFn: (t: IDBTransaction) => void,
|
addWork(workFn: (t: IDBTransaction) => void,
|
||||||
storeName?: string,
|
storeName?: string,
|
||||||
isWrite?: boolean) {
|
isWrite?: boolean) {
|
||||||
this.work.push(workFn);
|
this.work.push(workFn);
|
||||||
if (storeName) {
|
if (storeName) {
|
||||||
this.addStoreAccess(storeName, isWrite);
|
this.addStoreAccess(storeName, isWrite);
|
||||||
|
@ -30,7 +30,7 @@ import {
|
|||||||
WireInfo, RefreshSession, ReserveRecord, CoinPaySig
|
WireInfo, RefreshSession, ReserveRecord, CoinPaySig
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import {HttpResponse, RequestException} from "./http";
|
import {HttpResponse, RequestException} from "./http";
|
||||||
import {QueryRoot, Store} from "./query";
|
import {QueryRoot, Store, Index} from "./query";
|
||||||
import {Checkable} from "./checkable";
|
import {Checkable} from "./checkable";
|
||||||
import {canonicalizeBaseUrl} from "./helpers";
|
import {canonicalizeBaseUrl} from "./helpers";
|
||||||
import {ReserveCreationInfo, Amounts} from "./types";
|
import {ReserveCreationInfo, Amounts} from "./types";
|
||||||
@ -306,12 +306,36 @@ function getWithdrawDenomList(amountAvailable: AmountJson,
|
|||||||
|
|
||||||
|
|
||||||
namespace Stores {
|
namespace Stores {
|
||||||
export let exchanges: Store<IExchangeInfo> = new Store<IExchangeInfo>("exchanges");
|
class ExchangeStore extends Store<IExchangeInfo> {
|
||||||
|
constructor() {
|
||||||
|
super("exchanges");
|
||||||
|
}
|
||||||
|
pubKeyIndex = new Index<string,IExchangeInfo>(this, "pubKey");
|
||||||
|
}
|
||||||
|
|
||||||
|
class CoinsStore extends Store<Coin> {
|
||||||
|
constructor() {
|
||||||
|
super("coins");
|
||||||
|
}
|
||||||
|
|
||||||
|
exchangeBaseUrlIndex = new Index<string,Coin>(this, "exchangeBaseUrl");
|
||||||
|
}
|
||||||
|
|
||||||
|
class HistoryStore extends Store<HistoryRecord> {
|
||||||
|
constructor() {
|
||||||
|
super("history");
|
||||||
|
}
|
||||||
|
|
||||||
|
timestampIndex = new Index<number,HistoryRecord>(this, "timestamp");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export let exchanges: ExchangeStore = new ExchangeStore();
|
||||||
export let transactions: Store<Transaction> = new Store<Transaction>("transactions");
|
export let transactions: Store<Transaction> = new Store<Transaction>("transactions");
|
||||||
export let reserves: Store<ReserveRecord> = new Store<ReserveRecord>("reserves");
|
export let reserves: Store<ReserveRecord> = new Store<ReserveRecord>("reserves");
|
||||||
export let coins: Store<Coin> = new Store<Coin>("coins");
|
export let coins: CoinsStore = new CoinsStore();
|
||||||
export let refresh: Store<RefreshSession> = new Store<RefreshSession>("refresh");
|
export let refresh: Store<RefreshSession> = new Store<RefreshSession>("refresh");
|
||||||
export let history: Store<HistoryRecord> = new Store<HistoryRecord>("history");
|
export let history: HistoryStore = new HistoryStore();
|
||||||
export let precoins: Store<PreCoin> = new Store<PreCoin>("precoins");
|
export let precoins: Store<PreCoin> = new Store<PreCoin>("precoins");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,9 +487,8 @@ export class Wallet {
|
|||||||
console.log("Checking for merchant's exchange", JSON.stringify(info));
|
console.log("Checking for merchant's exchange", JSON.stringify(info));
|
||||||
return [
|
return [
|
||||||
this.q()
|
this.q()
|
||||||
.iter(Stores.exchanges, {indexName: "pubKey", only: info.master_pub})
|
.iterIndex(Stores.exchanges.pubKeyIndex, info.master_pub)
|
||||||
.indexJoin("coins",
|
.indexJoin(Stores.coins.exchangeBaseUrlIndex,
|
||||||
"exchangeBaseUrl",
|
|
||||||
(exchange) => exchange.baseUrl)
|
(exchange) => exchange.baseUrl)
|
||||||
.reduce((x) => storeExchangeCoin(x, info.url))
|
.reduce((x) => storeExchangeCoin(x, info.url))
|
||||||
];
|
];
|
||||||
@ -997,8 +1020,7 @@ export class Wallet {
|
|||||||
private async suspendCoins(exchangeInfo: IExchangeInfo): Promise<void> {
|
private async suspendCoins(exchangeInfo: IExchangeInfo): Promise<void> {
|
||||||
let suspendedCoins = await (
|
let suspendedCoins = await (
|
||||||
this.q()
|
this.q()
|
||||||
.iter(Stores.coins,
|
.iterIndex(Stores.coins.exchangeBaseUrlIndex, exchangeInfo.baseUrl)
|
||||||
{indexName: "exchangeBaseUrl", only: exchangeInfo.baseUrl})
|
|
||||||
.reduce((coin: Coin, suspendedCoins: Coin[]) => {
|
.reduce((coin: Coin, suspendedCoins: Coin[]) => {
|
||||||
if (!exchangeInfo.active_denoms.find((c) => c.denom_pub == coin.denomPub)) {
|
if (!exchangeInfo.active_denoms.find((c) => c.denom_pub == coin.denomPub)) {
|
||||||
return Array.prototype.concat(suspendedCoins, [coin]);
|
return Array.prototype.concat(suspendedCoins, [coin]);
|
||||||
@ -1375,7 +1397,7 @@ export class Wallet {
|
|||||||
|
|
||||||
let history = await (
|
let history = await (
|
||||||
this.q()
|
this.q()
|
||||||
.iter(Stores.history, {indexName: "timestamp"})
|
.iterIndex(Stores.history.timestampIndex)
|
||||||
.reduce(collect, []));
|
.reduce(collect, []));
|
||||||
|
|
||||||
return {history};
|
return {history};
|
||||||
|
Loading…
Reference in New Issue
Block a user