/**
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jfinal.plugin.activerecord.sql;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.template.Engine;
import com.jfinal.template.IStringSource;
import com.jfinal.template.Template;
/**
* SqlKit
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class SqlKit {
static final String SQL_TEMPLATE_MAP_KEY = "_SQL_TEMPLATE_MAP_";
static final String SQL_PARA_KEY = "_SQL_PARA_";
static final String PARA_ARRAY_KEY = "_PARA_ARRAY_";
private String configName;
private boolean devMode;
private Engine engine;
private List<SqlSource> sqlSourceList = new ArrayList<SqlSource>();
private Map<String, Template> sqlTemplateMap;
public SqlKit(String configName, boolean devMode) {
this.configName = configName;
this.devMode = devMode;
engine = new Engine(configName);
engine.setDevMode(devMode);
engine.addDirective("namespace", new NameSpaceDirective());
engine.addDirective("sql", new SqlDirective());
engine.addDirective("para", new ParaDirective());
engine.addDirective("p", new ParaDirective()); // 配置 #para 指令的别名指令 #p,不建议使用,在此仅为兼容 3.0 版本
}
public SqlKit(String configName) {
this(configName, false);
}
public Engine getEngine() {
return engine;
}
public void setDevMode(boolean devMode) {
this.devMode = devMode;
engine.setDevMode(devMode);
}
public void setBaseSqlTemplatePath(String baseSqlTemplatePath) {
engine.setBaseTemplatePath(baseSqlTemplatePath);
}
public void addSqlTemplate(String sqlTemplate) {
if (StrKit.isBlank(sqlTemplate)) {
throw new IllegalArgumentException("sqlTemplate can not be blank");
}
sqlSourceList.add(new SqlSource(sqlTemplate));
}
public void addSqlTemplate(IStringSource sqlTemplate) {
if (sqlTemplate == null) {
throw new IllegalArgumentException("sqlTemplate can not be null");
}
sqlSourceList.add(new SqlSource(sqlTemplate));
}
public synchronized void parseSqlTemplate() {
Map<String, Template> sqlTemplateMap = new HashMap<String, Template>();
for (SqlSource ss : sqlSourceList) {
Template template = ss.isFile() ? engine.getTemplate(ss.file) : engine.getTemplate(ss.stringSource);
Map<Object, Object> data = new HashMap<Object, Object>();
data.put(SQL_TEMPLATE_MAP_KEY, sqlTemplateMap);
template.renderToString(data);
}
this.sqlTemplateMap = sqlTemplateMap;
}
private void reloadModifiedSqlTemplate() {
engine.removeAllTemplateCache(); // 去除 Engine 中的缓存,以免 get 出来后重新判断 isModified
parseSqlTemplate();
}
private boolean isSqlTemplateModified() {
for (Template template : sqlTemplateMap.values()) {
if (template.isModified()) {
return true;
}
}
return false;
}
private Template getSqlTemplate(String key) {
Template template = sqlTemplateMap.get(key);
if (template == null) { // 此 if 分支,处理起初没有定义,但后续不断追加 sql 的情况
if ( !devMode ) {
return null;
}
if (isSqlTemplateModified()) {
synchronized (this) {
if (isSqlTemplateModified()) {
reloadModifiedSqlTemplate();
template = sqlTemplateMap.get(key);
}
}
}
return template;
}
if (devMode && template.isModified()) {
synchronized (this) {
template = sqlTemplateMap.get(key);
if (template.isModified()) {
reloadModifiedSqlTemplate();
template = sqlTemplateMap.get(key);
}
}
}
return template;
}
public String getSql(String key) {
Template template = getSqlTemplate(key);
return template != null ? template.renderToString(null) : null;
}
/**
* 示例:
* 1:sql 定义
* #sql("key")
* select * from xxx where id = #para(id) and age > #para(age)
* #end
*
* 2:java 代码
* Kv cond = Kv.create("id", 123).set("age", 18);
* getSqlPara("key", cond);
*/
public SqlPara getSqlPara(String key, Map data) {
Template template = getSqlTemplate(key);
if (template == null) {
return null;
}
SqlPara sqlPara = new SqlPara();
data.put(SQL_PARA_KEY, sqlPara);
sqlPara.setSql(template.renderToString(data));
data.remove(SQL_PARA_KEY); // 避免污染传入的 Map
return sqlPara;
}
/**
* 示例:
* 1:sql 定义
* #sql("key")
* select * from xxx where a = #para(0) and b = #para(1)
* #end
*
* 2:java 代码
* getSqlPara("key", 123, 456);
*/
public SqlPara getSqlPara(String key, Object... paras) {
Template template = getSqlTemplate(key);
if (template == null) {
return null;
}
SqlPara sqlPara = new SqlPara();
Map data = new HashMap();
data.put(SQL_PARA_KEY, sqlPara);
data.put(PARA_ARRAY_KEY, paras);
sqlPara.setSql(template.renderToString(data));
return sqlPara;
}
public String toString() {
return "SqlKit for config : " + configName;
}
}