Linked queries accept params again (#1217)

* Linked queries accept params again

* Remove invalidated test, cleanup prefix strip
This commit is contained in:
Jaco Greeff
2019-07-27 23:58:09 +02:00
committed by GitHub
parent 8aed9a4170
commit 4094b44625
5 changed files with 40 additions and 43 deletions
@@ -103,12 +103,12 @@ export default function createFunction ({ meta, method, prefix, section }: Creat
storageFn.toJSON = (): any => meta.toJSON();
if (meta.type.isMap && meta.type.asMap.isLinked) {
const keyHash = new U8a(hasher(`head of ${stringKey}`));
const keyFn: any = (): U8a => keyHash;
const headHash = new U8a(hasher(`head of ${stringKey}`));
const headFn: any = (): U8a => headHash;
// metadata with a flabbcak value using the type of the key, the normal
// metadata with a fallback value using the type of the key, the normal
// meta fallback only applies to actual entry values, create one for head
keyFn.meta = new StorageEntryMetadata({
headFn.meta = new StorageEntryMetadata({
name: meta.name,
modifier: new StorageEntryModifier('Required'),
type: new StorageEntryType(new PlainType(meta.type.asMap.key), 0),
@@ -116,17 +116,12 @@ export default function createFunction ({ meta, method, prefix, section }: Creat
documentation: meta.documentation
});
// here we pass the section/methos through as well - these are not on
// here we pass the section/method through as well - these are not on
// the function itself, so specify these explicitly to the constructor
storageFn.headKey = new StorageKey(keyFn, {
storageFn.headKey = new StorageKey(headFn, {
method: storageFn.method,
section: `head of ${storageFn.section}`
});
// adjust the fallback value - the metadata only specifies the value
// part, add a Linkage<Type> to the fallback aswell. The additional
// bytes here are a representation of the Options for next/prev
meta.set('fallback', new Bytes(meta.fallback.toHex().concat('0000')));
}
return storageFn;
+18 -14
View File
@@ -653,9 +653,7 @@ export default abstract class ApiBase<ApiType> {
.pipe(
// state_storage returns an array of values, since we have just subscribed to
// a single entry, we pull that from the array and return it as-is
map((result: Codec[]): Codec =>
result[0]
)
map(([data]): Codec => data)
);
}, {
methodName: creator.method
@@ -707,7 +705,7 @@ export default abstract class ApiBase<ApiType> {
return this.decorateFunctionMeta(creator, decorated) as unknown as QueryableStorageEntry<ApiType>;
}
private decorateStorageEntryLinked<ApiType> (method: StorageEntry, decorateMethod: ApiBase<ApiType>['decorateMethod']): ReturnType<ApiBase<ApiType>['decorateMethod']> {
private decorateStorageEntryLinked<ApiType> (creator: StorageEntry, decorateMethod: ApiBase<ApiType>['decorateMethod']): ReturnType<ApiBase<ApiType>['decorateMethod']> {
const result: Map<Codec, [Codec, Linkage<Codec>]> = new Map();
let subject: BehaviorSubject<LinkageResult>;
let head: Codec | null = null;
@@ -716,7 +714,7 @@ export default abstract class ApiBase<ApiType> {
// entries can be re-linked in the middle of a list, we subscribe here to make
// sure we catch any updates, no matter the list position
const getNext = (key: Codec): Observable<LinkageResult> => {
return this._rpcCore.state.subscribeStorage([[method, key]])
return this._rpcCore.state.subscribeStorage([[creator, key]])
.pipe(
switchMap(([data]: [[Codec, Linkage<Codec>]]): Observable<LinkageResult> => {
const linkage = data[1];
@@ -777,16 +775,22 @@ export default abstract class ApiBase<ApiType> {
// this handles the case where the head changes effectively, i.e. a new entry
// appears at the top of the list, the new getNext gets kicked off
return decorateMethod(
(): Observable<LinkageResult> =>
this._rpcCore.state
.subscribeStorage([method.headKey])
.pipe(
switchMap(([key]: Codec[]): Observable<LinkageResult> => {
head = key;
(...args: any[]): Observable<LinkageResult | [Codec, Linkage<Codec>]> =>
args.length
? this._rpcCore.state
.subscribeStorage([[creator, ...args]])
.pipe(
map(([data]): [Codec, Linkage<Codec>] => data)
)
: this._rpcCore.state
.subscribeStorage([creator.headKey])
.pipe(
switchMap(([key]): Observable<LinkageResult> => {
head = key;
return getNext(key);
})
)
return getNext(key);
})
)
);
}
+11
View File
@@ -7,6 +7,8 @@ import { Constructor, Codec } from '../types';
type TypeWithValues = [Constructor, any[]];
const EMPTY = new Uint8Array();
export default class Linkage<T extends Codec> extends Struct {
public constructor (Type: Constructor, value?: any) {
super({
@@ -30,6 +32,15 @@ export default class Linkage<T extends Codec> extends Struct {
public get next (): Option<T> {
return this.get('next') as Option<T>;
}
/**
* @description Custom toU8a which with bare mode does not return the linkage if empty
*/
public toU8a (isBare?: boolean): Uint8Array {
return isBare && this.isEmpty
? EMPTY
: super.toU8a();
}
}
export class LinkageResult extends Tuple {
@@ -273,22 +273,6 @@ describe('createType', (): void => {
).toEqual(new Uint8Array([0x00, 0x12, 0x00, 0x23, 0x00, 0x45, 0x00, 0x67]));
});
it('throw error when create base is a StorageData with null value and isPedantic is true', (): void => {
const base = createType('StorageData', null);
expect(
(): Codec => createTypeUnsafe('DoubleMap<Vec<(BlockNumber,EventIndex)>>', [base], true)
).toThrow(/ Input doesn't match output, received 0x, created 0x00/);
});
it('throw error when create base is a StorageData with null value and isPedantic is true', (): void => {
const base = createType('StorageData', null);
expect(
(): Codec => createTypeUnsafe('Vec<(BlockNumber,EventIndex)>', [base], true)
).toThrow(/Input doesn't match output, received 0x, created 0x00/);
});
describe('instanceof', (): void => {
it('instanceof should work (primitive type)', (): void => {
const value = createType('Balance', 1234);
+5 -2
View File
@@ -321,8 +321,11 @@ function initType<T extends Codec = Codec, K extends string = string> (Type: Con
inHex === crHex || // check that the hex matches, if matching, all-ok
(
(value instanceof ClassOf('StorageData')) && // input is from storage
(created instanceof Uint8Array) && // we are a variable-lneght structure
(value.toU8a(true).toString() === created.toU8a().toString()) // strip the input length
(created instanceof Uint8Array) // we are a variable-length structure
// strip the input length
? (value.toU8a(true).toString() === created.toU8a().toString())
// compare raw
: (value.toU8a(true).toString() === created.toU8a(true).toString()) // check raw
),
`Input doesn't match output, received ${inHex}, created ${crHex}`
);