com.sap.cds.impl.qat.QatNode Maven / Gradle / Ivy
/*******************************************************************
* © 2019 SAP SE or an SAP affiliate company. All rights reserved. *
*******************************************************************/
package com.sap.cds.impl.qat;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import com.sap.cds.ql.cqn.CqnPredicate;
public abstract class QatNode {
private final QatNode parent;
private final Map children = new LinkedHashMap<>();
public QatNode(QatNode parent) {
this.parent = parent;
}
public abstract String name();
public abstract boolean inSource();
public abstract void accept(QatVisitor visitor);
public QatNode parent() {
return parent;
}
public Collection children() {
return Collections.unmodifiableCollection(children.values());
}
public boolean hasChildren() {
return !children().isEmpty();
}
public QatNode child(String name, Optional filter) {
return children.get(new Key(name, filter));
}
@SuppressWarnings("unchecked")
public T addChild(T child, Optional filter) {
Key key = new Key(child.name(), filter);
children.putIfAbsent(key, child);
QatNode node = children.get(key);
propagateInSource(child, node);
try {
return (T) node;
} catch (ClassCastException ex) {
throw new IllegalStateException("Query association tree contains element " + child.name()
+ " with unexpected type " + node.getClass().getName(), ex);
}
}
private static void propagateInSource(QatNode newNode, QatNode existingNode) {
if (newNode != existingNode &&
newNode instanceof QatEntityNode newEntityNode &&
existingNode instanceof QatEntityNode existingEntityNode &&
newEntityNode.inSource() == true &&
existingEntityNode.inSource() == false) {
existingEntityNode.setInSource();
}
}
public T addChild(T child) {
return addChild(child, Optional.empty());
}
public static class Key {
final String name;
final String filterAsJson;
final int hashCode;
public Key(String name, Optional filter) {
this.name = name;
this.filterAsJson = filter.map(CqnPredicate::toJson).orElse("[]");
this.hashCode = calculateHash(name, filterAsJson);
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null) {
return false;
}
if (obj.getClass() != this.getClass())
return false;
Key other = (Key) obj;
if (hashCode != other.hashCode) {
return false;
}
if (!name.equals(other.name))
return false;
return filterAsJson.equals(other.filterAsJson);
}
private static int calculateHash(String name, String filterAsJson) {
final int prime = 31;
int result = 1;
result = prime * result + filterAsJson.hashCode();
result = prime * result + name.hashCode();
return result;
}
}
@Override
public String toString() {
return name();
}
}