'How to configure custom key for data that has composite primary key in @urql/exchange-graphcache cacheExchange
On the frontend I have a Cart, it has buttons to call a GraphQL mutation to increase or decrease the quantity of a product. The mutation worked as expected, except for one thing is that the quantity number on the frontend doesn't change until I reload the page. I know the problem is at the cache and I need to somehow update the cache when I click the button and call the mutation.
On the backend I use TypeGraphQL together with TypeORM, on the frontend I use urql, with @urql/exchange-graphcache to configure caching. Here is my attempt on updating the cache:
const client = createClient({
url: "http://localhost:4000/graphql",
fetchOptions: {
credentials: "include" as const,
},
exchanges: [
dedupExchange,
cacheExchange({
updates: {
Mutation: {
qtyCart: (_result, args, cache, info) => {
const { productId, type } = args as QtyCartMutationVariables;
const data = cache.readFragment(
gql`
fragment _ on Cart {
productId
userId
qty
}
`,
{ productId }
);
if (data) {
let newQty = 0;
if (type === "inc") {
newQty = (data.qty as number) + 1;
} else if (type === "dec") {
newQty = (data.qty as number) - 1;
}
cache.writeFragment(
gql`
fragment __ on Cart {
qty
}
`,
{ productId, qty: newQty }
);
}
},
},
},
}),
fetchExchange,
],
});
Also here are the mutation and the Cart entity:
Mutation handle quantity update:
@Mutation(() => Cart) async qtyCart( @Arg("productId", () => Int) productId: number, @Arg("type") type: "inc" | "dec", @Ctx() { req }: MyContext ): Promise<Cart | null> { const userId = req.session.userId; if (!userId) { return null; } const cart = await Cart.findOne({ where: { userId, productId } }); if (!cart) { return null; } const product = await Product.findOne({ where: { id: productId } }); const stock = product!.countInStock; if (type === "inc" && cart.qty < stock) { await Cart.update({ userId, productId }, { qty: cart.qty + 1 }); } else if (type === "dec" && cart.qty > 1) { await Cart.update({ userId, productId }, { qty: cart.qty - 1 }); } return cart; }Cart entity:
@ObjectType()
@Entity()
export class Cart extends BaseEntity {
@Field()
@PrimaryColumn()
userId!: number;
@Field(() => User)
@ManyToOne(() => User, (user) => user.items)
user: User;
@Field()
@PrimaryColumn()
productId!: number;
@Field(() => Product)
@ManyToOne(() => Product, (product) => product.cart)
product: Product;
@Field(() => Int)
@Column()
qty!: number;
}
On my attempt I do spot an error which is mentioned on urql/graphcache documentation, which is the invalid key error. Then I tried to figure out how to create a custom keys config, but still don't know how to do it right, since my Cart entity has a composite primary key, which the documentation doesn't mention.
Thanks in advance for the help. If you need further details then I am pleased to provide.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
