package org.n3r.eql.parser;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
import org.n3r.eql.EqlPage;
import org.n3r.eql.cache.EqlCacheKey;
import org.n3r.eql.cache.EqlCacheProvider;
import org.n3r.eql.cache.EqlCacheSettings;
import org.n3r.eql.codedesc.CodeDesc;
import org.n3r.eql.codedesc.CodeDescs;
import org.n3r.eql.config.EqlConfigDecorator;
import org.n3r.eql.impl.EqlUniqueSqlId;
import org.n3r.eql.map.EqlRun;
import org.n3r.eql.map.EqlType;
import org.n3r.eql.param.EqlParamsParser;
import org.n3r.eql.util.C;
import org.n3r.eql.util.EqlUtils;
import org.n3r.eql.util.O;
import org.n3r.eql.util.S;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class EqlBlock {
@Getter Map<String, String> options = Maps.newHashMap();
@Getter Class<?> returnType;
@Getter String split;
@Getter @Setter List<Sql> sqls = Lists.<Sql>newArrayList();
@Getter @Setter Collection<String> sqlLines;
@Getter EqlUniqueSqlId uniqueSqlId;
private EqlCacheProvider cacheProvider;
@Getter @Setter String returnTypeName;
@Getter boolean iterateOption;
@Getter List<CodeDesc> codeDescs;
@Getter @Setter boolean override;
@Getter boolean onErrResume;
public EqlBlock(String sqlClassPath, String sqlId, String options, int startLineNo) {
this.uniqueSqlId = new EqlUniqueSqlId(sqlClassPath, sqlId);
this.options = BlockOptionsParser.parseOptions(options);
initSomeOptions();
}
public EqlBlock(String options) {
this.uniqueSqlId = new EqlUniqueSqlId("<DirectSql>", "auto");
this.options = BlockOptionsParser.parseOptions(options);
initSomeOptions();
}
private void initSomeOptions() {
String onerr = options.get("onerr");
onErrResume = "resume".equalsIgnoreCase(onerr);
returnTypeName = options.get("returnType");
iterateOption = options.containsKey("iterate");
codeDescs = CodeDescs.parseOption(this, options.get("desc"));
returnType = C.tryLoadClass(returnTypeName);
override = options.containsKey("override");
split = options.get("split");
if (Strings.isNullOrEmpty(split)) split = ";";
initEqlCache(options.containsKey("cache"), options.get("cacheModel"));
}
private void initEqlCache(boolean useCache, String cacheModel) {
if (Strings.isNullOrEmpty(cacheModel) && !useCache) return;
cacheProvider = EqlCacheSettings.getCacheProvider(uniqueSqlId, cacheModel);
}
public List<EqlRun> createEqlRuns(
String tagSqlId, EqlConfigDecorator eqlConfig,
Map<String, Object> executionContext,
Object[] params, Object[] dynamics, String[] directSqls) {
return directSqls.length == 0
? createEqlRunsByEqls(tagSqlId, eqlConfig,
executionContext, params, dynamics)
: createEqlRunsByDirectSqls(tagSqlId, eqlConfig,
executionContext, params, dynamics, directSqls);
}
public List<EqlRun> createEqlRunsByEqls(
String tagSqlId,
EqlConfigDecorator eqlConfig,
Map<String, Object> executionContext,
Object[] params, Object[] dynamics) {
Object paramBean = O.createSingleBean(params);
List<EqlRun> eqlRuns = Lists.<EqlRun>newArrayList();
EqlRun lastSelectSql = null;
for (Sql sql : sqls) {
EqlRun eqlRun = newEqlRun(tagSqlId, eqlConfig,
executionContext, params, dynamics, paramBean);
String sqlStr = sql.evalSql(eqlRun);
sqlStr = EqlUtils.trimLastUnusedPart(sqlStr);
if (S.isBlank(sqlStr)) continue;
eqlRuns.add(eqlRun);
addEqlRun(eqlConfig, eqlRun, sqlStr);
if (eqlRun.getSqlType() == EqlType.SELECT) lastSelectSql = eqlRun;
}
if (lastSelectSql != null) lastSelectSql.setLastSelectSql(true);
return eqlRuns;
}
public List<EqlRun> createEqlRunsByDirectSqls(
String tagSqlId, EqlConfigDecorator eqlConfig,
Map<String, Object> executionContext,
Object[] params, Object[] dynamics, String[] sqls) {
parseDirectSqlBlock(eqlConfig, sqls);
return createEqlRunsByEqls(tagSqlId, eqlConfig, executionContext, params, dynamics);
}
private void parseDirectSqlBlock(EqlConfigDecorator eqlConfig, String[] sqls) {
val langDriver = eqlConfig.getSqlResourceLoader().getDynamicLanguageDriver();
val blockParser = new EqlBlockParser(langDriver, false);
List<String> sqlLines = Lists.<String>newArrayList();
char sqlSplit = split.charAt(0);
Splitter sqlSplitter = Splitter.on(sqlSplit).trimResults().omitEmptyStrings();
Splitter lineSplitter = Splitter.onPattern("[\n\n]").omitEmptyStrings();
for (String sqlStr : sqls) {
for (String sql : sqlSplitter.split(sqlStr)) {
for (String line : lineSplitter.split(sql)) {
sqlLines.add(line);
}
sqlLines.add(";");
}
}
blockParser.parse(this, sqlLines);
}
private void addEqlRun(EqlConfigDecorator eqlConfig, EqlRun eqlRun, String sqlStr) {
EqlParamsParser.parseParams(eqlRun, sqlStr);
new DynamicReplacer().replaceDynamics(eqlConfig, eqlRun);
}
private EqlRun newEqlRun(
String tagSqlId, EqlConfigDecorator eqlConfig,
Map<String, Object> executionContext, Object[] params,
Object[] dynamics, Object paramBean) {
EqlRun eqlRun = new EqlRun();
eqlRun.setEqlConfig(eqlConfig);
eqlRun.setTagSqlId(tagSqlId);
eqlRun.setExecutionContext(executionContext);
eqlRun.setParams(params);
eqlRun.setDynamics(dynamics);
eqlRun.setParamBean(paramBean);
eqlRun.setEqlBlock(this);
return eqlRun;
}
public void tryParseSqls() {
for (Sql sql : sqls) {
if (sql instanceof DelaySql) {
((DelaySql) sql).parseSql();
}
}
}
public String getUniqueSqlIdStr() {
return uniqueSqlId.getSqlClassPath() + ":" + uniqueSqlId.getSqlId();
}
public String getSqlId() {
return uniqueSqlId.getSqlId();
}
public Optional<Object> getCachedResult(
Object[] params, Object[] dynamics, EqlPage page) {
if (cacheProvider == null) return null;
EqlCacheKey cacheKey = new EqlCacheKey(uniqueSqlId, params, dynamics, page);
val cache = cacheProvider.getCache(cacheKey);
if (cache != null && page != null) {
val totalRowSqlId = uniqueSqlId.newTotalRowSqlId();
cacheKey = new EqlCacheKey(totalRowSqlId, params, dynamics, page);
val totalNumber = cacheProvider.getCache(cacheKey);
if (totalNumber.isPresent())
page.setTotalRows((Integer) totalNumber.get());
}
return cache;
}
public void cacheResult(EqlRun currRun, EqlPage page) {
if (cacheProvider == null) return;
if (!currRun.isLastSelectSql()) return;
EqlCacheKey cacheKey = new EqlCacheKey(uniqueSqlId,
currRun.getParams(), currRun.getDynamics(), page);
cacheProvider.setCache(cacheKey, currRun.getResult());
if (page != null) {
val totalRowSqlId = uniqueSqlId.newTotalRowSqlId();
cacheKey = new EqlCacheKey(totalRowSqlId,
currRun.getParams(), currRun.getDynamics(), page);
cacheProvider.setCache(cacheKey, page.getTotalRows());
}
}
}