Skip to content

Remove CustomScalarAdapters argument from ApolloStore methods #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 9, 2025

Conversation

BoD
Copy link
Collaborator

@BoD BoD commented Apr 4, 2025

Fix for #122

@BoD BoD requested a review from martinbonnin as a code owner April 4, 2025 10:08
Comment on lines 203 to 204
.customScalarAdapters(customScalarAdapters)
.normalizedCache(MemoryCacheFactory(), customScalarAdapters = customScalarAdapters, cacheKeyGenerator = IdCacheKeyGenerator(), cacheResolver = IdCacheKeyResolver())
Copy link
Contributor

Choose a reason for hiding this comment

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

The repetition of customScalarAdapter is a bit unfortunate. One option would be .apolloStore(apolloStore: (CustomScalarAdapters) -> ApolloStore), and remove .normalizedCache(). There is a bit of brain muscle around this already so maybe not the best idea. Just a suggestion.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The issue is that it would only work if you call .apolloStore after any call to .customScalarAdapters / .addCustomScalarAdapter. Agreed the current API is not super ideal though. Hopefully using CustomScalarAdapters is not too common anymore since adapters can be configured via Gradle and now via schema extensions (by the way - should we deprecate it in v5?)

Copy link
Contributor

Choose a reason for hiding this comment

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

The issue is that it would only work if you call .apolloStore after any call to .customScalarAdapters / .addCustomScalarAdapter.

Hence the lambda. You would not pass the ApolloStore directly but a factory of ApolloStore that is called during build(), once the adapters are known.

Hopefully using CustomScalarAdapters is not too common anymore since adapters can be configured via Gradle and now via schema extensions (by the way - should we deprecate it in v5?)

Been thinking about that but I think we're definitely not there yet. Plus there might be good use cases for a runtime adapter if it needs some context that is only available at runtime.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hence the lambda. You would not pass the ApolloStore directly but a factory of ApolloStore that is called during build(), once the adapters are known.

Ooh I see! But .build() is in runtime which doesn't know ApolloStore.

Copy link
Contributor

Choose a reason for hiding this comment

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

The lambda could be wrapped in another one that returns an interceptor that holds the ApolloStore. It means the user does not control the order in which the cache interceptor is added but TBH feels like this was an error to have this user-controllable in the first place.

apollo-runtime could have Builder.storeInterceptor(storeInterceptor: ApolloInterceptor), Builder.apqInterceptor(apqInterceptor: ApolloInterceptor). It means the user won't be able to introduce new interceptors between those two but maybe it's for the best? Not 100% convinced but we have definitely had issues there in our API before so might be something to consider.

Copy link
Contributor

@martinbonnin martinbonnin Apr 7, 2025

Choose a reason for hiding this comment

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

Pull request there: https://github.com/apollographql/apollo-kotlin/pull/6455/files

As you can see, there's no lambda parameter to pass the CustomScalarAdapters because I was thinking we could get them from the ApolloClient:

val ApolloClient.apolloStore: ApolloStore
  get() {
    val lowLevelStore = interceptors.firstOrNull { it is CacheInterceptor }?.let {
      (it as CacheInterceptor).store
    } ?: error("no cache configured") 
    return ApolloStore(customScalarAdapters, lowLevelStore)
  }

This way the ApolloClient is still the source of truth for the adapters and we create a small bridge wrapper that connects the ApolloClient and the "thing that used to be called ApolloStore". It allocates a tiny bit but TBH this is probably nothing compared to any other ApolloStore call.

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 I think that works! Let me try to use it so we can see what it looks like 👀

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

All good! Now... do we think it's OK to have it in the 4.x branch too?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's a behaviour change but if advertise it well, it's easy enough to update. + will ease the 5.0 migration. I'm good to have it in the 4.x branch

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

All right! 🚀

@BoD BoD force-pushed the apollo-store-adapters branch from d40a087 to 854bfc3 Compare April 9, 2025 14:50
@BoD BoD merged commit 36f70d1 into main Apr 9, 2025
2 checks passed
@BoD BoD deleted the apollo-store-adapters branch April 9, 2025 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants