diff --git a/src/main/java/org/nlpcn/es4sql/parse/CastParser.java b/src/main/java/org/nlpcn/es4sql/parse/CastParser.java new file mode 100644 index 00000000..44d74c1f --- /dev/null +++ b/src/main/java/org/nlpcn/es4sql/parse/CastParser.java @@ -0,0 +1,63 @@ +package org.nlpcn.es4sql.parse; + +import com.alibaba.druid.sql.ast.expr.SQLCastExpr; +import com.google.common.base.Joiner; +import org.nlpcn.es4sql.SQLFunctions; +import org.nlpcn.es4sql.Util; +import org.nlpcn.es4sql.exception.SqlParseException; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by leonlu on 2017/9/21. + */ +public class CastParser { + + private enum DataType { + INT, LONG, FLOAT, DOUBLE, STRING, DATETIME + } + + private SQLCastExpr castExpr; + private String alias; + private String tableAlias; + + public CastParser(SQLCastExpr castExpr, String alias, String tableAlias) { + this.castExpr = castExpr; + this.alias = alias; + this.tableAlias = tableAlias; + } + + public String parse(boolean isReturn) throws SqlParseException { + List result = new ArrayList<>(); + + String dataType = castExpr.getDataType().getName().toUpperCase(); + String fileName = String.format("doc['%s'].value",Util.expr2Object(castExpr.getExpr())); + String name = "field_"+SQLFunctions.random(); + + try { + if (DataType.valueOf(dataType) == DataType.INT) { + result.add(String.format("def %s = Double.parseDouble(%s.toString()).intValue()", name, fileName)); + } else if (DataType.valueOf(dataType) == DataType.LONG) { + result.add(String.format("def %s = Double.parseDouble(%s.toString()).longValue()", name, fileName)); + } else if (DataType.valueOf(dataType) == DataType.FLOAT) { + result.add(String.format("def %s = Double.parseDouble(%s.toString()).floatValue()", name, fileName)); + } else if (DataType.valueOf(dataType) == DataType.DOUBLE) { + result.add(String.format("def %s = Double.parseDouble(%s.toString()).doubleValue()", name, fileName)); + } else if (DataType.valueOf(dataType) == DataType.STRING) { + result.add(String.format("def %s = %s.toString()",name, fileName)); + } else if (DataType.valueOf(dataType) == DataType.DATETIME) { + result.add(String.format("def %s = new Date(Double.parseDouble(%s.toString()).longValue())", name, fileName)); + } else { + throw new SqlParseException("not support cast to data type:" + dataType); + } + if(isReturn) { + result.add("return " + name); + } + + return Joiner.on("; ").join(result); + } catch (Exception ex) { + throw new SqlParseException(String.format("field cast to type: %s failed. error:%s",dataType, ex.getMessage())); + } + } +} diff --git a/src/main/java/org/nlpcn/es4sql/parse/FieldMaker.java b/src/main/java/org/nlpcn/es4sql/parse/FieldMaker.java index 827985b7..8e5951fd 100644 --- a/src/main/java/org/nlpcn/es4sql/parse/FieldMaker.java +++ b/src/main/java/org/nlpcn/es4sql/parse/FieldMaker.java @@ -61,6 +61,16 @@ public static Field makeField(SQLExpr expr, String alias, String tableAlias) thr methodParameters.add(new KVValue(alias)); methodParameters.add(new KVValue(scriptCode)); return new MethodField("script", methodParameters, null, alias); + }else if (expr instanceof SQLCastExpr) { + SQLCastExpr castExpr = (SQLCastExpr) expr; + if (alias == null) { + alias = "cast_" + castExpr.getExpr().toString(); + } + String scriptCode = new CastParser(castExpr, alias, tableAlias).parse(true); + List methodParameters = new ArrayList<>(); + methodParameters.add(new KVValue(alias)); + methodParameters.add(new KVValue(scriptCode)); + return new MethodField("script", methodParameters, null, alias); } else { throw new SqlParseException("unknown field name : " + expr); } @@ -251,6 +261,9 @@ public static MethodField makeMethodField(String name, List arguments, } else if (object instanceof SQLCaseExpr) { String scriptCode = new CaseWhenParser((SQLCaseExpr) object, alias, tableAlias).parse(); paramers.add(new KVValue("script",new SQLCharExpr(scriptCode))); + } else if(object instanceof SQLCastExpr) { + String scriptCode = new CastParser((SQLCastExpr) object, alias, tableAlias).parse(false); + paramers.add(new KVValue("script",new SQLCharExpr(scriptCode))); } else { paramers.add(new KVValue(Util.removeTableAilasFromField(object, tableAlias))); } diff --git a/src/test/java/org/nlpcn/es4sql/SqlParserTests.java b/src/test/java/org/nlpcn/es4sql/SqlParserTests.java index 1351c599..9ef82e3a 100644 --- a/src/test/java/org/nlpcn/es4sql/SqlParserTests.java +++ b/src/test/java/org/nlpcn/es4sql/SqlParserTests.java @@ -986,6 +986,131 @@ public void caseWhenTestWithouhtElseExpr() throws SqlParseException { } + @Test + public void castToIntTest() throws Exception { + String query = "select cast(age as int) from "+ TestsConstants.TEST_INDEX + "/account limit 10"; + SQLExpr sqlExpr = queryToExpr(query); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + Field castField = select.getFields().get(0); + Assert.assertTrue(castField instanceof MethodField); + + MethodField methodField = (MethodField) castField; + Assert.assertEquals("script",castField.getName()); + + String alias = (String) methodField.getParams().get(0).value; + String scriptCode = (String) methodField.getParams().get(1).value; + Assert.assertEquals("cast_age",alias); + Assert.assertTrue(scriptCode.contains("doc['age'].value")); + Assert.assertTrue(scriptCode.contains("Double.parseDouble(doc['age'].value.toString()).intValue()")); + } + + @Test + public void castToLongTest() throws Exception { + String query = "select cast(insert_time as long) from "+ TestsConstants.TEST_INDEX + " limit 10"; + SQLExpr sqlExpr = queryToExpr(query); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + Field castField = select.getFields().get(0); + Assert.assertTrue(castField instanceof MethodField); + + MethodField methodField = (MethodField) castField; + Assert.assertEquals("script",castField.getName()); + + String alias = (String) methodField.getParams().get(0).value; + String scriptCode = (String) methodField.getParams().get(1).value; + Assert.assertEquals("cast_insert_time",alias); + Assert.assertTrue(scriptCode.contains("doc['insert_time'].value")); + Assert.assertTrue(scriptCode.contains("Double.parseDouble(doc['insert_time'].value.toString()).longValue()")); + } + + @Test + public void castToFloatTest() throws Exception { + String query = "select cast(age as float) from "+ TestsConstants.TEST_INDEX + " limit 10"; + SQLExpr sqlExpr = queryToExpr(query); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + Field castField = select.getFields().get(0); + Assert.assertTrue(castField instanceof MethodField); + + MethodField methodField = (MethodField) castField; + Assert.assertEquals("script",castField.getName()); + + String alias = (String) methodField.getParams().get(0).value; + String scriptCode = (String) methodField.getParams().get(1).value; + Assert.assertEquals("cast_age",alias); + Assert.assertTrue(scriptCode.contains("doc['age'].value")); + Assert.assertTrue(scriptCode.contains("Double.parseDouble(doc['age'].value.toString()).floatValue()")); + } + + @Test + public void castToDoubleTest() throws Exception { + String query = "select cast(age as double) from "+ TestsConstants.TEST_INDEX + "/account limit 10"; + SQLExpr sqlExpr = queryToExpr(query); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + Field castField = select.getFields().get(0); + Assert.assertTrue(castField instanceof MethodField); + + MethodField methodField = (MethodField) castField; + Assert.assertEquals("script",castField.getName()); + + String alias = (String) methodField.getParams().get(0).value; + String scriptCode = (String) methodField.getParams().get(1).value; + Assert.assertEquals("cast_age",alias); + Assert.assertTrue(scriptCode.contains("doc['age'].value")); + Assert.assertTrue(scriptCode.contains("Double.parseDouble(doc['age'].value.toString()).doubleValue()")); + } + + @Test + public void castToStringTest() throws Exception { + String query = "select cast(age as string) from "+ TestsConstants.TEST_INDEX + "/account limit 10"; + SQLExpr sqlExpr = queryToExpr(query); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + Field castField = select.getFields().get(0); + Assert.assertTrue(castField instanceof MethodField); + + MethodField methodField = (MethodField) castField; + Assert.assertEquals("script",castField.getName()); + + String alias = (String) methodField.getParams().get(0).value; + String scriptCode = (String) methodField.getParams().get(1).value; + Assert.assertEquals("cast_age",alias); + Assert.assertTrue(scriptCode.contains("doc['age'].value.toString()")); + } + + @Test + public void castToDateTimeTest() throws Exception { + String query = "select cast(age as datetime) from "+ TestsConstants.TEST_INDEX + "/account limit 10"; + SQLExpr sqlExpr = queryToExpr(query); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + Field castField = select.getFields().get(0); + Assert.assertTrue(castField instanceof MethodField); + + MethodField methodField = (MethodField) castField; + Assert.assertEquals("script",castField.getName()); + + String alias = (String) methodField.getParams().get(0).value; + String scriptCode = (String) methodField.getParams().get(1).value; + Assert.assertEquals("cast_age",alias); + Assert.assertTrue(scriptCode.contains("doc['age'].value")); + Assert.assertTrue(scriptCode.contains("new Date(Double.parseDouble(doc['age'].value.toString()).longValue())")); + } + + @Test + public void castToDoubleThenDivideTest() throws Exception { + String query = "select cast(age as double)/2 from "+ TestsConstants.TEST_INDEX + "/account limit 10"; + SQLExpr sqlExpr = queryToExpr(query); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + Field castField = select.getFields().get(0); + Assert.assertTrue(castField instanceof MethodField); + + MethodField methodField = (MethodField) castField; + Assert.assertEquals("script",castField.getName()); + + String alias = (String) methodField.getParams().get(0).value; + String scriptCode = (String) methodField.getParams().get(1).value; + Assert.assertTrue(scriptCode.contains("doc['age'].value")); + Assert.assertTrue(scriptCode.contains("Double.parseDouble(doc['age'].value.toString()).doubleValue()")); + Assert.assertTrue(scriptCode.contains("/ 2")); + } + @Test public void multiSelectMinusOperationCheckIndices() throws SqlParseException {