Search code examples
cachinggraphqlapollo

Cache in Apollo is avoiding GraphQL from resolving the polymorphic association


In GraphQL (Apollo, Sequelize and SQLite), I am using a field to resolve the model type of a polymorphic association. When caching, a problem in resolving the association appears.

Backend:

class AssignTModel extends Model {
    async getAction(options)  {     
        if (!this.actionType) return Promise.resolve(null);
            const mixinMethodName = `get${uppercaseFirst(this.actionType)}`;
            const action=await this[mixinMethodName](options);
            if (action) action.myResolve=this.actionType;
            return action;
        }
    }
    AssignTModel.init({
        id:{ type: Sequelize.INTEGER,
            primaryKey: true,
            autoIncrement: true     },
    . . .
        actionId:{ type: Sequelize.INTEGER},
        actionType:{ type: DataTypes.STRING },
    }, {sequelize,modelName: 'assignt'});
    . . .
    AssignTModel.belongsTo(ReminderModel, { foreignKey: 'actionId', constraints: false });
    AssignTModel.belongsTo(ServiceModel, { foreignKey: 'actionId', constraints: false });
    const AssignT = sequelize.models.assignt;
    . . .
const typeDefs = gql`
 union Action = Reminder | Service
    type AssignT{
        id:Int
  . . .

        action:Action
    }
. . .
    type Query {
      . . .
      action(id:Int):[Action],
    . . .

  const resolvers = {
. . .
    Action:{
        __resolveType(obj, context, info){
          if(obj && obj.myResolve && obj.myResolve === "reminder" ){
            return 'Reminder';
          }

          if(obj && obj.myResolve && obj.myResolve === "service" ){
            return 'Service';
          }
          return null;
        },
    },
. . .
    AssignT: {
        . . .
        action: async (assignt) => assignt.getAction(),
    },

Frontend:

In the React.JS application when I enable Cache on a Query I am getting a problem in resolving the polymorphic association:

FORM_QUERY = gql`query ($id:Int){
                  nodes:assignT(id:$id){
                    id
                    . . .
                    action {
                        ... on Reminder{
                            id
                            label
                          }
                        ... on Service{
                            id
                            label
                          }
                    }
                  }
                }`;

Not OK --> <Query query={FORM_QUERY} variables={{id:id}} fetchPolicy="cache-and-network">

OK --> <Query query={FORM_QUERY} variables={{id:id}} fetchPolicy="no-cache">

This problem does not appear on the GraphQL Playground that is why I doubted the Cache.

How can I solve this problem while maintaining Cache?


Solution

  • Found and solved. I am posting the answer so it may help someone facing the same problem.

    The problem was about not using the IntrospectionFragmentMatcher. In fact, I have seen this warning but I was planning to solve it later on and did not directly make the link to my problem.

    the solution is as follows:

    import { InMemoryCache, NormalizedCacheObject,IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
    import {ApolloClient} from "apollo-boost";
    
    const possibleTypes = {
      __schema: {
        types: [{
            kind: 'UNION',
            name: 'Action',
            possibleTypes: [
              { name: 'Service' },
              { name: 'Reminder' },
            ]
          },
        ]
      },
    }
    
    const fragmentMatcher = new IntrospectionFragmentMatcher({
        introspectionQueryResultData: possibleTypes
    })
    const cache = new InMemoryCache({
                        fragmentMatcher
                    })
    const uri= 'http://localhost:4000/';
    const link = createHttpLink({ uri, fetch });
    const client= new ApolloClient({
      cache,
      link
    });