spuerx 9 роки тому
батько
коміт
3475376cda
33 змінених файлів з 472 додано та 242 видалено
  1. 2 2
      README.md
  2. 5 5
      create_index.sh
  3. 4 37
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/helper/ElasticSqlMethodInvokeHelper.java
  4. 3 5
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/AbstractFieldSpecificMethodQueryParser.java
  5. 0 28
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/CheckableMethodQueryParser.java
  6. 1 1
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/MethodInvocation.java
  7. 2 8
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/MethodQueryParser.java
  8. 14 40
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/ParameterizedMethodQueryParser.java
  9. 67 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/expr/AbstractParameterizedMethodExpression.java
  10. 8 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/expr/FieldSpecificMethodExpression.java
  11. 14 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/expr/MethodExpression.java
  12. 9 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/expr/ParameterizedMethodExpression.java
  13. 2 2
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/fulltext/MatchAtomQueryParser.java
  14. 1 1
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/fulltext/MultiMatchAtomQueryParser.java
  15. 10 10
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/fulltext/QueryStringAtomQueryParser.java
  16. 10 10
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/fulltext/SimpleQueryStringAtomQueryParser.java
  17. 5 14
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/script/ScriptAtomQueryParser.java
  18. 2 2
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/FuzzyAtomQueryParser.java
  19. 5 5
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/PrefixAtomQueryParser.java
  20. 2 2
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/RegexpAtomQueryParser.java
  21. 2 2
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/TermAtomQueryParser.java
  22. 2 2
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/TermsAtomQueryParser.java
  23. 2 2
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/WildcardAtomQueryParser.java
  24. 25 62
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/QueryOrderConditionParser.java
  25. 45 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/AbstractMethodSortParser.java
  26. 7 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/ConditionSortBuilder.java
  27. 11 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/MethodSortParser.java
  28. 87 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/NvlMethodSortParser.java
  29. 41 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/ParseSortBuilderHelper.java
  30. 58 0
      elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/ScriptMethodSortParser.java
  31. 24 0
      elasticsearch-query-core/src/test/java/org/es/test/query/SqlParserOrderByTest.java
  32. 1 1
      elasticsearch-query-jdbc/src/test/java/org/es/test/jdbc/BaseJdbcTest.java
  33. 1 1
      elasticsearch-query-spring/src/test/resources/application-context.xml

+ 2 - 2
README.md

@@ -72,12 +72,12 @@ SearchResponse response = searchReq.execute().actionGet();
 ## 二、集成MyBatis、Spring
 首先在Spring配置文件中增加如下代码
 1. 指定driverClassName:org.elasticsearch.jdbc.api.ElasticDriver
-2. 指定连接ES的连接串:jdbc:elastic:192.168.0.109:9300/product_cluster
+2. 指定连接ES的连接串:jdbc:elastic:192.168.0.108:9300/product_cluster
 3. 创建一个SqlMapClient对象,并指定sqlMapConfig.xml路径
 ```bash
 <bean id="elasticDataSource" class="org.es.jdbc.api.ElasticSingleConnectionDataSource" destroy-method="destroy">
     <property name="driverClassName" value="org.es.jdbc.api.ElasticDriver" />
-    <property name="url" value="jdbc:elastic:192.168.0.109:9300/lu-search-cluster" />
+    <property name="url" value="jdbc:elastic:192.168.0.108:9300/lu-search-cluster" />
     <property name="suppressClose" value="true" />
 </bean>
 

+ 5 - 5
create_index.sh

@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
-curl -XDELETE 'http://192.168.0.109:9200/index/'
+curl -XDELETE 'http://192.168.0.108:9200/index/'
 
-curl -XPUT 'http://192.168.0.109:9200/index/' -d '{
+curl -XPUT 'http://192.168.0.108:9200/index/' -d '{
 	"settings": {
 		"index": {
 			"number_of_shards": 1,
@@ -55,7 +55,7 @@ curl -XPUT 'http://192.168.0.109:9200/index/' -d '{
 }'
 
 
-curl -XPUT 'http://192.168.0.109:9200/index/product/1' -d '{
+curl -XPUT 'http://192.168.0.108:9200/index/product/1' -d '{
 	"productName" : "iphone 6s",
 	"productCode" : "IP_6S",
 	"minPrice" : 2288.00,
@@ -78,7 +78,7 @@ curl -XPUT 'http://192.168.0.109:9200/index/product/1' -d '{
 	}]
 }'
 
-curl -XPUT 'http://192.168.0.109:9200/index/product/2' -d '{
+curl -XPUT 'http://192.168.0.108:9200/index/product/2' -d '{
 	"productName" : "apple watch os2",
 	"productCode" : "AW_OS2",
 	"minPrice" : 1000.00,
@@ -101,4 +101,4 @@ curl -XPUT 'http://192.168.0.109:9200/index/product/2' -d '{
 	}]
 }'
 
-curl -XPOST 'http://192.168.0.109:9200/index/_refresh'
+curl -XPOST 'http://192.168.0.108:9200/index/_refresh'

+ 4 - 37
elasticsearch-query-core/src/main/java/org/es/sql/dsl/helper/ElasticSqlMethodInvokeHelper.java

@@ -1,18 +1,19 @@
 package org.es.sql.dsl.helper;
 
 import com.alibaba.druid.sql.ast.SQLExpr;
-import com.alibaba.druid.sql.ast.expr.*;
+import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
+import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
+import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
+import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
 import com.google.common.collect.ImmutableList;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
-import org.es.sql.dsl.enums.SortOption;
 import org.es.sql.dsl.exception.ElasticSql2DslException;
 
 import java.util.List;
 
 public class ElasticSqlMethodInvokeHelper {
     public static final List<String> DATE_METHOD = ImmutableList.of("date", "to_date", "toDate");
-    public static final List<String> NVL_METHOD = ImmutableList.of("nvl", "is_null", "isnull");
 
     public static final List<String> AGG_TERMS_METHOD = ImmutableList.of("terms", "terms_agg");
     public static final List<String> AGG_RANGE_METHOD = ImmutableList.of("range", "range_agg");
@@ -90,38 +91,4 @@ public class ElasticSqlMethodInvokeHelper {
             throw new ElasticSql2DslException("[syntax error] The second arg of date method should be a string of time");
         }
     }
-
-    public static void checkNvlMethod(SQLMethodInvokeExpr nvlInvokeExpr) {
-        if (!isMethodOf(NVL_METHOD, nvlInvokeExpr.getMethodName())) {
-            throw new ElasticSql2DslException("[syntax error] Sql sort condition only support nvl method invoke");
-        }
-
-        if (CollectionUtils.isEmpty(nvlInvokeExpr.getParameters()) || nvlInvokeExpr.getParameters().size() > 3) {
-            throw new ElasticSql2DslException(String.format("[syntax error] There is no %s args method named nvl",
-                    nvlInvokeExpr.getParameters() != null ? nvlInvokeExpr.getParameters().size() : 0));
-        }
-
-        SQLExpr fieldArg = nvlInvokeExpr.getParameters().get(0);
-        SQLExpr valueArg = nvlInvokeExpr.getParameters().get(1);
-
-        if (!(fieldArg instanceof SQLPropertyExpr) && !(fieldArg instanceof SQLIdentifierExpr)) {
-            throw new ElasticSql2DslException("[syntax error] The first arg of nvl method should be field param name");
-        }
-
-        if (!(valueArg instanceof SQLCharExpr) && !(valueArg instanceof SQLIntegerExpr) && !(valueArg instanceof SQLNumberExpr)) {
-            throw new ElasticSql2DslException("[syntax error] The second arg of nvl method should be number or string");
-        }
-
-        if (nvlInvokeExpr.getParameters().size() == 3) {
-            SQLExpr sortModArg = nvlInvokeExpr.getParameters().get(2);
-            if (!(sortModArg instanceof SQLCharExpr)) {
-                throw new ElasticSql2DslException("[syntax error] The third arg of nvl method should be string");
-            }
-            String sortModeText = ((SQLCharExpr) sortModArg).getText();
-            if (!SortOption.AVG.mode().equalsIgnoreCase(sortModeText) && !SortOption.MIN.mode().equalsIgnoreCase(sortModeText)
-                    && !SortOption.MAX.mode().equalsIgnoreCase(sortModeText) && !SortOption.SUM.mode().equalsIgnoreCase(sortModeText)) {
-                throw new ElasticSql2DslException("[syntax error] The third arg of nvl method should be one of the string[min,max,avg,sum]");
-            }
-        }
-    }
 }

+ 3 - 5
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/AbstractFieldSpecificMethodQueryParser.java

@@ -1,17 +1,17 @@
 package org.es.sql.dsl.parser.query.method;
 
-import com.alibaba.druid.sql.ast.SQLExpr;
+import org.elasticsearch.index.query.QueryBuilder;
 import org.es.sql.dsl.bean.AtomQuery;
 import org.es.sql.dsl.bean.ElasticSqlQueryField;
 import org.es.sql.dsl.enums.QueryFieldType;
 import org.es.sql.dsl.exception.ElasticSql2DslException;
 import org.es.sql.dsl.listener.ParseActionListener;
+import org.es.sql.dsl.parser.query.method.expr.FieldSpecificMethodExpression;
 import org.es.sql.dsl.parser.sql.QueryFieldParser;
-import org.elasticsearch.index.query.QueryBuilder;
 
 import java.util.Map;
 
-public abstract class AbstractFieldSpecificMethodQueryParser extends ParameterizedMethodQueryParser {
+public abstract class AbstractFieldSpecificMethodQueryParser extends ParameterizedMethodQueryParser implements FieldSpecificMethodExpression {
 
     protected ParseActionListener parseActionListener;
 
@@ -21,8 +21,6 @@ public abstract class AbstractFieldSpecificMethodQueryParser extends Parameteriz
 
     protected abstract QueryBuilder buildQuery(MethodInvocation invocation, String fieldName, Map<String, String> extraParams);
 
-    protected abstract SQLExpr defineFieldExpr(MethodInvocation invocation);
-
     @Override
     protected String defineExtraParamString(MethodInvocation invocation) {
         //ignore extra params, subclass can override if necessary

+ 0 - 28
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/CheckableMethodQueryParser.java

@@ -1,28 +0,0 @@
-package org.es.sql.dsl.parser.query.method;
-
-import org.es.sql.dsl.bean.AtomQuery;
-import org.es.sql.dsl.exception.ElasticSql2DslException;
-import org.es.sql.dsl.helper.ElasticSqlMethodInvokeHelper;
-
-public abstract class CheckableMethodQueryParser implements MethodQueryParser {
-
-    protected abstract void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException;
-
-    protected abstract AtomQuery parseMethodQueryWithCheck(MethodInvocation invocation) throws ElasticSql2DslException;
-
-    @Override
-    public boolean isMatchMethodInvocation(MethodInvocation invocation) {
-        return ElasticSqlMethodInvokeHelper.isMethodOf(defineMethodNames(), invocation.getMethodName());
-    }
-
-    @Override
-    public AtomQuery parseAtomMethodQuery(MethodInvocation invocation) throws ElasticSql2DslException {
-        if (!isMatchMethodInvocation(invocation)) {
-            throw new ElasticSql2DslException(
-                    String.format("[syntax error] Expected method name is one of [%s],but get [%s]",
-                            defineMethodNames(), invocation.getMethodName()));
-        }
-        checkMethodInvokeArgs(invocation);
-        return parseMethodQueryWithCheck(invocation);
-    }
-}

+ 1 - 1
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/MethodInvocation.java

@@ -40,7 +40,7 @@ public class MethodInvocation {
         return methodInvokeExpr.getParameters().size();
     }
 
-    public SQLExpr getFirstParameter(int index) {
+    public SQLExpr getFirstParameter() {
         return getParameter(0);
     }
 

+ 2 - 8
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/MethodQueryParser.java

@@ -2,14 +2,8 @@ package org.es.sql.dsl.parser.query.method;
 
 import org.es.sql.dsl.bean.AtomQuery;
 import org.es.sql.dsl.exception.ElasticSql2DslException;
+import org.es.sql.dsl.parser.query.method.expr.MethodExpression;
 
-import java.util.List;
-
-public interface MethodQueryParser {
-
-    List<String> defineMethodNames();
-
-    boolean isMatchMethodInvocation(MethodInvocation invocation);
-
+public interface MethodQueryParser extends MethodExpression {
     AtomQuery parseAtomMethodQuery(MethodInvocation invocation) throws ElasticSql2DslException;
 }

+ 14 - 40
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/ParameterizedMethodQueryParser.java

@@ -1,18 +1,13 @@
 package org.es.sql.dsl.parser.query.method;
 
-import com.google.common.collect.Maps;
-import org.apache.commons.lang.StringUtils;
 import org.es.sql.dsl.bean.AtomQuery;
 import org.es.sql.dsl.exception.ElasticSql2DslException;
+import org.es.sql.dsl.helper.ElasticSqlMethodInvokeHelper;
+import org.es.sql.dsl.parser.query.method.expr.AbstractParameterizedMethodExpression;
 
-import java.util.Collections;
 import java.util.Map;
 
-public abstract class ParameterizedMethodQueryParser extends CheckableMethodQueryParser {
-
-    protected static final String COMMA = ",";
-
-    protected static final String COLON = ":";
+public abstract class ParameterizedMethodQueryParser extends AbstractParameterizedMethodExpression implements MethodQueryParser {
 
     protected abstract String defineExtraParamString(MethodInvocation invocation);
 
@@ -20,41 +15,20 @@ public abstract class ParameterizedMethodQueryParser extends CheckableMethodQuer
             MethodInvocation invocation, Map<String, String> extraParamMap) throws ElasticSql2DslException;
 
     @Override
-    protected AtomQuery parseMethodQueryWithCheck(MethodInvocation invocation) {
-        Map<String, String> extraParamMap = buildExtraParamMap(invocation);
-        return parseMethodQueryWithExtraParams(invocation, extraParamMap);
+    public boolean isMatchMethodInvocation(MethodInvocation invocation) {
+        return ElasticSqlMethodInvokeHelper.isMethodOf(defineMethodNames(), invocation.getMethodName());
     }
 
-    private Map<String, String> buildExtraParamMap(MethodInvocation invocation) {
-        String extraParamString = defineExtraParamString(invocation);
-
-        if (StringUtils.isBlank(extraParamString)) {
-            return Collections.emptyMap();
-        }
-
-        Map<String, String> extraParamMap = Maps.newHashMap();
-        for (String paramPair : extraParamString.split(COMMA)) {
-            String[] paramPairArr = paramPair.split(COLON);
-            if (paramPairArr.length == 2) {
-                extraParamMap.put(paramPairArr[0].trim(), paramPairArr[1].trim());
-            }
-            else {
-                throw new ElasticSql2DslException("Failed to parse query method extra param string!");
-            }
+    @Override
+    public AtomQuery parseAtomMethodQuery(MethodInvocation invocation) throws ElasticSql2DslException {
+        if (!isMatchMethodInvocation(invocation)) {
+            throw new ElasticSql2DslException(
+                    String.format("[syntax error] Expected method name is one of [%s],but get [%s]",
+                            defineMethodNames(), invocation.getMethodName()));
         }
-        return extraParamMap;
-    }
+        checkMethodInvocation(invocation);
 
-    protected Boolean isExtraParamsString(String extraParams) {
-        if (StringUtils.isBlank(extraParams)) {
-            return Boolean.FALSE;
-        }
-        for (String paramPair : extraParams.split(COMMA)) {
-            String[] paramPairArr = paramPair.split(COLON);
-            if (paramPairArr.length != 2) {
-                return Boolean.FALSE;
-            }
-        }
-        return Boolean.TRUE;
+        Map<String, String> extraParamMap = generateParameterMap(invocation);
+        return parseMethodQueryWithExtraParams(invocation, extraParamMap);
     }
 }

+ 67 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/expr/AbstractParameterizedMethodExpression.java

@@ -0,0 +1,67 @@
+package org.es.sql.dsl.parser.query.method.expr;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.es.sql.dsl.exception.ElasticSql2DslException;
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+
+import java.util.Collections;
+import java.util.Map;
+
+public abstract class AbstractParameterizedMethodExpression implements ParameterizedMethodExpression {
+
+    protected static final String COMMA = ",";
+
+    protected static final String COLON = ":";
+
+    protected abstract String defineExtraParamString(MethodInvocation invocation);
+
+    public Map<String, String> generateParameterMap(MethodInvocation invocation) {
+        String extraParamString = defineExtraParamString(invocation);
+
+        if (StringUtils.isBlank(extraParamString)) {
+            return Collections.emptyMap();
+        }
+
+        Map<String, String> extraParamMap = Maps.newHashMap();
+        for (String paramPair : extraParamString.split(COMMA)) {
+            String[] paramPairArr = paramPair.split(COLON);
+            if (paramPairArr.length == 2) {
+                extraParamMap.put(paramPairArr[0].trim(), paramPairArr[1].trim());
+            }
+            else {
+                throw new ElasticSql2DslException("Failed to parse query method extra param string!");
+            }
+        }
+        return extraParamMap;
+    }
+
+    public Map<String, Object> generateRawTypeParameterMap(MethodInvocation invocation) {
+        Map<String, String> extraParamMap = generateParameterMap(invocation);
+        if (MapUtils.isNotEmpty(extraParamMap)) {
+            return Maps.transformEntries(extraParamMap, new Maps.EntryTransformer<String, String, Object>() {
+                @Override
+                public Object transformEntry(String key, String value) {
+                    return NumberUtils.isNumber(value) ? NumberUtils.createNumber(value) : value;
+                }
+            });
+        }
+
+        return Collections.emptyMap();
+    }
+
+    protected Boolean isExtraParamsString(String extraParams) {
+        if (StringUtils.isBlank(extraParams)) {
+            return Boolean.FALSE;
+        }
+        for (String paramPair : extraParams.split(COMMA)) {
+            String[] paramPairArr = paramPair.split(COLON);
+            if (paramPairArr.length != 2) {
+                return Boolean.FALSE;
+            }
+        }
+        return Boolean.TRUE;
+    }
+}

+ 8 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/expr/FieldSpecificMethodExpression.java

@@ -0,0 +1,8 @@
+package org.es.sql.dsl.parser.query.method.expr;
+
+import com.alibaba.druid.sql.ast.SQLExpr;
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+
+public interface FieldSpecificMethodExpression extends MethodExpression {
+    SQLExpr defineFieldExpr(MethodInvocation invocation);
+}

+ 14 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/expr/MethodExpression.java

@@ -0,0 +1,14 @@
+package org.es.sql.dsl.parser.query.method.expr;
+
+import org.es.sql.dsl.exception.ElasticSql2DslException;
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+
+import java.util.List;
+
+public interface MethodExpression {
+    List<String> defineMethodNames();
+
+    boolean isMatchMethodInvocation(MethodInvocation invocation);
+
+    void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException;
+}

+ 9 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/expr/ParameterizedMethodExpression.java

@@ -0,0 +1,9 @@
+package org.es.sql.dsl.parser.query.method.expr;
+
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+
+import java.util.Map;
+
+public interface ParameterizedMethodExpression extends MethodExpression {
+    Map<String, String> generateParameterMap(MethodInvocation methodInvocation);
+}

+ 2 - 2
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/fulltext/MatchAtomQueryParser.java

@@ -47,12 +47,12 @@ public class MatchAtomQueryParser extends AbstractFieldSpecificMethodQueryParser
     }
 
     @Override
-    protected SQLExpr defineFieldExpr(MethodInvocation invocation) {
+    public SQLExpr defineFieldExpr(MethodInvocation invocation) {
         return invocation.getParameter(0);
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException {
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
         if (invocation.getParameterCount() != 2 && invocation.getParameterCount() != 3) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",

+ 1 - 1
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/fulltext/MultiMatchAtomQueryParser.java

@@ -44,7 +44,7 @@ public class MultiMatchAtomQueryParser extends ParameterizedMethodQueryParser {
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException {
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
         if (invocation.getParameterCount() != 2 && invocation.getParameterCount() != 3) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",

+ 10 - 10
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/fulltext/QueryStringAtomQueryParser.java

@@ -38,18 +38,18 @@ public class QueryStringAtomQueryParser extends ParameterizedMethodQueryParser {
         String queryFields = null;
         if (invocation.getParameterCount() == 3) {
             queryFields = invocation.getParameterAsString(1);
-        }
 
-        if (StringUtils.isNotBlank(queryFields)) {
-            String[] tArr = queryFields.split(COLON);
-            if ("fields".equalsIgnoreCase(tArr[0])) {
-                for (String fieldItem : tArr[1].split(COMMA)) {
-                    queryStringQuery.field(fieldItem);
+            if (StringUtils.isNotBlank(queryFields)) {
+                String[] tArr = queryFields.split(COLON);
+                if ("fields".equalsIgnoreCase(tArr[0])) {
+                    for (String fieldItem : tArr[1].split(COMMA)) {
+                        queryStringQuery.field(fieldItem);
+                    }
                 }
-            }
 
-            if ("default_field".equalsIgnoreCase(tArr[0])) {
-                queryStringQuery.defaultField(tArr[1]);
+                if ("default_field".equalsIgnoreCase(tArr[0])) {
+                    queryStringQuery.defaultField(tArr[1]);
+                }
             }
         }
 
@@ -58,7 +58,7 @@ public class QueryStringAtomQueryParser extends ParameterizedMethodQueryParser {
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException {
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
         int paramCount = invocation.getParameterCount();
         if (paramCount != 1 && paramCount != 2 && paramCount != 3) {
             throw new ElasticSql2DslException(

+ 10 - 10
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/fulltext/SimpleQueryStringAtomQueryParser.java

@@ -33,19 +33,19 @@ public class SimpleQueryStringAtomQueryParser extends ParameterizedMethodQueryPa
 
     @Override
     protected AtomQuery parseMethodQueryWithExtraParams(MethodInvocation invocation, Map<String, String> extraParamMap) throws ElasticSql2DslException {
+        String text = invocation.getParameterAsString(0);
+        SimpleQueryStringBuilder simpleQueryString = QueryBuilders.simpleQueryStringQuery(text);
+
         String queryFields = null;
         if (invocation.getParameterCount() == 3) {
             queryFields = invocation.getParameterAsString(1);
-        }
-
-        String text = invocation.getParameterAsString(0);
-        SimpleQueryStringBuilder simpleQueryString = QueryBuilders.simpleQueryStringQuery(text);
 
-        if (StringUtils.isNotBlank(queryFields)) {
-            String[] tArr = queryFields.split(COLON);
-            if ("fields".equalsIgnoreCase(tArr[0])) {
-                for (String fieldItem : tArr[1].split(COMMA)) {
-                    simpleQueryString.field(fieldItem);
+            if (StringUtils.isNotBlank(queryFields)) {
+                String[] tArr = queryFields.split(COLON);
+                if ("fields".equalsIgnoreCase(tArr[0])) {
+                    for (String fieldItem : tArr[1].split(COMMA)) {
+                        simpleQueryString.field(fieldItem);
+                    }
                 }
             }
         }
@@ -58,7 +58,7 @@ public class SimpleQueryStringAtomQueryParser extends ParameterizedMethodQueryPa
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException {
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
         int paramCount = invocation.getParameterCount();
         if (paramCount != 1 && paramCount != 2 && paramCount != 3) {
             throw new ElasticSql2DslException(

+ 5 - 14
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/script/ScriptAtomQueryParser.java

@@ -1,19 +1,15 @@
 package org.es.sql.dsl.parser.query.method.script;
 
-import com.alibaba.druid.sql.ast.SQLExpr;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.math.NumberUtils;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.script.Script;
+import org.elasticsearch.script.ScriptService;
 import org.es.sql.dsl.bean.AtomQuery;
 import org.es.sql.dsl.exception.ElasticSql2DslException;
-import org.es.sql.dsl.helper.ElasticSqlArgTransferHelper;
 import org.es.sql.dsl.parser.query.method.MethodInvocation;
 import org.es.sql.dsl.parser.query.method.ParameterizedMethodQueryParser;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.script.Script;
-import org.elasticsearch.script.ScriptService;
 
 import java.util.List;
 import java.util.Map;
@@ -36,7 +32,7 @@ public class ScriptAtomQueryParser extends ParameterizedMethodQueryParser {
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException {
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
         if (invocation.getParameterCount() != 1 && invocation.getParameterCount() != 2) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",
@@ -54,12 +50,7 @@ public class ScriptAtomQueryParser extends ParameterizedMethodQueryParser {
         String script = invocation.getParameterAsString(0);
 
         if (MapUtils.isNotEmpty(extraParamMap)) {
-            Map<String, Object> scriptParamMap = Maps.transformEntries(extraParamMap, new Maps.EntryTransformer<String, String, Object>() {
-                @Override
-                public Object transformEntry(String key, String value) {
-                    return NumberUtils.isNumber(value) ? NumberUtils.createNumber(value) : value;
-                }
-            });
+            Map<String, Object> scriptParamMap = generateRawTypeParameterMap(invocation);
             return new AtomQuery(QueryBuilders.scriptQuery(new Script(script, ScriptService.ScriptType.INLINE, null, scriptParamMap)));
         }
         return new AtomQuery(QueryBuilders.scriptQuery(new Script(script)));

+ 2 - 2
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/FuzzyAtomQueryParser.java

@@ -30,7 +30,7 @@ public class FuzzyAtomQueryParser extends AbstractFieldSpecificMethodQueryParser
     }
 
     @Override
-    protected SQLExpr defineFieldExpr(MethodInvocation invocation) {
+    public SQLExpr defineFieldExpr(MethodInvocation invocation) {
         return invocation.getParameter(0);
     }
 
@@ -43,7 +43,7 @@ public class FuzzyAtomQueryParser extends AbstractFieldSpecificMethodQueryParser
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) {
+    public void checkMethodInvocation(MethodInvocation invocation) {
         if (invocation.getParameterCount() != 2 && invocation.getParameterCount() != 3) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",

+ 5 - 5
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/PrefixAtomQueryParser.java

@@ -4,13 +4,13 @@ import com.alibaba.druid.sql.ast.SQLExpr;
 import com.google.common.collect.ImmutableList;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
+import org.elasticsearch.index.query.PrefixQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
 import org.es.sql.dsl.exception.ElasticSql2DslException;
 import org.es.sql.dsl.listener.ParseActionListener;
 import org.es.sql.dsl.parser.query.method.AbstractFieldSpecificMethodQueryParser;
 import org.es.sql.dsl.parser.query.method.MethodInvocation;
-import org.elasticsearch.index.query.PrefixQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
 
 import java.util.List;
 import java.util.Map;
@@ -29,7 +29,7 @@ public class PrefixAtomQueryParser extends AbstractFieldSpecificMethodQueryParse
     }
 
     @Override
-    protected SQLExpr defineFieldExpr(MethodInvocation invocation) {
+    public SQLExpr defineFieldExpr(MethodInvocation invocation) {
         return invocation.getParameter(0);
     }
 
@@ -42,7 +42,7 @@ public class PrefixAtomQueryParser extends AbstractFieldSpecificMethodQueryParse
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) {
+    public void checkMethodInvocation(MethodInvocation invocation) {
         if (invocation.getParameterCount() != 2 && invocation.getParameterCount() != 3) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",

+ 2 - 2
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/RegexpAtomQueryParser.java

@@ -31,7 +31,7 @@ public class RegexpAtomQueryParser extends AbstractFieldSpecificMethodQueryParse
     }
 
     @Override
-    protected SQLExpr defineFieldExpr(MethodInvocation invocation) {
+    public SQLExpr defineFieldExpr(MethodInvocation invocation) {
         return invocation.getParameter(0);
     }
 
@@ -44,7 +44,7 @@ public class RegexpAtomQueryParser extends AbstractFieldSpecificMethodQueryParse
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException {
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
         if (invocation.getParameterCount() != 2 && invocation.getParameterCount() != 3) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",

+ 2 - 2
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/TermAtomQueryParser.java

@@ -29,7 +29,7 @@ public class TermAtomQueryParser extends AbstractFieldSpecificMethodQueryParser
     }
 
     @Override
-    protected SQLExpr defineFieldExpr(MethodInvocation invocation) {
+    public SQLExpr defineFieldExpr(MethodInvocation invocation) {
         return invocation.getParameter(0);
     }
 
@@ -42,7 +42,7 @@ public class TermAtomQueryParser extends AbstractFieldSpecificMethodQueryParser
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException {
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
         if (invocation.getParameterCount() != 2 && invocation.getParameterCount() != 3) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",

+ 2 - 2
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/TermsAtomQueryParser.java

@@ -30,7 +30,7 @@ public class TermsAtomQueryParser extends AbstractFieldSpecificMethodQueryParser
     }
 
     @Override
-    protected SQLExpr defineFieldExpr(MethodInvocation invocation) {
+    public SQLExpr defineFieldExpr(MethodInvocation invocation) {
         return invocation.getParameter(0);
     }
 
@@ -44,7 +44,7 @@ public class TermsAtomQueryParser extends AbstractFieldSpecificMethodQueryParser
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) {
+    public void checkMethodInvocation(MethodInvocation invocation) {
         if (invocation.getParameterCount() <= 1) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",

+ 2 - 2
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/query/method/term/WildcardAtomQueryParser.java

@@ -37,12 +37,12 @@ public class WildcardAtomQueryParser extends AbstractFieldSpecificMethodQueryPar
     }
 
     @Override
-    protected SQLExpr defineFieldExpr(MethodInvocation invocation) {
+    public SQLExpr defineFieldExpr(MethodInvocation invocation) {
         return invocation.getParameter(0);
     }
 
     @Override
-    protected void checkMethodInvokeArgs(MethodInvocation invocation) throws ElasticSql2DslException {
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
         if (invocation.getParameterCount() != 2 && invocation.getParameterCount() != 3) {
             throw new ElasticSql2DslException(
                     String.format("[syntax error] There's no %s args method named [%s].",

+ 25 - 62
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/QueryOrderConditionParser.java

@@ -8,6 +8,7 @@ import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
 import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
 import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
 import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import org.apache.commons.collections.CollectionUtils;
 import org.es.sql.druid.ElasticSqlSelectQueryBlock;
@@ -23,6 +24,8 @@ import org.elasticsearch.search.sort.FieldSortBuilder;
 import org.elasticsearch.search.sort.SortBuilder;
 import org.elasticsearch.search.sort.SortBuilders;
 import org.elasticsearch.search.sort.SortOrder;
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+import org.es.sql.dsl.parser.sql.sort.*;
 
 import java.util.List;
 
@@ -30,8 +33,15 @@ public class QueryOrderConditionParser implements QueryParser {
 
     private ParseActionListener parseActionListener;
 
+    private List<MethodSortParser> methodSortParsers;
+
     public QueryOrderConditionParser(ParseActionListener parseActionListener) {
         this.parseActionListener = parseActionListener;
+
+        methodSortParsers = ImmutableList.of(
+                new NvlMethodSortParser(),
+                new ScriptMethodSortParser()
+        );
     }
 
     @Override
@@ -51,76 +61,29 @@ public class QueryOrderConditionParser implements QueryParser {
     }
 
     private SortBuilder parseOrderCondition(SQLSelectOrderByItem orderByItem, String queryAs, Object[] sqlArgs) {
-        if (orderByItem.getExpr() instanceof SQLPropertyExpr || orderByItem.getExpr() instanceof SQLIdentifierExpr) {
-            return parseCondition(orderByItem.getExpr(), queryAs, new ConditionSortBuilder() {
+
+        SortOrder order = orderByItem.getType() == SQLOrderingSpecification.ASC ? SortOrder.ASC : SortOrder.DESC;
+
+        if (ParseSortBuilderHelper.isFieldExpr(orderByItem.getExpr())) {
+            QueryFieldParser fieldParser = new QueryFieldParser();
+            ElasticSqlQueryField sortField = fieldParser.parseConditionQueryField(orderByItem.getExpr(), queryAs);
+            return ParseSortBuilderHelper.parseBasedOnFieldSortBuilder(sortField, new ConditionSortBuilder() {
                 @Override
                 public FieldSortBuilder buildSort(String queryFieldName) {
-                    if (SQLOrderingSpecification.ASC == orderByItem.getType()) {
-                        return SortBuilders.fieldSort(queryFieldName).order(SortOrder.ASC);
-                    }
-                    else {
-                        return SortBuilders.fieldSort(queryFieldName).order(SortOrder.DESC);
-                    }
+                    return SortBuilders.fieldSort(queryFieldName).order(order);
                 }
             });
         }
-        if (orderByItem.getExpr() instanceof SQLMethodInvokeExpr) {
-            SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr) orderByItem.getExpr();
-            //nvl method
-            if (ElasticSqlMethodInvokeHelper.isMethodOf(ElasticSqlMethodInvokeHelper.NVL_METHOD, methodInvokeExpr.getMethodName())) {
-                ElasticSqlMethodInvokeHelper.checkNvlMethod(methodInvokeExpr);
-                Object valueArg = ElasticSqlArgTransferHelper.transferSqlArg(methodInvokeExpr.getParameters().get(1), sqlArgs);
-                return parseCondition(methodInvokeExpr.getParameters().get(0), queryAs, new ConditionSortBuilder() {
-                    @Override
-                    public FieldSortBuilder buildSort(String idfName) {
-                        FieldSortBuilder fieldSortBuilder = null;
-
-                        if (SQLOrderingSpecification.ASC == orderByItem.getType()) {
-                            fieldSortBuilder = SortBuilders.fieldSort(idfName).order(SortOrder.ASC).missing(valueArg);
-                        }
-                        else {
-                            fieldSortBuilder = SortBuilders.fieldSort(idfName).order(SortOrder.DESC).missing(valueArg);
-                        }
 
-                        if (methodInvokeExpr.getParameters().size() == 3) {
-                            SQLExpr sortModArg = methodInvokeExpr.getParameters().get(2);
-                            String sortModeText = ((SQLCharExpr) sortModArg).getText();
-                            fieldSortBuilder.sortMode(SortOption.get(sortModeText).mode());
-                        }
-
-                        return fieldSortBuilder;
-                    }
-                });
+        if (ParseSortBuilderHelper.isMethodInvokeExpr(orderByItem.getExpr())) {
+            MethodInvocation sortMethodInvocation = new MethodInvocation((SQLMethodInvokeExpr) orderByItem.getExpr(), queryAs, sqlArgs);
+            for (MethodSortParser methodSortParser : methodSortParsers) {
+                if (methodSortParser.isMatchMethodInvocation(sortMethodInvocation)) {
+                    return methodSortParser.parseMethodSortBuilder(sortMethodInvocation, order);
+                }
             }
         }
-        throw new ElasticSql2DslException("[syntax error] can not support sort type: " + orderByItem.getExpr().getClass());
-    }
-
-    private SortBuilder parseCondition(SQLExpr sqlExpr, String queryAs, ConditionSortBuilder sortBuilder) {
-        QueryFieldParser queryFieldParser = new QueryFieldParser();
-        ElasticSqlQueryField sortField = queryFieldParser.parseConditionQueryField(sqlExpr, queryAs);
-
-        SortBuilder rtnSortBuilder = null;
-        if (sortField.getQueryFieldType() == QueryFieldType.RootDocField || sortField.getQueryFieldType() == QueryFieldType.InnerDocField) {
-            rtnSortBuilder = sortBuilder.buildSort(sortField.getQueryFieldFullName());
-        }
-
-        if (sortField.getQueryFieldType() == QueryFieldType.NestedDocField) {
-            FieldSortBuilder originalSort = sortBuilder.buildSort(sortField.getQueryFieldFullName());
-            originalSort.setNestedPath(sortField.getNestedDocContextPath());
-            rtnSortBuilder = originalSort;
-        }
-
-        if (rtnSortBuilder == null) {
-            throw new ElasticSql2DslException(String.format("[syntax error] sort condition field can not support type[%s]", sortField.getQueryFieldType()));
-        }
-
-        return rtnSortBuilder;
-    }
 
-
-    @FunctionalInterface
-    private interface ConditionSortBuilder {
-        FieldSortBuilder buildSort(String idfName);
+        throw new ElasticSql2DslException("[syntax error] can not support sort type: " + orderByItem.getExpr().getClass());
     }
 }

+ 45 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/AbstractMethodSortParser.java

@@ -0,0 +1,45 @@
+package org.es.sql.dsl.parser.sql.sort;
+
+import org.apache.commons.lang.StringUtils;
+import org.elasticsearch.search.sort.SortBuilder;
+import org.elasticsearch.search.sort.SortOrder;
+import org.es.sql.dsl.exception.ElasticSql2DslException;
+import org.es.sql.dsl.helper.ElasticSqlMethodInvokeHelper;
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+import org.es.sql.dsl.parser.query.method.expr.AbstractParameterizedMethodExpression;
+
+import java.util.Map;
+
+public abstract class AbstractMethodSortParser extends AbstractParameterizedMethodExpression implements MethodSortParser {
+
+    protected abstract SortBuilder parseMethodSortBuilderWithExtraParams(
+            MethodInvocation invocation, SortOrder order, Map<String, Object> extraParamMap) throws ElasticSql2DslException;
+
+    @Override
+    protected String defineExtraParamString(MethodInvocation invocation) {
+        return StringUtils.EMPTY;
+    }
+
+    @Override
+    public void checkMethodInvocation(MethodInvocation invocation) throws ElasticSql2DslException {
+
+    }
+
+    @Override
+    public boolean isMatchMethodInvocation(MethodInvocation invocation) {
+        return ElasticSqlMethodInvokeHelper.isMethodOf(defineMethodNames(), invocation.getMethodName());
+    }
+
+    @Override
+    public SortBuilder parseMethodSortBuilder(MethodInvocation invocation, SortOrder order) throws ElasticSql2DslException {
+        if (!isMatchMethodInvocation(invocation)) {
+            throw new ElasticSql2DslException(
+                    String.format("[syntax error] Expected method name is one of [%s],but get [%s]",
+                            defineMethodNames(), invocation.getMethodName()));
+        }
+        checkMethodInvocation(invocation);
+
+        Map<String, Object> extraParamMap = generateRawTypeParameterMap(invocation);
+        return parseMethodSortBuilderWithExtraParams(invocation, order, extraParamMap);
+    }
+}

+ 7 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/ConditionSortBuilder.java

@@ -0,0 +1,7 @@
+package org.es.sql.dsl.parser.sql.sort;
+
+import org.elasticsearch.search.sort.FieldSortBuilder;
+
+public interface ConditionSortBuilder {
+    FieldSortBuilder buildSort(String idfName);
+}

+ 11 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/MethodSortParser.java

@@ -0,0 +1,11 @@
+package org.es.sql.dsl.parser.sql.sort;
+
+import org.elasticsearch.search.sort.SortBuilder;
+import org.elasticsearch.search.sort.SortOrder;
+import org.es.sql.dsl.exception.ElasticSql2DslException;
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+import org.es.sql.dsl.parser.query.method.expr.MethodExpression;
+
+public interface MethodSortParser extends MethodExpression {
+    SortBuilder parseMethodSortBuilder(MethodInvocation invocation, SortOrder order) throws ElasticSql2DslException;
+}

+ 87 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/NvlMethodSortParser.java

@@ -0,0 +1,87 @@
+package org.es.sql.dsl.parser.sql.sort;
+
+import com.alibaba.druid.sql.ast.SQLExpr;
+import com.alibaba.druid.sql.ast.expr.*;
+import com.google.common.collect.ImmutableList;
+import org.elasticsearch.search.sort.FieldSortBuilder;
+import org.elasticsearch.search.sort.SortBuilder;
+import org.elasticsearch.search.sort.SortBuilders;
+import org.elasticsearch.search.sort.SortOrder;
+import org.es.sql.dsl.bean.ElasticSqlQueryField;
+import org.es.sql.dsl.enums.SortOption;
+import org.es.sql.dsl.exception.ElasticSql2DslException;
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+import org.es.sql.dsl.parser.sql.QueryFieldParser;
+
+import java.util.List;
+import java.util.Map;
+
+public class NvlMethodSortParser extends AbstractMethodSortParser {
+
+    public static final List<String> NVL_METHOD = ImmutableList.of("nvl", "is_null", "isnull");
+
+    @Override
+    public List<String> defineMethodNames() {
+        return NVL_METHOD;
+    }
+
+    @Override
+    public void checkMethodInvocation(MethodInvocation nvlMethodInvocation) throws ElasticSql2DslException {
+        if (!isMatchMethodInvocation(nvlMethodInvocation)) {
+            throw new ElasticSql2DslException("[syntax error] Sql sort condition only support nvl method invoke");
+        }
+
+        int methodParameterCount = nvlMethodInvocation.getParameterCount();
+        if (methodParameterCount == 0 || methodParameterCount > 3) {
+            throw new ElasticSql2DslException(String.format("[syntax error] There is no %s args method named nvl", methodParameterCount));
+        }
+
+        SQLExpr fieldArg = nvlMethodInvocation.getParameter(0);
+        SQLExpr valueArg = nvlMethodInvocation.getParameter(1);
+
+        if (!(fieldArg instanceof SQLPropertyExpr) && !(fieldArg instanceof SQLIdentifierExpr)) {
+            throw new ElasticSql2DslException("[syntax error] The first arg of nvl method should be field param name");
+        }
+
+        if (!(valueArg instanceof SQLCharExpr) && !(valueArg instanceof SQLIntegerExpr) && !(valueArg instanceof SQLNumberExpr)) {
+            throw new ElasticSql2DslException("[syntax error] The second arg of nvl method should be number or string");
+        }
+
+        if (methodParameterCount == 3) {
+            SQLExpr sortModArg = nvlMethodInvocation.getParameter(2);
+            if (!(sortModArg instanceof SQLCharExpr)) {
+                throw new ElasticSql2DslException("[syntax error] The third arg of nvl method should be string");
+            }
+            String sortModeText = ((SQLCharExpr) sortModArg).getText();
+            if (!SortOption.AVG.mode().equalsIgnoreCase(sortModeText) && !SortOption.MIN.mode().equalsIgnoreCase(sortModeText)
+                    && !SortOption.MAX.mode().equalsIgnoreCase(sortModeText) && !SortOption.SUM.mode().equalsIgnoreCase(sortModeText)) {
+                throw new ElasticSql2DslException("[syntax error] The third arg of nvl method should be one of the string[min,max,avg,sum]");
+            }
+        }
+    }
+
+    @Override
+    protected SortBuilder parseMethodSortBuilderWithExtraParams(
+            MethodInvocation sortMethodInvocation, SortOrder order, Map<String, Object> extraParamMap) throws ElasticSql2DslException {
+
+        String queryAs = sortMethodInvocation.getQueryAs();
+        SQLExpr fieldExpr = sortMethodInvocation.getParameter(0);
+        Object valueArg = sortMethodInvocation.getParameterAsObject(1);
+
+        QueryFieldParser queryFieldParser = new QueryFieldParser();
+        ElasticSqlQueryField sortField = queryFieldParser.parseConditionQueryField(fieldExpr, queryAs);
+
+        return ParseSortBuilderHelper.parseBasedOnFieldSortBuilder(sortField, new ConditionSortBuilder() {
+            @Override
+            public FieldSortBuilder buildSort(String idfName) {
+                FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort(idfName).order(order).missing(valueArg);
+
+                if (sortMethodInvocation.getParameterCount() == 3) {
+                    String sortModeText = sortMethodInvocation.getParameterAsString(2);
+                    fieldSortBuilder.sortMode(SortOption.get(sortModeText).mode());
+                }
+                return fieldSortBuilder;
+            }
+        });
+    }
+}

+ 41 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/ParseSortBuilderHelper.java

@@ -0,0 +1,41 @@
+package org.es.sql.dsl.parser.sql.sort;
+
+import com.alibaba.druid.sql.ast.SQLExpr;
+import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
+import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
+import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
+import org.elasticsearch.search.sort.FieldSortBuilder;
+import org.elasticsearch.search.sort.SortBuilder;
+import org.es.sql.dsl.bean.ElasticSqlQueryField;
+import org.es.sql.dsl.enums.QueryFieldType;
+import org.es.sql.dsl.exception.ElasticSql2DslException;
+
+public class ParseSortBuilderHelper {
+
+    public static boolean isFieldExpr(SQLExpr expr) {
+        return expr instanceof SQLPropertyExpr || expr instanceof SQLIdentifierExpr;
+    }
+
+    public static boolean isMethodInvokeExpr(SQLExpr expr) {
+        return expr instanceof SQLMethodInvokeExpr;
+    }
+
+    public static SortBuilder parseBasedOnFieldSortBuilder(ElasticSqlQueryField sortField, ConditionSortBuilder sortBuilder) {
+        SortBuilder rtnSortBuilder = null;
+        if (sortField.getQueryFieldType() == QueryFieldType.RootDocField || sortField.getQueryFieldType() == QueryFieldType.InnerDocField) {
+            rtnSortBuilder = sortBuilder.buildSort(sortField.getQueryFieldFullName());
+        }
+
+        if (sortField.getQueryFieldType() == QueryFieldType.NestedDocField) {
+            FieldSortBuilder originalSort = sortBuilder.buildSort(sortField.getQueryFieldFullName());
+            originalSort.setNestedPath(sortField.getNestedDocContextPath());
+            rtnSortBuilder = originalSort;
+        }
+
+        if (rtnSortBuilder == null) {
+            throw new ElasticSql2DslException(String.format("[syntax error] sort condition field can not support type[%s]", sortField.getQueryFieldType()));
+        }
+
+        return rtnSortBuilder;
+    }
+}

+ 58 - 0
elasticsearch-query-core/src/main/java/org/es/sql/dsl/parser/sql/sort/ScriptMethodSortParser.java

@@ -0,0 +1,58 @@
+package org.es.sql.dsl.parser.sql.sort;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+import org.elasticsearch.search.sort.SortBuilder;
+import org.elasticsearch.search.sort.SortBuilders;
+import org.elasticsearch.search.sort.SortOrder;
+import org.es.sql.dsl.exception.ElasticSql2DslException;
+import org.es.sql.dsl.parser.query.method.MethodInvocation;
+
+import java.util.List;
+import java.util.Map;
+
+public class ScriptMethodSortParser extends AbstractMethodSortParser {
+
+    public static final List<String> SCRIPT_SORT_METHOD = ImmutableList.of("script_sort", "scriptSort");
+
+    @Override
+    public List<String> defineMethodNames() {
+        return SCRIPT_SORT_METHOD;
+    }
+
+    @Override
+    protected String defineExtraParamString(MethodInvocation invocation) {
+        if (invocation.getParameterCount() == 3) {
+            return invocation.getParameterAsString(2);
+        }
+        return StringUtils.EMPTY;
+    }
+
+    @Override
+    public void checkMethodInvocation(MethodInvocation nvlMethodInvocation) throws ElasticSql2DslException {
+        if (!isMatchMethodInvocation(nvlMethodInvocation)) {
+            throw new ElasticSql2DslException("[syntax error] Sql sort condition only support script_query method invoke");
+        }
+
+        int methodParameterCount = nvlMethodInvocation.getParameterCount();
+        if (methodParameterCount != 2 && methodParameterCount != 3) {
+            throw new ElasticSql2DslException(String.format("[syntax error] There is no %s args method named script_sort", methodParameterCount));
+        }
+    }
+
+    @Override
+    protected SortBuilder parseMethodSortBuilderWithExtraParams(
+            MethodInvocation scriptSortMethodInvocation, SortOrder order, Map<String, Object> extraParamMap) throws ElasticSql2DslException {
+
+        String script = scriptSortMethodInvocation.getParameterAsString(0);
+        String type = scriptSortMethodInvocation.getParameterAsString(1);
+
+        if (MapUtils.isNotEmpty(extraParamMap)) {
+            Map<String, Object> scriptParamMap = generateRawTypeParameterMap(scriptSortMethodInvocation);
+            return SortBuilders.scriptSort(script, type).order(order).setParams(scriptParamMap);
+        }
+
+        return SortBuilders.scriptSort(script, type).order(order);
+    }
+}

+ 24 - 0
elasticsearch-query-core/src/test/java/org/es/test/query/SqlParserOrderByTest.java

@@ -1,7 +1,9 @@
 package org.es.test.query;
 
+import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.es.sql.dsl.bean.ElasticSqlParseResult;
 import org.es.sql.dsl.parser.ElasticSql2DslParser;
+import org.es.sql.utils.ElasticMockClient;
 import org.junit.Test;
 
 
@@ -59,4 +61,26 @@ public class SqlParserOrderByTest {
 //        targetSort = SortBuilders.fieldSort("productTags.sortNo").order(SortOrder.DESC).setNestedPath("productTags");
 //        Assert.assertEquals(parseResult.getOrderBy().get(1).toString(), targetSort.toString());
     }
+
+    @Test
+    public void testX() {
+        ElasticMockClient esClient = new ElasticMockClient();
+
+        String sql = "select * from index.order where status='SUCCESS' order by nvl(pride, 0) asc, script_sort('doc[\"price\"].value * 1.5 / vp', 'number', 'vp:2.1') desc routing by 'CA','CB' limit 0, 20";
+
+        ElasticSql2DslParser sql2DslParser = new ElasticSql2DslParser();
+        //解析SQL
+        ElasticSqlParseResult parseResult = sql2DslParser.parse(sql);
+
+        //生成DSL,可用于rest api调用
+        String dsl = parseResult.toDsl();
+
+        //toRequest方法接收一个client对象参数,用于生成SearchRequestBuilder
+        SearchRequestBuilder searchReq = parseResult.toRequest(esClient);
+
+        //执行查询
+        //SearchResponse response = searchReq.execute().actionGet();
+
+        System.out.println(dsl);
+    }
 }

+ 1 - 1
elasticsearch-query-jdbc/src/test/java/org/es/test/jdbc/BaseJdbcTest.java

@@ -2,5 +2,5 @@ package org.es.test.jdbc;
 
 public class BaseJdbcTest {
     protected static final String driver = "org.es.jdbc.api.ElasticDriver";
-    protected static final String url = "jdbc:elastic:192.168.0.109:9300/lu-search-cluster";
+    protected static final String url = "jdbc:elastic:192.168.0.108:9300/lu-search-cluster";
 }

+ 1 - 1
elasticsearch-query-spring/src/test/resources/application-context.xml

@@ -17,7 +17,7 @@
 
     <bean id="elasticDataSource" class="org.es.jdbc.api.ElasticSingleConnectionDataSource" destroy-method="destroy">
         <property name="driverClassName" value="org.es.jdbc.api.ElasticDriver" />
-        <property name="url" value="jdbc:elastic:192.168.0.109:9300/lu-search-cluster" />
+        <property name="url" value="jdbc:elastic:192.168.0.108:9300/lu-search-cluster" />
         <property name="suppressClose" value="true" />
     </bean>