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 b4b3a7f..5176bd3 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 @@ -22,6 +22,7 @@ import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaE import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaNotFoundException; import org.gcube.informationsystem.resourceregistry.queries.operators.ConditionalOperator; import org.gcube.informationsystem.resourceregistry.queries.operators.LogicalOperator; +import org.gcube.informationsystem.resourceregistry.queries.operators.MatemathicsOperator; import org.gcube.informationsystem.resourceregistry.queries.operators.ProjectionOperator; import org.gcube.informationsystem.resourceregistry.types.TypesCache; import org.gcube.informationsystem.utils.TypeUtility; @@ -187,10 +188,10 @@ public abstract class JsonQueryERElement { protected StringBuffer generateAlias() { StringBuffer sb = new StringBuffer(); sb.append(type.toLowerCase()); - - // The entry point will have 00 as suffix - sb.append(breadcrumb.size()); - sb.append(position); + for(JsonQueryERElement elem : breadcrumb) { + sb.append(elem.getPosition()); + } + sb.append(this.position); return sb; } @@ -243,13 +244,11 @@ public abstract class JsonQueryERElement { JsonNode node = objectNode.get(fieldName); StringBuffer evBuffer = evaluateNode(node, fieldName, fieldNamePrefix); - if(!first) { - stringBuffer.append(queryLogicalOperator.getLogicalOperator()); - } - if(evBuffer!=null && evBuffer.length()>0) { if(first) { first = false; + }else { + stringBuffer.append(queryLogicalOperator.getLogicalOperator()); } stringBuffer.append(evBuffer); } @@ -293,13 +292,23 @@ public abstract class JsonQueryERElement { b.append(getAlias(true)); b.append("."); b.append(fieldNameToEmit); - b.append(" AS "); + b.append(" AS `"); b.append(nameOfFieldToEmit); + b.append("`"); addFieldToEmit(b.toString()); } return null; } + if(MatemathicsOperator.getOperators().contains(fieldName)) { + --size; + setProjection(true); + MatemathicsOperator mo = MatemathicsOperator.getMatemathicsOperator(fieldName); + String fieldToEmit = mo.generateFieldToEmit(jsonNode, getAlias(true)); + addFieldToEmit(fieldToEmit); + return null; + } + StringBuffer stringBuffer = new StringBuffer(); @@ -347,6 +356,11 @@ public abstract class JsonQueryERElement { stringBuffer.append(addCondition(ConditionalOperator.EQ, key, value)); } + if(jsonNode.isNull()) { + StringBuffer key = getKey(fieldName, null); + stringBuffer.append(addCondition(ConditionalOperator.IS, key, null)); + } + return stringBuffer; } diff --git a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/operators/MatemathicsOperator.java b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/operators/MatemathicsOperator.java index 2dc2ab5..fc38e30 100644 --- a/src/main/java/org/gcube/informationsystem/resourceregistry/queries/operators/MatemathicsOperator.java +++ b/src/main/java/org/gcube/informationsystem/resourceregistry/queries/operators/MatemathicsOperator.java @@ -5,6 +5,15 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.ws.rs.BadRequestException; + +import org.gcube.com.fasterxml.jackson.databind.JsonNode; +import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode; +import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode; +import org.gcube.com.fasterxml.jackson.databind.node.TextNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * @author Luca Frosini (ISTI - CNR) * @@ -32,46 +41,137 @@ public enum MatemathicsOperator { BITWISE_XOR("_bitxor", " ^ ", ""), ARRAY_CONCATENATION("_arrayconcat", " || ", ""); - protected final String operator; - protected final String matemathicsOperator; + protected static Logger logger = LoggerFactory.getLogger(MatemathicsOperator.class); + + public static final String VALUES_KEY = "values"; + public static final String SEPARATOR_KEY = "separator"; + public static final String AS_KEY = "as"; + + protected final String operatorKey; + protected final String dbQueryOperator; protected final String description; - private MatemathicsOperator(String operator, String matemathicsOperator, String description) { - this.operator = operator; - this.matemathicsOperator = matemathicsOperator; + private MatemathicsOperator(String operatorKey, String dbQueryOperator, String description) { + this.operatorKey = operatorKey; + this.dbQueryOperator = dbQueryOperator; this.description = description; } - public String getOperator() { - return operator; + public String getOperatorKey() { + return operatorKey; } - public String getMatemathicsOperator() { - return matemathicsOperator; + public String getDbQueryOperator() { + return dbQueryOperator; } public String getDescription() { return description; } - private static Set operators; private static Map operatorByKey; static { - MatemathicsOperator.operators = new HashSet<>(); MatemathicsOperator.operatorByKey = new HashMap<>(); - for(MatemathicsOperator queryLogicalOperator : MatemathicsOperator.values()) { - MatemathicsOperator.operators.add(queryLogicalOperator.getOperator()); - MatemathicsOperator.operatorByKey.put(queryLogicalOperator.getOperator(), queryLogicalOperator); + for(MatemathicsOperator matemathicsOperator : MatemathicsOperator.values()) { + MatemathicsOperator.operatorByKey.put(matemathicsOperator.getOperatorKey(), matemathicsOperator); } } public static Set getOperators() { - return MatemathicsOperator.operators; + return new HashSet<>(MatemathicsOperator.operatorByKey.keySet()); } - public static MatemathicsOperator getQueryLogicalOperator(String key) { + public static MatemathicsOperator getMatemathicsOperator(String key) { return operatorByKey.get(key); } + + protected String getError(String key, Class clazz, boolean mandatory) { + StringBuffer error = new StringBuffer(); + error.append("Root emitting MatemathicsOperator (i.e. "); + error.append(this.operatorKey); + error.append(")"); + error.append(" contains "); + if(mandatory) { + error.append("mandatory "); + } + error.append(key); + error.append(" which must be a"); + error.append(clazz.getSimpleName()); + error.append(". This is a client error. Please fix your query"); + logger.error(error.toString()); + throw new BadRequestException(error.toString()); + } + + public String generateFieldToEmit(JsonNode jsonNode, String fieldPrefix) { + JsonNode jn = jsonNode.get(VALUES_KEY); + if(jn.isNull() || !jn.isArray()) { + getError(VALUES_KEY, ArrayNode.class, true); + } + String fieldSeparator = null; + if(this == MatemathicsOperator.SUM && jsonNode.has(SEPARATOR_KEY)) { + JsonNode sep = jsonNode.get(SEPARATOR_KEY); + if(!sep.isTextual()) { + getError(SEPARATOR_KEY, TextNode.class, false); + } + fieldSeparator = sep.asText(); + } + StringBuffer sb = new StringBuffer(); + sb.append("("); + sb.append(generateFieldToEmit((ArrayNode) jn, fieldSeparator, fieldPrefix)); + JsonNode jnAs = jsonNode.get(AS_KEY); + if(jnAs.isNull() || !jnAs.isTextual()) { + getError(AS_KEY, TextNode.class, true); + } + sb.append(") AS `"); + sb.append(jnAs.asText()); + sb.append("`"); + return sb.toString(); + } + + protected StringBuffer addFieldPrefix(StringBuffer sb, String fieldPrefix) { + if(fieldPrefix !=null && fieldPrefix.trim().length()>0) { + sb.append(fieldPrefix.trim()); + sb.append("."); + } + return sb; + } + + protected StringBuffer generateFieldToEmit(ArrayNode arrayNode, String fieldsSeparator, String fieldPrefix) { + StringBuffer buffer = new StringBuffer(); + int size = arrayNode.size(); + for(int i=0; i