diff --git a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/JsonQueryERElement.java b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/JsonQueryERElement.java index aa46049..b4b3a7f 100644 --- a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/JsonQueryERElement.java +++ b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/JsonQueryERElement.java @@ -54,13 +54,7 @@ public abstract class JsonQueryERElement { * Instruct the JSON query analyzer if it is a projection */ protected boolean projection; - /** - * The caller of this instance analyzer. - * It is null if this instance is an entry point. - * (e.g. a JsonQueryResource instance for a JsonQueryConsistsOf instance) - * - */ - protected JsonQueryERElement caller; + /** * The chain of callers of this instance analyzer. * breadcrumb.get(breadcrumb.size-1) == caller @@ -113,7 +107,6 @@ public abstract class JsonQueryERElement { this.traverseBack = true; this.projection = false; - this.caller = null; this.breadcrumb = new ArrayList<>(); this.position = 0; this.alias = null; @@ -164,14 +157,6 @@ public abstract class JsonQueryERElement { } } - public JsonQueryERElement getCaller() { - return caller; - } - - public void setCaller(JsonQueryERElement caller) { - this.caller = caller; - } - public List getBreadcrumb() { return breadcrumb; } @@ -298,6 +283,7 @@ public abstract class JsonQueryERElement { protected StringBuffer evaluateNode(JsonNode jsonNode, String fieldName, String fieldNamePrefix) throws InvalidQueryException { if(ProjectionOperator.getOperators().contains(fieldName)) { + --size; setProjection(true); Iterator iterator = jsonNode.fieldNames(); while(iterator.hasNext()) { @@ -411,6 +397,11 @@ public abstract class JsonQueryERElement { if(entryPoint) { alias = getAlias(true); + StringBuffer sb = null; + if(size > 1) { + sb = addConstraints(jsonNode, null, alias); + } + StringBuffer entryBuffer = new StringBuffer(); entryBuffer.append("MATCH\n"); entryBuffer.append("\t{class: "); // The { has to be closed @@ -418,18 +409,21 @@ public abstract class JsonQueryERElement { entryBuffer.append(", as: "); entryBuffer.append(alias); entryBuffer.append(", where: "); - entryBuffer.append("(($currentMatch['@class'] INSTANCEOF '"); // The first and the second ( has to be closed + if(sb!=null && sb.length()>0) { + entryBuffer.append("("); + } + entryBuffer.append("($currentMatch['@class'] INSTANCEOF '"); entryBuffer.append(type); entryBuffer.append("')"); // close the second ( - if(size>1) { + if(sb!=null && sb.length()>0) { entryBuffer.append(" AND ("); - entryBuffer.append(addConstraints(jsonNode, null, null)); + entryBuffer.append(sb); + entryBuffer.append(")"); entryBuffer.append(")"); } - entryBuffer.append(")"); // close the first ( - entryBuffer.append("}"); + entryBuffer.append("}\n"); entryBuffer.append(buffer); entryBuffer.append("\nRETURN\n"); diff --git a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/entities/JsonQueryFacet.java b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/entities/JsonQueryFacet.java index 6d4369d..5922d37 100644 --- a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/entities/JsonQueryFacet.java +++ b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/entities/JsonQueryFacet.java @@ -94,8 +94,77 @@ public class JsonQueryFacet extends JsonQueryEntity { @Override protected StringBuffer getSpecificMatchQuery(List childrenBreadcrumb) throws SchemaException, ResourceRegistryException { - // TODO Auto-generated method stub - return new StringBuffer(); + StringBuffer newBuffer = new StringBuffer(); + + if(jsonNode.has(_SOURCE)) { + if(!entryPoint) { + throw new InvalidQueryException(_SOURCE + " property cannot be used in a facet if it is not the entry object"); + } + JsonNode consistsOfNode = jsonNode.get(_SOURCE); + JsonQueryConsistsOf jsonQueryConsistsOf = new JsonQueryConsistsOf(consistsOfNode); + jsonQueryConsistsOf.setTraverseBack(traverseBack); + jsonQueryConsistsOf.setDirection(Direction.OUT); + newBuffer = jsonQueryConsistsOf.createMatchQuery(newBuffer); + + /* Need to substract 1 from size otherwise + * it add WHERE at the end because _in + * is not a property to be used for a WHERE compare + */ + --size; + } + + StringBuffer buffer = new StringBuffer(); + + if(!entryPoint) { + buffer.append("\n\t"); + buffer.append(".inV('"); + buffer.append(type); + buffer.append("')"); + + + alias = getAlias(true); + StringBuffer sb = null; + if(size > 0) { + sb = addConstraints(jsonNode, null, alias); + } + + buffer.append(" {"); + buffer.append(" as: "); + buffer.append(alias); + buffer.append(","); + buffer.append(" where: "); + if(sb!=null && sb.length()>0) { + buffer.append("("); + } + buffer.append("($currentMatch['@class'] INSTANCEOF '"); + buffer.append(type); + buffer.append("')"); + + if(sb!=null && sb.length()>0) { + buffer.append(" AND ("); + buffer.append(sb); + buffer.append(")"); + buffer.append(")"); + } + + buffer.append("}"); + + } + + buffer.append(newBuffer); + + if(traverseBack) { + buffer.append("\n\t"); + buffer.append(".outV('"); + buffer.append(type); + buffer.append("')"); + buffer.append(" { where: ($matched."); + buffer.append(alias); + buffer.append(" == $currentMatch)}"); + } + + return buffer; + } } diff --git a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/entities/JsonQueryResource.java b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/entities/JsonQueryResource.java index d62271e..f0b1a5c 100644 --- a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/entities/JsonQueryResource.java +++ b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/entities/JsonQueryResource.java @@ -120,15 +120,7 @@ public class JsonQueryResource extends JsonQueryEntity { @Override protected StringBuffer getSpecificMatchQuery(List childrenBreadcrumb) throws SchemaException, ResourceRegistryException { - StringBuffer buffer = new StringBuffer(); - - if(!entryPoint) { - buffer.append("\n\t."); - buffer.append(direction.name().toLowerCase()); - buffer.append("V('"); - buffer.append(type); - buffer.append("'"); - } + StringBuffer newBuffer = new StringBuffer(); int isRelatedToSize = 0; @@ -146,69 +138,111 @@ public class JsonQueryResource extends JsonQueryEntity { JsonNode isRelatedToJsonNode = isRelatedToArray.get(i); JsonQueryIsRelatedTo jsonQueryIsRelatedTo = new JsonQueryIsRelatedTo(isRelatedToJsonNode); jsonQueryIsRelatedTo.setRequestedResourceType(type); - jsonQueryIsRelatedTo.setDirectionByJson(); - jsonQueryIsRelatedTo.setCaller(this); + jsonQueryIsRelatedTo.setDirectionByJson(true); jsonQueryIsRelatedTo.setBreadcrumb(childrenBreadcrumb); jsonQueryIsRelatedTo.setPosition(i); - boolean traverseBack = false; - if(i<(isRelatedToSize-1) || consistsOfSize>0) { - traverseBack = true; - } + boolean traverseBack = true; +// boolean traverseBack = false; +// if(i<(isRelatedToSize-1) || consistsOfSize>0) { +// traverseBack = true; +// } jsonQueryIsRelatedTo.setTraverseBack(traverseBack); - buffer = jsonQueryIsRelatedTo.createMatchQuery(buffer); + newBuffer = jsonQueryIsRelatedTo.createMatchQuery(newBuffer); + if(traverseBack) { - buffer.append("\n\t."); - buffer.append(jsonQueryIsRelatedTo.getDirection().name().toLowerCase()); - buffer.append("V('"); - buffer.append(type); - buffer.append("') "); - if(getAlias()!=null || entryPoint) { - buffer.append("{ where: ($matched."); - buffer.append(getAlias()); - buffer.append(" == $currentMatch)}\n"); + newBuffer.append("\n\t."); + newBuffer.append(jsonQueryIsRelatedTo.getDirection().name().toLowerCase()); + newBuffer.append("V('"); + newBuffer.append(type); + newBuffer.append("') "); + newBuffer.append("{ where: ($matched."); + newBuffer.append(getAlias(true)); + newBuffer.append(" == $currentMatch)}"); + if(i<(isRelatedToSize-1) || consistsOfSize>0) { + newBuffer.append("\n"); } } } } - if(consistsOfSize>0) { --size; for(int i=0; i 0) { + sb = addConstraints(jsonNode, null, alias); + } + + buffer.append(" {"); + buffer.append(" as: "); + buffer.append(alias); + buffer.append(","); + buffer.append(" where: "); + if(sb!=null && sb.length()>0) { + buffer.append("("); + } + buffer.append("($currentMatch['@class'] INSTANCEOF '"); + buffer.append(type); + buffer.append("')"); + + if(sb!=null && sb.length()>0) { + buffer.append(" AND ("); + buffer.append(sb); + buffer.append(")"); + buffer.append(")"); + } + + buffer.append("}"); + } + + buffer.append(newBuffer); + if(entryPoint) { + buffer.append("\n"); + } + return buffer; } diff --git a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/relations/JsonQueryConsistsOf.java b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/relations/JsonQueryConsistsOf.java index 664b4ae..28abb30 100644 --- a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/relations/JsonQueryConsistsOf.java +++ b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/relations/JsonQueryConsistsOf.java @@ -141,14 +141,16 @@ public class JsonQueryConsistsOf extends JsonQueryRelation { @Override protected StringBuffer getSpecificMatchQuery(List childrenBreadcrumb) throws SchemaException, ResourceRegistryException { - + int childrenPosition = 0; StringBuffer newBuffer = new StringBuffer(); if(jsonNode.has(ConsistsOf.TARGET_PROPERTY)) { --size; JsonNode facetJsonNode = jsonNode.get(ConsistsOf.TARGET_PROPERTY); JsonQueryFacet jsonQueryFacet = new JsonQueryFacet(facetJsonNode); - jsonQueryFacet.setTraverseBack(true); + jsonQueryFacet.setBreadcrumb(childrenBreadcrumb); + jsonQueryFacet.setPosition(childrenPosition++); + jsonQueryFacet.setTraverseBack(false); newBuffer = jsonQueryFacet.createMatchQuery(newBuffer); } @@ -156,6 +158,8 @@ public class JsonQueryConsistsOf extends JsonQueryRelation { --size; JsonNode resourceJsonNode = jsonNode.get(ConsistsOf.SOURCE_PROPERTY); JsonQueryResource jsonQueryResource = new JsonQueryResource(resourceJsonNode); + jsonQueryResource.setBreadcrumb(childrenBreadcrumb); + jsonQueryResource.setPosition(childrenPosition++); jsonQueryResource.setTraverseBack(true); newBuffer = jsonQueryResource.createMatchQuery(newBuffer); } @@ -164,25 +168,40 @@ public class JsonQueryConsistsOf extends JsonQueryRelation { if(!entryPoint) { buffer.append("\n\t"); + buffer.append("."); buffer.append(direction.name().toLowerCase()); buffer.append("E('"); buffer.append(type); buffer.append("')"); - if(size>0) { - alias = getAlias(true); - buffer.append("{ where: ($matched."); - buffer.append(alias); - buffer.append(" == $currentMatch)"); - - StringBuffer sb = addConstraints(jsonNode, null, alias); - if(sb!=null && sb.length()>0) { - buffer.append(" AND "); - buffer.append(sb); - } - - buffer.append("}\n"); + + alias = getAlias(true); + StringBuffer sb = null; + if(size > 0) { + sb = addConstraints(jsonNode, null, alias); } + + buffer.append(" {"); + buffer.append(" as: "); + buffer.append(alias); + buffer.append(","); + buffer.append(" where: "); + if(sb!=null && sb.length()>0) { + buffer.append("("); + } + buffer.append("($currentMatch['@class'] INSTANCEOF '"); + buffer.append(type); + buffer.append("')"); + + if(sb!=null && sb.length()>0) { + buffer.append(" AND ("); + buffer.append(sb); + buffer.append(")"); + buffer.append(")"); + } + + buffer.append("}"); + } @@ -190,12 +209,16 @@ public class JsonQueryConsistsOf extends JsonQueryRelation { if(traverseBack) { buffer.append("\n\t"); + buffer.append("."); buffer.append(direction.opposite().name().toLowerCase()); buffer.append("E('"); buffer.append(type); - buffer.append("')"); + buffer.append("') "); + buffer.append(" { where: ($matched."); + buffer.append(alias); + buffer.append(" == $currentMatch)}"); } - + return buffer; } diff --git a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/relations/JsonQueryIsRelatedTo.java b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/relations/JsonQueryIsRelatedTo.java index 5d39a30..aea2eb3 100644 --- a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/relations/JsonQueryIsRelatedTo.java +++ b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/json/base/relations/JsonQueryIsRelatedTo.java @@ -7,6 +7,7 @@ import javax.ws.rs.InternalServerErrorException; import org.gcube.com.fasterxml.jackson.databind.JsonNode; import org.gcube.informationsystem.base.reference.AccessType; import org.gcube.informationsystem.base.reference.Direction; +import org.gcube.informationsystem.model.reference.relations.ConsistsOf; import org.gcube.informationsystem.model.reference.relations.IsRelatedTo; import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException; import org.gcube.informationsystem.resourceregistry.api.exceptions.queries.InvalidQueryException; @@ -81,6 +82,10 @@ public class JsonQueryIsRelatedTo extends JsonQueryRelation { } public void setDirectionByJson() throws InvalidQueryException { + setDirectionByJson(false); + } + + public void setDirectionByJson(boolean matchQuery) throws InvalidQueryException { if(entryPoint) { String error = "The function JsonQueryIsRelatedTo#setDirectionByJson() cannot be called for an entry point"; logger.error(error); @@ -112,7 +117,11 @@ public class JsonQueryIsRelatedTo extends JsonQueryRelation { throw new InvalidQueryException(buffer.toString()); } direction = Direction.IN; - } + } + + if(matchQuery) { + direction = direction.opposite(); + } } @Override @@ -197,17 +206,94 @@ public class JsonQueryIsRelatedTo extends JsonQueryRelation { } @Override - protected StringBuffer getSpecificMatchQuery(List childrenBreadcrumb) { + protected StringBuffer getSpecificMatchQuery(List childrenBreadcrumb) throws SchemaException, ResourceRegistryException { if(!entryPoint && direction==null) { throw new InternalServerErrorException("Caller Resource must invoke setDirectionByJson() first. This is a server bug. Please contact the administator. "); } + int childrenPosition = 0; + + StringBuffer newBuffer = new StringBuffer(); + if(jsonNode.has(ConsistsOf.TARGET_PROPERTY)) { + --size; + JsonNode targetJsonNode = jsonNode.get(IsRelatedTo.TARGET_PROPERTY); + JsonQueryResource jsonQueryResource = new JsonQueryResource(targetJsonNode); + jsonQueryResource.setDirection(Direction.IN); + jsonQueryResource.setBreadcrumb(childrenBreadcrumb); + jsonQueryResource.setPosition(childrenPosition++); + jsonQueryResource.setTraverseBack(true); + newBuffer = jsonQueryResource.createMatchQuery(newBuffer); + } + + if(jsonNode.has(ConsistsOf.SOURCE_PROPERTY)) { + --size; + JsonNode sourceJsonNode = jsonNode.get(IsRelatedTo.SOURCE_PROPERTY); + JsonQueryResource jsonQueryResource = new JsonQueryResource(sourceJsonNode); + jsonQueryResource.setDirection(Direction.OUT); + jsonQueryResource.setBreadcrumb(childrenBreadcrumb); + jsonQueryResource.setPosition(childrenPosition++); + jsonQueryResource.setTraverseBack(true); + newBuffer = jsonQueryResource.createMatchQuery(newBuffer); + } + StringBuffer buffer = new StringBuffer(); + if(!entryPoint) { + buffer.append("\n\t"); + buffer.append("."); + buffer.append(direction.name().toLowerCase()); + buffer.append("E('"); + buffer.append(type); + buffer.append("')"); + + + alias = getAlias(true); + StringBuffer sb = null; + if(size > 0) { + sb = addConstraints(jsonNode, null, alias); + } + + buffer.append(" {"); + buffer.append(" as: "); + buffer.append(alias); + buffer.append(","); + buffer.append(" where: "); + if(sb!=null && sb.length()>0) { + buffer.append("("); + } + buffer.append("($currentMatch['@class'] INSTANCEOF '"); + buffer.append(type); + buffer.append("')"); + + if(sb!=null && sb.length()>0) { + buffer.append(" AND ("); + buffer.append(sb); + buffer.append(")"); + buffer.append(")"); + } + + buffer.append("}"); + + + } + buffer.append(newBuffer); + if(traverseBack) { + buffer.append("\n\t"); + buffer.append("."); + buffer.append(direction.opposite().name().toLowerCase()); + buffer.append("E('"); + buffer.append(type); + buffer.append("') "); + buffer.append(" { where: ($matched."); + buffer.append(alias); + buffer.append(" == $currentMatch)}"); + } + return buffer; + } diff --git a/src/test/resources/projection-queries/EService-query.json b/src/test/resources/projection-queries/EService-query.json index b697e85..020e16e 100644 --- a/src/test/resources/projection-queries/EService-query.json +++ b/src/test/resources/projection-queries/EService-query.json @@ -1,49 +1,47 @@ { - - "type": "EService", - "_emit" : { - "id" : "id" - }, - "consistsOf": [ - { - "type": "IsIdentifiedBy", - "target": { - "type": "SoftwareFacet", - "_emit" : { - "group" : "Group", - "name": "Name", - "version" : "Version" - } - } - }, - { - "type": "ConsistsOf", - "target": { - "type": "StateFacet", - "_emit" : { - "value" : "Status" - } + "type": "EService", + "_emit": { + "id": "ID" + }, + "consistsOf": [ + { + "type": "IsIdentifiedBy", + "target": { + "type": "SoftwareFacet", + "_emit": { + "group": "Group", + "name": "Name", + "version": "Version" } } - ], - "isRelatedTo" : [ - { - "type": "Activates", - "source": { - "type": "HostingNode", - "consistsOf": [ - { - "type": "IsIdentifiedBy", - "target": { - "type": "NetworkingFacet", - "_emit" : { - "hostName" : "Host" - } + }, + { + "type": "ConsistsOf", + "target": { + "type": "StateFacet", + "_emit": { + "value": "Status" + } + } + } + ], + "isRelatedTo": [ + { + "type": "Activates", + "source": { + "type": "HostingNode", + "consistsOf": [ + { + "type": "IsIdentifiedBy", + "target": { + "type": "NetworkingFacet", + "_emit": { + "hostName": "Host" } } - ] - } + } + ] } - ] - + } + ] } \ No newline at end of file diff --git a/src/test/resources/projection-queries/EService.match.oquery b/src/test/resources/projection-queries/EService.match.oquery index e9143cf..9cf01b1 100644 --- a/src/test/resources/projection-queries/EService.match.oquery +++ b/src/test/resources/projection-queries/EService.match.oquery @@ -1,16 +1,29 @@ -MATCH - {class: EService, as: eservice, where: ($currentMatch['@class'] INSTANCEOF 'EService')} - .outE('IsIdentifiedBy').inV('SoftwareFacet') {as: softwarefacet, where: ($currentMatch['@class'] INSTANCEOF 'SoftwareFacet')} - .inE('IsIdentifiedBy') - .outV('Eservice') {where: ($matched.eservice == $currentMatch)} - .outE('ConsistsOf').inV("StateFacet") {as: statefacet, where: (($currentMatch['@class'] INSTANCEOF 'StateFacet'))} - .inE('ConsistsOf') - .outV('Eservice') {where: ($matched.eservice == $currentMatch)} - .inE('Activates').outV('HostingNode').outE('IsIdentifiedBy').inV('NetworkingFacet') {as: networkingfacet, where: ($currentMatch['@class'] INSTANCEOF 'NetworkingFacet')} +MATCH + {class: EService, as: eservice00, where: ($currentMatch['@class'] INSTANCEOF 'EService')} + + .inE('Activates') { as: activates10, where: ($currentMatch['@class'] INSTANCEOF 'Activates')} + .outV('HostingNode') { as: hostingnode20, where: ($currentMatch['@class'] INSTANCEOF 'HostingNode')} + .outE('IsIdentifiedBy') { as: isidentifiedby30, where: ($currentMatch['@class'] INSTANCEOF 'IsIdentifiedBy')} + .inV('NetworkingFacet') { as: networkingfacet40, where: ($currentMatch['@class'] INSTANCEOF 'NetworkingFacet')} + .inE('IsIdentifiedBy') { where: ($matched.isidentifiedby30 == $currentMatch)} + .outV('HostingNode') { where: ($matched.hostingnode20 == $currentMatch)} + .outE('Activates') { where: ($matched.activates10 == $currentMatch)} + .inV('EService') { where: ($matched.eservice00 == $currentMatch)} + + .outE('IsIdentifiedBy') { as: isidentifiedby11, where: ($currentMatch['@class'] INSTANCEOF 'IsIdentifiedBy')} + .inV('SoftwareFacet') { as: softwarefacet20, where: ($currentMatch['@class'] INSTANCEOF 'SoftwareFacet')} + .inE('IsIdentifiedBy') { where: ($matched.isidentifiedby11 == $currentMatch)} + .outV('EService') { where: ($matched.eservice00 == $currentMatch)} + + .outE('ConsistsOf') { as: consistsof12, where: ($currentMatch['@class'] INSTANCEOF 'ConsistsOf')} + .inV('StateFacet') { as: statefacet20, where: ($currentMatch['@class'] INSTANCEOF 'StateFacet')} + .inE('ConsistsOf') { where: ($matched.consistsof12 == $currentMatch)} + .outV('EService') { where: ($matched.eservice00 == $currentMatch)} + RETURN - eservice.id AS ID, - softwarefacet.group AS Group, - softwarefacet.name AS Name, - softwarefacet.version AS Version, - statefacet.value AS Status, - networkingfacet.hostName AS Host \ No newline at end of file + networkingfacet40.hostName AS Host, + softwarefacet20.group AS Group, + softwarefacet20.name AS Name, + softwarefacet20.version AS Version, + statefacet20.value AS Status, + eservice00.id AS ID \ No newline at end of file diff --git a/src/test/resources/projection-queries/EService.traversal.oquery b/src/test/resources/projection-queries/EService.traversal.oquery index 7f2cb1c..aaf6f84 100644 --- a/src/test/resources/projection-queries/EService.traversal.oquery +++ b/src/test/resources/projection-queries/EService.traversal.oquery @@ -1,4 +1,4 @@ -SELECT id, +SELECT id AS ID, outE("IsIdentifiedBy").inV("SoftwareFacet").name[0] AS `Name`, outE("IsIdentifiedBy").inV("SoftwareFacet").group[0] AS `Group`, outE("IsIdentifiedBy").inV("SoftwareFacet").version[0] AS `Version`,