From 01b96a015597567e02234a9028632633eed9e9ae Mon Sep 17 00:00:00 2001 From: Owen Stephens Date: Wed, 7 Mar 2018 09:10:11 +0000 Subject: [PATCH 1/3] Add coalesce function --- .../refine/expr/functions/Coalesce.java | 72 ++++++++++++ .../refine/grel/ControlFunctionRegistry.java | 2 + .../tests/expr/functions/CoalesceTests.java | 104 ++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 main/src/com/google/refine/expr/functions/Coalesce.java create mode 100644 main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java diff --git a/main/src/com/google/refine/expr/functions/Coalesce.java b/main/src/com/google/refine/expr/functions/Coalesce.java new file mode 100644 index 000000000..ffdcc9b1c --- /dev/null +++ b/main/src/com/google/refine/expr/functions/Coalesce.java @@ -0,0 +1,72 @@ +/* + +Copyright 2018, Owen Stephens +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +package com.google.refine.expr.functions; + +import java.util.Properties; + +import org.json.JSONException; +import org.json.JSONWriter; + +import com.google.refine.expr.EvalError; +import com.google.refine.grel.ControlFunctionRegistry; +import com.google.refine.grel.Function; + +public class Coalesce implements Function { + + @Override + public Object call(Properties bindings, Object[] args) { + if (args.length> 0) { + for (int i = 0; i < args.length; i++){ + if (args[i] == null) { + continue; + } else { + return args[i]; + } + } + return null; + } + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects at least one argument"); + } + + @Override + public void write(JSONWriter writer, Properties options) + throws JSONException { + + writer.object(); + writer.key("description"); writer.value("Returns the first non-null from a series of values"); + writer.key("params"); writer.value("one or more objects"); + writer.key("returns"); writer.value("object"); + writer.endObject(); + } +} diff --git a/main/src/com/google/refine/grel/ControlFunctionRegistry.java b/main/src/com/google/refine/grel/ControlFunctionRegistry.java index abc343a74..083f5e697 100644 --- a/main/src/com/google/refine/grel/ControlFunctionRegistry.java +++ b/main/src/com/google/refine/grel/ControlFunctionRegistry.java @@ -38,6 +38,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import com.google.refine.expr.functions.Coalesce; import com.google.refine.expr.functions.Cross; import com.google.refine.expr.functions.FacetCount; import com.google.refine.expr.functions.Get; @@ -186,6 +187,7 @@ public class ControlFunctionRegistry { } static { + registerFunction("coalesce", new Coalesce()); registerFunction("type", new Type()); registerFunction("toString", new ToString()); diff --git a/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java b/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java new file mode 100644 index 000000000..667fd73b7 --- /dev/null +++ b/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java @@ -0,0 +1,104 @@ +/* + +Copyright 2011, Owen Stephens +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +package com.google.refine.tests.expr.functions.strings; + +import java.util.Properties; + +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.google.refine.expr.EvalError; +import com.google.refine.grel.ControlFunctionRegistry; +import com.google.refine.grel.Function; +import com.google.refine.tests.RefineTest; + + +public class CoalesceTests extends RefineTest { + + static Properties bindings; + private static final Integer[] ZERO_TO_TWO = new Integer[] {0, 1, 2}; + + @Override + @BeforeTest + public void init() { + logger = LoggerFactory.getLogger(this.getClass()); + } + + @BeforeMethod + public void SetUp() { + bindings = new Properties(); + } + + @AfterMethod + public void TearDown() { + bindings = null; + } + + /** + * Lookup a control function by name and invoke it with a variable number of args + */ + private static Object invoke(String name,Object... args) { + // registry uses static initializer, so no need to set it up + Function function = ControlFunctionRegistry.getFunction(name); + if (function == null) { + throw new IllegalArgumentException("Unknown function "+name); + } + if (args == null) { + return function.call(bindings,new Object[0]); + } else { + return function.call(bindings,args); + } + } + + @Test + public void testCoalesceInvalidParams() { + Assert.assertTrue(invoke("coalesce") instanceof EvalError); + } + + @Test + public void testCoalesce() { + Assert.assertNull(invoke("coalesce", (Object) null)); + Assert.assertEquals(invoke("coalesce", "string"),"string"); + Assert.assertEquals(invoke("coalesce", 1),1); + Assert.assertEquals(invoke("coalesce", (Object) null, "string"),"string"); + Assert.assertEquals(invoke("coalesce", (Object) null, (Object) null, "string"),"string"); + Assert.assertEquals(invoke("coalesce", (Object) null, 1),1); + Assert.assertEquals(invoke("coalesce", (Object) null, ZERO_TO_TWO),ZERO_TO_TWO); + } + +} From 998eefc8692d613d30c6e14d8a8f50f4e948c74a Mon Sep 17 00:00:00 2001 From: Owen Stephens Date: Wed, 14 Mar 2018 23:59:13 +0000 Subject: [PATCH 2/3] Make codacy happier --- .../google/refine/tests/expr/functions/CoalesceTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java b/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java index 667fd73b7..3e1072bcf 100644 --- a/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java +++ b/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java @@ -50,7 +50,7 @@ import com.google.refine.tests.RefineTest; public class CoalesceTests extends RefineTest { - static Properties bindings; + private static Properties bindings; private static final Integer[] ZERO_TO_TWO = new Integer[] {0, 1, 2}; @Override @@ -60,12 +60,12 @@ public class CoalesceTests extends RefineTest { } @BeforeMethod - public void SetUp() { + public void setUp() { bindings = new Properties(); } @AfterMethod - public void TearDown() { + public void tearDown() { bindings = null; } From 6e02baaa8af2f2b3ba1333bd4061f281fd7a788e Mon Sep 17 00:00:00 2001 From: Owen Stephens Date: Sat, 17 Mar 2018 16:21:05 +0000 Subject: [PATCH 3/3] Coalesce must have at least two arguments --- main/src/com/google/refine/expr/functions/Coalesce.java | 8 ++++---- .../google/refine/tests/expr/functions/CoalesceTests.java | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/main/src/com/google/refine/expr/functions/Coalesce.java b/main/src/com/google/refine/expr/functions/Coalesce.java index ffdcc9b1c..5ef489c35 100644 --- a/main/src/com/google/refine/expr/functions/Coalesce.java +++ b/main/src/com/google/refine/expr/functions/Coalesce.java @@ -46,7 +46,7 @@ public class Coalesce implements Function { @Override public Object call(Properties bindings, Object[] args) { - if (args.length> 0) { + if (args.length> 1) { for (int i = 0; i < args.length; i++){ if (args[i] == null) { continue; @@ -56,7 +56,7 @@ public class Coalesce implements Function { } return null; } - return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects at least one argument"); + return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects at least two arguments"); } @Override @@ -65,8 +65,8 @@ public class Coalesce implements Function { writer.object(); writer.key("description"); writer.value("Returns the first non-null from a series of values"); - writer.key("params"); writer.value("one or more objects"); - writer.key("returns"); writer.value("object"); + writer.key("params"); writer.value("two or more objects"); + writer.key("returns"); writer.value("object or null"); writer.endObject(); } } diff --git a/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java b/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java index 3e1072bcf..a2f1be5fa 100644 --- a/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java +++ b/main/tests/server/src/com/google/refine/tests/expr/functions/CoalesceTests.java @@ -88,13 +88,12 @@ public class CoalesceTests extends RefineTest { @Test public void testCoalesceInvalidParams() { Assert.assertTrue(invoke("coalesce") instanceof EvalError); + Assert.assertTrue(invoke("coalesce", 1) instanceof EvalError); } @Test - public void testCoalesce() { - Assert.assertNull(invoke("coalesce", (Object) null)); - Assert.assertEquals(invoke("coalesce", "string"),"string"); - Assert.assertEquals(invoke("coalesce", 1),1); + public void testCoalesce() { + Assert.assertNull(invoke("coalesce", (Object) null, (Object) null)); Assert.assertEquals(invoke("coalesce", (Object) null, "string"),"string"); Assert.assertEquals(invoke("coalesce", (Object) null, (Object) null, "string"),"string"); Assert.assertEquals(invoke("coalesce", (Object) null, 1),1);