/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you 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 jlibs.jdbc.annotations.processor; import jlibs.core.annotation.processing.AnnotationError; import jlibs.core.annotation.processing.Printer; import jlibs.core.lang.StringUtil; import jlibs.core.lang.model.ModelUtil; import jlibs.core.util.CollectionUtil; import jlibs.jdbc.Order; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import static jlibs.core.annotation.processing.Printer.MINUS; import static jlibs.core.annotation.processing.Printer.PLUS; /** * @author Santhosh Kumar T */ // @enhancement allow to return single/listOf column values public class WhereMethod extends DMLMethod{ protected WhereMethod(Printer printer, ExecutableElement method, AnnotationMirror mirror, Columns columns){ super(printer, method, mirror, columns); } @Override protected CharSequence[] defaultSQL(){ return defaultSQL(new ArrayList<VariableElement>(method.getParameters()).iterator()); } protected String initialQuery = null; protected CharSequence[] defaultSQL(Iterator<VariableElement> iter){ int paramCount = method.getParameters().size(); List<String> code = new ArrayList<String>(); CollectionUtil.addAll(code, "java.util.List<String> __conditions = new java.util.ArrayList<String>("+paramCount+");", "java.util.List<Object> __params = new java.util.ArrayList<Object>("+paramCount+");" ); List<String> params = new ArrayList<String>(); List<String> where = new ArrayList<String>(); while(iter.hasNext()){ VariableElement param = iter.next(); String paramName = param.getSimpleName().toString(); boolean primitive = ModelUtil.isPrimitive(param.asType()); if(paramName.indexOf('_')==-1){ ColumnProperty column = getColumn(param); where.add("\"+"+column.columnName(true)+"+\"=?"); params.add(column.toNativeTypeCode(paramName)); if(!primitive) CollectionUtil.addAll(code, "if("+paramName+"!=null){", PLUS ); CollectionUtil.addAll(code, "__conditions.add("+where.get(where.size()-1).substring(2)+"\");", "__params.add("+column.toNativeTypeCode(paramName)+");" ); if(!primitive) CollectionUtil.addAll(code, MINUS, "}" ); iter.remove(); }else{ int underscore = paramName.indexOf('_'); String hint = paramName.substring(0, underscore); String propertyName = paramName.substring(underscore+1); ColumnProperty column = getColumn(param, propertyName); String hintValue = HINTS.get(hint); if(hintValue!=null){ where.add("\"+"+column.columnName(true)+"+\""+hintValue); params.add(column.toNativeTypeCode(paramName)); if(!primitive) CollectionUtil.addAll(code, "if("+paramName+"!=null){", PLUS ); CollectionUtil.addAll(code, "__conditions.add("+where.get(where.size()-1).substring(2)+"\");", "__params.add("+column.toNativeTypeCode(paramName)+");" ); if(!primitive) CollectionUtil.addAll(code, MINUS, "}" ); iter.remove(); }else if("from".equals(hint)){ iter.remove(); final VariableElement nextParam = iter.next(); final String nextParamName = nextParam.getSimpleName().toString(); boolean nextPrimitive = ModelUtil.isPrimitive(nextParam.asType()); if(!nextParamName.equals("to_"+propertyName)) throw new AnnotationError(method, "the next parameter of "+paramName+" must be to_"+propertyName); if(param.asType()!=nextParam.asType()) throw new AnnotationError(method, paramName+" and "+nextParamName+" must be of same type"); where.add("\"+"+column.columnName(true)+"+\" BETWEEN ? and ?"); params.add(column.toNativeTypeCode(paramName)); params.add(column.toNativeTypeCode(nextParamName)); if(!primitive || !nextPrimitive){ String condition = ""; if(!primitive) condition = paramName+"!=null"; if(!nextPrimitive){ if(condition.length()>0) condition += " && "; condition += nextParamName+"!=null"; } CollectionUtil.addAll(code, "if("+condition+"){", PLUS ); } CollectionUtil.addAll(code, "__conditions.add("+where.get(where.size()-1).substring(2)+"\");", "__params.add("+column.toNativeTypeCode(paramName)+");", "__params.add("+column.toNativeTypeCode(nextParamName)+");" ); if(!primitive || !nextPrimitive) CollectionUtil.addAll(code, MINUS, "}" ); iter.remove(); }else throw new AnnotationError(param, "invalid hint: "+hint); } } Boolean ignoreNullConditions = false; try{ ignoreNullConditions = ModelUtil.getAnnotationValue(method, mirror, "ignoreNullConditions"); }catch(AnnotationError ex){ // ignore } if(ignoreNullConditions){ String orderByPhrase = orderByPhrase(); if(orderByPhrase.length()>0) initialQuery = ""; String queryInitialValue; if(initialQuery==null) queryInitialValue = "null"; else queryInitialValue = '"'+ initialQuery +'"'; CollectionUtil.addAll(code, "String __query = "+queryInitialValue+";", "if(__conditions.size()>0)", PLUS, "__query "+(initialQuery==null?"":"+")+"= \" WHERE \" + "+StringUtil.class.getName()+".join(__conditions.iterator(), \" AND \");", MINUS ); if(orderByPhrase.length()>0){ CollectionUtil.addAll(code, "__query += \""+orderByPhrase+"\";" ); } CollectionUtil.addAll(code, "__query", "__params.toArray()" ); return code.toArray(new CharSequence[code.size()]); }else{ StringBuilder query = new StringBuilder(); if(initialQuery!=null) query.append(initialQuery).append(' '); if(where.size()>0) query.append("WHERE ").append(StringUtil.join(where.iterator(), " AND ")); query.append(orderByPhrase()); return new CharSequence[]{ query, StringUtil.join(params.iterator(), ", ") }; } } private String orderByPhrase(){ List<String> orderByList = new ArrayList<String>(); try{ Collection<AnnotationValue> orderBys = ModelUtil.getAnnotationValue(method, mirror, "orderBy"); for(AnnotationValue orderByValue: orderBys){ AnnotationMirror orderByMirror = (AnnotationMirror)orderByValue.getValue(); String columnProperty = ModelUtil.getAnnotationValue(method, orderByMirror, "column"); ColumnProperty column = columns.findByProperty(columnProperty); if(column==null) throw new AnnotationError(method, mirror, "invalid column property: "+columnProperty); Order order = Order.valueOf(((VariableElement)ModelUtil.getAnnotationValue(method, orderByMirror, "order")).getSimpleName().toString()); orderByList.add("\"+"+column.columnName(true)+"+\" "+order.keyword); } }catch(AnnotationError ex){ // ignore } return orderByList.size()>0 ? " ORDER BY "+StringUtil.join(orderByList.iterator(), ", ") : ""; } }