package eu.eudat.queryable.collector; import javax.persistence.Tuple; import java.util.*; import java.util.stream.Collectors; public class ProjectionField { private String key; private List fields; private ProjectionField parent; public ProjectionField(List field, ProjectionField parent) { this.parse(field); this.parent = parent; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public List getFields() { return fields; } public void setFields(List fields) { this.fields = fields; } private void parse(List fields) { String[] fieldsArr = fields.get(0).split("\\."); this.key = fieldsArr[0]; this.fields = fields.stream() .map(x -> x.replace(x.contains(".") ? this.key + "." : this.key, "")) .filter(x -> !x.isEmpty()) .map(x -> x.split("\\.")) .collect(Collectors.groupingBy(x -> x[0])) .values() .stream() .map(field -> new ProjectionField(field.stream().map(x -> String.join(".", x)).collect(Collectors.toList()), this)) .collect(Collectors.toList()); } public Map collect(Map map, List tuples) { if (fields != null && !fields.isEmpty()) { this.collect(map, this.fields, tuples); } else { map.put(key, this.createObject(tuples, this.generatePath())); } return map; } public Map collect(Map map, List projectionGroup, List tuples) { map.put(key, this.createObject(tuples, projectionGroup)); return map; } private String generatePath() { List list = new LinkedList<>(); ProjectionField current = this; list.add(current.key); while (current.parent != null) { list.add(current.parent.key); current = current.parent; } Collections.reverse(list); return String.join(".", list); } private Object createObject(List tuples, String field) { List values = tuples.stream() .map(x -> x.get(field)) .distinct() .collect(Collectors.toList()); if (values.size() > 1) { return values.stream().map(x -> { Map map = new LinkedHashMap(); map.put(field, x); return map; }).collect(Collectors.toList()); } else if (values.size() == 1) { return values.get(0); } else return null; } private Object createObject(List tuples, List group) { Collection values = tuples.stream() .map(x -> getValuesFrom(tuples, x, group)) .collect(Collectors.toMap(x -> x.get("id"), x -> x, (x, y) -> x)).values(); return values; } private Map getValuesFrom(List tuples, Tuple tuple, List group) { Map map = new LinkedHashMap(); group.forEach(x -> { if (x.fields != null && !x.fields.isEmpty()) map.put(x.key, this.createObject(tuples, x.fields)); else map.put(x.key, tuple.get(x.generatePath())); }); return map; } }