Conversation
Pull Request Test Coverage Report for Build 157
💛 - Coveralls |
const [namespace, method] = pubsub.split('_'); | ||
const api = provider ? createApiFromProvider(provider) : getApi(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to memoize at this point based on pubsub
and api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for example
const createPubsubObservable = <T>(
pubsub: string,
{ provider }: FrequencyObservableOptions = {}
) => {
const [namespace, method] = pubsub.split('_');
const api = provider ? createApiFromProvider(provider) : getApi();
return memoize(createPubsubObservableWithApi)(pubsub, api);
};
and put the rest of the code in createPubsubObservableWithApi
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, except memoization needs to be made later on. Currently, if we change the api with a second call to setApi(), the next calls to the FrequencyObservable$ or RpcObservable$ will return the memoized observable based on the old api.
(address: Address, abiJson: any[], provider: any) => { | ||
const api = provider ? createApiFromProvider(provider) : getApi(); | ||
return api.newContract(abiJson, address); | ||
}, // use types from @parity/abi | ||
{ length: 1 } // Only memoize by address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memoization needs to be done based on address & api
(provider ? createApiFromProvider(provider) : getApi()
), otherwise if we do setApi() getContract() setApi() getContract()
the last getContract()
will return the memoized return value from the first getContract()
call with the old api
const abi = new Abi(abiJson); | ||
(address: Address, abiJson: any[], options: { provider?: any } = {}) => { | ||
const { provider } = options; | ||
const abi = new Abi(abiJson); // use types from @parity/abi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memoization needs to be done based on address and api (same as above)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so it's a bit more tricky here
we could have getContract
require an api/provider to be passed as parameter; put const api = provider ? createApiFromProvider(provider) : getApi();
here (in makeContract) and at that point memoize based on address
and api
packages/light.js/src/rpc/rpc.ts
Outdated
|
||
const rpc = { ...eth, ...net, ...parity, post$ }; | ||
|
||
export default memoizeAll(rpc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove memoization here (see previous comments)
options: RpcObservableOptions = {} | ||
) => { | ||
const { provider, withoutLoading } = options; | ||
const api = provider ? createApiFromProvider(provider) : getApi(); | ||
// rpc$ will hold the RpcObservable minus its metadata | ||
const rpc$: RpcObservableWithoutMetadata<Source, Out> = (...args: any[]) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add memoization based on api
and the observable args
|
||
beforeAll(() => { | ||
setApi(resolveApi()); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can add a test for should memoize based on arguments & api
setApi(resolveApi())
const a = createRpc({})()();
const a2 = createRpc({})()();
expect(a).toEqual(a2);
setApi(resolveNewApi());
const b = createRpc({})()();
expect(a).not.toEqual(b);
setApi(resolveApi())
const a = createRpc({})()('a');
const b = createRpc({})()('b');
expect(a).not.toEqual(b);
same for frequency tests
For all Also, for simplicity's sake, I removed the withoutLoading option, end-devs need to use the |
// `args` is arguments object as accessible in memoized function | ||
return `${args[0].name}${args[1].provider.id}${JSON.stringify( | ||
Array.from(args).slice(2) | ||
)}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only place where I'm not so satisfied.
Normalizer is a function that given the args, generates a unique id used for memoization.
For args[0] = metadata, I take the name, that's alright.
For args[1] = api object, I use provider.id, but this is not guaranteed to be unique per provider (or is it?)
Then for the other args, I JSON.stringify them, that should be alright too.
I didn't find anything with memoizee
to customize a compare function, where we'd use === for the api argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable to me, I don't have any better idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return api.newContract(abiJson, address); | ||
}, // use types from @parity/abi | ||
(address: Address, abiJson: any[], api: any) => | ||
api.newContract(abiJson, address), // use types from @parity/abi | ||
{ length: 1 } // Only memoize by address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the memoization here needs to be based on api also or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, api.newContract(...).contractMethod.call()
makes a rpc call with that api object, fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! 🍻
pipes.push(multicast(() => subject$), refCount()); | ||
if (options.withoutLoading === true) { | ||
pipes.push(withoutLoading()); | ||
pipes.push(multicast(() => subject$), refCount(), distinctValues()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(we can probably use distinctReplayRefCount
like in createPubsubObservable
here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally correct.
I used to put the subject$ inside the RpcObservable's metadata, so we can track the number of subscribers, the current value etc, but removed all that.
options?
argument, which contains a provider field. If not empty, that provider will be used.api.ts
.