Browse Source

新增支持like、in子句

James 3 years ago
parent
commit
36252c8065
1 changed files with 107 additions and 13 deletions
  1. 107 13
      src/main/java/com/jfinal/plugin/activerecord/sql/ParaDirective.java

+ 107 - 13
src/main/java/com/jfinal/plugin/activerecord/sql/ParaDirective.java

@@ -16,6 +16,8 @@
 
 package com.jfinal.plugin.activerecord.sql;
 
+import java.lang.reflect.Array;
+import java.util.Collection;
 import com.jfinal.plugin.activerecord.SqlPara;
 import com.jfinal.template.Directive;
 import com.jfinal.template.Env;
@@ -55,6 +57,22 @@ import com.jfinal.template.stat.Scope;
  * 
  * 3:以上用法会在 #para(0) 与 #para(1) 处生成问号占位字符,并且将 10、100 这两个参数放入
  *    SqlPara 对象的参数列表中
+ * 
+ * 三、4.9.23 新增支持 like、in 子句
+ *    ### 一般用法,第二个参数传入 "like"、"in" 参数即可
+ *    select * from t title like #para(title, "like")
+ *    select * from t title like #para(title, "in")
+ *    
+ *    ### like 类型第一个参数支持 int 类型。注意:in 类型不支持第一个参数为 int 类型
+ *    select * from t title like #para(0, "like")
+ *    
+ *    ### like 支持左侧与右侧百分号用法
+ *    select * from t title like #para(title, "%like")
+ *    select * from t title like #para(title, "like%")
+ *    
+ *    ### 注意:in 子句第一个参数不支持 int 类型
+ *    select * from t id in #para(idList, "in")
+ * 
  * </pre>
  */
 public class ParaDirective extends Directive {
@@ -63,6 +81,13 @@ public class ParaDirective extends Directive {
 	private String paraName = null;
 	private static boolean checkParaAssigned = true;
 	
+	// 支持 like、in 子句
+	private int type = 0;
+	private static final int TYPE_LIKE = 1;
+	private static final int TYPE_LIKE_LEFT = 2;
+	private static final int TYPE_LIKE_RIGHT = 3;
+	private static final int TYPE_IN = 4;
+	
 	public static void setCheckParaAssigned(boolean checkParaAssigned) {
 		ParaDirective.checkParaAssigned = checkParaAssigned;
 	}
@@ -72,18 +97,34 @@ public class ParaDirective extends Directive {
 			throw new ParseException("The parameter of #para directive can not be blank", location);
 		}
 		
-		if (exprList.length() == 1) {
-			Expr expr = exprList.getExpr(0);
-			if (expr instanceof Const && ((Const)expr).isInt()) {
-				index = ((Const)expr).getInt();
-				if (index < 0) {
-					throw new ParseException("The index of para array must greater than -1", location);
-				}
+		Expr expr = exprList.getExpr(0);
+		if (expr instanceof Const && ((Const)expr).isInt()) {
+			index = ((Const)expr).getInt();
+			if (index < 0) {
+				throw new ParseException("The index of para array must greater than -1", location);
 			}
 		}
 		
-		if (checkParaAssigned && exprList.getLastExpr() instanceof Id) {
-			Id id = (Id)exprList.getLastExpr();
+		if (exprList.length() > 1) {
+		    expr = exprList.getExpr(1);
+		    if (expr instanceof Const && ((Const)expr).isStr()) {
+		        String typeStr = ((Const)expr).getStr();
+		        if ("like".equalsIgnoreCase(typeStr) || "%like%".equalsIgnoreCase(typeStr)) {
+		            type = TYPE_LIKE;
+		        } else if ("%like".equalsIgnoreCase(typeStr)) {
+		            type = TYPE_LIKE_LEFT;
+		        } else if ("like%".equalsIgnoreCase(typeStr)) {
+		            type = TYPE_LIKE_RIGHT;
+		        } else if ("in".equalsIgnoreCase(typeStr)) {
+		            type = TYPE_IN;
+		        } else {
+		            throw new ParseException("The type of para must be: like, %like, like%, in", location);
+		        }
+		    }
+		}
+		
+		if (checkParaAssigned && exprList.getExpr(0) instanceof Id) {
+			Id id = (Id)exprList.getExpr(0);
 			paraName = id.getId();
 		}
 		
@@ -96,7 +137,6 @@ public class ParaDirective extends Directive {
 			throw new TemplateException("#para directive invoked by getSqlPara(...) method only", location);
 		}
 		
-		write(writer, "?");
 		if (index == -1) {
 			// #para(paraName) 中的 paraName 没有赋值时抛出异常
 			// issue: https://jfinal.com/feedback/1832
@@ -104,18 +144,72 @@ public class ParaDirective extends Directive {
 				throw new TemplateException("The parameter \""+ paraName +"\" must be assigned", location);
 			}
 			
-			sqlPara.addPara(exprList.eval(scope));
+			handleSqlPara(writer, sqlPara, exprList.getExpr(0).eval(scope));
 		} else {
 			Object[] paras = (Object[])scope.get(SqlKit.PARA_ARRAY_KEY);
 			if (paras == null) {
-				throw new TemplateException("The #para(" + index + ") directive must invoked by getSqlPara(String, Object...) method", location);
+				throw new TemplateException("The #para(" + index + ") directive must invoked by template(String, Object...) or getSqlPara(String, Object...) method", location);
 			}
 			if (index >= paras.length) {
 				throw new TemplateException("The index of #para directive is out of bounds: " + index, location);
 			}
-			sqlPara.addPara(paras[index]);
+			
+			handleSqlPara(writer, sqlPara, paras[index]);
 		}
 	}
+	
+	private void handleSqlPara(Writer writer, SqlPara sqlPara, Object value) {
+	    if (type == 0) {
+	        write(writer, "?");
+	        sqlPara.addPara(value);
+	    } else if (type == TYPE_LIKE) {
+	        write(writer, "?");
+	        sqlPara.addPara("%" + value + "%");
+	    } else if (type == TYPE_LIKE_LEFT) {
+	        write(writer, "?");
+	        sqlPara.addPara("%" + value);
+        } else if (type == TYPE_LIKE_RIGHT) {
+            write(writer, "?");
+            sqlPara.addPara(value + "%");
+        } else if (type == TYPE_IN) {
+            if (value instanceof Collection) {
+                handleCollection(writer, sqlPara, (Collection<?>)value);
+            } else if (value.getClass().isArray()) {
+                handleArray(writer, sqlPara, value);
+            } else {
+                write(writer, "(?)");
+                sqlPara.addPara(value);
+            }
+        }
+	}
+	
+	private void handleCollection(Writer writer, SqlPara sqlPara, Collection<?> collection) { 
+	    write(writer, "(");
+        boolean first = true;
+        for (Object element : collection) {
+            if (first) {
+                first = false;
+            } else {
+                write(writer, ",");
+            }
+            write(writer, "?");
+            sqlPara.addPara(element);
+        }
+        write(writer, ")");
+	}
+	
+	private void handleArray(Writer writer, SqlPara sqlPara, Object array) {
+        write(writer, "(");
+        int size = Array.getLength(array);
+        for (int i=0; i<size; i++) {
+            if (i > 0) {
+                write(writer, ",");
+            }
+            write(writer, "?");
+            sqlPara.addPara(Array.get(array, i));
+        }
+        write(writer, ")");
+    }
 }