This is an automated email from the ASF dual-hosted git repository. dockerzhang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/inlong.git
The following commit(s) were added to refs/heads/master by this push: new f73e0e5a94 [INLONG-11109][SDK] Transform SQL supports parsing of IS (#11111) f73e0e5a94 is described below commit f73e0e5a945bcbed9110004189b457959b1652d0 Author: Zkplo <87751516+zk...@users.noreply.github.com> AuthorDate: Fri Sep 20 09:56:05 2024 +0800 [INLONG-11109][SDK] Transform SQL supports parsing of IS (#11111) Co-authored-by: ZKpLo <14148880+zk...@user.noreply.gitee.com> --- .../process/converter/BooleanConverter.java | 26 +++++ .../process/operator/IsBooleanOperator.java | 72 ++++++++++++++ .../transform/process/operator/IsNullOperator.java | 63 ++++++++++++ .../AbstractFunctionArithmeticTestBase.java | 3 + .../process/operator/TestIsBooleanOperator.java | 109 +++++++++++++++++++++ .../process/operator/TestIsNullOperator.java | 107 ++++++++++++++++++++ 6 files changed, 380 insertions(+) diff --git a/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/converter/BooleanConverter.java b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/converter/BooleanConverter.java new file mode 100644 index 0000000000..7c0f055ada --- /dev/null +++ b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/converter/BooleanConverter.java @@ -0,0 +1,26 @@ +/* + * 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 org.apache.inlong.sdk.transform.process.converter; + +public class BooleanConverter implements TypeConverter { + + @Override + public Object convert(String value) throws Exception { + return Boolean.parseBoolean(value); + } +} diff --git a/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/IsBooleanOperator.java b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/IsBooleanOperator.java new file mode 100644 index 0000000000..b402d9f8c3 --- /dev/null +++ b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/IsBooleanOperator.java @@ -0,0 +1,72 @@ +/* + * 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 org.apache.inlong.sdk.transform.process.operator; + +import org.apache.inlong.sdk.transform.decode.SourceData; +import org.apache.inlong.sdk.transform.process.Context; +import org.apache.inlong.sdk.transform.process.parser.ValueParser; + +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression; + +/** + * IsBooleanOperator -> expr is [not] boolean_value + * Description: expr can accept valueParser and expressionOperation: + * return the judgment result, if a boolean or numeric (note: 0 represents false, non-zero represents true) type is obtained; + * return false otherwise. + */ +@Slf4j +@TransformOperator(values = IsBooleanExpression.class) +public class IsBooleanOperator implements ExpressionOperator { + + private ValueParser leftParser; + private ExpressionOperator operator; + private final boolean isNot; + private final Boolean isTure; + + public IsBooleanOperator(IsBooleanExpression expr) { + try { + leftParser = OperatorTools.buildParser(expr.getLeftExpression()); + } catch (Exception e) { + operator = OperatorTools.buildOperator(expr.getLeftExpression()); + } + isNot = expr.isNot(); + isTure = expr.isTrue(); + } + + @Override + public boolean check(SourceData sourceData, int rowIndex, Context context) { + Object leftObj = null; + if (leftParser != null) { + leftObj = leftParser.parse(sourceData, rowIndex, context); + } else { + leftObj = operator.check(sourceData, rowIndex, context); + } + Boolean ret = null; + try { + ret = Double.parseDouble(leftObj.toString()) != 0; + } catch (Exception e) { + ret = isTure.equals(leftObj); + } + if (isNot) { + return !ret; + } else { + return ret; + } + } +} diff --git a/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/IsNullOperator.java b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/IsNullOperator.java new file mode 100644 index 0000000000..bec312c161 --- /dev/null +++ b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/IsNullOperator.java @@ -0,0 +1,63 @@ +/* + * 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 org.apache.inlong.sdk.transform.process.operator; + +import org.apache.inlong.sdk.transform.decode.SourceData; +import org.apache.inlong.sdk.transform.process.Context; +import org.apache.inlong.sdk.transform.process.parser.ValueParser; + +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.operators.relational.IsNullExpression; + +/** + * IsNullOperator -> expr is [not] null + * Description: expr can accept ValueParser and ExpressionOperation: + * return the judgment result + */ +@Slf4j +@TransformOperator(values = IsNullExpression.class) +public class IsNullOperator implements ExpressionOperator { + + private ValueParser leftParser; + private ExpressionOperator operator; + private final boolean isNot; + + public IsNullOperator(IsNullExpression expr) { + try { + leftParser = OperatorTools.buildParser(expr.getLeftExpression()); + } catch (Exception e) { + operator = OperatorTools.buildOperator(expr.getLeftExpression()); + } + isNot = expr.isNot(); + } + + @Override + public boolean check(SourceData sourceData, int rowIndex, Context context) { + Object leftObj = null; + if (leftParser != null) { + leftObj = leftParser.parse(sourceData, rowIndex, context); + } else { + leftObj = operator.check(sourceData, rowIndex, context); + } + if (isNot) { + return !(leftObj == null); + } else { + return leftObj == null; + } + } +} diff --git a/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/function/arithmetic/AbstractFunctionArithmeticTestBase.java b/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/function/arithmetic/AbstractFunctionArithmeticTestBase.java index e296391652..94e4912a7f 100644 --- a/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/function/arithmetic/AbstractFunctionArithmeticTestBase.java +++ b/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/function/arithmetic/AbstractFunctionArithmeticTestBase.java @@ -20,9 +20,11 @@ package org.apache.inlong.sdk.transform.process.function.arithmetic; import org.apache.inlong.sdk.transform.pojo.CsvSourceInfo; import org.apache.inlong.sdk.transform.pojo.FieldInfo; import org.apache.inlong.sdk.transform.pojo.KvSinkInfo; +import org.apache.inlong.sdk.transform.process.converter.BooleanConverter; import java.util.ArrayList; import java.util.List; + /** * AbstractFunctionArithmeticTestBase * description: define static parameters for ArithmeticFunction tests @@ -40,6 +42,7 @@ public abstract class AbstractFunctionArithmeticTestBase { field.setName("numeric" + i); srcFields.add(field); } + srcFields.add(new FieldInfo("booleanVal", new BooleanConverter())); FieldInfo field = new FieldInfo(); field.setName("result"); dstFields.add(field); diff --git a/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/operator/TestIsBooleanOperator.java b/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/operator/TestIsBooleanOperator.java new file mode 100644 index 0000000000..8aec150567 --- /dev/null +++ b/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/operator/TestIsBooleanOperator.java @@ -0,0 +1,109 @@ +/* + * 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 org.apache.inlong.sdk.transform.process.operator; + +import org.apache.inlong.sdk.transform.decode.SourceDecoderFactory; +import org.apache.inlong.sdk.transform.encode.SinkEncoderFactory; +import org.apache.inlong.sdk.transform.pojo.TransformConfig; +import org.apache.inlong.sdk.transform.process.TransformProcessor; +import org.apache.inlong.sdk.transform.process.function.arithmetic.AbstractFunctionArithmeticTestBase; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; + +public class TestIsBooleanOperator extends AbstractFunctionArithmeticTestBase { + + @Test + public void testIsBooleanOperator() throws Exception { + String transformSql = null, data = null; + TransformConfig config = null; + TransformProcessor<String, String> processor = null; + List<String> output = null; + + // case1: if(true is true,'true','false') + transformSql = "select if(booleanVal is true,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|||true"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=true", output.get(0)); + + // case2: if(false is true,'true','false') + data = "5|3|||false"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=false", output.get(0)); + + // case3: if(true is not true,'true','false') + transformSql = "select if(booleanVal is not true,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|||true"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=false", output.get(0)); + + // case4: if(false is not true,'true','false') + data = "5|3|||false"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=true", output.get(0)); + + // case5: if(null is not true,'true','false') + transformSql = "select if(booleanValX is not true,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|||true"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=true", output.get(0)); + + // case6: if((5 = 3) is true,'true','false') + transformSql = "select if((numeric1 = numeric2) is true,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|||false"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=false", output.get(0)); + + // case7: if((5 / 2) is not true,'true','false') + transformSql = "select if((numeric1 / numeric2) is not true,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|2|||false"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=false", output.get(0)); + + } +} diff --git a/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/operator/TestIsNullOperator.java b/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/operator/TestIsNullOperator.java new file mode 100644 index 0000000000..ed9136274b --- /dev/null +++ b/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/operator/TestIsNullOperator.java @@ -0,0 +1,107 @@ +/* + * 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 org.apache.inlong.sdk.transform.process.operator; + +import org.apache.inlong.sdk.transform.decode.SourceDecoderFactory; +import org.apache.inlong.sdk.transform.encode.SinkEncoderFactory; +import org.apache.inlong.sdk.transform.pojo.TransformConfig; +import org.apache.inlong.sdk.transform.process.TransformProcessor; +import org.apache.inlong.sdk.transform.process.function.arithmetic.AbstractFunctionArithmeticTestBase; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; + +public class TestIsNullOperator extends AbstractFunctionArithmeticTestBase { + + @Test + public void testIsNullOperator() throws Exception { + String transformSql = null, data = null; + TransformConfig config = null; + TransformProcessor<String, String> processor = null; + List<String> output = null; + + // case1: if(5 is null,true,false) + transformSql = "select if(numeric1 is null,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|3|5"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=false", output.get(0)); + + // case2: if(5 is not null,true,false) + transformSql = "select if(numeric1 is not null,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|3|5"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=true", output.get(0)); + + // case3: if(null is null,true,false) + transformSql = "select if(numericx is null,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|3|5"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=true", output.get(0)); + + // case4: if(null not is null,true,false) + transformSql = "select if(numericx is not null,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|3|5"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=false", output.get(0)); + + // case5: if((3 + 5) not is null,true,false) + transformSql = "select if((numeric1 + numeric2) is not null,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|3|5"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=true", output.get(0)); + + // case6: if((3 = 5) not is null,true,false) + transformSql = "select if((numeric1 = numeric2) is not null,'true','false') from source"; + config = new TransformConfig(transformSql); + processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + data = "5|3|3|5"; + output = processor.transform(data, new HashMap<>()); + Assert.assertEquals(1, output.size()); + Assert.assertEquals("result=true", output.get(0)); + } +}