All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.onetwo.common.db.filequery.postfunc.SqlParamterPostfixFunctions Maven / Gradle / Ivy

package org.onetwo.common.db.filequery.postfunc;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.onetwo.common.convert.Types;
import org.onetwo.common.db.spi.SqlParamterPostfixFunctionRegistry;
import org.onetwo.common.db.sqlext.ExtQueryUtils;
import org.onetwo.common.reflect.ReflectUtils;
import org.onetwo.common.spring.Springs;
import org.onetwo.common.utils.JodatimeUtils;
import org.onetwo.common.utils.LangUtils;
import org.onetwo.common.utils.StringUtils;
import org.onetwo.dbm.exception.DbmException;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/*****
 * 自定义sql语句里,命名参数的后缀函数
 * 比如 where u.userName = :userName.likeString
 * @author way
 *
 */
public class SqlParamterPostfixFunctions implements SqlParamterPostfixFunctionRegistry {

	public static final String FUNC_START = "$";
	public static final String FUNC_END = "_";
	
	public static final String SQL_POST_FIX_FUNC_MARK = "?";
	
	/*final private static SqlParamterPostfixFunctionRegistry instance = new SqlParamterPostfixFunctions();
	public static SqlParamterPostfixFunctionRegistry getInstance() {
		return instance;
	}*/
	
	public String getFuncPostfixMark(){
		return SQL_POST_FIX_FUNC_MARK;
	}

	private Map funcMap = LangUtils.newHashMap();
	private Map, Map> typeFuncMap = Maps.newLinkedHashMap();

	public SqlParamterPostfixFunctions(){
		// %value%
		register(new String[]{"like", "likeString"}, new SimpleSqlPostfixFunction(){
			@Override
			public Object toSqlParameterValue(String paramName, Object value) {
				if (value==null) {
					value = "";
				}
				return ExtQueryUtils.getLikeString(value.toString());
			}
		});

		// %value
		register(new String[]{"prelike", "preLikeString"}, new SimpleSqlPostfixFunction(){
			@Override
			public Object toSqlParameterValue(String paramName, Object value) {
				if (value==null) {
					value = "";
				}
				return StringUtils.appendStartWith(value.toString(), "%");
			}
		});

		// value%
		register(new String[]{"postlike", "postLikeString"}, new SimpleSqlPostfixFunction(){
			@Override
			public Object toSqlParameterValue(String paramName, Object value) {
				if (value==null) {
					value = "";
				}
				return StringUtils.appendEndWith(value.toString(), "%");
			}
		});

		register(new String[]{"atStartOfDate"}, new SimpleSqlPostfixFunction(){
			@Override
			public Object toSqlParameterValue(String paramName, Object value) {
				if(!Date.class.isInstance(value)){
					throw new DbmException(paramName+" is not a date, can not invoke atStartOfDate");
				}
				Date date = Types.convertValue(value, Date.class);
				return JodatimeUtils.atStartOfDate(date);
			}
		});

		register(new String[]{"atEndOfDate"}, new SimpleSqlPostfixFunction(){
			@Override
			public Object toSqlParameterValue(String paramName, Object value) {
				if(!Date.class.isInstance(value)){
					throw new DbmException(paramName+" is not a date, can not invoke atEndOfDate");
				}
				Date date = Types.convertValue(value, Date.class);
				return JodatimeUtils.atEndOfDate(date);
			}
		});

		register(new String[]{"atStartOfNextDate"}, (paramName, value)->{
			if(!Date.class.isInstance(value)){
				throw new DbmException(paramName+" is not a date, can not invoke atStartOfNextDate");
			}
			Date date = Types.convertValue(value, Date.class);
			return JodatimeUtils.atStartOfDate(date, 1);
		});

		register(new String[]{"encrypt"}, (paramName, value)->{
			if (value==null) {
				return null;
			}
			if(!String.class.isInstance(value)){
				throw new DbmException("the encrypt field[" + paramName + "] must be String type!");
			}
			StandardPBEStringEncryptor encryptor = Springs.getInstance().getBean(StandardPBEStringEncryptor.class);
			return encryptor.encrypt(value.toString());
		});
		
		bindingTypeFunc(Date.class, DateTypeFuncSet.class);

		/*register("inlist", new SqlParamterPostfixFunction(){
			@Override
			public Object toSqlString(String paramName, Object value) {
				return ParserContextFunctionSet.getInstance().inValue(paramName, value);
			}
		});*/
		
	}

	public SqlParamterPostfixFunctionRegistry register(String postfix, SqlPostfixFunction func){
		return register(postfix, func, true);
	}
	
	public SqlParamterPostfixFunctionRegistry register(String funcName, SqlPostfixFunction func, boolean registerSnakeName){
		checkFuncName(funcName);
		funcMap.put(funcName, func);
		
		String snakeName = StringUtils.convert2UnderLineName(funcName);
		if (!funcName.equals(snakeName) && registerSnakeName) {
			checkFuncName(snakeName);
			funcMap.put(snakeName, func);
		}
		return this;
	}
	
	/****
	 * 检查函数名是否已存在
	 * @param funcName
	 */
	private void checkFuncName(String funcName) {
		if (funcMap.containsKey(funcName)) {
			throw new DbmException("the sql postfix function already exists, name: " + funcName);
		}
	}
	private SqlParamterPostfixFunctionRegistry register(String[] postfixs, SimpleSqlPostfixFunction func){
		for(String postfix : postfixs){
			register(postfix, func);
		}
		return this;
	}
	
	private SqlParamterPostfixFunctionRegistry bindingTypeFunc(Class type, Class typeFuncClass){
		Map funcMap = typeFuncMap.get(type);
		if (funcMap==null) {
			funcMap = Maps.newConcurrentMap();
			typeFuncMap.put(type, funcMap);
		}
		List staticMethods = ReflectUtils.findAllStaticMethods(typeFuncClass);
		for (Method method : staticMethods) {
			String funcName = method.getName();
			
			SqlPostfixFunction func = new SqlPostfixFunction() {
				@Override
				public Object execute(SqlPostfixFunctionInfo funcInfo, String paramName, Object value) {
					try {
						if (method.getParameterCount()==1) {
							return method.invoke(null, value);
						} else {
							return method.invoke(null, value, funcInfo);
						}
					} catch (Exception e) {
						ReflectUtils.handleReflectionException(e);
					}
					return null;
				}
			};
			register(funcName, func);
		}
		return this;
	}
	
	/* (non-Javadoc)
	 * @see org.onetwo.common.spring.sql.SqlParamterPostfixFunctionRegistry#getFunc(java.lang.String)
	 */
//	@Override
//	@Deprecated
//	public SqlParamterPostfixFunction getFunc(String postfix){
//		if(!funcMap.containsKey(postfix)){
//			throw new DbmException("no postfix func fund: " + postfix);
//		}
//		return funcMap.get(postfix);
//	}
	
	@Override
//	public SqlParamterPostfixFunction getFunc(Object value, String postfix){
	public Object executeFunc(String property, Object value, String postfix){
		Object res = null;
		SqlPostfixFunctionInfo funcInfo = parseSqlPostfixFunc(postfix);
		
		String funcName = funcInfo.getFunctionName();
		SqlPostfixFunction func = funcMap.get(funcName);
		if (func!=null) {
			res = func.execute(funcInfo, property, value);
			return res;
		}
		if (value==null) {
			throw new DbmException("postfix func not fund for null, postfix:" + postfix);
		}
		for (Entry, Map> entry : typeFuncMap.entrySet()) {
			Class type = entry.getKey();
			if (type.isAssignableFrom(value.getClass())) {
				func = entry.getValue().get(funcName);
				if (func!=null) {
					break;
				}
			}
		}
		
		if(func==null){
			throw new DbmException("postfix func not fund for type: " + value.getClass() + ", postfix:" + postfix);
		} else {
			res = func.execute(funcInfo, property, value);
		}

		return res;
	}

	/***
	 * 以下划线“_”分割为字符为数组,$开头的视作参数,其余部分再用下划线“_”连接起来,作为需要调用的方法名
	 * 如:d.upload_time <= :request.uploadTime?$30_minutes_ago
	 * 将会调用minutesAgo(30) 或者 minutes_ago(30)
	 * @see https://github.com/wayshall/dbm/issues/51
	 * @see DateTypeFuncSet#minutesAgo(Date, SqlPostfixFunctionInfo)
	 * @param input
	 * @return
	 */
	public SqlPostfixFunctionInfo parseSqlPostfixFunc(String input) {
		List paramsList = Lists.newArrayList();
        List funcNames = Lists.newArrayList();
        
        String[] strs = StringUtils.split(input, FUNC_END);
        for (String str : strs) {
        	if (str.startsWith(FUNC_START)) {
        		String param = str.substring(FUNC_START.length());
        		if (StringUtils.isNotBlank(param)) {
        			paramsList.add(param);
        		}
        	} else {
        		funcNames.add(str);
        	}
        }
		
        String funcName = StringUtils.join(funcNames, FUNC_END);
		return new SqlPostfixFunctionInfo(funcName, paramsList);
	}

	static public class SqlPostfixFunctionInfo {
	    private String functionName;
	    private List argumentNames;
	    
	    public SqlPostfixFunctionInfo(String functionName, List argumentNames) {
	        this.functionName = functionName;
	        this.argumentNames = argumentNames;
	    }
	    
	    public String getFunctionName() {
	        return functionName;
	    }
	    
	    public List getArgumentNames() {
	        return argumentNames;
	    }
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy