package net.ion.craken.script;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import net.ion.craken.expression.ExpressionParser;
import net.ion.craken.expression.Projection;
import net.ion.craken.expression.SetComparable;
import net.ion.craken.expression.TerminalParser;
import net.ion.craken.expression.ValueObject;
import net.ion.craken.node.ReadNode;
import net.ion.framework.db.Rows;
import net.ion.framework.parse.gson.JsonArray;
import net.ion.framework.parse.gson.JsonElement;
import net.ion.framework.parse.gson.JsonUtil;
import net.ion.framework.util.ArrayUtil;
import net.ion.framework.util.ListUtil;
import net.ion.framework.util.MapUtil;
import net.ion.framework.util.ObjectUtil;
import net.ion.framework.util.StringUtil;
import net.ion.rosetta.Parser;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
/**
* Author: Ryunhee Han
* Date: 2014. 1. 14.
*/
public abstract class AbstractBuilder {
private Cache<String, Object> props = CacheBuilder.newBuilder().build() ;
private Parser<MyProjection> parser = ExpressionParser.projections2(MyProjection.class) ;
protected AbstractBuilder(){
}
public BasicBuilder inner(final String key) throws ExecutionException {
return (BasicBuilder) props.get(key, new Callable<BasicBuilder>() {
@Override
public BasicBuilder call() throws Exception {
BasicBuilder basic = new BasicBuilder(AbstractBuilder.this);
props.put(key, basic);
return basic;
}
});
}
public AbstractBuilder property(ReadNode node, String values) {
MyProjection sp = TerminalParser.parse(parser, values);
Map<String, Object> map = sp.map(node) ;
for(Entry<String, Object> entry : map.entrySet()){
Object value = entry.getValue();
if (value instanceof SetComparable) {
Object[] vals = ((SetComparable)value).asArray() ;
property(entry.getKey(), new JsonArray().adds(vals)) ;
} else {
property(entry.getKey(), ObjectUtil.coalesce(value, ObjectUtil.NULL)) ;
}
}
return this;
}
public Cache<String, Object> props(){
return props ;
}
public AbstractBuilder root() {
AbstractBuilder parent = this.parent();
if (parent == null) return this ;
while(!parent.isRoot()){
parent = parent.parent();
}
return parent;
}
public abstract AbstractBuilder parent() ;
public boolean isRoot() {
return parent() == null ? true : false;
}
public abstract AbstractBuilder property(String key, Object value) ;
protected abstract JsonElement makeJson() ;
public JsonElement buildJson(){
return root().makeJson() ;
}
public Rows buildRows() throws SQLException {
return JsonUtil.toRows(buildJson());
}
public Rows buildRows(String cols) throws SQLException {
String[] colNames = StringUtil.split(cols, ", ") ;
return JsonUtil.toRows(buildJson(), colNames[0], (String[])ArrayUtil.subarray(colNames, 1, colNames.length));
}
}
class MyProjection extends ValueObject {
private List<Projection> projections;
public MyProjection (List<Projection> projections) {
this.projections = projections;
}
public Map<String, Object> map(ReadNode node){
Map<String, Object> map = MapUtil.newMap() ;
for (Projection p : projections) {
map.put(p.label(), p.value(node)) ;
}
return map ;
}
public List<Map<String, Object>> mapList(Iterable<ReadNode> nodes){
List<Map<String, Object>> result = ListUtil.newList() ;
for (ReadNode node : nodes) {
result.add(map(node)) ;
}
return result ;
}
}