Open Astn opened 7 years ago
re @Astn, there is a major difference between a GraphQLUnionType (badly named, it returns only one type, the resource must belong to either of the classes), and a owl:unionOf class (which is many classes at the same time, the resource must belong to all the classes).
Also, what about an interface ?
Mmm my bad it seems I'm wrong about owl:unionOf
Ok owl:unionOf is a logical disjunction so it could be either or both classes
A GraphQLUnion type would handle the "either" case, but not if it is "both". A GraphQLInterface type would handle fragments on "both", but we'd still have to resolve only one type (because GraphQL requires a single type) for a particular resource.
Let's say a field returns an owl:unionOf(Dog, Cat) and a user queries a resource that is both a Dog and a Cat (whatever) using a fragment on Dog and another one on Cat, for that resource we would have to resolve only one type (Dog or Cat) not both, and only one fragment would be collected.
This is a typical case where GraphQL and Semantic data do not mix well.
I've been thinking about a fix that would solve many GraphQL vs Semantic conflicts like this one : it would be to add some magic into the resolveType function, by introspecting the AST and knowing what the user wants. Does it need a Dog ? Then return 'Dog' as the type. A Cat ? 'Cat'. A Dog and a Cat ? Return a special DogCat GraphQL type.
From the brief testing I was doing earlier, this case is already handled O.K. I'm sure it could be better. Likely is the case that anything can be an owlThing. So is there a way for us to create a fragment on an objectProperty that has a rdfs:range of owlThing? My currently implementation does not allow such a thing.
But so far, I am able to formulate queries such as:
query {
foo(bar:"bar"){
__typename
... on I_sdo_Action {
startTime
agent {
... on sdo_Person {
url
}
}
}
... on sdo_FollowAction {
followee {
... on I_sdo_Thing {
url
}
}
}
... on sdo_MarryAction {
object {
... on I_sdo_Thing {
url
}
}
}
}
}
So it appears that if the components of a Union implement a common interface, then you are able to pull the common fields from it right now. Not sure of what to do when some Thing is both a Cat and a Dog.
Yes the "both" case is still missing in the GraphQLUnion type solution. But the "both" case is the essence of owl:unionOf. Otherwise simply listing the classes instead of using an owl:unionOf would do.
Do you know any way that graphql supports some kind of a Both case? All I can think of at the moment, which I think you suggested earlier would be to generate another type that represented the logical disjunction. But that then still has the issue that derived types or more specific types are also allowed.
So in the case of
### http://schema.org/acquiredFrom
<http://schema.org/acquiredFrom> rdf:type owl:ObjectProperty ;
rdfs:domain <http://schema.org/OwnershipInfo> ;
rdfs:range [ rdf:type owl:Class ;
owl:unionOf ( <http://schema.org/Organization>
<http://schema.org/Person>
)
] ;
rdfs:comment "The organization or person from which the product was acquired."^^xsd:string ;
rdfs:label "acquired from"^^xsd:string .
The resource returned as the object of http://schema.org/aquiredFrom could be a schema:CafeOrCoffeeShop because
schema:CafeOrCoffeeShop subClassOf schema:LocalBusiness subClassOf schema:Organization
schema:CafeOrCoffeeShop rdf:type owl:Class ; rdfs:comment "A cafe or coffee shop." ; rdfs:label "Cafe or coffee shop" ; rdfs:subClassOf schema:FoodEstablishment ;
schema:FoodEstablishment rdf:type owl:Class ; rdfs:comment "A food-related business." ; rdfs:label "Food establishment" ; rdfs:subClassOf schema:LocalBusiness ;
schema:LocalBusiness rdf:type owl:Class ; rdfs:comment "A particular physical business or branch of an organization. Examples of LocalBusiness include a restaurant, a particular branch of a restaurant chain, a branch of a bank, a medical practice, a club, a bowling alley, etc." ; rdfs:label "Local business" ; rdfs:subClassOf schema:Organization ; rdfs:subClassOf schema:Place ;
So that makes me conclude that in the simple case of
schema:error rdf:type owl:ObjectProperty ; rdfs:comment "For failed actions, more information on the cause of the failure." ; rdfs:domain schema:Action ; rdfs:label "error" ; rdfs:range owl:Thing ;
you *should* be able to formulate the following query because schema:APIReference is an owl:Thing
query { schemaActions { schemaerror { ... on schemaAPIReference { id } } } }
So where do we go from here?
Yes, you're right, that's why I wanted the "type" of fields to be GraphQLInterfaceType instead of GraphQLObjectType. This kind of fragments would then be available, without breaking changes. I never made the swich, it's on the TODO list thought.
So I think we have two separate issues here.
I would still like to try to solve this #3 without tackling the Interface / subtype issue yet. Currently there is no support for unions, so IMO some support is a step forward.
When using ontologies such as the OWL compliant version of schema.org created by topbraid (http://topbraid.org/schema) @ http://topbraid.org/schema/schema.ttl
It is common to encounter a union of resources as the object of rdfs:range. Example:
I propose that we handle this case by adding all of the resources found in the owl:unionOf to a GraphQLUnionType and return that from the call to getGraphqlPolymorphicObjectType.
I have been working on a solution for this particular issue, and should be able to submit a pull request for review shortly.