Linked queries accept params again (#1217)
* Linked queries accept params again * Remove invalidated test, cleanup prefix strip
This commit is contained in:
@@ -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
@@ -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);
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}`
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user