org.mayanjun.mybatisx.dal.parser.BaseParser Maven / Gradle / Ivy
/*
* Copyright 2016-2018 mayanjun.org
*
* 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 org.mayanjun.mybatisx.dal.parser;
import org.mayanjun.mybatisx.api.annotation.Column;
import org.mayanjun.mybatisx.api.annotation.Table;
import org.mayanjun.mybatisx.api.enums.DataType;
import org.mayanjun.mybatisx.api.query.*;
import org.mayanjun.mybatisx.dal.generator.AnnotationHelper;
import org.mayanjun.mybatisx.dal.generator.AnnotationHolder;
import org.mayanjun.mybatisx.dal.util.SqlUtils;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* BaseParser
*
* @author mayanjun(6/20/16)
* @since 0.0.5
*/
public abstract class BaseParser implements QueryParser {
public Pattern FIELD_PATTERN = Pattern.compile("#\\{([a-zA-Z_$0-9]+)\\}");
private static final ConcurrentHashMap, Map> FIELDS_CACHE = new ConcurrentHashMap, Map>();
/**
*
* @param beanType
* @return
*/
protected Collection getAllFields(Class> beanType) {
Map fs = FIELDS_CACHE.get(beanType);
if(fs != null) return fs.values();
else fs = new HashMap();
List ahs = AnnotationHelper.getAnnotationHolders(beanType);
if(ahs != null && !ahs.isEmpty()) {
fs = new HashMap();
int size = ahs.size();
for(int i = 0; i < size; i++) {
AnnotationHolder ah = ahs.get(i);
String columnName = AnnotationHelper.getColumnName(ah);
String name = AnnotationHelper.quoteField(columnName);
String as = ah.getField().getName();
String ref = ah.getColumn().referenceField();
String ognl = ah.getOgnl();
if(SqlUtils.isNotBlank(ognl)) {
as = ognl + "." + ah.getField().getName();
name = name + " AS `" + as + "`";
} else if(SqlUtils.isNotBlank(ref)) {
String refAs = as + "." + ref;
name = name + " AS `" + refAs + "`";
fs.put(refAs, name);
} else if(!columnName.equals(as)) {
name = name + " AS `" + as + "`";
}
fs.put(as, name);
}
FIELDS_CACHE.put(beanType, fs);
}
return fs.values();
}
/**
* Returns select field with specified OGNL field name
* @param field ognl-style field name
* @param query query to be parsed
* @param inWhere if false, the 'AS' clause will be generated
* @return select field with specified OGNL field name
*/
protected String getSelectField(String field, Query query, boolean inWhere) {
Class> beanType = query.getBeanType();
AnnotationHolder ah = AnnotationHelper.getAnnotationHolder(field, beanType);
if(ah == null) throw new IllegalArgumentException("no field found by name '" + field + "' in class '" + beanType);
String columnName = AnnotationHelper.getColumnName(ah);
String fieldName = ah.getField().getName();
String name = AnnotationHelper.quoteField(columnName);
if(!inWhere) {
String ref = ah.getColumn().referenceField();
if(SqlUtils.isNotBlank(ah.getOgnl())) {
name = name + " AS `" + ah.getOgnl() + "." + fieldName + "`";
} else if(SqlUtils.isNotBlank(ref)) {
name = name + " AS `" + fieldName + "." + ref + "`";
} else if(!columnName.equals(fieldName)) {
name = name + " AS `" + fieldName + "`";
}
}
return name;
}
public void parseSelectedFields(SQLParameter parameter, Query extends Serializable> query) {
Collection list = getSelectedFields(query);
String sql = SqlUtils.listToString(list, ",");
parameter.setSelectedFields(sql);
}
public void parseFrom(SQLParameter parameter, Query extends Serializable> query) {
String tableName = AnnotationHelper.getTableName(query.getBeanType());
parameter.setTableName(tableName);
}
/**
*
* @param query
* @return
*/
protected Collection getSelectedFields(Query extends Serializable> query) {
List includeList = query.getIncludeFields();
Class> beanType = query.getBeanType();
Collection allFields0 = getAllFields(beanType);
Collection allFields = new ArrayList(allFields0);
if(includeList != null && !includeList.isEmpty()) {
Map fs = FIELDS_CACHE.get(beanType);
List ins = new ArrayList();
for(String s : includeList) {
String field = fs.get(s);
if(field != null) ins.add(field);
}
allFields = ins;
}
List excludedFields = query.getExcludeFields();
if(excludedFields != null && !excludedFields.isEmpty()) {
List excludedParsedFields = new ArrayList();
for(String name : excludedFields) {
String parsedName = getSelectField(name, query, false);
excludedParsedFields.add(parsedName);
}
allFields.removeAll(excludedParsedFields);
}
return allFields;
}
public void parseWhere(SQLParameter parameter, Query query) {
StringBuilder where = new StringBuilder();
if(query != null) {
List comparators = query.getComparators();
boolean hasComparators = (comparators != null && !comparators.isEmpty());
if(hasComparators) {
where.append(" WHERE ");
for(int i = 0; i < comparators.size(); i++) {
SqlComparator c = comparators.get(i);
if(i > 0) {
if(c instanceof GroupComparator) {
if(!((GroupComparator) c).isStart()) {
where.append(c.getExpression());
continue;
}
}
if(c instanceof LogicalComparator) {
SqlComparator prev = comparators.get(i - 1);
if(!(prev instanceof GroupComparator) || !((GroupComparator) prev).isStart()) {
LogicalOperator lo = c.getLogicalOperator();
if(lo == null) lo = LogicalComparator.DEFAULT_LOGICAL_OPERATOR;
where.append(" " + lo + " ");
}
}
}
Table table = (Table) query.getBeanType().getAnnotation(Table.class);
String charset = AnnotationHelper.DEFAULT_CHARSET;
if(table != null) {
charset = table.charset();
}
String comString = renderComparator(parameter, c, query, charset);
where.append(comString);
}
}
parameter.setWhereClause(where.toString());
}
}
public void parseOrderClause(SQLParameter parameter, Query query) {
StringBuilder sb = new StringBuilder();
Set sorts = query.sorts();
if (sorts != null && !sorts.isEmpty()) {
for (Sort sort : sorts) {
if(sort != null && !SqlUtils.isBlank(sort.getName())) {
sb.append(SqlUtils.escapeSQLField(sort.getName(), false) + "");
if(sort.getDirection() != null) sb.append(" " + sort.getDirection().name());
sb.append(",");
}
}
int len = sb.length();
if (len > 0) {
if (sb.charAt(len - 1) == ',') sb.deleteCharAt(len - 1);
sb.insert(0, " ORDER BY ");
}
parameter.setOrderClause(sb.toString());
}
}
public void parseLimitClause(SQLParameter parameter, Query query) {
int limits[] = query.getLimits();
int offset = limits[0];
int limit = limits[1];
if (limit > 0) {
if(offset <= 0) parameter.setLimitClause(" LIMIT " + limit);
else parameter.setLimitClause(" LIMIT " + offset + "," + limit);
}
}
public String renderComparator(SQLParameter parameter, SqlComparator comparator, Query> query, String charset){
String expression = comparator.getExpression();
Matcher m = FIELD_PATTERN.matcher(expression);
DataType dataType = null;
StringBuffer sb = new StringBuffer();
while(m.find()) {
String field = m.group(1);
if("name".equals(field)) {
try {
PropertyDescriptor pd = new PropertyDescriptor(field, comparator.getClass());
Method mmm = pd.getReadMethod();
String value = (String) mmm.invoke(comparator);
String selectedField = getSelectField(value.toString(), query, true);
String sss = SqlUtils.escapeSQLField(selectedField, false);
m.appendReplacement(sb, sss);
AnnotationHolder ah = AnnotationHelper.getAnnotationHolder(value, query.getBeanType());
Column col = ah.getColumn();
dataType = col.type();
}catch (Exception e) {
throw new RuntimeException(e);
}
} else {
Object value = renderFieldValue(parameter, field, comparator, query, charset, dataType);
m.appendReplacement(sb, value.toString());
}
}
m.appendTail(sb);
return sb.toString();
}
/**
* Parse value for a field
* @param name java field name
* @param comparator current SqlComparator
* @param query query
* @param charset charset to be used
* @param dataType JDBC data type
* @return
*/
public Object renderFieldValue(SQLParameter parameter, String name, SqlComparator comparator, Query query, String charset, DataType dataType){
try {
PropertyDescriptor pd = new PropertyDescriptor(name, comparator.getClass());
Method mmm = pd.getReadMethod();
Object value = mmm.invoke(comparator);
if(comparator instanceof InComparator) {
Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy