Skip to content

Commit

Permalink
Merge b6f9bc4 into 6b7cd32
Browse files Browse the repository at this point in the history
  • Loading branch information
jacogr committed Oct 9, 2018
2 parents 6b7cd32 + b6f9bc4 commit f5a9364
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 27 deletions.
26 changes: 16 additions & 10 deletions packages/api/src/index.ts
Expand Up @@ -169,37 +169,43 @@ export default class Api implements ApiInterface {
);
}

private formatOutput (method: RpcMethod, params: Array<Base>, result?: any): Base {
private formatOutput (method: RpcMethod, params: Array<Base>, result?: any): Base | Array<Base | undefined> {
const base = createType(method.type as string).fromJSON(result);

if (method.type === 'StorageData') {
// single return value (via state.getStorage), decode the value based on the
// outputType that we have specified
const type = (params[0] as StorageKey).outputType;

if (type) {
return createType(type, base.raw);
}
} else if (method.type === 'StorageChangeSet') {
return (params[0] as Vector<StorageKey>).reduce((vector, _key: StorageKey) => {
// multiple return values (via state.storage subscription), decode the values
// one at a time, all based on the query types
return (params[0] as Vector<StorageKey>).reduce((result, _key: StorageKey) => {
const type = _key.outputType;

if (!type) {
throw new Error('Cannot format StorageChangeSet, output type missing for key');
}

// see if we have a result value for this specific key
const key = _key.toHex();

const item = (base as StorageChangeSet).changes.find((item) =>
item.key.toHex() === key
);

if (!item) {
throw new Error('No result found for key in StorageChangeSet');
}

vector.push(createType(type, item.value.value));
// if we don't have a value, do not fill in the entry, it will be up to the
// caller to sort this out, either ignoring or having a cache for older values
result.push(
item
? createType(type, item.value.value)
: undefined
);

return vector;
}, new (Vector.with(Base))());
return result;
}, [] as Array<Base | undefined>);
}

return base;
Expand Down
17 changes: 17 additions & 0 deletions packages/types/src/codec/Vector.spec.js
Expand Up @@ -2,6 +2,10 @@
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.

import extrinsics from '@polkadot/extrinsics/static';

import createType from './createType';
import Method from '../Method';
import Text from '../Text';
import Vector from './Vector';

Expand All @@ -10,6 +14,8 @@ describe('Vector', () => {

beforeEach(() => {
array = new Vector(Text, [ '1', '23', '345', '4567', new Text('56789') ]);

Method.injectExtrinsics(extrinsics);
});

it('wraps a sequence of values', () => {
Expand Down Expand Up @@ -41,6 +47,17 @@ describe('Vector', () => {
expect(array.Type).toEqual('Text');
});

it('decodes a complex type via construction', () => {
const test = createType('Vec<(PropIndex, Proposal, AccountId)>', new Uint8Array([
4, 10, 0, 0, 0, 0, 3, 80, 123, 10, 9, 34, 48, 120, 52, 50, 34, 58, 32, 34, 48, 120, 52, 51, 34, 10, 125, 10, 209, 114, 167, 76, 218, 76, 134, 89, 18, 195, 43, 160, 168, 10, 87, 174, 105, 171, 174, 65, 14, 92, 203, 89, 222, 232, 78, 47, 68, 50, 219, 79
]));
const first = test.get(0);

expect(first.get(0).toNumber()).toEqual(10);
expect(first.get(1).callIndex).toEqual(new Uint8Array([0, 3]));
expect(first.get(2).toString()).toEqual('5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ');
});

describe('array-like functions', () => {
it('allows retrieval of a specific item', () => {
expect(
Expand Down
49 changes: 32 additions & 17 deletions packages/types/src/codec/Vector.ts
Expand Up @@ -3,6 +3,7 @@
// of the ISC license. See the LICENSE file for details.

import u8aConcat from '@polkadot/util/u8a/concat';
import toU8a from '@polkadot/util/u8a/toU8a';

import Base from './Base';
import Compact, { DEFAULT_LENGTH_BITS } from './Compact';
Expand All @@ -17,16 +18,39 @@ export default class Vector <
> extends Base<Array<T>> {
private _Type: { new(value?: any): T };

constructor (Type: { new(value?: any): T }, value: Array<any> = [] as Array<any>) {
constructor (Type: { new(value?: any): T }, value: Uint8Array | string | Array<any> = [] as Array<any>) {
super(
value.map((entry) =>
Vector.decode(Type, value)
);

this._Type = Type;
}

static decode <T> (Type: { new(value?: any): T }, value: Uint8Array | string | Array<any>): Array<T> {
if (Array.isArray(value)) {
return value.map((entry) =>
entry instanceof Type
? entry
: new Type(entry)
)
);
);
}

this._Type = Type;
const u8a = toU8a(value);

let [offset, _length] = Compact.decodeU8a(value, DEFAULT_LENGTH_BITS);
const length = _length.toNumber();

const result = [];

for (let index = 0; index < length; index++) {
// @ts-ignore Not sure why we get "Property 'fromU8a' does not exist on type 'T'.", T extends Base in def?
const decoded = new Type().fromU8a(u8a.subarray(offset));

result.push(decoded as T);
offset += decoded.byteLength();
}

return result;
}

static with <O extends Base> (Type: { new(value?: any): O }): { new(value?: any): Vector<O> } {
Expand Down Expand Up @@ -64,25 +88,16 @@ export default class Vector <
}

fromJSON (input: any): Vector<T> {
this.raw = input.map((input: any) =>
// input could be null/undefined to indicate empty
this.raw = (input || []).map((input: any) =>
new this._Type().fromJSON(input)
);

return this;
}

fromU8a (input: Uint8Array): Vector<T> {
let [offset, _length] = Compact.decodeU8a(input, DEFAULT_LENGTH_BITS);
const length = _length.toNumber();

this.raw = [];

for (let index = 0; index < length; index++) {
const raw = new this._Type().fromU8a(input.subarray(offset));

this.raw.push(raw as T);
offset += raw.byteLength();
}
this.raw = Vector.decode(this._Type, input);

return this;
}
Expand Down
27 changes: 27 additions & 0 deletions packages/types/src/codec/createType.spec.js
Expand Up @@ -111,6 +111,33 @@ describe('getTypeValue', () => {
]
});
});

it('returns a type structure (actual)', () => {
expect(
getTypeDef('Vec<(PropIndex, Proposal, AccountId)>')
).toEqual({
info: TypeDefInfo.Vector,
type: 'Vec<(PropIndex, Proposal, AccountId)>',
sub: {
info: TypeDefInfo.Tuple,
type: '(PropIndex, Proposal, AccountId)',
sub: [
{
info: TypeDefInfo.Plain,
type: 'PropIndex'
},
{
info: TypeDefInfo.Plain,
type: 'Proposal'
},
{
info: TypeDefInfo.Plain,
type: 'AccountId'
}
]
}
});
});
});

describe('getTypeClass', () => {
Expand Down

0 comments on commit f5a9364

Please sign in to comment.