This is an automated email from the ASF dual-hosted git repository. jiayu pushed a commit to branch SEDONA-590 in repository https://gitbox.apache.org/repos/asf/sedona.git
commit fc7e6df86b8abb8a5148963c1d153e9afaab79eb Author: Furqaan Khan <[email protected]> AuthorDate: Fri Apr 26 16:18:00 2024 -0400 [TASK-238] Add ST_GeomCollFromText (#171) --- .../org/apache/sedona/common/Constructors.java | 8 +++ .../org/apache/sedona/common/ConstructorsTest.java | 17 ++++++ docs/api/flink/Constructor.md | 60 ++++++++++++++++++++++ docs/api/snowflake/vector-data/Constructor.md | 56 ++++++++++++++++++++ docs/api/sql/Constructor.md | 60 ++++++++++++++++++++++ .../main/java/org/apache/sedona/flink/Catalog.java | 1 + .../sedona/flink/expressions/Constructors.java | 11 ++++ .../org/apache/sedona/flink/ConstructorTest.java | 20 ++++++++ python/sedona/sql/st_constructors.py | 15 ++++++ python/tests/sql/test_constructor_test.py | 13 +++++ python/tests/sql/test_dataframe_api.py | 8 ++- .../sedona/snowflake/snowsql/TestConstructors.java | 14 +++++ .../org/apache/sedona/snowflake/snowsql/UDFs.java | 14 +++++ .../scala/org/apache/sedona/sql/UDF/Catalog.scala | 1 + .../sql/sedona_sql/expressions/Constructors.scala | 8 +++ .../sedona_sql/expressions/st_constructors.scala | 5 ++ .../apache/sedona/sql/constructorTestScala.scala | 13 +++++ .../apache/sedona/sql/dataFrameAPITestScala.scala | 13 +++++ 18 files changed, 336 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/apache/sedona/common/Constructors.java b/common/src/main/java/org/apache/sedona/common/Constructors.java index 93dd8b00d..106bc1d13 100644 --- a/common/src/main/java/org/apache/sedona/common/Constructors.java +++ b/common/src/main/java/org/apache/sedona/common/Constructors.java @@ -108,6 +108,14 @@ public class Constructors { return new WKTReader(geometryFactory).read(wkt); } + public static Geometry geomCollFromText(String wkt, int srid) throws ParseException { + if (wkt == null || !wkt.startsWith("GEOMETRYCOLLECTION")) { + return null; + } + GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), srid); + return new WKTReader(geometryFactory).read(wkt); + } + /** * Creates a point from the given coordinate. diff --git a/common/src/test/java/org/apache/sedona/common/ConstructorsTest.java b/common/src/test/java/org/apache/sedona/common/ConstructorsTest.java index 49336f9f4..0f5c4fec4 100644 --- a/common/src/test/java/org/apache/sedona/common/ConstructorsTest.java +++ b/common/src/test/java/org/apache/sedona/common/ConstructorsTest.java @@ -98,6 +98,23 @@ public class ConstructorsTest { } + @Test + public void geomCollFromText() throws ParseException { + assertNull(Constructors.geomCollFromText(null, 0)); + assertNull(Constructors.geomCollFromText("MULTIPOLYGON (((0 0, 20 0, 20 20, 0 20, 0 0), (5 5, 5 7, 7 7, 7 5, 5 5)))", 0)); + Geometry geom = Constructors.geomCollFromText("GEOMETRYCOLLECTION (POINT (10 20),LINESTRING (30 40, 50 60, 70 80),POLYGON ((10 10, 20 20, 10 20, 10 10)))", 0); + assertEquals(0,geom.getSRID()); + assertEquals("GEOMETRYCOLLECTION (POINT (10 20), LINESTRING (30 40, 50 60, 70 80), POLYGON ((10 10, 20 20, 10 20, 10 10)))",geom.toText()); + + geom = Constructors.geomCollFromText("GEOMETRYCOLLECTION (POINT (10 20),LINESTRING (30 40, 50 60, 70 80),POLYGON ((10 10, 20 20, 10 20, 10 10)))", 3306); + assertEquals(3306,geom.getSRID()); + assertEquals("GEOMETRYCOLLECTION (POINT (10 20), LINESTRING (30 40, 50 60, 70 80), POLYGON ((10 10, 20 20, 10 20, 10 10)))" + ,geom.toText()); + + ParseException parseException = assertThrows(ParseException.class, () -> Constructors.geomCollFromText("GEOMETRYCOLLECTION (POLYGON(not valid))", 0)); + assertEquals("Expected EMPTY or ( but found 'not' (line 1)", parseException.getMessage()); + } + @Test public void point() { Geometry point = Constructors.point(1.0d, 2.0d); diff --git a/docs/api/flink/Constructor.md b/docs/api/flink/Constructor.md index ae3c32e9a..9061b14f8 100644 --- a/docs/api/flink/Constructor.md +++ b/docs/api/flink/Constructor.md @@ -1,3 +1,63 @@ +## ST_GeomCollFromText + +Introduction: Constructs a GeometryCollection from the WKT with the given SRID. If SRID is not provided then it defaults to 0. It returns `null` if the WKT is not a `GEOMETRYCOLLECTION`. + +Format: + +`ST_GeomCollFromText (Wkt: String)` + +`ST_GeomCollFromText (Wkt: String, srid: Integer)` + +Since: `vTBD` + +SQL Example: + +```sql +SELECT ST_GeomCollFromText('GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))') +``` + +Output: + +``` +GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15))) +``` + +## ST_GeomFromEWKB + +Introduction: Construct a Geometry from EWKB string or Binary. This function is an alias of [ST_GeomFromWKB](#st_geomfromwkb). + +Format: + +`ST_GeomFromEWKB (Wkb: String)` + +`ST_GeomFromEWKB (Wkb: Binary)` + +Since: `vTBD` + +SQL Example + +```sql +SELECT ST_GeomFromEWKB([01 02 00 00 00 02 00 00 00 00 00 00 00 84 D6 00 C0 00 00 00 00 80 B5 D6 BF 00 00 00 60 E1 EF F7 BF 00 00 00 80 07 5D E5 BF]) +``` + +Output: + +``` +LINESTRING (-2.1047439575195312 -0.354827880859375, -1.49606454372406 -0.6676061153411865) +``` + +SQL Example + +```sql +SELECT ST_asEWKT(ST_GeomFromEWKB('01010000a0e6100000000000000000f03f000000000000f03f000000000000f03f')) +``` + +Output: + +``` +SRID=4326;POINT Z(1 1 1) +``` + ## ST_GeomFromEWKT Introduction: Construct a Geometry from OGC Extended WKT diff --git a/docs/api/snowflake/vector-data/Constructor.md b/docs/api/snowflake/vector-data/Constructor.md index f35972a30..44bac2825 100644 --- a/docs/api/snowflake/vector-data/Constructor.md +++ b/docs/api/snowflake/vector-data/Constructor.md @@ -1,6 +1,62 @@ !!!note Please always keep the schema name `SEDONA` (e.g., `SEDONA.ST_GeomFromWKT`) when you use Sedona functions to avoid conflicting with Snowflake's built-in functions. +## ST_GeomCollFromText + +Introduction: Constructs a GeometryCollection from the WKT with the given SRID. If SRID is not provided then it defaults to 0. It returns `null` if the WKT is not a `GEOMETRYCOLLECTION`. + +Format: + +`ST_GeomCollFromText (Wkt: String)` + +`ST_GeomCollFromText (Wkt: String, srid: Integer)` + +SQL Example: + +```sql +SELECT ST_GeomCollFromText('GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))') +``` + +Output: + +``` +GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15))) +``` + +## ST_GeomFromEWKB + +Introduction: Construct a Geometry from EWKB string or Binary. This function is an alias of [ST_GeomFromWKB](#st_geomfromwkb). + +Format: + +`ST_GeomFromEWKB (Wkb: String)` + +`ST_GeomFromEWKB (Wkb: Binary)` + +SQL Example + +```sql +SELECT ST_GeomFromEWKB([01 02 00 00 00 02 00 00 00 00 00 00 00 84 D6 00 C0 00 00 00 00 80 B5 D6 BF 00 00 00 60 E1 EF F7 BF 00 00 00 80 07 5D E5 BF]) +``` + +Output: + +``` +LINESTRING (-2.1047439575195312 -0.354827880859375, -1.49606454372406 -0.6676061153411865) +``` + +SQL Example + +```sql +SELECT ST_asEWKT(ST_GeomFromEWKB('01010000a0e6100000000000000000f03f000000000000f03f000000000000f03f')) +``` + +Output: + +``` +SRID=4326;POINT Z(1 1 1) +``` + ## ST_GeomFromEWKT Introduction: Construct a Geometry from OGC Extended WKT diff --git a/docs/api/sql/Constructor.md b/docs/api/sql/Constructor.md index e3ca74631..68888c2c7 100644 --- a/docs/api/sql/Constructor.md +++ b/docs/api/sql/Constructor.md @@ -44,6 +44,66 @@ spark.driver.extraJavaOptions -Dsedona.global.charset=utf8 spark.executor.extraJavaOptions -Dsedona.global.charset=utf8 ``` +## ST_GeomCollFromText + +Introduction: Constructs a GeometryCollection from the WKT with the given SRID. If SRID is not provided then it defaults to 0. It returns `null` if the WKT is not a `GEOMETRYCOLLECTION`. + +Format: + +`ST_GeomCollFromText (Wkt: String)` + +`ST_GeomCollFromText (Wkt: String, srid: Integer)` + +Since: `vTBD` + +SQL Example: + +```sql +SELECT ST_GeomCollFromText('GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))') +``` + +Output: + +``` +GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15))) +``` + +## ST_GeomFromEWKB + +Introduction: Construct a Geometry from EWKB string or Binary. This function is an alias of [ST_GeomFromWKB](#st_geomfromwkb). + +Format: + +`ST_GeomFromEWKB (Wkb: String)` + +`ST_GeomFromEWKB (Wkb: Binary)` + +Since: `vTBD` + +SQL Example + +```sql +SELECT ST_GeomFromEWKB([01 02 00 00 00 02 00 00 00 00 00 00 00 84 D6 00 C0 00 00 00 00 80 B5 D6 BF 00 00 00 60 E1 EF F7 BF 00 00 00 80 07 5D E5 BF]) +``` + +Output: + +``` +LINESTRING (-2.1047439575195312 -0.354827880859375, -1.49606454372406 -0.6676061153411865) +``` + +SQL Example + +```sql +SELECT ST_asEWKT(ST_GeomFromEWKB('01010000a0e6100000000000000000f03f000000000000f03f000000000000f03f')) +``` + +Output: + +``` +SRID=4326;POINT Z(1 1 1) +``` + ## ST_GeomFromEWKT Introduction: Construct a Geometry from OGC Extended WKT 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 591b783d0..0cea5e694 100644 --- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java +++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java @@ -47,6 +47,7 @@ public class Catalog { new Constructors.ST_GeomFromKML(), new Constructors.ST_MPolyFromText(), new Constructors.ST_MLineFromText(), + new Constructors.ST_GeomCollFromText(), new Functions.GeometryType(), new Functions.ST_Area(), new Functions.ST_AreaSpheroid(), diff --git a/flink/src/main/java/org/apache/sedona/flink/expressions/Constructors.java b/flink/src/main/java/org/apache/sedona/flink/expressions/Constructors.java index 2f60623b0..a0719642f 100644 --- a/flink/src/main/java/org/apache/sedona/flink/expressions/Constructors.java +++ b/flink/src/main/java/org/apache/sedona/flink/expressions/Constructors.java @@ -373,4 +373,15 @@ public class Constructors { } } + public static class ST_GeomCollFromText extends ScalarFunction { + @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) + public Geometry eval(@DataTypeHint(value = "String") String wkt, @DataTypeHint("Int") Integer srid) throws ParseException { + return org.apache.sedona.common.Constructors.geomCollFromText(wkt, srid); + } + @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) + public Geometry eval(@DataTypeHint(value = "String") String wkt) throws ParseException { + return org.apache.sedona.common.Constructors.geomCollFromText(wkt, 0); + } + } + } diff --git a/flink/src/test/java/org/apache/sedona/flink/ConstructorTest.java b/flink/src/test/java/org/apache/sedona/flink/ConstructorTest.java index 693aadac4..5ec29d54f 100644 --- a/flink/src/test/java/org/apache/sedona/flink/ConstructorTest.java +++ b/flink/src/test/java/org/apache/sedona/flink/ConstructorTest.java @@ -559,4 +559,24 @@ public class ConstructorTest extends TestBase{ String expectedGeom = "MULTILINESTRING ((1 2, 3 4), (4 5, 6 7))"; assertEquals(expectedGeom, result); } + + @Test + public void testGeomCollFromText() { + Table tbl = tableEnv.sqlQuery("SELECT 'GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90),POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))' AS coll, 4326 as srid"); + String actualColl = first( + tbl.select(call(Constructors.ST_GeomCollFromText.class.getSimpleName(), $("coll"))) + ).getFieldAs(0).toString(); + String expectedColl = "GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))"; + assertEquals(expectedColl, actualColl); + + actualColl = first( + tbl.select(call(Constructors.ST_GeomCollFromText.class.getSimpleName(), $("coll"), $("srid"))) + ).getFieldAs(0).toString(); + assertEquals(expectedColl, actualColl); + int actualSrid = first( + tbl.select(call(Constructors.ST_GeomCollFromText.class.getSimpleName(), $("coll"), $("srid"))) + .as("geom").select(call(Functions.ST_SRID.class.getSimpleName(), $("geom"))) + ).getFieldAs(0); + assertEquals(4326, actualSrid); + } } diff --git a/python/sedona/sql/st_constructors.py b/python/sedona/sql/st_constructors.py index 50ab1899f..f04ac9e5e 100644 --- a/python/sedona/sql/st_constructors.py +++ b/python/sedona/sql/st_constructors.py @@ -395,3 +395,18 @@ def ST_MLineFromText(wkt: ColumnOrName, srid: Optional[ColumnOrNameOrNumber] = N args = (wkt) if srid is None else (wkt, srid) return _call_constructor_function("ST_MLineFromText", args) + +@validate_argument_types +def ST_GeomCollFromText(wkt: ColumnOrName, srid: Optional[ColumnOrNameOrNumber] = None) -> Column: + """Generate GeometryCollection geometry from a GeometryCollection WKT representation. + + :param wkt: GeometryCollection WKT string column to generate from. + :type wkt: ColumnOrName + :param srid: SRID for the geometry + :type srid: ColumnOrNameOrNumber + :return: GeometryCollection geometry generated from the wkt column. + :rtype: Column + """ + args = (wkt) if srid is None else (wkt, srid) + + return _call_constructor_function("ST_GeomCollFromText", args) diff --git a/python/tests/sql/test_constructor_test.py b/python/tests/sql/test_constructor_test.py index cd9a30b93..302cf5d1d 100644 --- a/python/tests/sql/test_constructor_test.py +++ b/python/tests/sql/test_constructor_test.py @@ -190,3 +190,16 @@ class TestConstructors(TestBase): input_df.createOrReplaceTempView("input_wkt") line_df = self.spark.sql("select ST_MPolyFromText(wkt) as geom from input_wkt") assert line_df.count() == 1 + + def test_geom_coll_from_text(self): + baseDf = self.spark.sql("SELECT 'GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))' as geom, 4326 as srid") + actual = baseDf.selectExpr("ST_AsText(ST_GeomCollFromText(geom))").take(1)[0][0] + expected = 'GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))' + assert expected == actual + + actualGeom = baseDf.selectExpr("ST_GeomCollFromText(geom, srid) as geom") + actual = actualGeom.selectExpr("ST_AsText(geom)").take(1)[0][0] + assert expected == actual + + actualSrid = actualGeom.selectExpr("ST_SRID(geom)").take(1)[0][0] + assert actualSrid == 4326 diff --git a/python/tests/sql/test_dataframe_api.py b/python/tests/sql/test_dataframe_api.py index 0426c7414..a1450c880 100644 --- a/python/tests/sql/test_dataframe_api.py +++ b/python/tests/sql/test_dataframe_api.py @@ -70,6 +70,8 @@ test_configurations = [ (stc.ST_PolygonFromEnvelope, ("minx", "miny", "maxx", "maxy"), "min_max_x_y", "", "POLYGON ((0 1, 0 3, 2 3, 2 1, 0 1))"), (stc.ST_PolygonFromEnvelope, (0.0, 1.0, 2.0, 3.0), "null", "", "POLYGON ((0 1, 0 3, 2 3, 2 1, 0 1))"), (stc.ST_PolygonFromText, ("multiple_point", lambda: f.lit(',')), "constructor", "", "POLYGON ((0 0, 1 0, 1 1, 0 0))"), + (stc.ST_GeomCollFromText, ("collection",), "constructor", "", "GEOMETRYCOLLECTION (POINT (1 1), LINESTRING (0 0, 1 1))"), + (stc.ST_GeomCollFromText, ("collection", 4326), "constructor", "ST_SRID(geom)", 4326), # functions (stf.GeometryType, ("line",), "linestring_geom", "", "LINESTRING"), @@ -268,6 +270,8 @@ wrong_type_configurations = [ (stc.ST_PolygonFromEnvelope, ("", "", "", None)), (stc.ST_PolygonFromText, (None, "")), (stc.ST_PolygonFromText, ("", None)), + (stc.ST_PolygonFromText, (None, None)), + (stc.ST_PolygonFromText, ("", None)), # functions (stf.ST_3DDistance, (None, "")), @@ -444,6 +448,7 @@ class TestDataFrameAPI(TestBase): geojson = "{ \"type\": \"Feature\", \"properties\": { \"prop\": \"01\" }, \"geometry\": { \"type\": \"Point\", \"coordinates\": [ 0.0, 1.0 ] }}," gml_string = "<gml:LineString srsName=\"EPSG:4269\"><gml:coordinates>-71.16,42.25 -71.17,42.25 -71.18,42.25</gml:coordinates></gml:LineString>" kml_string = "<LineString><coordinates>-71.16,42.26 -71.17,42.26</coordinates></LineString>" + wktCollection = 'GEOMETRYCOLLECTION(POINT(1 1), LINESTRING(0 0, 1 1)))' if request.param == "constructor": return TestDataFrameAPI.spark.sql("SELECT null").selectExpr( @@ -459,7 +464,8 @@ class TestDataFrameAPI(TestBase): f"'{geojson}' AS geojson", "'s00twy01mt' AS geohash", f"'{gml_string}' AS gml", - f"'{kml_string}' AS kml" + f"'{kml_string}' AS kml", + f"'{wktCollection}' AS collection" ) elif request.param == "point_geom": return TestDataFrameAPI.spark.sql("SELECT ST_Point(0.0, 1.0) AS point") diff --git a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestConstructors.java b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestConstructors.java index c22d36814..d8a4f7edb 100644 --- a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestConstructors.java +++ b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestConstructors.java @@ -200,6 +200,20 @@ public class TestConstructors extends TestBase{ "MULTIPOLYGON (((1 2, 3 4, 5 6, 1 2)), ((7 8, 9 10, 11 12, 7 8)))" ); } + + @Test + public void test_ST_GeomCollFromText() { + registerUDF("ST_GeomCollFromText", String.class); + verifySqlSingleRes( + "select sedona.ST_AsText(sedona.ST_GeomCollFromText('GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))'))", + "GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))" + ); + registerUDF("ST_GeomCollFromText", String.class, int.class); + verifySqlSingleRes( + "select sedona.ST_SRID(sedona.ST_GeomCollFromText('GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))',4269))", + 4269 + ); + } @Test public void test_ST_Point() { registerUDF("ST_Point", double.class, double.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 a184cc6ec..b3e2570cd 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 @@ -837,6 +837,20 @@ public class UDFs { ); } + @UDFAnnotations.ParamMeta(argNames = {"wkt", "srid"}) + public static byte[] ST_GeomCollFromText(String wkt, int srid) throws ParseException { + return GeometrySerde.serialize( + Constructors.geomCollFromText(wkt, srid) + ); + } + + @UDFAnnotations.ParamMeta(argNames = {"wkt", "srid"}) + public static byte[] ST_GeomCollFromText(String wkt) throws ParseException { + return GeometrySerde.serialize( + Constructors.geomCollFromText(wkt, 0) + ); + } + @UDFAnnotations.ParamMeta(argNames = {"shell"}) public static byte[] ST_MakePolygon(byte[] shell) { return GeometrySerde.serialize( 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 f3b46011d..502ae1ace 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 @@ -182,6 +182,7 @@ object Catalog { function[ST_LineFromMultiPoint](), function[ST_MPolyFromText](0), function[ST_MLineFromText](0), + function[ST_GeomCollFromText](0), function[ST_Split](), function[ST_S2CellIDs](), function[ST_S2ToGeom](), diff --git a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Constructors.scala b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Constructors.scala index cdbe0a5c9..45d9c3162 100644 --- a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Constructors.scala +++ b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Constructors.scala @@ -454,3 +454,11 @@ case class ST_MLineFromText(inputExpressions: Seq[Expression]) copy(inputExpressions = newChildren) } } + +case class ST_GeomCollFromText(inputExpressions: Seq[Expression]) + extends InferredExpression(Constructors.geomCollFromText _) { + + protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = { + copy(inputExpressions = newChildren) + } +} diff --git a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_constructors.scala b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_constructors.scala index 5b52df90b..b3a8f8500 100644 --- a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_constructors.scala +++ b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_constructors.scala @@ -161,4 +161,9 @@ object st_constructors extends DataFrameAPI { def ST_MLineFromText(wkt: Column, srid: Column): Column = wrapExpression[ST_MLineFromText](wkt, srid) def ST_MLineFromText(wkt: String, srid: Int): Column = wrapExpression[ST_MLineFromText](wkt, srid) + + def ST_GeomCollFromText(wkt: Column): Column = wrapExpression[ST_GeomCollFromText](wkt, 0) + def ST_GeomCollFromText(wkt: String): Column = wrapExpression[ST_GeomCollFromText](wkt, 0) + def ST_GeomCollFromText(wkt: Column, srid: Column): Column = wrapExpression[ST_GeomCollFromText](wkt, srid) + def ST_GeomCollFromText(wkt: String, srid: Int): Column = wrapExpression[ST_GeomCollFromText](wkt, srid) } diff --git a/spark/common/src/test/scala/org/apache/sedona/sql/constructorTestScala.scala b/spark/common/src/test/scala/org/apache/sedona/sql/constructorTestScala.scala index d989eb611..aec9408f7 100644 --- a/spark/common/src/test/scala/org/apache/sedona/sql/constructorTestScala.scala +++ b/spark/common/src/test/scala/org/apache/sedona/sql/constructorTestScala.scala @@ -423,5 +423,18 @@ class constructorTestScala extends TestBaseScala { var mLineDf = sparkSession.sql("select ST_MPolyFromText('MULTIPOLYGON(((-70.916 42.1002,-70.9468 42.0946,-70.9765 42.0872 )))',4269)") assert(mLineDf.count() == 1) } + + it("Passed ST_GeomCollFromText") { + val baseDf = sparkSession.sql("SELECT 'GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))' as geom, 4326 as srid") + var actual = baseDf.selectExpr("ST_GeomCollFromText(geom)").first().get(0).asInstanceOf[Geometry].toText + val expected = "GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))" + assert(expected.equals(actual)) + + val actualGeom = baseDf.selectExpr("ST_GeomCollFromText(geom, srid)").first().get(0).asInstanceOf[Geometry] + actual = actualGeom.toText + assert(expected.equals(actual)) + val actualSrid = actualGeom.getSRID + assert(4326 == actualSrid) + } } } 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 1fa25d270..5074707f6 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 @@ -246,6 +246,19 @@ class dataFrameAPITestScala extends TestBaseScala { assert(actualResult == expectedResult) } + it("Passed ST_GeomCollFromText") { + val df = sparkSession.sql("SELECT 'GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))' as geom") + var actual = df.select(ST_GeomCollFromText("geom")).first().get(0).asInstanceOf[Geometry].toText + val expected = "GEOMETRYCOLLECTION (POINT (50 50), LINESTRING (20 30, 40 60, 80 90), POLYGON ((30 10, 40 20, 30 20, 30 10), (35 15, 45 15, 40 25, 35 15)))" + assert(expected == actual) + + val actualGeom = df.select(ST_GeomCollFromText("geom", 4326)).first().get(0).asInstanceOf[Geometry] + actual = actualGeom.toText + assert(actual == expected) + val actualSrid = actualGeom.getSRID + assert(4326 == actualSrid) + } + it("passed st_geomfromgeohash") { val df = sparkSession.sql("SELECT 's00twy01mt' AS geohash").select(ST_GeomFromGeoHash("geohash", 4)) val actualResult = df.take(1)(0).get(0).asInstanceOf[Geometry].toText()
