On 17 Jul 2024, at 9:49 PM, Davide Sottara <dso...@gmail.com> wrote:Hi!
I have been using the out of the box GraphQL mutations, "createX", "addToX", "updateX" where X is one of my class/shapes.I have been observing some behaviors that are not immediately evident from thedocumentation here:
https://www.topquadrant.com/doc/7.8/graphql/mutations.html
For example, "createX(uri)" does not violate any constraint if "uri" already
exists as an individual, but reports a violation if uri is an instance of X.
That is, it does not check that "uri ?p ?o", but rather "uri a _ subClassOf* X".This would be consistent with the documentation.
@SuppressWarnings("rawtypes")
private static boolean create(DataFetchingEnvironment environment, ObjectType objectType) {
Map obj = environment.getArgument(INPUT);
String uri = (String) obj.get(Schema.URI_FIELD_NAME);
if(uri != null) {
QueryContext context = environment.getContext();
Model dataModel = ModelFactory.createModelForGraph(context.getDiffGraph());
Resource r = GraphQLUtil.getResource(dataModel, uri);
Resource type = r.getPropertyResourceValue(RDF.type);
if(type != null) {
Report report = context.getDiffReport();
ValidationResult result = report.createValidationResult(null, r.asNode());
result.addMessage("URI " + uri + " already used as instance of " + RDFLabels.get().getCustomizedLabel(type));
result.constraintComponent(NodeFactory.createURI(DASH.NS + "URIAlreadyUsedConstraintComponent"));
}
}
return mutate(environment, objectType, false, false);
}
However, updateX(uri) does not seem to check "uri a X" as a precondition.
In fact, if the mutation is able to assert "uri a Y" through a property shape
bound to rdf:type, the mutation succeeds, effectively creating a new
individual with a type that may be unrelated to X.Besides being a way to implement "duck typing", this operation behavesmore like "upsert" than "update" - very useful!, but not exactly what I wouldexpect from the name and the docs.
private static boolean update(DataFetchingEnvironment environment, ObjectType objectType) {
return mutate(environment, objectType, true, false);
}
@SuppressWarnings("rawtypes")
private static boolean mutate(DataFetchingEnvironment environment, ObjectType objectType, boolean replace, boolean addTo) {
QueryContext context = environment.getContext();
Model dataModel = ModelFactory.createModelForGraph(context.getDiffGraph());
Map obj = environment.getArgument(INPUT);
addFieldValues(dataModel, obj, objectType, replace, addTo, context);
return true;
}
@SuppressWarnings("rawtypes")
private static Resource addFieldValues(Model dataModel, Map obj, ObjectType objectType, boolean replace, boolean addTo, QueryContext context) {
// replace is true when called from an 'update', false for 'create'
String uri = (String) obj.get(Schema.URI_FIELD_NAME);
Resource resource = GraphQLUtil.getResource(dataModel, uri);
context.addDiffReportFocusNode(resource.asNode());
// Update rdf:type/dash:shape based on the object type and the GraphQL field "type"
Resource nodeShape = objectType.getNodeShape();
Set<Resource> newTypes = new HashSet<>();
Object types = obj.get(Schema.TYPE_FIELD_NAME);
Property typePredicate = JenaUtil.hasIndirectType(nodeShape, RDFS.Class) ? RDF.type : DASH.shape;
if(types instanceof List) {
// If types have been explicitly passed in, just use those
typePredicate = RDF.type;
for(Object member : ((List)types)) {
String typeURI = (String) ((Map)member).get(Schema.URI_FIELD_NAME);
newTypes.add(GraphQLUtil.getResource(dataModel, typeURI));
}
for(RDFNode node : newTypes) {
dataModel.add(resource, typePredicate, node);
context.addDiffReportFocusNode(resource.asNode());
}
if(replace) {
for(RDFNode old : JenaUtil.getResourceProperties(resource, typePredicate)) {
if(!newTypes.contains(old)) {
removeIfFromBaseModel(dataModel, resource, typePredicate, old);
}
}
}
}
else if(!replace && !addTo) {
// For newly created instances, add type triple, unless this is called from an addTo mutation
dataModel.add(resource, typePredicate, nodeShape);
}
...
In general, is there a more precise definition of the mutations - for exampleby means of an equivalent SPARQL query ?
Thank you in advanceDavide
--
The topics of this mailing list include TopBraid EDG and related technologies such as SHACL.
To post to this group, send email to topbrai...@googlegroups.com
---
You received this message because you are subscribed to the Google Groups "TopBraid Suite Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to topbraid-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/topbraid-users/3cf38e5a-e1b2-4ed6-afbf-c5665f7e6fe9n%40googlegroups.com.