Skip to content

Commit

Permalink
Merge 4328c8d into e09dd25
Browse files Browse the repository at this point in the history
  • Loading branch information
jacogr authored Oct 19, 2018
2 parents e09dd25 + 4328c8d commit 595fa13
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 20 deletions.
31 changes: 13 additions & 18 deletions packages/api/src/Base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ export default abstract class ApiBase<R, S, E> implements ApiBaseInterface<R, S,
* <BR>
*
* ```javascript
* import Api from '@polkadot/api/rx';
* import Api from '@polkadot/api/promise';
*
* new Api().isReady.subscribe((api) => {
* api.rpc.subscribeNewHead().subscribe((header) => {
* console.log(`new block #${header.blockNumber.toNumber()}`);
* });
* const api = new Api().isReady();
*
* api.rpc.subscribeNewHead((header) => {
* console.log(`new block #${header.blockNumber.toNumber()}`);
* });
* ```
*/
Expand Down Expand Up @@ -99,11 +99,9 @@ export default abstract class ApiBase<R, S, E> implements ApiBaseInterface<R, S,
* <BR>
*
* ```javascript
* api.query.balances
* .freeBalance(<accountId>)
* .subscribe((balance) => {
* console.log('new balance', balance);
* });
* api.query.balances.freeBalance(<accountId>, (balance) => {
* console.log('new balance', balance);
* });
* ```
*/
get query (): S {
Expand All @@ -121,11 +119,9 @@ export default abstract class ApiBase<R, S, E> implements ApiBaseInterface<R, S,
* <BR>
*
* ```javascript
* api.rpc.chain
* .subscribeNewHead()
* .subscribe((header) => {
* console.log('new header', header);
* });
* api.rpc.chain.subscribeNewHead((header) => {
* console.log('new header', header);
* });
* ```
*/
get rpc (): R {
Expand All @@ -142,8 +138,7 @@ export default abstract class ApiBase<R, S, E> implements ApiBaseInterface<R, S,
* api.tx.balances
* .transfer(<recipientId>, <balance>)
* .sign(<keyPair>, <accountNonce>, <blockHash (optional)>)
* .send()
* .subscribe((status) => {
* .send((status) => {
* console.log('tx status', status);
* });
* ```
Expand All @@ -164,7 +159,7 @@ export default abstract class ApiBase<R, S, E> implements ApiBaseInterface<R, S,
* <BR>
*
* ```javascript
* * api.on('disconnected', () => {
* api.on('disconnected', () => {
* console.log('API has been connected to the endpoint');
* });
*
Expand Down
50 changes: 50 additions & 0 deletions packages/api/src/promise/Combinator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2017-2018 @polkadot/api authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.

import { isFunction } from '@polkadot/util';

export type CombinatorCallback = (value: Array<any>) => any;

type CombinatorFunction = (value: any) => void;

export default class Combinator {
protected _callback?: CombinatorCallback;
protected _results: Array<any>;

constructor (callback?: CombinatorCallback) {
this._callback = callback;
this._results = [];
}

next (): CombinatorFunction {
const index = this._results.length;

// Add an empty value, so we are not operating a sparse array
this._results[index] = undefined;

return (value: any): void => {
this._results[index] = value;

this.triggerUpdate();
};
}

subscribe (callback: CombinatorCallback): void {
this._callback = callback;

this.triggerUpdate();
}

protected triggerUpdate (): void {
if (!isFunction(this._callback) || !this._results.length) {
return;
}

try {
this._callback(this._results);
} catch (error) {
// swallow, we don't want the handler to trip us up
}
}
}
97 changes: 97 additions & 0 deletions packages/api/src/promise/Combinators.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2017-2018 @polkadot/api authors & contributors
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.

import Combinator from './Combinator';

describe('Combinator', () => {
it('creates a simple combinator, trigerring on all values', (done) => {
let count = 0;

const combinator = new Combinator((value: Array<any>) => {
expect(value[0]).toEqual(`test${count}`);

count++;

if (count === 3) {
done();
}
});

const fn = combinator.next();

fn('test0');
fn('test1');
fn('test2');
});

it('creates a combinator that combines values from 2 sources', (done) => {
let count = 0;

const combinator = new Combinator((value: Array<any>) => {
expect(value).toEqual(
count === 0
? ['test0']
: ['test0', 'test1']
);

count++;

if (count === 2) {
done();
}
});

combinator.next()('test0');
combinator.next()('test1');
});

it('creates a combinator that combines values from 2 sources (filling empty)', (done) => {
let count = 0;

const combinator = new Combinator((value: Array<any>) => {
expect(value).toEqual(
count === 0
? ['test0', undefined]
: ['test0', 'test1']
);

count++;

if (count === 2) {
done();
}
});

const fn0 = combinator.next();
const fn1 = combinator.next();

fn0('test0');
fn1('test1');
});

it('allows subscription after use, and subsequent next()', (done) => {
let count = 0;
const combinator = new Combinator();

combinator.next()('test0');
combinator.next()('test1');
combinator.next()('test2');

combinator.subscribe((value: Array<any>) => {
expect(value).toEqual(
count === 0
? ['test0', 'test1', 'test2']
: ['test0', 'test1', 'test2', 'test3']
);

count++;

if (count === 2) {
done();
}
});

combinator.next()('test3');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Method from '@polkadot/types/Method';
import SubmittableExtrinsic from './SubmittableExtrinsic';

describe('SubmittableExtrinsic', () => {
let api;
let api: any;

beforeEach(() => {
Method.injectExtrinsics(extrinsics);
Expand All @@ -28,7 +28,9 @@ describe('SubmittableExtrinsic', () => {
const result = await new SubmittableExtrinsic(
api,
new Extrinsic('0x010200ea51b75b00000000')
).send(() => { });
).send(() => {
// ignore
});

expect(result).toEqual('submitAndWatchExtrinsic');
});
Expand Down
22 changes: 22 additions & 0 deletions packages/api/src/promise/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { StorageFunction } from '@polkadot/types/StorageKey';
import { isFunction } from '@polkadot/util';

import ApiBase from '../Base';
import Combinator, { CombinatorCallback } from './Combinator';
import SubmittableExtrinsic from './SubmittableExtrinsic';

/**
Expand Down Expand Up @@ -165,6 +166,27 @@ export default class ApiPromise extends ApiBase<Rpc, QueryableStorage, Submittab
return rpc;
}

/**
* @description Creats a combinator that can be used to combine the results from multiple subscriptions
* @param callback A callback that will return an Array of all the values this combinator has been applied to
* @example
* <BR>
*
* ```javascript
* // create the combinator
* const combinator = api.combinator(([balance, nonce]) => {
* console.log(`You have ${balance} units, with ${nonce} transactions sent`);
* });
*
* // subscribe to balance & nonce using combinator
* api.query.balances.freeBalance(<address>, combinator.next());
* api.query.system.accountNonce(<address>, combinator.next());
* ```
*/
combinator (callback?: CombinatorCallback): Combinator {
return new Combinator(callback);
}

protected decorateExtrinsics (extrinsics: Extrinsics): SubmittableExtrinsics {
return Object.keys(extrinsics).reduce((result, sectionName) => {
const section = extrinsics[sectionName];
Expand Down

0 comments on commit 595fa13

Please sign in to comment.