@dgraph directive does not work as expected with union types

PROBLEM

Consider the following schema:

union Owner = User | Organization

type Metadata {
  id: String! @id @search(by: [hash])
  // ... other fields ...
}

type User implements Metadata {
  items: [Item!]! @dgraph(pred: "~Item.owner")
}

type Organization implements Metadata {
  items: [Item!]! @dgraph(pred: "~Item.owner")
}

type Item implements Metadata {
  owner: Owner! @dgraph(pred: "Item.owner")
}

while this expected to work as both Organization and User are union members of Owner it fails with the following error:

resolving updateGQLSchema failed because input:909: Type Item; Field owner: should be any of types User or Metadata to be compatible with @dgraph reverse directive but is of type Owner.\n (Locations: [{Line: 3, Column: 4}])

WORKAROUND ISSUE #1: Use @hasReverse instead of @dgraph

union Owner = User | Organization

type Metadata {
  id: String! @id @search(by: [hash])
  // ... other fields ...
}

type User implements Metadata {
  items: [Item!]! @hasInverse(field: owner)
}

type Organization implements Metadata {
  items: [Item!]! @hasInverse(field: owner)
}

type Item implements Metadata {
  owner: Owner!
}

this issue was already explored in Allow @hasInverse on union types and results in the following error:

resolving updateGQLSchema failed because input:790: Type User; Field library: @hasInverse is required to link the fields of same type, but the field owner is of the type Owner! instead of User. To link these make sure the fields are of the same type.\n (Locations: [{Line: 3, Column: 4}]

WORKAROUND ISSUE #2: Use interface instead of union

Consider the following schema:

type Metadata {
  id: String! @id @search(by: [hash])
  // ... other fields ...
}

type Actor {
  id: String! @id @search(by: [hash])
  // ... other fields ...
}

type User implements Metadata {
  items: [Item!]! @hasInverse(field: owner)
}

type Organization implements Metadata {
  items: [Item!]! @hasInverse(field: owner)
}

type Item implements Metadata {
  owner: Actor!
}

this issue was already explored in Slash doesn't generate the right input object and results in the following error:

resolving updateGQLSchema failed because input:325: Field User.id can only be defined once.\n (Locations: [{Line: 3, Column: 4}])

CONCLUSION

Considering that the workaround #2 is significantly more complex, either the workaround #1 or the original issue should be provided with a valid solution. Our suggestion is to allow the @hasInverse directive on unions as it is the one that makes the most sense and allows mutations in both directions.

Also related: Feature Request | Interface implements Interface

The error seems to be indicating that Owner does not have @reverse in the DQL schema. Can you paste the DQL schema?

1 Like

Hello @chewxy, I verified and you are right, I wrongly assumed that the @dgraph directive would automatically create a reverse directive in the schema when a predicate with prefix “~” was passed as an argument.

I also rechecked the documentation, and it seems like it is not possible to set the @reverse predicate in the schema through GraphQL but only through DQL. I read through some tickets related to this particular corner case and wonder whether you are still considering adding the “@dgraph” directive in the format of “@dgraph(pred: “Item.owner”, reverse: true)”.

I also wonder whether there is any plan to allow @hasInverse on union types at all or whether the @id directive will be allowed to be declared in two interfaces if implemented with exactly the same fingerprint (like it works for the ID type).

@pawan and @hardik - any plans on the above?

I think the best expectation is that the original schema should work as it is. That should add the @reverse directive, but it seems like a bug. So, we will fix the original issue itself.

We don’t have any plans for allowing either of these behaviors because of the associated issues with them as mentioned in the posts you have linked.

@christian-roggia Thanks for finding this corner-case.
Cheers!

2 Likes