/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.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 jef.database.query; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import jef.common.PairSO; import jef.common.log.LogUtil; import jef.database.DbUtils; import jef.database.Field; import jef.database.QueryAlias; import jef.database.dialect.DatabaseDialect; import jef.database.jsqlparser.JPQLSelectConvert; import jef.database.jsqlparser.SqlFunctionlocalization; import jef.database.jsqlparser.UndoableVisitor; import jef.database.jsqlparser.expression.Column; import jef.database.jsqlparser.expression.JpqlParameter; import jef.database.jsqlparser.parser.ParseException; import jef.database.jsqlparser.visitor.Expression; import jef.database.jsqlparser.visitor.ExpressionType; import jef.database.jsqlparser.visitor.ExpressionVisitor; import jef.database.jsqlparser.visitor.VisitorAdapter; import jef.database.meta.ITableMetadata; import jef.database.meta.MetaHolder; import jef.database.wrapper.variable.ConstantVariable; import jef.database.wrapper.variable.Variable; import com.google.common.base.Objects; public class JpqlExpression implements Expression, LazyQueryBindField { protected Query<?> instance; protected boolean bindBase; protected Expression st; // 当基于某个对象进行带函数的查询时,使用此方法构造 // 但是目前JEF上不支持SQL词法分析 public JpqlExpression(String str, Query<?> clz) { try { this.st = DbUtils.parseExpression(str); } catch (ParseException e) { LogUtil.exception(e); throw new RuntimeException(e.getMessage()); } this.instance = clz; } public JpqlExpression(Expression exp, Query<?> q) { this.st = exp; this.instance = q; } public JpqlExpression(String str) { this(str, (Query<?>) null); } /* * 1 #toSqlAndBindAttribs 不支持使用绑定变量,采用新的函数,逐渐代替旧的函数 2 * 最终替代旧的#toSqlAndBindAttrib方法 */ public PairSO<List<Variable>> toSqlAndBindAttribs2(final SqlContext context, final DatabaseDialect profile) { // 本地化 st.accept(new SqlFunctionlocalization(profile, null)); // 属性提供 final List<Variable> binder =new ArrayList<Variable>(); if (context != null) { @SuppressWarnings("unchecked") final Map<String, Object> attribs = context.attribute == null ? Collections.EMPTY_MAP : context.attribute; st.accept(new VisitorAdapter() { @Override public void visit(JpqlParameter parameter) { if (parameter.getName() == null) return; Object obj = attribs.get(parameter.getName()); if (obj == null) { if (!attribs.containsKey(parameter.getName())) { throw new IllegalArgumentException("You have not set the value of param '" + parameter.getName() + "'"); } else { parameter.setResolved("null"); } } else { parameter.setResolved(1); binder.add(new ConstantVariable(obj)); //原地解析(没有使用绑定变量) // if (obj instanceof Number) { // parameter.setResolved(String.valueOf(obj)); // } else { // parameter.setResolved("'" + String.valueOf(obj) + "'"); // } } } }); } // 字段转换 String result; if (instance == null) { st.accept(new JPQLSelectConvert(profile)); result = st.toString(); } else { String alias; if (context == null) { // TODO 从目前来看 context==null的情况应该几乎没有了 alias = null; } else if (bindBase && context.queries.get(0).getQuery().getMeta() == instance.getMeta()) { alias = context.queries.get(0).getAlias(); } else { alias = context.getAliasOf(instance); } ColumnAliasApplier convert = new ColumnAliasApplier(alias, profile); st.accept(convert); result = st.toString(); convert.undo(); } return new PairSO<List<Variable>>(result, binder); } /** * * @param context * @param profile * @deprecated 后续要重构为使用toSqlAndBindAttribs2方法 * @return */ public String toSqlAndBindAttribs(final SqlContext context, final DatabaseDialect profile) { // 本地化 st.accept(new SqlFunctionlocalization(profile, null)); // 属性提供 if (context != null) { @SuppressWarnings("unchecked") final Map<String, Object> attribs = context.attribute == null ? Collections.EMPTY_MAP : context.attribute; st.accept(new VisitorAdapter() { @Override public void visit(JpqlParameter parameter) { if (parameter.getName() == null) return; Object obj = attribs.get(parameter.getName()); if (obj == null) { if (!attribs.containsKey(parameter.getName())) { throw new IllegalArgumentException("You have not set the value of param '" + parameter.getName() + "'"); } else { parameter.setResolved("null"); } } else { if (obj instanceof Number) { parameter.setResolved(String.valueOf(obj)); } else { parameter.setResolved("'" + String.valueOf(obj) + "'"); } } } }); } // 字段转换 String result; if (instance == null) { st.accept(new JPQLSelectConvert(profile)); result = st.toString(); } else { String alias; if (context == null) { // TODO 从目前来看 context==null的情况应该几乎没有了 alias = null; } else if (bindBase && context.queries.get(0).getQuery().getMeta() == instance.getMeta()) { alias = context.queries.get(0).getAlias(); } else { alias = context.getAliasOf(instance); } ColumnAliasApplier convert = new ColumnAliasApplier(alias, profile); st.accept(convert); result = st.toString(); convert.undo(); } return result; } /** * 用于对简单对象中的列前引用的表别名进行替换的程序 * * @author Administrator * */ private class ColumnAliasApplier extends UndoableVisitor<Column, String[]> { private String alias; private DatabaseDialect profile; public ColumnAliasApplier(String alias, DatabaseDialect profile) { this.alias = alias; this.profile = profile; } @Override public void visit(Column tableColumn) { if (instance == null) { return; } ITableMetadata meta = MetaHolder.getMeta(instance.getInstance()); Field f = meta.getField(tableColumn.getColumnName()); String oldAlias = tableColumn.getTableAlias(); if (f != null) { savePoint(tableColumn, new String[] { oldAlias, tableColumn.getColumnName() }); tableColumn.setTableAlias(alias); tableColumn.setColumnName(meta.getColumnName(f, profile, true)); } else { // FIXME 现在设计没找到列是不替换名称的 } } @Override protected void undo(Column key, String[] value) { key.setTableAlias(value[0]); key.setColumnName(value[1]); } } public boolean isBind() { return instance != null; } public ITableMetadata getMeta() { if (instance == null) return null; return MetaHolder.getMeta(instance.getInstance()); } public String toString() { return st.toString(); } public void appendTo(StringBuilder sb) { st.appendTo(sb); } public Query<?> getInstanceQuery(AbstractEntityMappingProvider context) { if (instance != null) { return instance; } if (context != null && context.getReference().size() == 1) { this.instance = ((QueryAlias) context.queries.get(0)).getQuery(); } return instance; } public void accept(ExpressionVisitor expressionVisitor) { throw new UnsupportedOperationException(); } @Override public int hashCode() { return st.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null || !JpqlExpression.class.isAssignableFrom(obj.getClass())) return false; JpqlExpression o = (JpqlExpression) obj; if (!Objects.equal(this.instance, o.instance)) return false; if (!Objects.equal(this.st, o.st)) return false; return true; } public JpqlExpression bind(Query<?> query) { this.instance = query; return this; } public void setBind(Query<?> query) { this.instance = query; } public ExpressionType getType() { return ExpressionType.complex; } public boolean isBindBase() { return bindBase; } public void setBindBase(boolean bindBase) { this.bindBase = bindBase; } }