I have experienced a very strange behaviour - or at least I do not understand how Dgraph want’s this to be implemented - when it comes to interfaces. I guess it is partly related to this thread.
According to the GraphQL specs
An Interface is an abstract type that includes a certain set of fields that a type must include to implement the interface.
and
This means that any type that implements the interface needs to have the exact same fields as the interface, with these arguments and return types.
So far, so good. Let’s assume the following schema
# Schema ---
# The interface with some searchable fields
interface Implement {
id: ID!
some: String! @id
more: String! @id
fields: String @search
}
# Type One, which implements all the fields according to the specs
type One implements Implement {
id: ID!
one: Int
# Implemented
some: String! @id
more: String! @id
fields: String @search
}
# Type Two, which also implements the interface but I did not set the fields specifically
type Two implements Implement {
id: ID!
two: Int
# Implemented
# some: String @id
# more: String @id
# fields: String @search
}
DQL Mutation to populate the database
I’m running a DQL mutation to populate the database. Since the interface itself should be queryable (and has an ID), I need to set both types One
and Implement
or Two
and Implement
when setting both types One
and Two
. Since the additional fields are implemented via the interface Implement
, the predicate must be set to Implement.some
, Implement.more
, etc.
{
"set": [
{
"uid": "_:nOneUid",
"dgraph.type": ["One", "Implement"],
"One.one": 1,
"Implement.some": "unique_1",
"Implement.more": "unique_2",
"Implement.fields": "text for one"
},
{
"uid": "_:nTwoUid",
"dgraph.type": ["Two", "Implement"],
"Two.two": 2,
"Implement.some": "unique_3",
"Implement.more": "unique_4",
"Implement.fields": "text for two"
}
]
}
Query results
Now I’ve run the queries for each type and the interface. It pretty much does exactly what I would expect. Both One
and Two
inherit both types One
/Two
and Implement
. The value for the interface field some
, is only accessible via Interface.some
(this is clear since I did not define any other predicate in my DQL mutation).
# Query ---
{
qOne(func: type(One)) {
uid
dgraph.type
Implement.some
One.some
}
qTwo(func: type(Two)) {
uid
dgraph.type
Implement.some
Two.some
}
qImplement(func: type(Implement)) {
uid
dgraph.type
Implement.some
}
}
The query result gives
{
data: {
qOne: [
0: {
uid: "0x1a4863389c"
dgraph.type: [
0: "One"
1: "Implement"
]
Implement.some: "unique_1"
}
]
qTwo: [
0: {
uid: "0x1a4863389d"
dgraph.type: [
0: "Two"
1: "Implement"
]
Implement.some: "unique_3"
}
]
qImplement: [
0: {
uid: "0x1a4863389c"
dgraph.type: [
0: "One"
1: "Implement"
]
Implement.some: "unique_1"
}
1: {
uid: "0x1a4863389d"
dgraph.type: [
0: "Two"
1: "Implement"
]
Implement.some: "unique_3"
}
]
}
The Dgraph Cloud Data Studio
This is where I first realised there is something different with the 2 types I have just set up.
Type One
can be sorted by
one
some
more
fields
but type Two
only has a sorting option for
two
Furthermore, if I set the sort parameter to eg. some
for type One
, the DQL query fails and I get the
Failed to retrieve the data
error.
The Network tab reveals
{
"errors": [
{
"message": ": Cannot sort by unknown attribute One.more",
"extensions": {
"code": "ErrorInvalidRequest"
}
}
],
"data": null
}
that Dgraph is looking for the predicate One.some
, which obviously does not exist! This means that when actively implementing the interface fields into the type, somehow makes Dgraph “expect” that both predicates, “One.some” and “Interface.some” must exist.
Both implementations in the schema are GraphQL compliant if I’m not mistaken! So which is the right implementation? Would I have to add the missing predicates for type One
? So sth. like this
{
"set": [
{
"uid": "_:nOneUid",
"dgraph.type": ["One", "Implement"],
"One.one": 1,
"Implement.some": "unique_1",
"Implement.more": "unique_2",
"Implement.fields": "text for one",
"One.some": "unique_1",
"One.more": "unique_2",
"One.fields": "text for one"
}
]
}
I’m really confused! Any help appreciated.