Skip to content
This repository has been archived by the owner on May 24, 2022. It is now read-only.

Cleaner code #17

Merged
merged 36 commits into from Sep 17, 2018
Merged

Cleaner code #17

merged 36 commits into from Sep 17, 2018

Conversation

amaury1093
Copy link
Collaborator

@amaury1093 amaury1093 commented Sep 13, 2018

  • All RpcObservables and FrequencyObservables take an options? argument, which contains a provider field. If not empty, that provider will be used.
  • If provider is not specified, then they will use the global provider, defined in api.ts.
  • If an RpcObservable or FrequencyObservable is used before the provider is defined, then an error is thrown.
  • Removed overview. I don't think it's super useful, and only creates complications.

@amaury1093 amaury1093 changed the title Am null provider Cleaner code Sep 13, 2018
@coveralls
Copy link

coveralls commented Sep 13, 2018

Pull Request Test Coverage Report for Build 157

  • 169 of 179 (94.41%) changed or added relevant lines in 18 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+4.07%) to 46.589%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/light.js/src/utils/testHelpers/mockApi.ts 31 32 96.88%
packages/light.js/src/rpc/other/post.ts 9 10 90.0%
packages/light.js/src/rpc/other/makeContract.ts 4 12 33.33%
Totals Coverage Status
Change from base Build 118: 4.07%
Covered Lines: 838
Relevant Lines: 1799

💛 - Coveralls

@amaury1093 amaury1093 changed the title Cleaner code [WIP] Cleaner code Sep 13, 2018
@amaury1093 amaury1093 changed the title [WIP] Cleaner code Cleaner code Sep 13, 2018
@amaury1093 amaury1093 changed the title Cleaner code [WIP] Cleaner code Sep 13, 2018
@amaury1093 amaury1093 changed the title [WIP] Cleaner code Cleaner code Sep 13, 2018
const [namespace, method] = pubsub.split('_');
const api = provider ? createApiFromProvider(provider) : getApi();

Copy link
Contributor

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

Copy link
Contributor

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

Copy link
Contributor

@axelchalon axelchalon left a 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
Copy link
Contributor

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
Copy link
Contributor

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)

Copy link
Contributor

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


const rpc = { ...eth, ...net, ...parity, post$ };

export default memoizeAll(rpc);
Copy link
Contributor

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[]) => {
Copy link
Contributor

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());
});

Copy link
Contributor

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

@amaury1093
Copy link
Collaborator Author

amaury1093 commented Sep 17, 2018

For all func() that did something with api inside its body, I added funcWithApi(), which is a pure version of func(), and correctly memoized.

Also, for simplicity's sake, I removed the withoutLoading option, end-devs need to use the withouLoading operator to remove loading state.

// `args` is arguments object as accessible in memoized function
return `${args[0].name}${args[1].provider.id}${JSON.stringify(
Array.from(args).slice(2)
)}`;
Copy link
Collaborator Author

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.

Copy link
Contributor

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

Copy link
Collaborator Author

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
Copy link
Contributor

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?

Copy link
Collaborator Author

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.

Copy link
Contributor

@axelchalon axelchalon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! 🍻

@amaury1093 amaury1093 merged commit aab3ee3 into master Sep 17, 2018
@amaury1093 amaury1093 deleted the am-null-provider branch September 17, 2018 16:13
pipes.push(multicast(() => subject$), refCount());
if (options.withoutLoading === true) {
pipes.push(withoutLoading());
pipes.push(multicast(() => subject$), refCount(), distinctValues());
Copy link
Contributor

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)

Copy link
Collaborator Author

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants