graphql-platform icon indicating copy to clipboard operation
graphql-platform copied to clipboard

Extending edge type with relationship data

Open BohdanMaslowski opened this issue 3 years ago • 5 comments

Is your feature request related to a problem?

We use Hot Chocolate on top of EF Core with various entities being in many-to-many relationship with additional relationship data in the join entity types (eg. PostTag.PublicationDate in the sample below).

We would like to add the relationship data to the edge types (as suggested here), but couldn't figure out any way to achieve it.

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    [UsePaging]
    public ICollection<Tag> Tags { get; set; }

    public ICollection<PostTag> PostTags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

    [UsePaging]
    public ICollection<Post> Posts { get; set; }

    public ICollection<PostTag> PostTags { get; set; }
}

public class PostTag
{
    public DateTime PublicationDate { get; set; } // should be included in the edge type

    public int PostId { get; set; }
    public Post Post { get; set; }

    public string TagId { get; set; }
    public Tag Tag { get; set; }
}

(we also use projections, filtering and sorting)

The solution you'd like

Any solution, that would allow extending edge types with data from join entity type. For instance placing the UsePaging attribute on the navigation property of the join entity and specifying a selector for node.

public class Tag
{
    public string TagId { get; set; }

    // public ICollection<Post> Posts { get; set; }

    [UsePaging(NodeSelector = "Post"]
    public ICollection<PostTag> Posts { get; set; }
}

Product

Hot Chocolate

BohdanMaslowski avatar May 06 '22 15:05 BohdanMaslowski

@PascalSenn this is something that is at the moment possible but difficult to do. We need to have a look at how we can simplify this.

Essentially on the EdgeType, we want to expose metadata about the connection...

type FriendsEdge {
   node: User
   cursor: String!
   becameFriendsOn: DateTime # <---- metadata
}

michaelstaib avatar May 09 '22 08:05 michaelstaib

@michaelstaib i will need this in the elastic extensions soon too

PascalSenn avatar May 09 '22 10:05 PascalSenn

We use this pattern in our current API (which we want to migrate to HC without breaking changes) - relationship data are encapsulated within EdgeInfo type, which is then used in both directional edge types:

type CasePersonConnection {
  nodes: [Person]
  edges: [CasePersonEdge]
}
type CasePersonEdge {
  edgeInfo: CasePersonEdgeInfo
  node: Person
}
type PersonCaseConnection {
  nodes: [Case]
  edges: [PersonCaseEdge]
}
type PersonCaseEdge {
  edgeInfo: CasePersonEdgeInfo
  node: Case
}
type CasePersonEdgeInfo { #relationship data (shared type)
  processRole: CasePersonRole
  materialRole: CasePersonRole
  isMainPayer: Boolean
  isMainClient: Boolean
}

It would be great, if this is also supported.

BohdanMaslowski avatar May 10 '22 08:05 BohdanMaslowski

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Sep 07 '22 09:09 stale[bot]

Hi @michaelstaib, is this in the roadmap? Thanks!

BohdanMaslowski avatar Sep 07 '22 10:09 BohdanMaslowski

Just wanted to chime in that this would also be something that I would be interested in. It would be great if we could just create our own Edge Type that implements the Edge contract (cursor & node) and pass this collection of edges to the Connection<T> returned from the resolver. The type of the edges could be specified similar to the node type: [UsePaging<NodeType, EdgeType>]

tobias-tengler avatar Jan 05 '23 14:01 tobias-tengler

@tobias-tengler why not use type extensions?

[ExtendObjectType<IEdge<Bar>>]
public class EdgeExtensions
{
    public string Foo([Parent] IEdge<Bar> edge) => "bay"
}

michaelstaib avatar Feb 02 '23 16:02 michaelstaib

@michaelstaib doesn't solve our problem - we need to access properties of the join entity type, and there's no way to access them from the target/node entity.

BohdanMaslowski avatar Feb 02 '23 17:02 BohdanMaslowski

@BohdanMaslowski what do you mean by that? The parent object that has the field?

{
    foo {                       # <-- this
      bars {                   # <-- or this
          nodes {
             ...
         }
      }
   }
}

michaelstaib avatar Feb 02 '23 17:02 michaelstaib

We mean something like

{
  me {
    friends { # FriendsConnection
      edges { # [FriendEdge]
        cursor
        since # This field comes from a JOIN table or some other connection between entities
        node { # User
          name
      }
    }
  }
}

tobias-tengler avatar Feb 02 '23 17:02 tobias-tengler

Yes, in the example at the beginning, there is a Post ⇔ PostTag ⇔ Tag structure in EF, but I don't want to expose the join entity type PostTag as a type in GQL schema, but to include some of its fields in the PostTagEdge type.

BohdanMaslowski avatar Feb 02 '23 17:02 BohdanMaslowski

Any update on this topic?

kwiatopl avatar Nov 17 '23 13:11 kwiatopl