Implementing projection match query

This commit is contained in:
luca.frosini 2023-11-23 17:10:17 +01:00
parent 9450134790
commit 5fe0e5771b
8 changed files with 359 additions and 142 deletions

View File

@ -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<JsonQueryERElement> 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<String> 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");

View File

@ -94,8 +94,77 @@ public class JsonQueryFacet extends JsonQueryEntity {
@Override
protected StringBuffer getSpecificMatchQuery(List<JsonQueryERElement> 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;
}
}

View File

@ -120,15 +120,7 @@ public class JsonQueryResource extends JsonQueryEntity {
@Override
protected StringBuffer getSpecificMatchQuery(List<JsonQueryERElement> 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<consistsOfArray.size(); i++) {
JsonNode consistsOfJsonNode = consistsOfArray.get(i);
JsonQueryConsistsOf jsonQueryConsistsOf = new JsonQueryConsistsOf(consistsOfJsonNode);
jsonQueryConsistsOf.setRequestedResourceType(type);
jsonQueryConsistsOf.setDirection(Direction.IN);
jsonQueryConsistsOf.setCaller(this);
jsonQueryConsistsOf.setDirection(Direction.OUT);
jsonQueryConsistsOf.setBreadcrumb(childrenBreadcrumb);
jsonQueryConsistsOf.setPosition(isRelatedToSize+i);
boolean traverseBack = false;
if(i<(consistsOfSize-1)) {
traverseBack = true;
}
boolean traverseBack = true;
jsonQueryConsistsOf.setTraverseBack(traverseBack);
buffer = jsonQueryConsistsOf.createMatchQuery(buffer);
newBuffer = jsonQueryConsistsOf.createMatchQuery(newBuffer);
if(traverseBack) {
buffer.append("\n\t.");
buffer.append(jsonQueryConsistsOf.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(jsonQueryConsistsOf.getDirection().name().toLowerCase());
newBuffer.append("V('");
newBuffer.append(type);
newBuffer.append("')");
newBuffer.append(" { where: ($matched.");
newBuffer.append(getAlias(true));
newBuffer.append(" == $currentMatch)}");
if(i<(consistsOfSize-1)) {
newBuffer.append("\n");
}
}
}
}
StringBuffer buffer = new StringBuffer();
if(!entryPoint) {
buffer.append("\n\t");
buffer.append(".");
buffer.append(direction.name().toLowerCase());
buffer.append("V('");
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(entryPoint) {
buffer.append("\n");
}
return buffer;
}

View File

@ -141,14 +141,16 @@ public class JsonQueryConsistsOf extends JsonQueryRelation {
@Override
protected StringBuffer getSpecificMatchQuery(List<JsonQueryERElement> 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;
}

View File

@ -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<JsonQueryERElement> childrenBreadcrumb) {
protected StringBuffer getSpecificMatchQuery(List<JsonQueryERElement> 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;
}

View File

@ -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"
}
}
]
}
}
]
}
]
}
]
}

View File

@ -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
networkingfacet40.hostName AS Host,
softwarefacet20.group AS Group,
softwarefacet20.name AS Name,
softwarefacet20.version AS Version,
statefacet20.value AS Status,
eservice00.id AS ID

View File

@ -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`,