1

I'm asking this question because I wasn't able to find any ressource on the web (including SO, but also the documentation of Apollo-Client which is quite laconic on the subject), and I'm a out of solution.

I've got this client-side schema :

const typeDefs = gql'

    extend type Query @client {
        getMessageSliceByIdMessaging(id_messaging: String!): [MESSAGE_SLICE]!,
    }

    type MESSAGE_SLICE {
        _id: String!,
        __typename: String!,
        newest_date_creation: String!,
        oldest_date_creation: String!,
        list_id_message: [MESSAGE]!,
    },

'

I've made this typePolicies in the InMemoryCache

typePolicies: {
   Query: {
      fields: {
         getMessageSliceByIdMessaging : {
            merge(existing = [], incoming = [], {cache}) {
               //Doing some shenanigans
               return some_shenanigans
            },
            read(existing = []) {
               return [...existing] //existing properly return "some_shenanigans" generate in merge function
            },
         }
      }
   }
}

But, despite the read function returning the correct "some_shenanigans", when I'm calling :

///FRAGMENT OF MESSAGE_SLICE
const MESSAGE_SLICE_FRAGMENT = gql`
    fragment MessageSliceFragment on MESSAGE_SLICE {
        _id,
        newest_date_creation,
        oldest_date_creation,
        list_id_message {
            ...messageFragment,
        },
    },
    ${MESSAGE_FRAGMENT}
`

///QUERY TO GET A LIST OF MESSAGE_SLICE
const GET_MESSAGE_SLICE_BY_ID_MESSAGING = gql`
    query getMessageSliceByIdMessaging (
        $id_messaging: String!,
    ) {
        getMessageSliceByIdMessaging @client (
            id_messaging: $id_messaging,
        ) {
            ...MessageSliceFragment,
        },
    },
    ${MESSAGE_SLICE_FRAGMENT}
`

///CALL OF THE QUERY
const messageSliceListData = useQuery(GET_MESSAGE_SLICE_BY_ID_MESSAGING, {
   variables: {
      id_messaging: route.id_messaging,
   },
})

///CALLING THIS ALLOW TO PAST DATA TO THE MERGER (missing context, but work properly)
await client.writeQuery({
   query: GET_MESSAGE_SLICE_BY_ID_MESSAGING,
      variables: {
         id_messaging,  
      }, 
   data: {getMessageSliceByIdMessaging: [...SOME_ARRAY_DATA_THAT_NEED_TO_BE_MERGE_IN_THE_TYPE_POLICIES]}
})

messageSliceListData?.data always return [{}] or undefined, and I don't get any Error.

Some thing that I've tried :

  • Returning some_shenanigans as a reference (using toReference),
  • Returning some_shenanigans as raw data.

I wasn't able to find a tutorial or other sources treating this question with Apollo 3.0 and typePolicies (apart from this link: https://www.apollographql.com/tutorials/fullstack-quickstart/10-managing-local-state, but it's using reactives variables, not typePolicies)

So what is the proper way to implement such a solution ?

N.B : I'm using this in a React-Native App, and I'm not in capacity to use the Apollo Developer Tools.

1 Answers1

0

So, I've resolved my problem, and had succeed in getting my data properly.

There was a typo in my code elsewhere, and sometime the result of useQuery(GET_MESSAGE_SLICE_BY_ID_MESSAGING) return an undefined at the second call (easy turnaround with useEffect).

Howerver, I've test some things and I want to share it if someone else struggle with the populate of local Schema :

You need to return the Schema with raw data for the inner props and with ref for relations.

Example :

For this Schema :

type MESSAGE_SLICE {
   _id: String!,   
   __typename: String!,
   newest_date_creation: String!,
   oldest_date_creation: String!,
   list_id_message: [MESSAGE]!,
},

You need to return an object of this type :

CORRECT_FORMAT_FOR_MESSAGE_SLICE_TO_RETURN = [{
   _id: SOME_ID,
   __typename: "MESSAGE_SLICE",
   newest_date_creation,
   oldest_date_creation,
   list_id_message: [
      {__ref: "MESSAGE:ID_OF_MESSAGE_,"}, 
      {__ref: "MESSAGE:ID_OF_MESSAGE_2"},
   ] 
}]

Returning only the apollo ref of MESSAGE_SLICE will not work :

WRONG_FORMAT_FOR_MESSAGE_SLICE_TO_RETURN = [
   {__ref: "MESSAGE_SLICE:ID_OF_MESSAGE_SLICE_1"},
   {__ref: "MESSAGE_SLICE:ID_OF_MESSAGE_SLICE_2"},
]

And returning raw data for all MESSAGE_SLICE and relation will not work either:

WRONG_FORMAT_FOR_MESSAGE_SLICE_TO_RETURN = [{
   _id: SOME_ID,
   __typename: "MESSAGE_SLICE",
   newest_date_creation,
   oldest_date_creation,
   list_id_message: [
      {
         _id: SOME_ID,
         __typename: "MESSAGE",
         id_user: "SOME_ID",
         content_message: "SOME_CONTENT"
      }, 
      {
         _id: SOME_ID,
         __typename: "MESSAGE",
         id_user: "SOME_ID",
         content_message: "SOME_CONTENT"
      },
   ] 
}]

An another thing, in the defintion of Schema, __typename isn't mandatory BUT (see below):

type MESSAGE_SLICE {
   _id: String!,   
   __typename: String!, //this line is optionnal, BUT (see below again).
   newest_date_creation: String!,
   oldest_date_creation: String!,
   list_id_message: [MESSAGE]!,
},

BUT, you need to init a __typename in some way.

It's possible to proceed in this way:

CORRECT_FORMAT_FOR_MESSAGE_SLICE_TO_RETURN = [{
   _id: SOME_ID,
   __typename: "MESSAGE_SLICE", //Init this props in the merger function when creating a new MESSAGE_SLICE
   newest_date_creation,
   oldest_date_creation,
   list_id_message: [
      {__ref: "MESSAGE:ID_OF_MESSAGE_,"}, 
      {__ref: "MESSAGE:ID_OF_MESSAGE_2"},
   ] 
}]

Or in this way, using typePolicies :

typePolicies: {
    MESSAGE_SLICE: {
        fields: {
            __typename: {
                read() {
                    return "MESSAGE_SLICE"
                }
            },
        },
    },
}

Hoping that this will help someone.