Handle storage with optional modifiers (#717)
* Handle storage with optional modifiers * Storage docs indicate Option * Cleanup Option logic * Convert Optional derive to use Option * Bump version, update changelog * Update CHANGELOG description * Enum.spec.js -> Enum.spec.ts * Add isEmpty to primitive types
This commit is contained in:
@@ -1,3 +1,19 @@
|
||||
# 0.45.1
|
||||
|
||||
- Storage with option values now correctly return `Option<Type>` and is indicated as such in the documentation
|
||||
|
||||
```js
|
||||
// old
|
||||
const ll = await api.query.session.lastLengthChange();
|
||||
|
||||
console.log('ll', ll /* BlockNumber */); // would be 0 if not set yet
|
||||
|
||||
// new
|
||||
const llo = await api.query.session.lastLengthChange();
|
||||
|
||||
console.log('llo', llo.unwrapOr('not set') /* Option<BlockNumber> */)
|
||||
```
|
||||
|
||||
# 0.44.1
|
||||
|
||||
- Split primitives and types into seperate folders. This should not affect external use since the exports remain the same, however does have an impact where classes are referenced directly. e.g.
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "0.44.1"
|
||||
"version": "0.45.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/api-derive",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"description": "Common functions used across Polkadot, derived from RPC calls and storage queries.",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -31,8 +31,8 @@
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api-derive#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"@polkadot/api": "^0.44.1",
|
||||
"@polkadot/types": "^0.44.1",
|
||||
"@polkadot/api": "^0.45.0",
|
||||
"@polkadot/types": "^0.45.0",
|
||||
"@types/memoizee": "^0.4.2",
|
||||
"memoizee": "^0.4.14"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ApiInterface$Rx } from '@polkadot/api/types';
|
||||
import { ReferendumInfo, ReferendumIndex } from '@polkadot/types/index';
|
||||
import { Option, ReferendumInfo, ReferendumIndex } from '@polkadot/types/index';
|
||||
|
||||
import { drr } from '../util/drr';
|
||||
|
||||
@@ -16,27 +16,32 @@ import { drr } from '../util/drr';
|
||||
* A [[ReferendumInfo]] with an additional `index` field
|
||||
*/
|
||||
export class ReferendumInfoExtended extends ReferendumInfo {
|
||||
private _index: ReferendumIndex;
|
||||
|
||||
constructor (info: ReferendumInfo, index: BN | number) {
|
||||
constructor (info: any) {
|
||||
super(info);
|
||||
|
||||
this._index = new ReferendumIndex(index);
|
||||
this.set('index', new ReferendumIndex(info.index));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Convenience getter, returns the referendumIndex
|
||||
*/
|
||||
get index (): ReferendumIndex {
|
||||
return this._index;
|
||||
return this.get('index') as ReferendumIndex;
|
||||
}
|
||||
}
|
||||
|
||||
export function referendumInfo (api: ApiInterface$Rx) {
|
||||
return (id: BN | number): Observable<ReferendumInfoExtended> => {
|
||||
return (api.query.democracy.referendumInfoOf(id) as Observable<ReferendumInfo>)
|
||||
return (index: BN | number): Observable<Option<ReferendumInfoExtended>> => {
|
||||
return (api.query.democracy.referendumInfoOf(index) as Observable<Option<ReferendumInfo>>)
|
||||
.pipe(
|
||||
map((info) => new ReferendumInfoExtended(info, id)),
|
||||
map((info) =>
|
||||
new Option<ReferendumInfoExtended>(
|
||||
ReferendumInfoExtended,
|
||||
info.isSome
|
||||
? { ...info.toJSON(), index }
|
||||
: null
|
||||
)
|
||||
),
|
||||
drr()
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import BN from 'bn.js';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { ApiInterface$Rx } from '@polkadot/api/types';
|
||||
import { Option } from '@polkadot/types/index';
|
||||
|
||||
import { drr } from '../util/drr';
|
||||
import { referendumInfo, ReferendumInfoExtended } from './referendumInfo';
|
||||
@@ -12,7 +13,7 @@ import { referendumInfo, ReferendumInfoExtended } from './referendumInfo';
|
||||
export function referendumInfos (api: ApiInterface$Rx) {
|
||||
const referendumInfoOf = referendumInfo(api);
|
||||
|
||||
return (ids: Array<BN | number> = []): Observable<Array<ReferendumInfoExtended>> => {
|
||||
return (ids: Array<BN | number> = []): Observable<Array<Option<ReferendumInfoExtended>>> => {
|
||||
return !ids || !ids.length
|
||||
? of([]).pipe(drr())
|
||||
: combineLatest(
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { ApiInterface$Rx } from '@polkadot/api/types';
|
||||
import { ReferendumIndex } from '@polkadot/types/index';
|
||||
import { Option, ReferendumIndex } from '@polkadot/types/index';
|
||||
|
||||
import { drr } from '../util/drr';
|
||||
import { ReferendumInfoExtended } from './referendumInfo';
|
||||
import { referendumInfos } from './referendumInfos';
|
||||
|
||||
export function referendums (api: ApiInterface$Rx) {
|
||||
return (): Observable<Array<ReferendumInfoExtended>> =>
|
||||
return (): Observable<Array<Option<ReferendumInfoExtended>>> =>
|
||||
(combineLatest(
|
||||
api.query.democracy.nextTally(),
|
||||
api.query.democracy.referendumCount()
|
||||
|
||||
@@ -6,7 +6,7 @@ import BN from 'bn.js';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { ApiInterface$Rx } from '@polkadot/api/types';
|
||||
import { BlockNumber } from '@polkadot/types/index';
|
||||
import { BlockNumber, Option } from '@polkadot/types/index';
|
||||
|
||||
import { bestNumber } from '../chain';
|
||||
import { drr } from '../util/drr';
|
||||
@@ -21,7 +21,7 @@ export function sessionProgress (api: ApiInterface$Rx) {
|
||||
map(
|
||||
([bestNumber, sessionLength, lastLengthChange]) =>
|
||||
(bestNumber || new BN(0))
|
||||
.sub(lastLengthChange as BlockNumber || new BN(0))
|
||||
.sub((lastLengthChange as Option<BlockNumber>).unwrapOr(new BN(0)))
|
||||
.add(sessionLength as BlockNumber || new BN(1))
|
||||
.mod(sessionLength as BlockNumber || new BN(1))
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/api",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"description": "Promise and RxJS wrappers around the Polkadot JS RPC",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -30,12 +30,12 @@
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/api#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"@polkadot/api-derive": "^0.44.1",
|
||||
"@polkadot/extrinsics": "^0.44.1",
|
||||
"@polkadot/rpc-provider": "^0.44.1",
|
||||
"@polkadot/rpc-rx": "^0.44.1",
|
||||
"@polkadot/storage": "^0.44.1",
|
||||
"@polkadot/types": "^0.44.1",
|
||||
"@polkadot/api-derive": "^0.45.0",
|
||||
"@polkadot/extrinsics": "^0.45.0",
|
||||
"@polkadot/rpc-provider": "^0.45.0",
|
||||
"@polkadot/rpc-rx": "^0.45.0",
|
||||
"@polkadot/storage": "^0.45.0",
|
||||
"@polkadot/types": "^0.45.0",
|
||||
"@polkadot/util-crypto": "^0.34.20"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/rpc-core",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"description": "A JavaScript wrapper for the Polkadot JsonRPC interface",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -30,9 +30,9 @@
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-core#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"@polkadot/jsonrpc": "^0.44.1",
|
||||
"@polkadot/rpc-provider": "^0.44.1",
|
||||
"@polkadot/types": "^0.44.1",
|
||||
"@polkadot/jsonrpc": "^0.45.0",
|
||||
"@polkadot/rpc-provider": "^0.45.0",
|
||||
"@polkadot/types": "^0.45.0",
|
||||
"@polkadot/util": "^0.34.20"
|
||||
}
|
||||
}
|
||||
|
||||
+25
-25
@@ -2,6 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import BN from 'bn.js';
|
||||
import storage from '@polkadot/storage/static';
|
||||
|
||||
import Api from './index';
|
||||
@@ -13,8 +14,8 @@ const ENC_ONE = '0x24988a82b3bbaae58680bc9de5dea5aa';
|
||||
const ENC_TWO = '0xdb190750267d8849c35316ec9d342111';
|
||||
|
||||
describe('formatting', () => {
|
||||
let api;
|
||||
let provider;
|
||||
let api: Api;
|
||||
let provider: any;
|
||||
|
||||
beforeEach(() => {
|
||||
provider = {
|
||||
@@ -51,30 +52,29 @@ describe('formatting', () => {
|
||||
});
|
||||
|
||||
it('encodes multiple keys, decoding multiple results', (done) => {
|
||||
api.state
|
||||
.subscribeStorage(
|
||||
[
|
||||
[storage.balances.freeBalance, ADDR_ONE],
|
||||
[storage.balances.freeBalance, ADDR_TWO]
|
||||
],
|
||||
(value) => {
|
||||
console.error(value);
|
||||
return api.state.subscribeStorage(
|
||||
[
|
||||
[storage.balances.freeBalance, ADDR_ONE],
|
||||
[storage.balances.freeBalance, ADDR_TWO]
|
||||
],
|
||||
(value: any) => {
|
||||
console.error(value);
|
||||
|
||||
expect(
|
||||
provider.subscribe
|
||||
).toHaveBeenCalledWith(
|
||||
'state_storage',
|
||||
'state_subscribeStorage',
|
||||
[[ENC_ONE, ENC_TWO]],
|
||||
expect.anything()
|
||||
);
|
||||
expect(
|
||||
value.map((balance) =>
|
||||
balance.toNumber()
|
||||
)
|
||||
).toEqual([513, 258]);
|
||||
expect(
|
||||
provider.subscribe
|
||||
).toHaveBeenCalledWith(
|
||||
'state_storage',
|
||||
'state_subscribeStorage',
|
||||
[[ENC_ONE, ENC_TWO]],
|
||||
expect.anything()
|
||||
);
|
||||
expect(
|
||||
value.map((balance: BN) =>
|
||||
balance.toNumber()
|
||||
)
|
||||
).toEqual([513, 258]);
|
||||
|
||||
done();
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,13 +5,13 @@
|
||||
import Api from './index';
|
||||
|
||||
describe('Api', () => {
|
||||
let api;
|
||||
let provider;
|
||||
let sendSpy;
|
||||
let api: Api;
|
||||
let provider: any;
|
||||
let sendSpy: any;
|
||||
|
||||
beforeEach(() => {
|
||||
provider = {
|
||||
send: (method, params) => {
|
||||
send: (method: any, params: Array<any>) => {
|
||||
return Promise.resolve(params[0]);
|
||||
}
|
||||
};
|
||||
@@ -25,7 +25,7 @@ describe('Api', () => {
|
||||
|
||||
it('requires a provider with a send method', () => {
|
||||
expect(
|
||||
() => new Api({})
|
||||
() => new Api({} as any)
|
||||
).toThrow(/Expected Provider/);
|
||||
});
|
||||
|
||||
@@ -9,8 +9,8 @@ import { RpcInterface, RpcInterface$Method, RpcInterface$Section } from './types
|
||||
import interfaces from '@polkadot/jsonrpc/index';
|
||||
import WsProvider from '@polkadot/rpc-provider/ws';
|
||||
import { Codec } from '@polkadot/types/types';
|
||||
import { StorageChangeSet, StorageKey, Vector, createType } from '@polkadot/types/index';
|
||||
import { ExtError, assert, isFunction, logger } from '@polkadot/util';
|
||||
import { Option, StorageChangeSet, StorageKey, Vector, createClass, createType } from '@polkadot/types/index';
|
||||
import { ExtError, assert, isFunction, isNull, logger } from '@polkadot/util';
|
||||
|
||||
const l = logger('rpc-core');
|
||||
|
||||
@@ -189,24 +189,32 @@ export default class Rpc implements RpcInterface {
|
||||
if (method.type === 'StorageData') {
|
||||
// single return value (via state.getStorage), decode the value based on the
|
||||
// outputType that we have specified. Fallback to Data on nothing
|
||||
const type = (params[0] as StorageKey).outputType || 'Data';
|
||||
const key = params[0] as StorageKey;
|
||||
const type = key.outputType || 'Data';
|
||||
const meta = key.meta || { default: undefined, modifier: { isOptional: true } };
|
||||
const value = isNull(result)
|
||||
? null
|
||||
: base;
|
||||
|
||||
return createType(type, base);
|
||||
return meta.modifier.isOptional
|
||||
? new Option(createClass(type), value)
|
||||
: createType(type, value);
|
||||
} else if (method.type === 'StorageChangeSet') {
|
||||
// multiple return values (via state.storage subscription), decode the values
|
||||
// one at a time, all based on the query types. Three values can be returned -
|
||||
// - Base - There is a valid value, non-empty
|
||||
// - null - The storage key is empty (but in the resultset)
|
||||
// - undefined - The storage value is not in the resultset
|
||||
return (params[0] as Vector<StorageKey>).reduce((result, _key: StorageKey) => {
|
||||
return (params[0] as Vector<StorageKey>).reduce((result, key: StorageKey) => {
|
||||
// Fallback to Data (i.e. just the encoding) if we don't have a specific type
|
||||
const type = _key.outputType || 'Data';
|
||||
const type = key.outputType || 'Data';
|
||||
|
||||
// see if we have a result value for this specific key
|
||||
const key = _key.toHex();
|
||||
const hexKey = key.toHex();
|
||||
const item = (base as StorageChangeSet).changes.find((item) =>
|
||||
item.key.toHex() === key
|
||||
item.key.toHex() === hexKey
|
||||
);
|
||||
const meta = key.meta || { default: undefined, modifier: { isOptional: true } };
|
||||
|
||||
// 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
|
||||
@@ -214,11 +222,13 @@ export default class Rpc implements RpcInterface {
|
||||
!item
|
||||
? undefined
|
||||
: (
|
||||
// for `null` we fallback to the default value, or create an empty type,
|
||||
// otherwise we return the actual value as retrieved
|
||||
item.value.isNone
|
||||
? createType(type, (_key.meta || { default: undefined }).default)
|
||||
: createType(type, item.value.unwrap())
|
||||
meta.modifier.isOptional
|
||||
// create option either with the existing value, or empty when
|
||||
// there is no value returned
|
||||
? new Option(createClass(type), item.value.unwrapOr(null))
|
||||
// for `null` we fallback to the default value, or create an empty type,
|
||||
// otherwise we return the actual value as retrieved
|
||||
: createType(type, item.value.unwrapOr(meta.default))
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
import Api from './index';
|
||||
|
||||
describe('methodSend', () => {
|
||||
let api;
|
||||
let methods;
|
||||
let provider;
|
||||
let api: Api;
|
||||
let methods: any;
|
||||
let provider: any;
|
||||
|
||||
beforeEach(() => {
|
||||
methods = {
|
||||
@@ -37,6 +37,7 @@ describe('methodSend', () => {
|
||||
});
|
||||
|
||||
it('wraps errors with the call signature', () => {
|
||||
// @ts-ignore private method
|
||||
const method = api.createMethodSend(methods.blah);
|
||||
|
||||
return method().catch((error) => {
|
||||
@@ -45,6 +46,7 @@ describe('methodSend', () => {
|
||||
});
|
||||
|
||||
it('checks for mismatched parameters', () => {
|
||||
// @ts-ignore private method
|
||||
const method = api.createMethodSend(methods.bleh);
|
||||
|
||||
return method(1).catch((error) => {
|
||||
@@ -53,6 +55,7 @@ describe('methodSend', () => {
|
||||
});
|
||||
|
||||
it('calls the provider with the correct parameters', () => {
|
||||
// @ts-ignore private method
|
||||
const method = api.createMethodSend(methods.blah);
|
||||
|
||||
// Args are length-prefixed, because it's a Bytes
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/rpc-provider",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"description": "Transport providers for the API",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"@polkadot/keyring": "^0.34.20",
|
||||
"@polkadot/storage": "^0.44.1",
|
||||
"@polkadot/storage": "^0.45.0",
|
||||
"@polkadot/util": "^0.34.20",
|
||||
"@polkadot/util-crypto": "^0.34.20",
|
||||
"@types/nock": "^9.3.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/rpc-rx",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"description": "An RxJs wrapper around the Polkadot JS API",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
@@ -30,8 +30,8 @@
|
||||
"homepage": "https://github.com/polkadot-js/api/tree/master/packages/rpc-rx#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"@polkadot/rpc-core": "^0.44.1",
|
||||
"@polkadot/rpc-provider": "^0.44.1",
|
||||
"@polkadot/rpc-core": "^0.45.0",
|
||||
"@polkadot/rpc-provider": "^0.45.0",
|
||||
"@types/memoizee": "^0.4.2",
|
||||
"@types/rx": "^4.1.1",
|
||||
"memoizee": "^0.4.14",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/extrinsics",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"main": "index.js",
|
||||
"repository": "https://github.com/polkadot-js/api.git",
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
@@ -11,7 +11,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"@polkadot/types": "^0.44.1",
|
||||
"@polkadot/types": "^0.45.0",
|
||||
"@polkadot/util": "^0.34.20"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/jsonrpc",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"description": "Method definitions for the Polkadot RPC layer",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/storage",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"description": "Generic wrapper wrapper around state storage",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
@@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.3.1",
|
||||
"@polkadot/keyring": "^0.34.20",
|
||||
"@polkadot/types": "^0.44.1",
|
||||
"@polkadot/types": "^0.45.0",
|
||||
"@polkadot/util": "^0.34.20",
|
||||
"@polkadot/util-crypto": "^0.34.20"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const createRuntimeFunction = (method: string, key: string, { documentation, typ
|
||||
new Text(method),
|
||||
{
|
||||
documentation: new Vector(Text, [documentation]),
|
||||
modifier: new StorageFunctionModifier(0),
|
||||
modifier: new StorageFunctionModifier(1), // default
|
||||
type: new StorageFunctionType(type, 0),
|
||||
toJSON: (): any =>
|
||||
key
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@polkadot/types",
|
||||
"version": "0.44.1",
|
||||
"version": "0.45.0",
|
||||
"description": "Implementation of the Parity codec",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
|
||||
@@ -124,7 +124,14 @@ export class ModuleMetadata extends Struct {
|
||||
|
||||
export class StorageFunctionModifier extends Enum {
|
||||
constructor (value?: any) {
|
||||
super(['None', 'Default', 'Required'], value);
|
||||
super(['Optional', 'Default', 'Required'], value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description `true` if the storage entry is optional
|
||||
*/
|
||||
get isOptional (): boolean {
|
||||
return this.toNumber() === 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ function storageV0 (mod: MetadataModuleV1): StorageMetadata | null {
|
||||
|
||||
return new StorageMetadata({
|
||||
prefix: mod.prefix,
|
||||
functions: mod.storage.unwrap().map(({ docs, fallback, name, type }) =>
|
||||
functions: mod.storage.unwrap().map(({ docs, fallback, modifier, name, type }) =>
|
||||
new StorageFunctionMetadata({
|
||||
name,
|
||||
modifier: 0, // unused, don't specify
|
||||
modifier: modifier.toNumber(),
|
||||
type,
|
||||
default: fallback,
|
||||
documentation: docs
|
||||
|
||||
@@ -65,6 +65,13 @@ export default abstract class AbstractInt extends BN implements Codec {
|
||||
return this._bitLength / 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is a zero value (align elsewhere)
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.isZero();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the number of bits in the value
|
||||
*/
|
||||
|
||||
@@ -73,6 +73,13 @@ export default class Compact extends Base<UInt | Moment> implements Codec {
|
||||
return this.toU8a().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.raw.isEmpty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the number of bits in the value
|
||||
*/
|
||||
|
||||
@@ -4,15 +4,16 @@
|
||||
|
||||
import Enum from './Enum';
|
||||
|
||||
const testDecode = (type, input, expected) =>
|
||||
const testDecode = (type: string, input: any, expected: any) =>
|
||||
it(`can decode from ${type}`, () => {
|
||||
const e = new Enum(['foo', 'bar'], input);
|
||||
expect(e.toString()).toBe(expected);
|
||||
});
|
||||
|
||||
const testEncode = (to, expected) =>
|
||||
const testEncode = (to: 'toJSON' | 'toNumber' | 'toString' | 'toU8a', expected: any) =>
|
||||
it(`can encode ${to}`, () => {
|
||||
const e = new Enum(['foo', 'bar'], 1);
|
||||
|
||||
expect(e[to]()).toEqual(expected);
|
||||
});
|
||||
|
||||
@@ -65,6 +65,13 @@ export default class Enum extends Base<number> implements Codec {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value (always false)
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
|
||||
@@ -122,6 +122,13 @@ export default class EnumType<T> extends Base<Codec> implements Codec {
|
||||
return this._index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.isEmpty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the Enum points to a [[Null]] type
|
||||
*/
|
||||
|
||||
@@ -53,6 +53,13 @@ export default class Option<T extends Codec> extends Base<T> implements Codec {
|
||||
return 1 + this.raw.encodedLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the Option has no value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.isNone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the Option has no value
|
||||
*/
|
||||
|
||||
@@ -139,6 +139,21 @@ export default class Struct<
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
const items = this.toArray();
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (!items[i].isEmpty) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Returns the Type description to sthe structure
|
||||
*/
|
||||
|
||||
@@ -62,6 +62,13 @@ export default class Tuple extends Array<Codec> implements Codec {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The types definition of the tuple
|
||||
*/
|
||||
|
||||
@@ -53,6 +53,16 @@ export default class Vector<
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The type for the items
|
||||
*/
|
||||
get Type (): string {
|
||||
return this._Type.name;
|
||||
}
|
||||
|
||||
@@ -22,5 +22,5 @@ export { default as U8a } from './U8a';
|
||||
export { default as UInt } from './UInt';
|
||||
|
||||
// Type management helper functions
|
||||
export { default as createType, getTypeClass, getTypeDef, TypeDef, TypeDefInfo } from './createType';
|
||||
export { default as createType, createClass, getTypeClass, getTypeDef, TypeDef, TypeDefInfo } from './createType';
|
||||
export { default as typeRegistry } from './typeRegistry';
|
||||
|
||||
@@ -36,6 +36,13 @@ export default class Bool extends Boolean implements Codec {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value (always false)
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
|
||||
@@ -52,6 +52,13 @@ export default class Moment extends Date implements Codec {
|
||||
return BITLENGTH / 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.getTime() === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,13 @@ export default class Null implements Codec {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value (always true)
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
|
||||
@@ -46,6 +46,13 @@ export default class Text extends String implements Codec {
|
||||
return this.toU8a().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The length of the value
|
||||
*/
|
||||
|
||||
@@ -145,7 +145,10 @@ function addStorage (metadata: MetadataV0) {
|
||||
const methodName = stringLowerFirst(func.name.toString());
|
||||
const arg = func.type.isMap ? ('`' + func.type.asMap.key.toString() + '`') : '';
|
||||
const doc = func.documentation.reduce((md, doc) => `${md} ${doc}`, '');
|
||||
const renderSignature = `${md}\n▸ **${methodName}**(${arg}): ` + '`' + func.type + '`';
|
||||
const type = func.modifier.isOptional
|
||||
? `Option<${func.type}>`
|
||||
: func.type;
|
||||
const renderSignature = `${md}\n▸ **${methodName}**(${arg}): ` + '`' + type + '`';
|
||||
const renderSummary = `${doc ? `\n- **summary**: ${doc}\n` : '\n'}`;
|
||||
|
||||
return renderSignature + renderSummary;
|
||||
|
||||
@@ -6,6 +6,7 @@ import BN from 'bn.js';
|
||||
import { decodeAddress } from '@polkadot/keyring';
|
||||
import { hexToU8a, isBn, isHex, isNumber, isU8a, u8aConcat, u8aToHex, u8aToU8a, u8aToBn } from '@polkadot/util';
|
||||
|
||||
import { Codec } from '../types';
|
||||
import Base from '../codec/Base';
|
||||
import AccountId from './AccountId';
|
||||
import AccountIndex from './AccountIndex';
|
||||
@@ -22,7 +23,7 @@ export const ACCOUNT_ID_PREFIX = new Uint8Array([0xff]);
|
||||
* we extend from Base with an AccountId/AccountIndex wrapper. Basically the Address
|
||||
* is encoded as `[ <prefix-byte>, ...publicKey/...bytes ]` as per spec
|
||||
*/
|
||||
export default class Address extends Base<AccountId | AccountIndex> {
|
||||
export default class Address extends Base<AccountId | AccountIndex> implements Codec {
|
||||
constructor (value: AnyAddress = new Uint8Array()) {
|
||||
super(
|
||||
Address.decodeAddress(value)
|
||||
@@ -75,6 +76,13 @@ export default class Address extends Base<AccountId | AccountIndex> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return this.raw.isEmpty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The length of the raw value, either AccountIndex or AccountId
|
||||
*/
|
||||
|
||||
@@ -30,6 +30,13 @@ export default class ChainProperties extends Map<string, any> implements Codec {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
get isEmpty (): boolean {
|
||||
return [...this.keys()].length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description The token decimals, if defined (de-facto standard only)
|
||||
*/
|
||||
|
||||
@@ -33,6 +33,11 @@ export interface Codec {
|
||||
*/
|
||||
encodedLength: number;
|
||||
|
||||
/**
|
||||
* @description Checks if the value is an empty value
|
||||
*/
|
||||
isEmpty: boolean;
|
||||
|
||||
/**
|
||||
* @description Compares the value of the input to see if there is a match
|
||||
*/
|
||||
@@ -62,7 +67,9 @@ export interface Codec {
|
||||
|
||||
export type CodecTo = 'toHex' | 'toJSON' | 'toString' | 'toU8a';
|
||||
|
||||
export type Constructor<T = Codec> = { new(value?: any): T };
|
||||
export interface Constructor<T = Codec> {
|
||||
new(...value: Array<any>): T;
|
||||
}
|
||||
|
||||
export type ConstructorDef<T = Codec> = { [index: string]: Constructor<T> };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user