Using the readField function in Apollo Client policies allows you to sub-select a query that includes arguments

Utilizing version 3.4.7 of @apollo/client

I came across an informative blog post by Dan Reynolds here. The blog delves into transitioning from a Redux environment to an Apollo GraphQL setup. In Redux, selectors are handy for extracting specific data from the state. However, in Apollo, although you can run queries, sometimes you already possess the required data and simply need a subset of it. The article elaborates on achieving this with code like:

const schema: TypePoliciesSchema = {
  typeDefs: gql`
    extend type Query {
      readManagers: [Employee!]!
    }
  `,
  typePolicies: {
    Query: {
      fields: {
        readManagers: {
          read(employees, context) {
            const employees = readField<Query, 'readEmployees'>(context, 'readEmployees');

            return employees.filter(employeeRef => {
              const employeeRole = readField<Employee, 'role'>(context, 'role', employeeRef);
              return employeeRole === EmployeeRole.Manager;
            });
          },
        }
      }
    }
  }
}

This sample is based on a straightforward GraphQL query:

query GetEmployees {
  employees {
    id
    name
    role
    team
  }
}

The question arises when dealing with parameterized queries like:

query GetEmployees($companyId: ID!) {
  employees(companyId: $companyId) {
    id
    name
    role
    team
  }
}

Accessing readEmployees becomes tricky in such scenarios due to the altered cache key format like

readEmployees({"companyId": "uuid"})
?

One approach could be modifying the readManagers query to include parameters as well, ensuring the same ID is used for sub-selection. Attempting to manually match query keys might not yield the desired outcome.

A current workaround involves utilizing the context cache to rerun the query and convert the results to references using toReference:

const schema: TypePoliciesSchema = {
  typeDefs: gql`
    extend type Query {
      readManagers: [Employee!]!
    }
  `,
  typePolicies: {
    Query: {
      fields: {
        readManagers: {
          read(employees, context) {
            const employees = context.cache.readQuery('readEmployees', { variables: { companyId: context.args.companyId || context.variables.companyId } } );
            return employees.filter(employeeRef => {
              const employeeRole = readField<Employee, 'role'>(context, 'role', employeeRef);
              return employeeRole === EmployeeRole.Manager;
            });
          },
        }
      }
    }
  }
}

While effective, this workaround may not be optimal and seems to involve excessive boilerplate for fetching a subset of the cache.

Answer №1

As per the response provided in a GitHub issue, there is an alternative form of the readField function that accepts an object as an argument. This allows you to incorporate it into your type policy definition for reading data with specific arguments.

 users: {
        read(users, { args, readField }) {
             const { where: { id } } = args;

             const users = readField({
                fieldName: 'Users',
                args: { where: { id } },
              });

             return users;
        },
   }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having Trouble with Imported JavaScript File in Astro

Why isn't the js file working in Astro when I try to import or add a source in the Astro file? For example: <script src="../scripts/local.js"></script> or <script>import '../scripts/local.js'</script> I am ...

Combining a plain object with a TypeScript class

I am currently working on developing a function that dynamically defines a class extending another class based on a passed object. Here is an example of what I am aiming to achieve: const ObjectMixin = function<T>(obj: T): new () => T { return ...

Assigning values to objects based on the types of their properties in Typescript

In my Redux store, I want to create a reducer that can modify any attribute values within the store. Consider the state object defined with specific types: type StoreState = { admins: Admin[]; messages: Message[]; pageInformation: PageInformation; } ...

Encountering the error "Unable to access the 'user' property of an undefined object when working with Angular and Firebase

Exploring Firebase for the first time while attempting to configure email and Google authentication in an Angular (v5) application. While following a tutorial (), I encounter an error: ERROR TypeError: Cannot read property 'user' of undefined T ...

Node.js is having trouble locating a specific folder module within the local directory

My Typescript and NodeJS Visual Studio project compiles successfully, but I encounter a node runtime error regarding the inability to locate a local module. This is the specific error message: https://i.sstatic.net/6ydxj.png I find it perplexing that th ...

Repeating percentages displayed in a progress bar

I created a responsive progress bar, but the progress values are repeating. I only want the central value to be displayed. Any suggestions on how to fix this issue? DEMO <div id="tab1"> <dx-data-grid class="tableTask" [dataSource]="datas" ...

What could be causing the need for RxJs TypeScript files to be requested exclusively when my website is hosted on IIS?

When I develop my site using Visual Studio / IIS Express, everything runs smoothly without any unusual requests or 404 errors. However, once I publish the site to IIS and try to run it, I start receiving multiple requests for typescript files (.ts), prima ...

Traverse the elements of a BehaviorSubject named Layer_Template

I am currently facing an issue with displaying data from my BehaviorSubject. I have come across a way to iterate through a BehaviorSubject using asyncpipe which subscribes to the Observable SERVICE todo.service.ts @Injectable() export class TodoService ...

What is the best way to test a Nest Bull queue using Jest with dependency injection through @InjectQueue?

When working with an Injectable that utilizes a queue through the @InjectQueue decorator: @Injectable() export class EnqueuerService { constructor ( @InjectQueue(QUEUE_NAME) private readonly queue: Queue ) { } async foo () { return this.qu ...

What is the best way to implement two-way data binding to show local storage data on an input field in HTML?

After successfully fetching all the necessary data from a sign-up API, I am looking to display this data as default in specific fields on a page (such as First Name, Last Name, Email, and Phone Number). Any help with achieving this would be greatly appre ...

Obtain the filter criteria within the user interface of a Kendo grid

My Kendo grid looks like this: <kendo-grid [data]="gridData" [pageSize]="state.take" [skip]="state.skip" [sort]="state.sort" [filter]="state.filter" filterable="menu" (dataStateChange)="dataStateChange($event)" > In the ...

Issue with Typescript and React: Property not found on type 'IntrinsicAttributes'

While working on my app using Meteor, React, and Typescript, I encountered a transpiling error: The property 'gameId' is not recognized in the type 'IntrinsicAttributes & {} & { children?: ReactNode; } In my project, I have a com ...

Is there a speedy and efficient method for rearranging a UI list?

Currently utilizing Angular 2 and Typescript. In my current project, I am displaying a basic list of JSON objects. The HTML structure is as follows: <div> <!-- List Presentation Button --> <button md-button (click)="showList( ...

What is the best way to incorporate an image into the canvas element and then use it as a drawing surface?

I have been searching for solutions on various platforms, but I'm having trouble finding ones that work specifically with Ionic and Angular. One major issue I'm facing is trying to copy an image to the canvas. No matter what I try, I can't ...

What is the recommended approach for testing a different branch of a return guard using jest?

My code testing tool, Jest, is indicating that I have only covered 50% of the branches in my return statement test. How can I go about testing the alternate branches? The code snippet below defines a function called getClient. It returns a collection h ...

Fulfill the promise within yourself as well

I am looking to create a custom promise and have attempted the code below. My challenge lies in retrieving the value of recommendationCacheUrls after the inner promise, specifically the fileTransfer.download promise, has resolved. setNewCacheUrls(provided ...

Configuring babel-plugin-styled-components with TypeScript in a create-react-app environment

Currently, we are working on integrating the babel-plugin-styled-components into our setup, which is based on typescript and create-react-app. Our main goal is to improve the debugging experience, but we are facing challenges in achieving this. We want to ...

Next.js 13: Dealing with the "Objects are not valid as a React child" error while using async/await to retrieve data

Currently, I am working on a project using Next.js 13 and the new app directory structure. One of my tasks involves fetching data from an API. However, every time I attempt to do this with async/await, I encounter an error message stating: "Objects are not ...

When using Typescript, I am encountering an issue where declared modules in my declaration file, specifically those with the file

One of the declarations in my ./src/types.d.ts file includes various modules: /// <reference types="@emotion/react/types/css-prop" /> import '@emotion/react'; import { PureComponent, SVGProps } from 'react'; declare mod ...

refresh my graph on the user interface once the service responds with JSON data

After obtaining the object successfully from my API, I have already displayed my custom graph component with default values. However, I need to update the 'chart1Title' of the graph component with the value of 'title' from the object. ...