com.avaje.ebeaninternal.server.expression.PrepareDocNested Maven / Gradle / Ivy
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.Junction;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Prepare nested path expressions for
*/
class PrepareDocNested {
/**
* Prepare the top level expressions for nested path handling.
*/
static void prepare(DefaultExpressionList> expressions, BeanDescriptor> beanDescriptor) {
new PrepareDocNested(expressions, beanDescriptor, null).process();
}
/**
* Prepare the Junction expressions for nested path handling.
*/
static void prepare(DefaultExpressionList> expressions, BeanDescriptor> beanDescriptor, Junction.Type type) {
new PrepareDocNested(expressions, beanDescriptor, type).process();
}
enum Mode {
NONE,
SINGLE,
MIXED
}
private final Junction.Type type;
private final DefaultExpressionList> original;
private final BeanDescriptor> beanDescriptor;
private final List origUnderlying;
private final int origSize;
private boolean hasNesting;
private boolean hasMixedNesting;
private String firstNestedPath;
PrepareDocNested(DefaultExpressionList> original, BeanDescriptor> beanDescriptor, Junction.Type type) {
this.type = type;
this.beanDescriptor = beanDescriptor;
this.original = original;
this.origUnderlying = original.getUnderlyingList();
this.origSize = origUnderlying.size();
}
void process() {
PrepareDocNested.Mode mode = determineMode();
if (mode == PrepareDocNested.Mode.SINGLE) {
original.setAllDocNested(firstNestedPath);
} else if (mode == PrepareDocNested.Mode.MIXED) {
original.setUnderlying(group());
}
}
/**
* Reorganise the flat list of expressions into a tree grouping expressions by nested path.
*
* Returns the new top level list of expressions.
*/
private List group() {
Map groups = new LinkedHashMap();
// organise expressions by nestedPath
for (int i = 0; i < origSize; i++) {
SpiExpression expr = origUnderlying.get(i);
String nestedPath = expr.nestedPath(beanDescriptor);
Group group = groups.get(nestedPath);
if (group == null) {
group = new Group(nestedPath);
groups.put(nestedPath, group);
}
group.list.add(expr);
}
List newList = new ArrayList();
Collection values = groups.values();
for (Group group : values) {
group.addTo(newList);
}
return newList;
}
/**
* Determined the nested path mode.
*/
private Mode determineMode() {
if (!hasNesting()) {
// no nested paths at all
return Mode.NONE;
}
if (!hasMixedNesting) {
// single nested path for all expressions
return Mode.SINGLE;
}
// mixed nested paths to underlying expression list needs re-organising by nested path
return Mode.MIXED;
}
/**
* Return true if the expressions have nested paths.
*/
private boolean hasNesting() {
for (int i = 0; i < origSize; i++) {
SpiExpression expr = origUnderlying.get(i);
String nestedPath = expr.nestedPath(beanDescriptor);
if (nestedPath == null) {
hasMixedNesting = true;
} if (nestedPath != null) {
hasNesting = true;
if (firstNestedPath == null) {
firstNestedPath = nestedPath;
} else if (hasMixedNesting || !firstNestedPath.equals(nestedPath)) {
hasMixedNesting = true;
return true;
}
}
}
return hasNesting;
}
/**
* List of SpiExpression grouped by nested path.
*/
class Group {
final String nestedPath;
final List list = new ArrayList();
Group(String nestedPath) {
this.nestedPath = nestedPath;
}
void addTo(List newList) {
if (nestedPath == null) {
newList.addAll(list);
} else {
newList.add(original.wrap(list, nestedPath, type));
}
}
}
}