diff options
author | Florian Dold <florian.dold@gmail.com> | 2016-10-18 01:36:47 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2016-10-18 01:36:47 +0200 |
commit | 700eb32f5a8852a8004782b199e5fcca4c847116 (patch) | |
tree | da6022f47f52e4b34df6aeb0b251c0b30f9229b6 /lib | |
parent | 89c3c2d58d1a7102a10edfb716cbc7434d0bc117 (diff) |
be even more safe in db
Diffstat (limited to 'lib')
-rw-r--r-- | lib/wallet/query.ts | 68 | ||||
-rw-r--r-- | lib/wallet/wallet.ts | 42 |
2 files changed, 74 insertions, 36 deletions
diff --git a/lib/wallet/query.ts b/lib/wallet/query.ts index ce0308ed3..03b443a6e 100644 --- a/lib/wallet/query.ts +++ b/lib/wallet/query.ts @@ -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 * with indices. */ export interface QueryStream<T> { - indexJoin<S>(storeName: string, - indexName: string, - keyFn: (obj: any) => any): QueryStream<[T, S]>; + indexJoin<S,I>(index: Index<I,S>, + keyFn: (obj: T) => I): QueryStream<[T, S]>; filter(f: (x: any) => boolean): QueryStream<T>; reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>; flatMap(f: (x: T) => T[]): QueryStream<T>; @@ -64,14 +73,14 @@ function openPromise<T>() { // Never happens, unless JS implementation is broken throw Error(); } - return { resolve, reject, promise }; + return {resolve, reject, promise}; } abstract class QueryStreamBase<T> implements QueryStream<T> { abstract subscribe(f: (isDone: boolean, - value: any, - tx: IDBTransaction) => void): void; + value: any, + tx: IDBTransaction) => void): void; root: QueryRoot; @@ -83,11 +92,10 @@ abstract class QueryStreamBase<T> implements QueryStream<T> { return new QueryStreamFlatMap(this, f); } - indexJoin<S>(storeName: string, - indexName: string, - key: any): QueryStream<[T, S]> { - this.root.addStoreAccess(storeName, false); - return new QueryStreamIndexJoin(this, storeName, indexName, key); + indexJoin<S,I>(index: Index<I,S>, + keyFn: (obj: T) => I): QueryStream<[T, S]> { + this.root.addStoreAccess(index.storeName, false); + return new QueryStreamIndexJoin(this, index.storeName, index.indexName, keyFn); } filter(f: (x: any) => boolean): QueryStream<T> { @@ -107,8 +115,8 @@ abstract class QueryStreamBase<T> implements QueryStream<T> { }); return Promise.resolve() - .then(() => this.root.finish()) - .then(() => promise); + .then(() => this.root.finish()) + .then(() => promise); } 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() - .then(() => this.root.finish()) - .then(() => promise); + .then(() => this.root.finish()) + .then(() => promise); } } @@ -191,7 +199,8 @@ class QueryStreamIndexJoin<T, S> extends QueryStreamBase<[T, S]> { key: any; 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); this.s = s; this.storeName = storeName; @@ -238,7 +247,7 @@ class IterQueryStream<T> extends QueryStreamBase<T> { let s: any; if (indexName !== void 0) { s = tx.objectStore(this.storeName) - .index(this.options.indexName); + .index(this.options.indexName); } else { s = tx.objectStore(this.storeName); } @@ -287,10 +296,17 @@ export class QueryRoot { this.db = db; } - iter<T>(store: Store<T>, - {only = <string | undefined>undefined, indexName = <string | undefined>undefined} = {}): QueryStream<T> { + iter<T>(store: Store<T>): QueryStream<T> { 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); return Promise.resolve() - .then(() => this.finish()) - .then(() => promise); + .then(() => this.finish()) + .then(() => promise); } /** @@ -377,8 +393,8 @@ export class QueryRoot { this.addWork(doGetIndexed, storeName, false); return Promise.resolve() - .then(() => this.finish()) - .then(() => promise); + .then(() => this.finish()) + .then(() => promise); } /** @@ -420,8 +436,8 @@ export class QueryRoot { * Low-level function to add a task to the internal work queue. */ addWork(workFn: (t: IDBTransaction) => void, - storeName?: string, - isWrite?: boolean) { + storeName?: string, + isWrite?: boolean) { this.work.push(workFn); if (storeName) { this.addStoreAccess(storeName, isWrite); diff --git a/lib/wallet/wallet.ts b/lib/wallet/wallet.ts index 6ab777801..54c979919 100644 --- a/lib/wallet/wallet.ts +++ b/lib/wallet/wallet.ts @@ -30,7 +30,7 @@ import { WireInfo, RefreshSession, ReserveRecord, CoinPaySig } from "./types"; import {HttpResponse, RequestException} from "./http"; -import {QueryRoot, Store} from "./query"; +import {QueryRoot, Store, Index} from "./query"; import {Checkable} from "./checkable"; import {canonicalizeBaseUrl} from "./helpers"; import {ReserveCreationInfo, Amounts} from "./types"; @@ -306,12 +306,36 @@ function getWithdrawDenomList(amountAvailable: AmountJson, 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 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 history: Store<HistoryRecord> = new Store<HistoryRecord>("history"); + export let history: HistoryStore = new HistoryStore(); 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)); return [ this.q() - .iter(Stores.exchanges, {indexName: "pubKey", only: info.master_pub}) - .indexJoin("coins", - "exchangeBaseUrl", + .iterIndex(Stores.exchanges.pubKeyIndex, info.master_pub) + .indexJoin(Stores.coins.exchangeBaseUrlIndex, (exchange) => exchange.baseUrl) .reduce((x) => storeExchangeCoin(x, info.url)) ]; @@ -997,8 +1020,7 @@ export class Wallet { private async suspendCoins(exchangeInfo: IExchangeInfo): Promise<void> { let suspendedCoins = await ( this.q() - .iter(Stores.coins, - {indexName: "exchangeBaseUrl", only: exchangeInfo.baseUrl}) + .iterIndex(Stores.coins.exchangeBaseUrlIndex, exchangeInfo.baseUrl) .reduce((coin: Coin, suspendedCoins: Coin[]) => { if (!exchangeInfo.active_denoms.find((c) => c.denom_pub == coin.denomPub)) { return Array.prototype.concat(suspendedCoins, [coin]); @@ -1375,7 +1397,7 @@ export class Wallet { let history = await ( this.q() - .iter(Stores.history, {indexName: "timestamp"}) + .iterIndex(Stores.history.timestampIndex) .reduce(collect, [])); return {history}; |