This is an automated email from the ASF dual-hosted git repository. jiayu pushed a commit to branch SEDONA-576 in repository https://gitbox.apache.org/repos/asf/sedona.git
commit 22cf352867ac0c9cdbefd2ddd988a4b35c50e717 Author: Furqaan Khan <[email protected]> AuthorDate: Fri Apr 5 16:55:11 2024 -0400 [TASK-105] Add ST_HasZ (#154) * feat: add ST_HasZ * fix: type * fix: typo * fix: snowflake tests * fix: old broken snowflake tests * fix: old broken snowflake tests * fix: old broken snowflake tests --- .../java/org/apache/sedona/common/Functions.java | 5 +++++ .../org/apache/sedona/common/FunctionsTest.java | 15 +++++++++++++++ docs/api/flink/Function.md | 22 ++++++++++++++++++++++ docs/api/snowflake/vector-data/Function.md | 20 ++++++++++++++++++++ docs/api/sql/Function.md | 22 ++++++++++++++++++++++ .../main/java/org/apache/sedona/flink/Catalog.java | 1 + .../apache/sedona/flink/expressions/Functions.java | 8 ++++++++ .../java/org/apache/sedona/flink/FunctionTest.java | 7 +++++++ python/sedona/sql/st_functions.py | 11 +++++++++++ python/tests/sql/test_dataframe_api.py | 2 ++ python/tests/sql/test_function.py | 5 +++++ .../sedona/snowflake/snowsql/TestFunctions.java | 16 ++++++++++++---- .../sedona/snowflake/snowsql/TestFunctionsV2.java | 9 +++++++++ .../org/apache/sedona/snowflake/snowsql/UDFs.java | 7 +++++++ .../apache/sedona/snowflake/snowsql/UDFsV2.java | 7 +++++++ .../scala/org/apache/sedona/sql/UDF/Catalog.scala | 1 + .../sql/sedona_sql/expressions/Functions.scala | 8 ++++++++ .../sql/sedona_sql/expressions/st_functions.scala | 3 +++ .../apache/sedona/sql/dataFrameAPITestScala.scala | 6 ++++++ .../org/apache/sedona/sql/functionTestScala.scala | 6 ++++++ 20 files changed, 177 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/apache/sedona/common/Functions.java b/common/src/main/java/org/apache/sedona/common/Functions.java index 774a2bfe3..79be14b83 100644 --- a/common/src/main/java/org/apache/sedona/common/Functions.java +++ b/common/src/main/java/org/apache/sedona/common/Functions.java @@ -483,6 +483,11 @@ public class Functions { return !Double.isNaN(coord.getM()); } + public static boolean hasZ(Geometry geom) { + Coordinate coord = geom.getCoordinate(); + return !Double.isNaN(coord.getZ()); + } + public static Geometry flipCoordinates(Geometry geometry) { GeomUtils.flipCoordinates(geometry); return geometry; diff --git a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java index 6d15e20ca..3e1f1cb68 100644 --- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java +++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java @@ -388,6 +388,21 @@ public class FunctionsTest extends TestBase { assertEquals(actualResult, expectedResult); } + @Test + public void hasZ() throws ParseException { + Geometry geom = Constructors.geomFromWKT("POINT ZM(1 2 3 4)", 0); + assertTrue(Functions.hasZ(geom)); + + geom = Constructors.geomFromWKT("POINT(1 2)", 0); + assertFalse(Functions.hasZ(geom)); + + geom = Constructors.geomFromWKT("POINT(34 25)", 0); + assertFalse(Functions.hasZ(geom)); + + geom = Constructors.geomFromWKT("POLYGON ZM ((30 10 5 1, 40 40 10 2, 20 40 15 3, 10 20 20 4, 30 10 5 1))", 0); + assertTrue(Functions.hasZ(geom)); + } + @Test public void hasM() throws ParseException { Geometry geom = Constructors.geomFromWKT("POINT ZM(1 2 3 4)", 0); diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md index 318c97354..83efa8d89 100644 --- a/docs/api/flink/Function.md +++ b/docs/api/flink/Function.md @@ -1574,6 +1574,28 @@ Output: True ``` +## ST_HasZ + +Introduction: Checks for the presence of Z coordinate values representing measures or linear references. Returns true if the input geometry includes an Z coordinate, false otherwise. + +Format: `ST_HasZ(geom: Geometry)` + +Since: `vTBD` + +SQL Example + +```sql +SELECT ST_HasZ( + ST_GeomFromWKT('LINESTRING Z (30 10 5, 40 40 10, 20 40 15, 10 20 20)') +) +``` + +Output: + +``` +True +``` + ## ST_HausdorffDistance Introduction: Returns a discretized (and hence approximate) [Hausdorff distance](https://en.wikipedia.org/wiki/Hausdorff_distance) between the given 2 geometries. diff --git a/docs/api/snowflake/vector-data/Function.md b/docs/api/snowflake/vector-data/Function.md index 54afc40d6..bda335535 100644 --- a/docs/api/snowflake/vector-data/Function.md +++ b/docs/api/snowflake/vector-data/Function.md @@ -1125,6 +1125,26 @@ SELECT ST_GeometryType(polygondf.countyshape) FROM polygondf ``` +## ST_HasZ + +Introduction: Checks for the presence of Z coordinate values representing measures or linear references. Returns true if the input geometry includes an Z coordinate, false otherwise. + +Format: `ST_HasZ(geom: Geometry)` + +SQL Example + +```sql +SELECT ST_HasZ( + ST_GeomFromWKT('LINESTRING Z (30 10 5, 40 40 10, 20 40 15, 10 20 20)') +) +``` + +Output: + +``` +True +``` + ## ST_HausdorffDistance Introduction: Returns a discretized (and hence approximate) [Hausdorff distance](https://en.wikipedia.org/wiki/Hausdorff_distance) between the given 2 geometries. diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md index 928770887..0643d5662 100644 --- a/docs/api/sql/Function.md +++ b/docs/api/sql/Function.md @@ -1580,6 +1580,28 @@ Output: True ``` +## ST_HasZ + +Introduction: Checks for the presence of Z coordinate values representing measures or linear references. Returns true if the input geometry includes an Z coordinate, false otherwise. + +Format: `ST_HasZ(geom: Geometry)` + +Since: `vTBD` + +SQL Example + +```sql +SELECT ST_HasZ( + ST_GeomFromWKT('LINESTRING Z (30 10 5, 40 40 10, 20 40 15, 10 20 20)') +) +``` + +Output: + +``` +True +``` + ## ST_HausdorffDistance Introduction: Returns a discretized (and hence approximate) [Hausdorff distance](https://en.wikipedia.org/wiki/Hausdorff_distance) between the given 2 geometries. diff --git a/flink/src/main/java/org/apache/sedona/flink/Catalog.java b/flink/src/main/java/org/apache/sedona/flink/Catalog.java index 6b5639f97..d635e1bf8 100644 --- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java +++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java @@ -126,6 +126,7 @@ public class Catalog { new Functions.ST_LineFromMultiPoint(), new Functions.ST_LineMerge(), new Functions.ST_LineSubstring(), + new Functions.ST_HasZ(), new Functions.ST_HasM(), new Functions.ST_M(), new Functions.ST_MMin(), diff --git a/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java b/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java index 7397087c5..001cbb627 100644 --- a/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java +++ b/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java @@ -757,6 +757,14 @@ public class Functions { } } + public static class ST_HasZ extends ScalarFunction { + @DataTypeHint("Boolean") + public Boolean eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o) { + Geometry geom = (Geometry) o; + return org.apache.sedona.common.Functions.hasZ(geom); + } + } + public static class ST_M extends ScalarFunction { @DataTypeHint("Double") public Double eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o) { diff --git a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java index 9d4d6bb79..99781c4d1 100644 --- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java +++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java @@ -699,6 +699,13 @@ public class FunctionTest extends TestBase{ assertEquals(7.89, first(pointTable).getField(0)); } + @Test + public void testHasZ() { + Table polyTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POLYGON ZM ((30 10 5 1, 40 40 10 2, 20 40 15 3, 10 20 20 4, 30 10 5 1))') as poly"); + boolean actual = (boolean) first(polyTable.select(call(Functions.ST_HasZ.class.getSimpleName(), $("poly")))).getField(0); + assertTrue(actual); + } + @Test public void testHasM() { Table polyTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POLYGON ZM ((30 10 5 1, 40 40 10 2, 20 40 15 3, 10 20 20 4, 30 10 5 1))') as poly"); diff --git a/python/sedona/sql/st_functions.py b/python/sedona/sql/st_functions.py index 07814947a..f65141f95 100644 --- a/python/sedona/sql/st_functions.py +++ b/python/sedona/sql/st_functions.py @@ -857,6 +857,17 @@ def ST_LineSubstring(line_string: ColumnOrName, start_fraction: ColumnOrNameOrNu """ return _call_st_function("ST_LineSubstring", (line_string, start_fraction, end_fraction)) +@validate_argument_types +def ST_HasZ(geom: ColumnOrName) -> Column: + """Check whether geometry has Z coordinate + + :param geom: Geometry + :type geom: ColumnOrName + :return: True if geometry has Z coordinate, else False + :rtype: Column + """ + return _call_st_function("ST_HasZ", geom) + @validate_argument_types def ST_HasM(geom: ColumnOrName) -> Column: """Check whether geometry has M coordinate diff --git a/python/tests/sql/test_dataframe_api.py b/python/tests/sql/test_dataframe_api.py index 628aceefa..60cf13984 100644 --- a/python/tests/sql/test_dataframe_api.py +++ b/python/tests/sql/test_dataframe_api.py @@ -146,6 +146,7 @@ test_configurations = [ (stf.ST_LineLocatePoint, ("line", "point"), "line_and_point", "", 0.5), (stf.ST_LineMerge, ("geom",), "multiline_geom", "", "LINESTRING (0 0, 1 0, 1 1, 0 0)"), (stf.ST_LineSubstring, ("line", 0.5, 1.0), "linestring_geom", "", "LINESTRING (2.5 0, 3 0, 4 0, 5 0)"), + (stf.ST_HasZ, ("a",), "two_points", "", True), (stf.ST_HasM, ("point",), "4D_point", "", True), (stf.ST_M, ("point",), "4D_point", "", 4.0), (stf.ST_MMin, ("line",), "4D_line", "", -1.0), @@ -319,6 +320,7 @@ wrong_type_configurations = [ (stf.ST_LineSubstring, (None, 0.5, 1.0)), (stf.ST_LineSubstring, ("", None, 1.0)), (stf.ST_LineSubstring, ("", 0.5, None)), + (stf.ST_HasZ, (None,)), (stf.ST_HasM, (None,)), (stf.ST_M, (None,)), (stf.ST_MMin, (None,)), diff --git a/python/tests/sql/test_function.py b/python/tests/sql/test_function.py index 1df5e8508..0d6bde534 100644 --- a/python/tests/sql/test_function.py +++ b/python/tests/sql/test_function.py @@ -931,6 +931,11 @@ class TestPredicateJoin(TestBase): # Then assert subdivided.count() == 16 + def test_st_has_z(self): + baseDf = self.spark.sql("SELECT ST_GeomFromWKT('POLYGON Z ((30 10 5, 40 40 10, 20 40 15, 10 20 20, 30 10 5))') as poly") + actual = baseDf.selectExpr("ST_HasZ(poly)") + assert actual + def test_st_has_m(self): baseDf = self.spark.sql("SELECT ST_GeomFromWKT('POLYGON ZM ((30 10 5 1, 40 40 10 2, 20 40 15 3, 10 20 20 4, 30 10 5 1))') as poly") actual = baseDf.selectExpr("ST_HasM(poly)") diff --git a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java index a83645497..c682c869f 100644 --- a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java +++ b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java @@ -192,10 +192,9 @@ public class TestFunctions extends TestBase { ); registerUDF("ST_Buffer", byte[].class, double.class, boolean.class); registerUDF("ST_ReducePrecision", byte[].class, int.class); - registerUDF("ST_Area", byte[].class); verifySqlSingleRes( - "select sedona.ST_Area(sedona.ST_ReducePrecision(sedona.ST_GeomFromText(sedona.ST_AsText(sedona.ST_Buffer(sedona.ST_GeomFromText('LINESTRING(0.05 15, -0.05 15)'), 10000, true))), 8))", - 0.04424254827358593 + "select sedona.ST_AsText(sedona.ST_ReducePrecision(sedona.ST_Buffer(sedona.ST_GeomFromText('LINESTRING(5 15, -5 15)'), 100, true), 4))", + "POLYGON ((-5.0002 14.9991, -5.0003 14.9992, -5.0005 14.9993, -5.0006 14.9994, -5.0007 14.9995, -5.0008 14.9997, -5.0009 14.9998, -5.0009 15, -5.0009 15.0002, -5.0008 15.0003, -5.0007 15.0005, -5.0006 15.0006, -5.0005 15.0007, -5.0003 15.0008, -5.0002 15.0009, -5 15.0009, 5 15.0009, 5.0002 15.0009, 5.0003 15.0008, 5.0005 15.0007, 5.0006 15.0006, 5.0007 15.0005, 5.0008 15.0003, 5.0009 15.0002, 5.0009 15, 5.0009 14.9998, 5.0008 14.9997, 5.0007 14.9995, 5.0006 14.9994, 5.000 [...] ); } @@ -409,6 +408,15 @@ public class TestFunctions extends TestBase { ); } + @Test + public void test_ST_HasZ() { + registerUDF("ST_HasZ", byte[].class); + verifySqlSingleRes( + "SELECT sedona.ST_HasZ(sedona.ST_GeomFromText('POINT Z(1 2 3)'))", + true + ); + } + @Test public void test_ST_HausdorffDistance() { registerUDF("ST_HausdorffDistance", byte[].class, byte[].class); @@ -831,7 +839,7 @@ public class TestFunctions extends TestBase { public void test_ST_Snap() { registerUDF("ST_Snap", byte[].class, byte[].class, double.class); verifySqlSingleRes( - "SELECT sedona.ST_AsText(sedona.ST_Snap(sedona.ST_GeomFromText('POLYGON((2.6 12.5, 2.6 20.0, 12.6 20.0, 12.6 12.5, 2.6 12.5 ))'), sedona.ST_GeomFromText('LINESTRING (0.5 10.7, 5.4 8.4, 10.1 10.0)'), 2.525))", + "SELECT sedona.ST_AsText(sedona.ST_Snap(sedona.ST_GeomFromWKT('POLYGON((2.6 12.5, 2.6 20.0, 12.6 20.0, 12.6 12.5, 2.6 12.5 ))'), sedona.ST_GeomFromWKT('LINESTRING (0.5 10.7, 5.4 8.4, 10.1 10.0)'), 2.525))", "POLYGON ((2.6 12.5, 2.6 20, 12.6 20, 12.6 12.5, 10.1 10, 2.6 12.5))" ); } diff --git a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctionsV2.java b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctionsV2.java index 299cbcdc9..0be3705c1 100644 --- a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctionsV2.java +++ b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctionsV2.java @@ -400,6 +400,15 @@ public class TestFunctionsV2 ); } + @Test + public void test_ST_HasZ() { + registerUDFV2("ST_HasZ", String.class); + verifySqlSingleRes( + "SELECT sedona.ST_HasZ(ST_GeomFromText('POINT Z(1 2 3)'))", + true + ); + } + @Test public void test_ST_HausdorffDistance() { registerUDFV2("ST_HausdorffDistance", String.class, String.class); diff --git a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java index 14c00a64f..43789f4fd 100644 --- a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java +++ b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java @@ -533,6 +533,13 @@ public class UDFs { ); } + @UDFAnnotations.ParamMeta(argNames = {"geometry"}) + public static boolean ST_HasZ(byte[] geometry) { + return Functions.hasZ( + GeometrySerde.deserialize(geometry) + ); + } + @UDFAnnotations.ParamMeta(argNames = {"geom1", "geom2"}) public static double ST_HausdorffDistance(byte[] geom1, byte[] geom2) { diff --git a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java index 08bad21ec..b5b485757 100644 --- a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java +++ b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java @@ -478,6 +478,13 @@ public class UDFsV2 ); } + @UDFAnnotations.ParamMeta(argNames = {"geometry"}, argTypes = {"Geometry"}) + public static boolean ST_HasZ(String geometry) { + return Functions.hasZ( + GeometrySerde.deserGeoJson(geometry) + ); + } + @UDFAnnotations.ParamMeta(argNames = {"geom1", "geom2"}, argTypes = {"Geometry", "Geometry"}) public static double ST_HausdorffDistance(String geom1, String geom2) { diff --git a/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala b/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala index 3e7eacf0a..957504e13 100644 --- a/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala +++ b/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala @@ -112,6 +112,7 @@ object Catalog { function[ST_Snap](), function[ST_ClosestPoint](), function[ST_Boundary](), + function[ST_HasZ](), function[ST_HasM](), function[ST_M](), function[ST_MMin](), diff --git a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala index 21613b37c..b4cb02502 100644 --- a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala +++ b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala @@ -511,6 +511,14 @@ case class ST_MinimumBoundingCircle(inputExpressions: Seq[Expression]) } } +case class ST_HasZ(inputExpressions: Seq[Expression]) + extends InferredExpression(Functions.hasZ _) { + + protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = { + copy(inputExpressions = newChildren) + } +} + case class ST_HasM(inputExpressions: Seq[Expression]) extends InferredExpression(Functions.hasM _) { diff --git a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala index 65cec5a29..b93aeb972 100644 --- a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala +++ b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala @@ -212,6 +212,9 @@ object st_functions extends DataFrameAPI { def ST_LineSubstring(lineString: Column, startFraction: Column, endFraction: Column): Column = wrapExpression[ST_LineSubstring](lineString, startFraction, endFraction) def ST_LineSubstring(lineString: String, startFraction: Double, endFraction: Double): Column = wrapExpression[ST_LineSubstring](lineString, startFraction, endFraction) + def ST_HasZ(geoms: Column): Column = wrapExpression[ST_HasZ](geoms) + def ST_HasZ(geoms: String): Column = wrapExpression[ST_HasZ](geoms) + def ST_HasM(geoms: Column): Column = wrapExpression[ST_HasM](geoms) def ST_HasM(geoms: String): Column = wrapExpression[ST_HasM](geoms) diff --git a/spark/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala b/spark/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala index 3bf263be4..acb1dd4d9 100644 --- a/spark/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala +++ b/spark/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala @@ -52,6 +52,12 @@ class dataFrameAPITestScala extends TestBaseScala { assert(actualResult == expectedResult) } + it("Passed ST_HasZ") { + val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON Z ((30 10 5, 40 40 10, 20 40 15, 10 20 20, 30 10 5))') as poly") + val actual = baseDf.select(ST_HasZ("poly")).first().getBoolean(0) + assert(actual) + } + it("Passed ST_HasM") { val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ZM ((30 10 5 1, 40 40 10 2, 20 40 15 3, 10 20 20 4, 30 10 5 1))') as poly") val actual = baseDf.select(ST_HasM("poly")).first().getBoolean(0) diff --git a/spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala b/spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala index 98f4975ea..7da6fbc41 100644 --- a/spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala +++ b/spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala @@ -385,6 +385,12 @@ class functionTestScala extends TestBaseScala with Matchers with GeometrySample assert(!testtable.take(1)(0).get(1).asInstanceOf[Boolean]) } + it("Passed ST_HasZ") { + val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON Z ((30 10 5, 40 40 10, 20 40 15, 10 20 20, 30 10 5))') as poly") + val actual = baseDf.selectExpr("ST_HasZ(poly)").first().getBoolean(0) + assert(actual) + } + it("Passed ST_HasM") { val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ZM ((30 10 5 1, 40 40 10 2, 20 40 15 3, 10 20 20 4, 30 10 5 1))') as poly") val actual = baseDf.selectExpr("ST_HasM(poly)").first().getBoolean(0)
