Add Option.unwrapOrDefault (#1942)

* Add Option.unwrapOrDefault

* linting

* metadata createType(registry, ...) -> registry.createType(...)

* Linting

* Cleanup tests
This commit is contained in:
Jaco Greeff
2020-02-25 14:15:25 +01:00
committed by GitHub
parent 71e82aece8
commit c3c77ffe43
16 changed files with 106 additions and 112 deletions
+17 -9
View File
@@ -49,7 +49,7 @@ describe('Option', (): void => {
// Option<Option<Bytes>> (hence the length, since it is from storage)
const HEX = '0x210100000000000000000000000000000000000000000000000000000000000000000000000000000000011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce';
// whatc the hex prefix and length
// watch the hex prefix and length
expect(
new Option(registry, Bytes, HEX).toHex().substr(6)
).toEqual(HEX.substr(2));
@@ -59,7 +59,7 @@ describe('Option', (): void => {
const HEX = '0x12345678';
expect(
(new Option(registry, U32, HEX).unwrap() as U32).toNumber()
new Option(registry, U32, HEX).unwrap().toNumber()
).toEqual(0x12345678);
});
@@ -97,22 +97,30 @@ describe('Option', (): void => {
});
describe('utils', (): void => {
const testeq = new Option(registry, Text, '1234');
const test = new Option(registry, Text, '1234');
it('compares against other option', (): void => {
expect(testeq.eq(new Option(registry, Text, '1234'))).toBe(true);
expect(test.eq(new Option(registry, Text, '1234'))).toBe(true);
});
it('compares against raw value', (): void => {
expect(testeq.eq('1234')).toBe(true);
expect(test.eq('1234')).toBe(true);
});
it('unwraps to default if empty', (): void => {
expect(new Option(registry, Text).unwrapOr('6789')).toBe('6789');
it('unwrapOr to specified if empty', (): void => {
expect(new Option(registry, Text).unwrapOr('6789').toString()).toEqual('6789');
});
it('unwraps to value if non-empty', (): void => {
expect((new Option(registry, Text, '1234').unwrapOr(null) as Text).toString()).toBe('1234');
it('unwrapOr to specified if non-empty', (): void => {
expect(new Option(registry, Text, '1234').unwrapOr(null)?.toString()).toEqual('1234');
});
it('unwrapOrDefault to default if empty', (): void => {
expect(new Option(registry, U32).unwrapOrDefault().toNumber()).toEqual(0);
});
it('unwrapOrDefault to specified if non-empty', (): void => {
expect(new Option(registry, U32, '1234').unwrapOrDefault().toNumber()).toEqual(1234);
});
});
});
+40 -29
View File
@@ -10,6 +10,32 @@ import Null from '../primitive/Null';
import { typeToConstructor } from './utils';
import Base from './Base';
/** @internal */
function decodeOptionU8a (registry: Registry, Type: Constructor, value: Uint8Array): Codec {
return !value.length || value[0] === 0
? new Null(registry)
: new Type(registry, value.subarray(1));
}
/** @internal */
function decodeOption (registry: Registry, Type: Constructor, value?: any): Codec {
if (isNull(value) || isUndefined(value) || value instanceof Null) {
return new Null(registry);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
} else if (value instanceof Option) {
return decodeOption(registry, Type, value.value);
} else if (value instanceof Type) {
// don't re-create, use as it (which also caters for derived types)
return value;
} else if (isU8a(value)) {
// the isU8a check happens last in the if-tree - since the wrapped value
// may be an instance of it, so Type and Option checks go in first
return decodeOptionU8a(registry, Type, value);
}
return new Type(registry, value);
}
/**
* @name Option
* @description
@@ -19,42 +45,17 @@ import Base from './Base';
* with a value if/as required/found.
*/
export default class Option<T extends Codec> extends Base<T> {
private _Type: Constructor;
private _Type: Constructor<T>;
constructor (registry: Registry, Type: Constructor | keyof InterfaceTypes, value?: any) {
constructor (registry: Registry, Type: Constructor<T> | keyof InterfaceTypes, value?: any) {
const Clazz = typeToConstructor(registry, Type);
super(registry, Option.decodeOption(registry, Clazz, value));
super(registry, decodeOption(registry, Clazz, value));
this._Type = Clazz;
}
/** @internal */
public static decodeOption (registry: Registry, Type: Constructor, value?: any): Codec {
if (isNull(value) || isUndefined(value) || value instanceof Null) {
return new Null(registry);
} else if (value instanceof Option) {
return Option.decodeOption(registry, Type, value.value);
} else if (value instanceof Type) {
// don't re-create, use as it (which also caters for derived types)
return value;
} else if (isU8a(value)) {
// the isU8a check happens last in the if-tree - since the wrapped value
// may be an instance of it, so Type and Option checks go in first
return Option.decodeOptionU8a(registry, Type, value);
}
return new Type(registry, value);
}
/** @internal */
private static decodeOptionU8a (registry: Registry, Type: Constructor, value: Uint8Array): Codec {
return !value.length || value[0] === 0
? new Null(registry)
: new Type(registry, value.subarray(1));
}
public static with<O extends Codec> (Type: Constructor | keyof InterfaceTypes): Constructor<Option<O>> {
public static with<O extends Codec> (Type: Constructor<O> | keyof InterfaceTypes): Constructor<Option<O>> {
return class extends Option<O> {
constructor (registry: Registry, value?: any) {
super(registry, Type, value);
@@ -170,4 +171,14 @@ export default class Option<T extends Codec> extends Base<T> {
? this.unwrap()
: defaultValue;
}
/**
* @description Returns the value that the Option represents (if available) or defaultValue if none
* @param defaultValue The value to return if the option isNone
*/
public unwrapOrDefault (): T {
return this.isSome
? this.unwrap()
: new this._Type(this.registry);
}
}