QueryWhereConditionParser.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. package org.elasticsearch.dsl.parser;
  2. import com.alibaba.druid.sql.ast.SQLExpr;
  3. import com.alibaba.druid.sql.ast.expr.*;
  4. import com.google.common.collect.Lists;
  5. import org.apache.commons.collections.CollectionUtils;
  6. import org.elasticsearch.dsl.ElasticDslContext;
  7. import org.elasticsearch.dsl.ElasticSqlIdentifier;
  8. import org.elasticsearch.dsl.ElasticSqlParseUtil;
  9. import org.elasticsearch.dsl.ParseActionListener;
  10. import org.elasticsearch.dsl.enums.SQLConditionOperator;
  11. import org.elasticsearch.dsl.exception.ElasticSql2DslException;
  12. import org.elasticsearch.dsl.parser.helper.ElasticSqlIdentifierHelper;
  13. import org.elasticsearch.index.query.BoolFilterBuilder;
  14. import org.elasticsearch.index.query.FilterBuilder;
  15. import org.elasticsearch.index.query.FilterBuilders;
  16. import org.elasticsearch.sql.ElasticSqlSelectQueryBlock;
  17. import java.util.List;
  18. import java.util.function.Consumer;
  19. public class QueryWhereConditionParser implements QueryParser {
  20. private ParseActionListener parseActionListener;
  21. public QueryWhereConditionParser(ParseActionListener parseActionListener) {
  22. this.parseActionListener = parseActionListener;
  23. }
  24. @Override
  25. public void parse(ElasticDslContext dslContext) {
  26. ElasticSqlSelectQueryBlock queryBlock = (ElasticSqlSelectQueryBlock) dslContext.getQueryExpr().getSubQuery().getQuery();
  27. BoolFilterBuilder whereCondition = FilterBuilders.boolFilter();
  28. if (queryBlock.getWhere() != null) {
  29. SqlCondition sqlCondition = parseFilterCondition(dslContext, queryBlock.getWhere());
  30. if (!sqlCondition.isAndOr()) {
  31. whereCondition.must(sqlCondition.getFilterList().get(0));
  32. } else {
  33. for (FilterBuilder filter : sqlCondition.getFilterList()) {
  34. if (sqlCondition.getOperator() == SQLBinaryOperator.BooleanAnd) {
  35. whereCondition.must(filter);
  36. }
  37. if (sqlCondition.getOperator() == SQLBinaryOperator.BooleanOr) {
  38. whereCondition.should(filter);
  39. }
  40. }
  41. }
  42. }
  43. dslContext.getParseResult().setWhereCondition(whereCondition);
  44. }
  45. private SqlCondition parseFilterCondition(ElasticDslContext dslContext, SQLExpr sqlExpr) {
  46. if (sqlExpr instanceof SQLBinaryOpExpr) {
  47. SQLBinaryOpExpr sqlBinOpExpr = (SQLBinaryOpExpr) sqlExpr;
  48. SQLBinaryOperator binaryOperator = sqlBinOpExpr.getOperator();
  49. if (SQLBinaryOperator.BooleanAnd == binaryOperator || SQLBinaryOperator.BooleanOr == binaryOperator) {
  50. final SqlCondition leftCondition = parseFilterCondition(dslContext, sqlBinOpExpr.getLeft());
  51. final SqlCondition rightCondition = parseFilterCondition(dslContext, sqlBinOpExpr.getRight());
  52. List<FilterBuilder> curFilterList = Lists.newArrayList();
  53. if (!leftCondition.isAndOr() || leftCondition.operator == binaryOperator) {
  54. curFilterList.addAll(leftCondition.getFilterList());
  55. } else {
  56. final BoolFilterBuilder subBoolFilter = FilterBuilders.boolFilter();
  57. leftCondition.getFilterList().stream().forEach(new Consumer<FilterBuilder>() {
  58. @Override
  59. public void accept(FilterBuilder filter) {
  60. if (leftCondition.getOperator() == SQLBinaryOperator.BooleanAnd) {
  61. subBoolFilter.must(filter);
  62. }
  63. if (leftCondition.getOperator() == SQLBinaryOperator.BooleanOr) {
  64. subBoolFilter.should(filter);
  65. }
  66. }
  67. });
  68. curFilterList.add(subBoolFilter);
  69. }
  70. if (!rightCondition.isAndOr() || rightCondition.operator == binaryOperator) {
  71. curFilterList.addAll(rightCondition.getFilterList());
  72. } else {
  73. final BoolFilterBuilder subBoolFilter = FilterBuilders.boolFilter();
  74. rightCondition.getFilterList().stream().forEach(new Consumer<FilterBuilder>() {
  75. @Override
  76. public void accept(FilterBuilder filter) {
  77. if (rightCondition.getOperator() == SQLBinaryOperator.BooleanAnd) {
  78. subBoolFilter.must(filter);
  79. }
  80. if (rightCondition.getOperator() == SQLBinaryOperator.BooleanOr) {
  81. subBoolFilter.should(filter);
  82. }
  83. }
  84. });
  85. curFilterList.add(subBoolFilter);
  86. }
  87. return new SqlCondition(curFilterList, binaryOperator);
  88. }
  89. }
  90. return new SqlCondition(parseAtomFilterCondition(dslContext, sqlExpr));
  91. }
  92. private FilterBuilder parseAtomFilterCondition(ElasticDslContext dslContext, SQLExpr sqlExpr) {
  93. if (sqlExpr instanceof SQLBinaryOpExpr) {
  94. SQLBinaryOpExpr sqlBinOpExpr = (SQLBinaryOpExpr) sqlExpr;
  95. final SQLBinaryOperator binaryOperator = sqlBinOpExpr.getOperator();
  96. if (ElasticSqlParseUtil.isValidBinOperator(binaryOperator)) {
  97. //EQ NEQ
  98. if (SQLBinaryOperator.Equality == binaryOperator || SQLBinaryOperator.LessThanOrGreater == binaryOperator || SQLBinaryOperator.NotEqual == binaryOperator) {
  99. Object targetVal = ElasticSqlParseUtil.transferSqlArg(sqlBinOpExpr.getRight(), dslContext.getSqlArgs());
  100. SQLConditionOperator operator = SQLBinaryOperator.Equality == binaryOperator ? SQLConditionOperator.Equality : SQLConditionOperator.NotEqual;
  101. return parseCondition(sqlBinOpExpr.getLeft(), operator, new Object[]{targetVal}, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  102. @Override
  103. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  104. FilterBuilder eqFilter = FilterBuilders.termFilter(leftIdfName, rightParamValues[0]);
  105. if (SQLConditionOperator.Equality == operator) {
  106. return eqFilter;
  107. } else {
  108. return FilterBuilders.notFilter(eqFilter);
  109. }
  110. }
  111. });
  112. }
  113. //GT GTE LT LTE
  114. if (SQLBinaryOperator.GreaterThan == binaryOperator || SQLBinaryOperator.GreaterThanOrEqual == binaryOperator
  115. || SQLBinaryOperator.LessThan == binaryOperator || SQLBinaryOperator.LessThanOrEqual == binaryOperator) {
  116. SQLConditionOperator operator = null;
  117. if (SQLBinaryOperator.GreaterThan == binaryOperator) {
  118. operator = SQLConditionOperator.GreaterThan;
  119. } else if (SQLBinaryOperator.GreaterThanOrEqual == binaryOperator) {
  120. operator = SQLConditionOperator.GreaterThanOrEqual;
  121. } else if (SQLBinaryOperator.LessThan == binaryOperator) {
  122. operator = SQLConditionOperator.LessThan;
  123. } else if (SQLBinaryOperator.LessThanOrEqual == binaryOperator) {
  124. operator = SQLConditionOperator.LessThanOrEqual;
  125. }
  126. Object targetVal = ElasticSqlParseUtil.transferSqlArg(sqlBinOpExpr.getRight(), dslContext.getSqlArgs());
  127. return parseCondition(sqlBinOpExpr.getLeft(), operator, new Object[]{targetVal}, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  128. @Override
  129. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  130. FilterBuilder rangeFilter = null;
  131. if (SQLConditionOperator.GreaterThan == operator) {
  132. rangeFilter = FilterBuilders.rangeFilter(leftIdfName).gt(rightParamValues[0]);
  133. } else if (SQLConditionOperator.GreaterThanOrEqual == operator) {
  134. rangeFilter = FilterBuilders.rangeFilter(leftIdfName).gte(rightParamValues[0]);
  135. } else if (SQLConditionOperator.LessThan == operator) {
  136. rangeFilter = FilterBuilders.rangeFilter(leftIdfName).lt(rightParamValues[0]);
  137. } else if (SQLConditionOperator.LessThanOrEqual == operator) {
  138. rangeFilter = FilterBuilders.rangeFilter(leftIdfName).lte(rightParamValues[0]);
  139. }
  140. return rangeFilter;
  141. }
  142. });
  143. }
  144. //IS / IS NOT
  145. if (SQLBinaryOperator.Is == binaryOperator || SQLBinaryOperator.IsNot == binaryOperator) {
  146. if (!(sqlBinOpExpr.getRight() instanceof SQLNullExpr)) {
  147. throw new ElasticSql2DslException("[syntax error] Is/IsNot expr right part should be null");
  148. }
  149. SQLConditionOperator operator = SQLBinaryOperator.Is == binaryOperator ? SQLConditionOperator.IsNull : SQLConditionOperator.IsNotNull;
  150. return parseCondition(sqlBinOpExpr.getLeft(), operator, null, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  151. @Override
  152. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  153. FilterBuilder missingFilter = FilterBuilders.missingFilter(leftIdfName);
  154. if (SQLConditionOperator.IsNotNull == operator) {
  155. return FilterBuilders.notFilter(missingFilter);
  156. }
  157. return missingFilter;
  158. }
  159. });
  160. }
  161. }
  162. } else if (sqlExpr instanceof SQLInListExpr) {
  163. final SQLInListExpr inListExpr = (SQLInListExpr) sqlExpr;
  164. if (CollectionUtils.isEmpty(inListExpr.getTargetList())) {
  165. throw new ElasticSql2DslException("[syntax error] In list expr target list cannot be blank");
  166. }
  167. Object[] targetInList = ElasticSqlParseUtil.transferSqlArgs(inListExpr.getTargetList(), dslContext.getSqlArgs());
  168. SQLConditionOperator operator = inListExpr.isNot() ? SQLConditionOperator.NotIn : SQLConditionOperator.In;
  169. return parseCondition(inListExpr.getExpr(), operator, targetInList, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  170. @Override
  171. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  172. if (SQLConditionOperator.NotIn == operator) {
  173. return FilterBuilders.notFilter(FilterBuilders.inFilter(leftIdfName, rightParamValues));
  174. } else {
  175. return FilterBuilders.inFilter(leftIdfName, rightParamValues);
  176. }
  177. }
  178. });
  179. } else if (sqlExpr instanceof SQLBetweenExpr) {
  180. SQLBetweenExpr betweenExpr = (SQLBetweenExpr) sqlExpr;
  181. Object from = ElasticSqlParseUtil.transferSqlArg(betweenExpr.getBeginExpr(), dslContext.getSqlArgs());
  182. Object to = ElasticSqlParseUtil.transferSqlArg(betweenExpr.getEndExpr(), dslContext.getSqlArgs());
  183. if (from == null || to == null) {
  184. throw new ElasticSql2DslException("[syntax error] Between Expr only support one of [number,date] arg type");
  185. }
  186. return parseCondition(betweenExpr.getTestExpr(), SQLConditionOperator.BetweenAnd, new Object[]{from, to}, dslContext.getParseResult().getQueryAs(), new ConditionFilterBuilder() {
  187. @Override
  188. public FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues) {
  189. return FilterBuilders.rangeFilter(leftIdfName).gte(rightParamValues[0]).lte(rightParamValues[1]);
  190. }
  191. });
  192. }
  193. throw new ElasticSql2DslException("[syntax error] Can not support syntax type: " + sqlExpr.toString());
  194. }
  195. private FilterBuilder parseCondition(SQLExpr leftIdentifierExpr, SQLConditionOperator operator, Object[] rightParamValues, String queryAs, final ConditionFilterBuilder filterBuilder) {
  196. final List<FilterBuilder> conditionCollector = Lists.newLinkedList();
  197. final Object[] pRightParamValues = rightParamValues;
  198. final SQLConditionOperator pOperator = operator;
  199. ElasticSqlIdentifier sqlIdentifier = ElasticSqlIdentifierHelper.parseSqlIdentifier(leftIdentifierExpr, queryAs, new ElasticSqlIdentifierHelper.ElasticSqlSinglePropertyFunc() {
  200. @Override
  201. public void parse(String propertyName) {
  202. FilterBuilder originalFilter = filterBuilder.buildFilter(propertyName, pOperator, pRightParamValues);
  203. conditionCollector.add(originalFilter);
  204. }
  205. }, new ElasticSqlIdentifierHelper.ElasticSqlPathPropertyFunc() {
  206. @Override
  207. public void parse(String propertyPath, String propertyName) {
  208. FilterBuilder originalFilter = filterBuilder.buildFilter(propertyName, pOperator, pRightParamValues);
  209. FilterBuilder nestFilter = FilterBuilders.nestedFilter(propertyPath, originalFilter);
  210. conditionCollector.add(nestFilter);
  211. }
  212. });
  213. if (CollectionUtils.isNotEmpty(conditionCollector)) {
  214. onAtomConditionParse(sqlIdentifier, rightParamValues, operator);
  215. return conditionCollector.get(0);
  216. }
  217. return null;
  218. }
  219. private void onAtomConditionParse(ElasticSqlIdentifier paramName, Object[] paramValues, SQLConditionOperator operator) {
  220. try {
  221. parseActionListener.onAtomConditionParse(paramName, paramValues, operator);
  222. } catch (Exception ex) {
  223. try {
  224. parseActionListener.onFailure(ex);
  225. } catch (Exception exp) {
  226. //ignore;
  227. }
  228. }
  229. }
  230. @FunctionalInterface
  231. private interface ConditionFilterBuilder {
  232. FilterBuilder buildFilter(String leftIdfName, SQLConditionOperator operator, Object[] rightParamValues);
  233. }
  234. private class SqlCondition {
  235. //是否AND/OR运算
  236. private boolean isAndOr = false;
  237. //运算符
  238. private SQLBinaryOperator operator;
  239. //条件集合
  240. private List<FilterBuilder> filterList;
  241. public SqlCondition(FilterBuilder atomFilter) {
  242. filterList = Lists.newArrayList(atomFilter);
  243. isAndOr = false;
  244. }
  245. public SqlCondition(List<FilterBuilder> filterList, SQLBinaryOperator operator) {
  246. this.filterList = filterList;
  247. isAndOr = true;
  248. this.operator = operator;
  249. }
  250. public boolean isAndOr() {
  251. return isAndOr;
  252. }
  253. public SQLBinaryOperator getOperator() {
  254. return operator;
  255. }
  256. public List<FilterBuilder> getFilterList() {
  257. return filterList;
  258. }
  259. }
  260. }