From 62fa7b3b5e3111773d5c866fbd85a276e7939fa6 Mon Sep 17 00:00:00 2001 From: simsevenx Date: Fri, 20 May 2022 15:41:47 +0800 Subject: [PATCH] Add method builder.sourceScript(sql, Object...vs); (#49) --- .../main/java/io/xream/sqli/builder/Bb.java | 8 +- .../xream/sqli/builder/ConditionBuilder.java | 1 - .../xream/sqli/builder/ConditionParser.java | 100 ++++++++++++++++++ .../io/xream/sqli/builder/ConditionToSql.java | 8 +- .../java/io/xream/sqli/builder/Criteria.java | 17 +++ .../xream/sqli/builder/CriteriaBuilder.java | 28 +++++ .../main/java/io/xream/sqli/builder/Op.java | 9 ++ .../io/xream/sqli/builder/SourceScript.java | 1 - .../sqli/builder/SourceScriptBuilder.java | 48 ++++++--- .../internal/DefaultCriteriaToSql.java | 16 ++- .../io/xream/sqli/mapping/SqlNormalizer.java | 7 +- 11 files changed, 215 insertions(+), 28 deletions(-) create mode 100644 sqli-builder/src/main/java/io/xream/sqli/builder/ConditionParser.java diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/Bb.java b/sqli-builder/src/main/java/io/xream/sqli/builder/Bb.java index 3caabcfd..745141a4 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/Bb.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/Bb.java @@ -32,7 +32,6 @@ public final class Bb { private String key; private Object value; private List subList; - private Bb parent; public Bb(){} public Bb(boolean isOr){ if (isOr) @@ -70,12 +69,7 @@ public List getSubList() { public void setSubList(List subList) { this.subList = subList; } - public Bb getParent() { - return parent; - } - public void setParent(Bb parent) { - this.parent = parent; - } + @Override public boolean equals(Object object) { diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionBuilder.java b/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionBuilder.java index dc2849ed..304df784 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionBuilder.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionBuilder.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import java.util.Objects; /** * @author Sim diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionParser.java b/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionParser.java new file mode 100644 index 00000000..f3db8bd9 --- /dev/null +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionParser.java @@ -0,0 +1,100 @@ +/* + * Copyright 2020 io.xream.sqli + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses 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 io.xream.sqli.builder; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Sim + */ +public interface ConditionParser { + + + static int parse(int i, List conditionScriptSplittedList, + List bbList, List valueList) { + int size = conditionScriptSplittedList.size(); + + Bb bb = null; + while (true) { + if (i > size - 1) + return i; + String s = conditionScriptSplittedList.get(i++); + + if (s.equals(SqlScript.PLACE_HOLDER)) { // ? + Object v = valueList.remove(0); + if (v == null || (v instanceof List && ((List) v).isEmpty())) { + bbList.remove(bbList.size()-1); + } + bb.setValue(v); + } + + String u = s.toUpperCase(); + if (s.startsWith("(")) { + bb = new Bb(); + bb.setKey(""); + bb.setC(Op.AND); + bb.setP(Op.SUB); + bbList.add(bb); + List subList = new ArrayList<>(); + bb.setSubList(subList); + i = parse(i, conditionScriptSplittedList, + subList, valueList); + continue; + } + + else if (s.startsWith(")")) { + return i; + } + + else if (u.startsWith("AND") || u.startsWith("OR")) { + + String next = conditionScriptSplittedList.get(i); + if (next.equals("(")){ + bb = new Bb(); + bb.setKey(""); + bb.setC(Op.valueOf(u)); + bb.setP(Op.SUB); + bbList.add(bb); + List subList = new ArrayList<>(); + bb.setSubList(subList); + i++; + i = parse(i, conditionScriptSplittedList, + subList, valueList); + continue; + } + + bb = new Bb(); + bb.setKey(""); + bb.setC(Op.valueOf(u)); + bb.setP(Op.X); + bbList.add(bb); + } else { + if (bb == null) { + bb = new Bb(); + bb.setKey(""); + bb.setP(Op.X); + bb.setC(Op.AND); + bbList.add(bb); + } + bb.setKey(bb.getKey() + " " + s); + } + } + } +} diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionToSql.java b/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionToSql.java index 9141016e..577f6e3d 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionToSql.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/ConditionToSql.java @@ -42,7 +42,6 @@ public interface ConditionToSql extends Mapper, SqlNormalizer, UnsafeSyntaxFilte default void buildConditionSql(StringBuilder sb, List bbList, Mappable mappable) { if (bbList == null || bbList.isEmpty()) return; - for (Bb bb : bbList) { Op p = bb.getP(); @@ -63,7 +62,10 @@ default void buildConditionSql(StringBuilder sb, List bbList, Mappable mappa String mapper = null; if (p == Op.X){ - final String str = normalizeSql(bb.getKey()); + String key = bb.getKey(); + if (SqliStringUtil.isNullOrEmpty(key)) + continue; + final String str = normalizeSql(key); StringBuilder sbx = new StringBuilder(); mapping((reg)->str.split(reg), mappable,sbx); mapper = sbx.toString(); @@ -162,7 +164,7 @@ default void filter(List bbList, Mappable mappable) { if (bb.getSubList().isEmpty()) { ite.remove(); } - }else if (p == Op.EQ + } else if (p == Op.EQ || p == Op.NE || p == Op.GT || p == Op.GTE diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/Criteria.java b/sqli-builder/src/main/java/io/xream/sqli/builder/Criteria.java index 97b4831c..37d29174 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/Criteria.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/Criteria.java @@ -174,6 +174,10 @@ public void paged(Paged paged) { } } + public List getSourceScriptValueList() { + return null; + } + @Override public String toString() { @@ -198,6 +202,7 @@ public static final class ResultMapCriteria extends Criteria implements ResultMa private List aggrList; private Distinct distinct; private String sourceScript; + private List sourceScriptValueList; private List sourceScripts; private List reduceList; private List havingList; @@ -280,6 +285,18 @@ public void setSourceScript(String sourceScript) { this.sourceScript = normalizeSql(sourceScript); } + @Override + public List getSourceScriptValueList() { + return sourceScriptValueList; + } + + public void setSourceScriptValueList(Object[] vs) { + this.sourceScriptValueList = new ArrayList<>(); + for (Object v : vs) { + this.sourceScriptValueList.add(v); + } + } + public List getResultKeyList() { return resultKeyList; } diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/CriteriaBuilder.java b/sqli-builder/src/main/java/io/xream/sqli/builder/CriteriaBuilder.java index 5199d867..78b1d438 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/CriteriaBuilder.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/CriteriaBuilder.java @@ -21,6 +21,7 @@ import io.xream.sqli.page.Paged; import io.xream.sqli.parser.Parsed; import io.xream.sqli.parser.Parser; +import io.xream.sqli.util.BeanUtil; import io.xream.sqli.util.SqliStringUtil; import java.util.ArrayList; @@ -155,6 +156,12 @@ public SourceScriptBuilder source(String source) { return this; } + @Override + public SourceScriptBuilder source(Class clzz) { + sourceScriptTemp.setSource(BeanUtil.getByFirstLower(clzz.getSimpleName())); + return this; + } + @Override public SourceScriptBuilder sub(Sub sub) { ResultMapBuilder subBuilder = CriteriaBuilder.resultMapBuilder(); @@ -220,8 +227,18 @@ public ConditionBuilder more() { return builder(bbList); } + @Override + public ResultMapBuilder build() { + return getInstance(); + } + }; + private ResultMapBuilder instance; + protected ResultMapBuilder getInstance(){ + return this.instance; + } + public SourceScriptBuilder sourceBuilder() { sourceScriptTemp = new SourceScript(); get().getSourceScripts().add(sourceScriptTemp); @@ -245,6 +262,7 @@ public Criteria.ResultMapCriteria build() { public ResultMapBuilder(Criteria criteria) { super(criteria); + instance = this; } public ResultMapBuilder resultKey(String resultKey) { @@ -294,7 +312,17 @@ public ResultMapBuilder resultKeyFunction(ResultKeyAlia resultKeyAlia, String fu public ResultMapBuilder sourceScript(String sourceScript) { if (SqliStringUtil.isNullOrEmpty(sourceScript)) return this; + sourceScript = normalizeSql(sourceScript); + get().setSourceScript(sourceScript); + return this; + } + + public ResultMapBuilder sourceScript(String sourceScript, Object...vs) { + if (SqliStringUtil.isNullOrEmpty(sourceScript)) + return this; + sourceScript = normalizeSql(sourceScript); get().setSourceScript(sourceScript); + get().setSourceScriptValueList(vs); return this; } diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/Op.java b/sqli-builder/src/main/java/io/xream/sqli/builder/Op.java index d7875f4c..3c76436f 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/Op.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/Op.java @@ -55,4 +55,13 @@ public enum Op { public String sql(){ return op; } + + public static Op valueOfSql(String str) { + String t = str.trim(); + for (Op op : values()) { + if (op.sql().equals(str)) + return op; + } + return NONE; + } } diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/SourceScript.java b/sqli-builder/src/main/java/io/xream/sqli/builder/SourceScript.java index ee49f866..5d7dac90 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/SourceScript.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/SourceScript.java @@ -173,7 +173,6 @@ public String sql(Mappable mappable) { ); } } - buildConditionSql(sb, bbList, mappable); return sb.toString(); diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/SourceScriptBuilder.java b/sqli-builder/src/main/java/io/xream/sqli/builder/SourceScriptBuilder.java index e50ca061..b71219d1 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/SourceScriptBuilder.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/SourceScriptBuilder.java @@ -19,13 +19,13 @@ package io.xream.sqli.builder; -import io.xream.sqli.exception.CriteriaSyntaxException; import io.xream.sqli.exception.NotSupportedException; import io.xream.sqli.exception.ParsingException; import io.xream.sqli.parser.Parser; import io.xream.sqli.util.SqliStringUtil; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; /** @@ -35,6 +35,8 @@ public interface SourceScriptBuilder { SourceScriptBuilder source(String source); + SourceScriptBuilder source(Class clzz); + SourceScriptBuilder sub(Sub sub); SourceScriptBuilder with(Sub sub); @@ -51,6 +53,8 @@ public interface SourceScriptBuilder { ConditionBuilder more(); + CriteriaBuilder.ResultMapBuilder build(); + static void checkSourceAndAlia(List list) { for (SourceScript sourceScript : list) { @@ -58,27 +62,32 @@ static void checkSourceAndAlia(List list) { if (SqliStringUtil.isNotNull(source) && !Parser.contains(source)) { String tip = ""; if (sourceScript.getJoinType() != null) { - tip += sourceScript.getJoinType().name().replace("_"," "); - }else if(SqliStringUtil.isNotNull(sourceScript.getJoinStr())){ + tip += sourceScript.getJoinType().name().replace("_", " "); + } else if (SqliStringUtil.isNotNull(sourceScript.getJoinStr())) { tip += sourceScript.getJoinStr(); - }else { + } else { tip += SqlScript.FROM; } throw new ParsingException(tip + SqlScript.SPACE + source); } String alia = sourceScript.getAlia(); - if (source !=null && alia !=null && !alia.equals(source) && Parser.contains(alia)) { + if (source != null && alia != null && !alia.equals(source) && Parser.contains(alia)) { throw new NotSupportedException("not support table alia = firstLetterLower(parsedEntityName), name+alia: " + source + " " + alia); } } } + /** - * * @param sourceScriptsSplittedList * @return */ - static List parse(List sourceScriptsSplittedList) { + static List parseScriptAndBuild(List sourceScriptsSplittedList, List sourceScriptValues) { + + List sourceScriptValueList = new LinkedList<>(); + if (sourceScriptValues != null) { + sourceScriptValueList.addAll(sourceScriptValues); + } List list = new ArrayList<>(); @@ -87,8 +96,20 @@ static List parse(List sourceScriptsSplittedList) { for (int i = 0; i < size; i++) { String str = sourceScriptsSplittedList.get(i); String strUpper = str.toUpperCase(); - if (strUpper.equals("AND") || strUpper.equals("OR")) - throw new CriteriaSyntaxException("SourceScript String does not support ON AND | OR, try to invoke builder.sourceBuilder()"); + + if (strUpper.equals("AND") || strUpper.equals("OR")) { + + sourceScript = getLast(list); + List bbList = sourceScript.getBbList(); + if (bbList == null) { + bbList = new ArrayList<>(); + sourceScript.setBbList(bbList); + } + + i = ConditionParser.parse(i, sourceScriptsSplittedList, + bbList, sourceScriptValueList); + continue; + } if ("FROM".equals(strUpper)) continue; @@ -128,7 +149,6 @@ static List parse(List sourceScriptsSplittedList) { sourceScript.setJoinType(JoinType.COMMA); break; case "ON": - String selfKey = sourceScriptsSplittedList.get(++i); String op = sourceScriptsSplittedList.get(++i);// op String fromKey = sourceScriptsSplittedList.get(++i); @@ -149,9 +169,7 @@ static List parse(List sourceScriptsSplittedList) { on.setOp(op); on.setJoinFrom(joinFrom); sourceScript.setOn(on); - break; - default: if (sourceScript == null) { sourceScript = createAndGet(list); @@ -170,7 +188,7 @@ static List parse(List sourceScriptsSplittedList) { return list; } - + static List split(String script) { String[] opArrTwo = {"!=", "<>", "<=", ">="}; String[] opArrTwoTemp = {"&ne", "&ne", "<e", ">e"}; @@ -215,4 +233,8 @@ static SourceScript createAndGet(List list) { return sourceScript; } + static SourceScript getLast(List list) { + return list.get(list.size() - 1); + } + } diff --git a/sqli-builder/src/main/java/io/xream/sqli/builder/internal/DefaultCriteriaToSql.java b/sqli-builder/src/main/java/io/xream/sqli/builder/internal/DefaultCriteriaToSql.java index de7c6aed..b099d4c0 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/builder/internal/DefaultCriteriaToSql.java +++ b/sqli-builder/src/main/java/io/xream/sqli/builder/internal/DefaultCriteriaToSql.java @@ -637,7 +637,7 @@ private void parseAliaFromRefresh(RefreshCondition refreshCondition) { String script = refreshCondition.getSourceScript();//string -> list<> List list = SourceScriptBuilder.split(script); - List sourceScripts = SourceScriptBuilder.parse(list); + List sourceScripts = SourceScriptBuilder.parseScriptAndBuild(list,null); SourceScriptBuilder.checkSourceAndAlia(sourceScripts); for (SourceScript sc : sourceScripts) { refreshCondition.getAliaMap().put(sc.alia(), sc.getSource()); @@ -655,7 +655,7 @@ private void parseAlia(Criteria criteria, SqlSth sqlSth) { String sourceScript = rmc.sourceScript();//string -> list<> List list = SourceScriptBuilder.split(sourceScript); - List sourceScripts = SourceScriptBuilder.parse(list); + List sourceScripts = SourceScriptBuilder.parseScriptAndBuild(list,rmc.getSourceScriptValueList()); rmc.getSourceScripts().addAll(sourceScripts); } @@ -804,12 +804,24 @@ private void condition(SqlSth sqlSth, Criteria criteria, List valueList) pre(valueList, bbList, criteria);//提取占位符对应的值 if (bbList.isEmpty()) return; + withSourceScriptValuelist(criteria,valueList); bbList.get(0).setC(Op.WHERE); buildConditionSql(xsb, bbList, criteria); sqlSth.sbCondition.append(xsb); } + private void withSourceScriptValuelist(Criteria criteria, List valueList){ + List objectList = criteria.getSourceScriptValueList(); + if (objectList != null ){ + for (Object v : objectList) { + if (v == null) continue; + if (v instanceof List && ((List) v).isEmpty()) continue; + valueList.add(0,v); + } + } + } + public static final class SqlSth { diff --git a/sqli-builder/src/main/java/io/xream/sqli/mapping/SqlNormalizer.java b/sqli-builder/src/main/java/io/xream/sqli/mapping/SqlNormalizer.java index 1a603ad4..b8091159 100644 --- a/sqli-builder/src/main/java/io/xream/sqli/mapping/SqlNormalizer.java +++ b/sqli-builder/src/main/java/io/xream/sqli/mapping/SqlNormalizer.java @@ -61,7 +61,7 @@ default int normalizeParentThesis(int idx, int length,String strEle, StringBuild for (; idx + 1 < length; ) { String nextOp = String.valueOf(handwritten.charAt(idx + 1)); if (nextOp.equals(strEle)) { - valueSb.append(nextOp); + valueSb.append(SPACE).append(nextOp); idx++; } else { break; @@ -96,6 +96,11 @@ default String normalizeSql(final String handwritten) { } if (strEle.equals(LEFT_PARENTTHESIS) || strEle.equals(RIGHT_PARENTTHESIS)) { + String pre = String.valueOf(handwritten.charAt(j-1)); + if (pre.equals(LEFT_PARENTTHESIS) || pre.equals(RIGHT_PARENTTHESIS)){ + valueSb.append(SPACE).append(strEle); + continue; + } j = normalizeParentThesis(j,length,strEle,valueSb,handwritten); continue; }