aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2016-10-18 01:36:47 +0200
committerFlorian Dold <florian.dold@gmail.com>2016-10-18 01:36:47 +0200
commit700eb32f5a8852a8004782b199e5fcca4c847116 (patch)
treeda6022f47f52e4b34df6aeb0b251c0b30f9229b6 /lib
parent89c3c2d58d1a7102a10edfb716cbc7434d0bc117 (diff)
be even more safe in db
Diffstat (limited to 'lib')
-rw-r--r--lib/wallet/query.ts68
-rw-r--r--lib/wallet/wallet.ts42
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};