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

cache readFragment return null #484

Closed
sahmadreza opened this issue Feb 5, 2023 · 10 comments
Closed

cache readFragment return null #484

sahmadreza opened this issue Feb 5, 2023 · 10 comments

Comments

@sahmadreza
Copy link

sahmadreza commented Feb 5, 2023

I try to use readFragment to get the PostFragment by id but it always returns null

Show example
 final client = GetIt.I<Client>();
 GAllPostReq request = GAllPostReq((b) => b..requestId = "posts"..vars.userId= "47244640263");

@override
  Widget build(BuildContext context) {
    super.build(context);
    return Operation(
        client: client,
        operationRequest: request,
        builder: (BuildContext context, OperationResponse<GAllPostData, GAllPostVars>? response, Object? error) {
          if (response == null || response.loading) return const PostLoader();
          final posts = response.data?.explore.edges ?? BuiltList();

          return ListView.builder(
            itemCount: posts.length,
            itemBuilder: (context, index) {
              debugPrint("cache identify:  ${client.cache.identify(posts[index]?.node)}");
              debugPrint("store get:  ${client.cache.store.get(client.cache.identify(posts[index])!)}");
              debugPrint("readFragment:  ${client.cache.readFragment(GPostFragmentReq(
                    (b) => b..idFields = {"id": posts[index]?.node?.id},
              ))}");
              debugPrint("cache keys:  ${client.cache.store.keys}");

              return const SizedBox();
            },
          );
        });
  }

Debug results:

readFragment:

null

cache identify:

Post:21474836490

store get:

{__typename: Post, id: 21474836490, slug: Usiay5vmwqQ, file: {$ref: File:4294967296}, favoritedUsers({"where":{"id":"47244640263"}}): {__typename: UserConnection, totalCount: 0}, likedUsers({"where":{"id":"47244640263"}}): {__typename: UserConnection, totalCount: 0}, owner: {$ref: User:47244640257}, tags: [{$ref: Tag:42949672960}, {$ref: Tag:42949672961}, {$ref: Tag:42949672962}, {$ref: Tag:42949672963}]}

cache keys:

[File:4294967296, File:4294967297, File:4294967298, Post:21474836480, Post:21474836490,  Tag:42949672964, User:47244640256, User:47244640257, UserProfile:47244640263]
Show ferry client
  final box = await Hive.openBox<Map<String, dynamic>>("graphql");
  await box.clear();
  
  final client = Client(
    defaultFetchPolicies: {OperationType.query: FetchPolicy.CacheAndNetwork},
    link: HttpLink(graphQLUrl),
    cache: Cache(store: HiveStore(box)),
  );

  GetIt.I.registerLazySingleton<Client>(() => client);
Show GraphQL Query
# import '../fragments/post_fragment.graphql'

query AllPost ( $userId: ID) {
    posts {
        pageInfo {
            hasNextPage
            hasPreviousPage
            endCursor
            startCursor
        }
        totalCount
        edges {
            cursor
            node {
              ...PostFragment
            }
        }
    }
}
Show GraphQL Fragments
fragment PostFragment on Post {
    id
    slug
    isFavorited: favoritedUsers(where: {id: $userId}){
        totalCount
    }
    isLiked: likedUsers(where: {id: $userId}){
        totalCount
    }
    file {
        ...File
    }
    owner {
        ...Person
    }
    tags {
        ...Tag
    }
}

fragment Tag on Tag {
    id
    name
    slug
    type
}

fragment Person on User {
    id
    avatarUrl
    username
     image {
        ...File
    }
}

fragment File on File {
    id
    smallSize
    thumbnail
    largeSize
}
Dependencies
dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0
  ferry: ^0.13.0
  ferry_flutter: ^0.8.0-dev.7
  ferry_hive_store: ^0.5.1-dev.1
  gql_http_link: ^0.4.6-alpha+1672756470520
  gql_code_builder: ^0.7.1-alpha+1672756470533
  get_it: ^7.2.0

dev_dependencies:
  build_runner: ^2.3.2
  ferry_generator: ^0.7.0-dev.0
  hive_generator: ^2.0.0
@sahmadreza
Copy link
Author

sahmadreza commented Feb 5, 2023

The problem is the use of variable in the fragment.

fragment PostFragment on Post {
   // ...
    isFavorited: favoritedUsers(where: {id: $userId}){
        totalCount
    }
    isLiked: likedUsers(where: {id: $userId}){
        totalCount
    }
   // ...
}

For this reason, readFragment cannot get the post fragment from the cache and returns null

@knaeckeKami
Copy link
Collaborator

I think you need to pass the variables used in the fragment (userId) also to the fragment request

@sahmadreza
Copy link
Author

sahmadreza commented Feb 5, 2023

I think you need to pass the variables used in the fragment (userId) also to the fragment request

Yes, but GPostFragmentReq has no generated vars for userId

I can just pass idFields

client.cache.readFragment(GPostFragmentReq(
                    (b) => b..idFields = {"id": posts[index]?.node?.id},
              ))

@knaeckeKami
Copy link
Collaborator

knaeckeKami commented Feb 5, 2023

I see. This sound like a bug.

I'll look into it.

readFragment is just a thin layer above denormalizeFragment though.
Does it work if you call denormalizeFragment directly, like this:

extension MyReadFragment on Cache {

 /// Reads denormalized data from the Cache for the given fragment.
  TData? readFragment2<TData, TVars>(
    FragmentRequest<TData, TVars> request, {
    bool optimistic = true,
    Map<String, dynamic> variables = {}
  }) {
    final json = denormalizeFragment(
      read: optimistic ? optimisticReader : (dataId) => store.get(dataId),
      document: request.document,
      idFields: request.idFields,
      fragmentName: request.fragmentName,
      // this is custom
      variables: variables,
      typePolicies: typePolicies,
      addTypename: addTypename,
      dataIdFromObject: dataIdFromObject,
      possibleTypes: possibleTypes,
    );
    return json == null ? null : request.parseData(json);
  }


}

?

@sahmadreza
Copy link
Author

@knaeckeKami

readFragment is just a thin layer above denormalizeFragment though.
Does it work if you call denormalizeFragment directly, like this:

Yes, it's working. 👍

@sahmadreza
Copy link
Author

@knaeckeKami

how can use this extension in CacheProxy?

@knaeckeKami
Copy link
Collaborator

You'll probably have to access to cache directly through some other means (like setting it as global variable or something like this) and bypass the cache proxy as workaround until this is fixed properly in ferry

@sahmadreza
Copy link
Author

OK, thanks for your help

@knaeckeKami
Copy link
Collaborator

This should be fixed in gql_code_builder: 0.7.1-alpha+1676138216360.

I added a fragment similar to yours: https://github.com/gql-dart/gql/pull/382/files#diff-86124cb045d0e2d1f35d90d940bfe72821613a8ca4999a43bcc9615aab57c719

and verified that now the variable userId is properly included: https://github.com/gql-dart/gql/pull/382/files#diff-0053d21550d6ab52170d9f97f8b74fadf9fd1d7da1b5357d6742bc854ed70d05R30.

Could you add this gql_code_builder: 0.7.1-alpha+1676138216360 via dependency_override and see if this works for you?

@sahmadreza
Copy link
Author

sahmadreza commented Feb 12, 2023

Very good, yes, I will definitely check it, but it seems to be fixed

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

No branches or pull requests

2 participants