Relay: Multiple insertEdgeBefore / insertEdgeAfter with cursor specified

Created on 11 Jun 2019  Â·  7Comments  Â·  Source: facebook/relay

We have been using relay in production for quite a while, but as we add a new edge to a connection, we always used to simply prepend or append it.

We just tried to order a connection alphabetically and therefore use the third argument in ConnectionHandler.insertEdgeAfter, i.e. cursor. It works for the first mutation, and then the next insertions happen mostly in wrong places.

A little digging in the code showed that the cursors generated with graphql-relay are merely a representation of the item's index in the array, therefore cursors are messed up after the first insertion in the middle (two edges have the same cursor and all the next have wrong cursors).

I only see two solutions :

  1. Add the possibility in relay runtime to insert an edge in a connection after or before a given node id instead of edge cursor
  2. Implement cursors differently on server side so that it does not depend on the order (i.e. the node id)

Any insights on this would be much appreciated !

Most helpful comment

The insertEdgeAfter/Before methods are just helpers for common tasks. Two thoughts:

  • change your cursors to be meaningful (ie not the index)
  • or alternatively, you can also do a pattern where you get the full set of existing edges, copy and sort/modify however you like, and then set the edges field to the new value.

Roughly:

const connection = getConnection(...);
const yourNewEdge = ...;

const prevEdges = connection.getLinkedRecords(‘edges’);
const nextEdges =[...prevEdges, yourNewEdge];
sortAndReorderEdgesArbitrsrily(nextEdges); // mutate in place, no reason to copy again

connection.setLinkedRecords(nextEdges, ‘edges’);

All 7 comments

Additional solution / idea I just thought of :

  1. A way to update cursors on the client after an insertion ?

I also found this old comment in #293 which suggests what I implemented in the first place but does not account for subsequent mutations.

I think this should be resolved server side. The real problem, which I guess is that cursors are not stable, is there.

I think you can get the connection, iterate and decide where to put the new edge

@sibelius as a quick workaround I returned the id of the previous edge along with the new one and did what you suggest by copy-pasting insertEdgeAfter and customizing it to insert the newly created edge at the right place and it works fine.

I am still wondering if that is the right thing to do. If it is, then it defeats the purpose of insertEdgeAfter using a cursor. If it is not, then it means I should use ids as cursor ?...

The insertEdgeAfter/Before methods are just helpers for common tasks. Two thoughts:

  • change your cursors to be meaningful (ie not the index)
  • or alternatively, you can also do a pattern where you get the full set of existing edges, copy and sort/modify however you like, and then set the edges field to the new value.

Roughly:

const connection = getConnection(...);
const yourNewEdge = ...;

const prevEdges = connection.getLinkedRecords(‘edges’);
const nextEdges =[...prevEdges, yourNewEdge];
sortAndReorderEdgesArbitrsrily(nextEdges); // mutate in place, no reason to copy again

connection.setLinkedRecords(nextEdges, ‘edges’);

@josephsavona thanks a lot for the answer ! It is almost what I do, only difference is I let the back end do the sorting and send the previous node id.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

luongthanhlam picture luongthanhlam  Â·  3Comments

MartinDawson picture MartinDawson  Â·  3Comments

johntran picture johntran  Â·  3Comments

amccloud picture amccloud  Â·  3Comments

leebyron picture leebyron  Â·  3Comments