Skip to content
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

Fix issue returning arrays from cache.modify modifier functions when the array contains a union type #11994

Merged
merged 6 commits into from
Aug 7, 2024

Conversation

jerelmiller
Copy link
Member

@jerelmiller jerelmiller commented Aug 7, 2024

Fixes an issue with the following type:

cache.modify<{
  union: Array<
    | { __typename: "Type1"; a: string }
    | { __typename: "Type2"; b: string }
  >;
}>({
  fields: {
    union(field) {
      return field.filter((a) => a);
    },
  },
});

This PR also makes it possible to return a DeepPartial object for fields that are more complex types and don't query for the whole value:

cache.modify<{
  union: Array<
    | { __typename: "Type1"; a: string; c: { foo: string } }
    | { __typename: "Type2"; b: string; d: { bar: number } }
  >;
}>({
  fields: {
    union(field) {
      return [{ __typename: "Type1", a: "foo" }];
    },
  },
});

This makes it easier to pass a raw server GraphQL parent type to cache.modify.

Caveat: We don't recommend intentionally omitting fields like this example in real app code. This does a direct cache write which means that if data were available on c or d, that data would get removed from the cache. This is just to illustrate that this would previously create a TypeScript error but is now allowed since you may only be working with a subset of the field data at any given time.

Copy link

changeset-bot bot commented Aug 7, 2024

🦋 Changeset detected

Latest commit: d6e7b4f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@apollo/client Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@jerelmiller
Copy link
Member Author

/release:pr

Copy link
Contributor

github-actions bot commented Aug 7, 2024

size-limit report 📦

Path Size
dist/apollo-client.min.cjs 39.33 KB (0%)
import { ApolloClient, InMemoryCache, HttpLink } from "dist/main.cjs" 47.99 KB (0%)
import { ApolloClient, InMemoryCache, HttpLink } from "dist/main.cjs" (production) 45.57 KB (0%)
import { ApolloClient, InMemoryCache, HttpLink } from "dist/index.js" 34.4 KB (0%)
import { ApolloClient, InMemoryCache, HttpLink } from "dist/index.js" (production) 32.28 KB (0%)
import { ApolloProvider } from "dist/react/index.js" 1.26 KB (0%)
import { ApolloProvider } from "dist/react/index.js" (production) 1.24 KB (0%)
import { useQuery } from "dist/react/index.js" 5.21 KB (0%)
import { useQuery } from "dist/react/index.js" (production) 4.29 KB (0%)
import { useLazyQuery } from "dist/react/index.js" 5.69 KB (0%)
import { useLazyQuery } from "dist/react/index.js" (production) 4.77 KB (0%)
import { useMutation } from "dist/react/index.js" 3.62 KB (0%)
import { useMutation } from "dist/react/index.js" (production) 2.84 KB (0%)
import { useSubscription } from "dist/react/index.js" 4.41 KB (0%)
import { useSubscription } from "dist/react/index.js" (production) 3.46 KB (0%)
import { useSuspenseQuery } from "dist/react/index.js" 5.49 KB (0%)
import { useSuspenseQuery } from "dist/react/index.js" (production) 4.15 KB (0%)
import { useBackgroundQuery } from "dist/react/index.js" 4.99 KB (0%)
import { useBackgroundQuery } from "dist/react/index.js" (production) 3.64 KB (0%)
import { useLoadableQuery } from "dist/react/index.js" 5.07 KB (0%)
import { useLoadableQuery } from "dist/react/index.js" (production) 3.72 KB (0%)
import { useReadQuery } from "dist/react/index.js" 3.39 KB (0%)
import { useReadQuery } from "dist/react/index.js" (production) 3.33 KB (0%)
import { useFragment } from "dist/react/index.js" 2.32 KB (0%)
import { useFragment } from "dist/react/index.js" (production) 2.27 KB (0%)

Copy link
Contributor

github-actions bot commented Aug 7, 2024

A new release has been made for this PR. You can install it with:

npm i @apollo/client@0.0.0-pr-11994-20240807160232

Copy link

netlify bot commented Aug 7, 2024

Deploy Preview for apollo-client-docs ready!

Name Link
🔨 Latest commit 6702ea7
🔍 Latest deploy log https://app.netlify.com/sites/apollo-client-docs/deploys/66b3a9f5cf1fbd00084254bb
😎 Deploy Preview https://deploy-preview-11994--apollo-client-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@jerelmiller
Copy link
Member Author

/release:pr

Copy link
Contributor

github-actions bot commented Aug 7, 2024

A new release has been made for this PR. You can install it with:

npm i @apollo/client@0.0.0-pr-11994-20240807171545


type StoreObjectValueMaybeReference<StoreVal> =
StoreVal extends Array<Record<string, any>> ?
StoreVal extends Array<infer Item> ?
Item extends Record<string, any> ?
[Item] extends [Record<string, any>] ?
ReadonlyArray<AsStoreObject<Item> | Reference>
Copy link
Member Author

@jerelmiller jerelmiller Aug 7, 2024

Choose a reason for hiding this comment

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

I think it eventually makes sense to also pass a DeepPartial as the value to the Modifier function since we can never guarantee you have data for the full type at any given time, only what has been written.

Doing this now might create a bit of churn though, so we might want to wait for a minor/major to make this change as fields that do property access with dot-notation might start complaining once we introduce this. I don't know what kind of impact that will have on our users, but might be good to avoid some anger for now.

@@ -257,7 +257,7 @@ export abstract class EntityStore implements NormalizedCache {
if (newValue !== fieldValue) {
changedFields[storeFieldName] = newValue;
needToMerge = true;
fieldValue = newValue;
fieldValue = newValue as StoreValue;
Copy link
Member Author

Choose a reason for hiding this comment

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

This is needed since the DeepPartial returns unknown on types that it doesn't know what to do with. StoreValue is a union of primitives and Reference so its unable to determine how to apply it.

Copy link
Contributor

@alessbell alessbell left a comment

Choose a reason for hiding this comment

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

Discussed during our 1:1 - great catch! 🚀

@github-actions github-actions bot added the auto-cleanup 🤖 label Aug 7, 2024
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants