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 95e06027f41ce51d9b743c3f2e9845bdcaa0b76f
Author: Furqaan Khan <[email protected]>
AuthorDate: Tue Apr 30 19:11:44 2024 -0400

    [TASK-151] Add ST_MPointFromText (#174)
---
 .../org/apache/sedona/common/Constructors.java     |  8 ++++++++
 .../org/apache/sedona/common/ConstructorsTest.java | 14 +++++++++++++
 docs/api/flink/Constructor.md                      | 24 ++++++++++++++++++++++
 docs/api/snowflake/vector-data/Constructor.md      | 22 ++++++++++++++++++++
 docs/api/sql/Constructor.md                        | 24 ++++++++++++++++++++++
 .../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             | 19 +++++++++--------
 .../sedona/snowflake/snowsql/TestConstructors.java | 15 ++++++++++++++
 .../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, 232 insertions(+), 8 deletions(-)

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 106bc1d13..910d650e5 100644
--- a/common/src/main/java/org/apache/sedona/common/Constructors.java
+++ b/common/src/main/java/org/apache/sedona/common/Constructors.java
@@ -92,6 +92,14 @@ public class Constructors {
         return geom;
     }
 
+    public static Geometry mPointFromText(String wkt, int srid) throws 
ParseException {
+        if (wkt == null || !wkt.startsWith("MULTIPOINT")) {
+            return null;
+        }
+        GeometryFactory geometryFactory = new GeometryFactory(new 
PrecisionModel(), srid);
+        return new WKTReader(geometryFactory).read(wkt);
+    }
+
     public static Geometry mLineFromText(String wkt, int srid) throws 
ParseException {
         if (wkt == null || !wkt.startsWith("MULTILINESTRING")) {
             return null;
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 0f5c4fec4..2aaa51d20 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,20 @@ public class ConstructorsTest {
 
     }
 
+    @Test
+    public void mPointFromText() throws ParseException {
+        assertNull(Constructors.mPointFromText(null, 0));
+        assertNull(Constructors.mPointFromText("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.mPointFromText("MULTIPOINT ((10 10), (20 
20), (30 30))", 0);
+        assertEquals(0,geom.getSRID());
+        assertEquals("MULTIPOINT ((10 10), (20 20), (30 30))",geom.toText());
+
+        geom = Constructors.mPointFromText("MULTIPOINT ((10 10), (20 20), (30 
30))", 3306);
+        assertEquals(3306,geom.getSRID());
+        assertEquals("MULTIPOINT ((10 10), (20 20), (30 30))"
+                ,geom.toText());
+    }
+
     @Test
     public void geomCollFromText() throws ParseException {
         assertNull(Constructors.geomCollFromText(null, 0));
diff --git a/docs/api/flink/Constructor.md b/docs/api/flink/Constructor.md
index 489615968..bf42c9634 100644
--- a/docs/api/flink/Constructor.md
+++ b/docs/api/flink/Constructor.md
@@ -466,6 +466,30 @@ Output:
 MULTILINESTRING ((1 2, 3 4), (4 5, 6 7))
 ```
 
+## ST_MPointFromText
+
+Introduction: Constructs a MultiPoint 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 `MULTIPOINT`.
+
+Format:
+
+`ST_MPointFromText (Wkt: String)`
+
+`ST_MPointFromText (Wkt: String, srid: Integer)`
+
+Since: `vTBD`
+
+SQL Example:
+
+```sql
+SELECT ST_MPointFromText('MULTIPOINT ((10 10), (20 20), (30 30))')
+```
+
+Output:
+
+```
+MULTIPOINT ((10 10), (20 20), (30 30))
+```
+
 ## ST_MPolyFromText
 
 Introduction: Construct a MultiPolygon from Text and Optional SRID
diff --git a/docs/api/snowflake/vector-data/Constructor.md 
b/docs/api/snowflake/vector-data/Constructor.md
index 44bac2825..feff729e6 100644
--- a/docs/api/snowflake/vector-data/Constructor.md
+++ b/docs/api/snowflake/vector-data/Constructor.md
@@ -430,6 +430,28 @@ Output:
 MULTILINESTRING ((1 2, 3 4), (4 5, 6 7))
 ```
 
+## ST_MPointFromText
+
+Introduction: Constructs a MultiPoint 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 `MULTIPOINT`.
+
+Format:
+
+`ST_MPointFromText (Wkt: String)`
+
+`ST_MPointFromText (Wkt: String, srid: Integer)`
+
+SQL Example:
+
+```sql
+SELECT ST_MPointFromText('MULTIPOINT ((10 10), (20 20), (30 30))')
+```
+
+Output:
+
+```
+MULTIPOINT ((10 10), (20 20), (30 30))
+```
+
 ## ST_MPolyFromText
 
 Introduction: Construct a MultiPolygon from Wkt. If srid is not set, it 
defaults to 0 (unknown).
diff --git a/docs/api/sql/Constructor.md b/docs/api/sql/Constructor.md
index e02bfe641..8e6d90f93 100644
--- a/docs/api/sql/Constructor.md
+++ b/docs/api/sql/Constructor.md
@@ -521,6 +521,30 @@ Output:
 MULTILINESTRING ((1 2, 3 4), (4 5, 6 7))
 ```
 
+## ST_MPointFromText
+
+Introduction: Constructs a MultiPoint 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 `MULTIPOINT`.
+
+Format:
+
+`ST_MPointFromText (Wkt: String)`
+
+`ST_MPointFromText (Wkt: String, srid: Integer)`
+
+Since: `vTBD`
+
+SQL Example:
+
+```sql
+SELECT ST_MPointFromText('MULTIPOINT ((10 10), (20 20), (30 30))')
+```
+
+Output:
+
+```
+MULTIPOINT ((10 10), (20 20), (30 30))
+```
+
 ## ST_MPolyFromText
 
 Introduction: Construct a MultiPolygon from Wkt. If srid is not set, it 
defaults to 0 (unknown).
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 0cea5e694..0241d4032 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -45,6 +45,7 @@ public class Catalog {
                 new Constructors.ST_GeomFromGeoHash(),
                 new Constructors.ST_GeomFromGML(),
                 new Constructors.ST_GeomFromKML(),
+                new Constructors.ST_MPointFromText(),
                 new Constructors.ST_MPolyFromText(),
                 new Constructors.ST_MLineFromText(),
                 new Constructors.ST_GeomCollFromText(),
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 a0719642f..3b4778f68 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,6 +373,17 @@ public class Constructors {
         }
     }
 
+    public static class ST_MPointFromText 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.mPointFromText(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.mPointFromText(wkt, 
0);
+        }
+    }
+
     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 {
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 5ec29d54f..bd39f758f 100644
--- a/flink/src/test/java/org/apache/sedona/flink/ConstructorTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/ConstructorTest.java
@@ -560,6 +560,26 @@ public class ConstructorTest extends TestBase{
         assertEquals(expectedGeom, result);
     }
 
+    @Test
+    public void testMPointFromText() {
+        Table tbl = tableEnv.sqlQuery("SELECT 'MULTIPOINT ((10 10), (20 20), 
(30 30))' AS coll, 4326 as srid");
+        String actualColl = first(
+                
tbl.select(call(Constructors.ST_MPointFromText.class.getSimpleName(), 
$("coll")))
+        ).getFieldAs(0).toString();
+        String expectedColl = "MULTIPOINT ((10 10), (20 20), (30 30))";
+        assertEquals(expectedColl, actualColl);
+
+        actualColl = first(
+                
tbl.select(call(Constructors.ST_MPointFromText.class.getSimpleName(), 
$("coll"), $("srid")))
+        ).getFieldAs(0).toString();
+        assertEquals(expectedColl, actualColl);
+        int actualSrid = first(
+                
tbl.select(call(Constructors.ST_MPointFromText.class.getSimpleName(), 
$("coll"), $("srid")))
+                        
.as("geom").select(call(Functions.ST_SRID.class.getSimpleName(), $("geom")))
+        ).getFieldAs(0);
+        assertEquals(4326, actualSrid);
+    }
+
     @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");
diff --git a/python/sedona/sql/st_constructors.py 
b/python/sedona/sql/st_constructors.py
index f04ac9e5e..3842d72d2 100644
--- a/python/sedona/sql/st_constructors.py
+++ b/python/sedona/sql/st_constructors.py
@@ -396,6 +396,21 @@ def ST_MLineFromText(wkt: ColumnOrName, srid: 
Optional[ColumnOrNameOrNumber] = N
 
     return _call_constructor_function("ST_MLineFromText", args)
 
+@validate_argument_types
+def ST_MPointFromText(wkt: ColumnOrName, srid: Optional[ColumnOrNameOrNumber] 
= None) -> Column:
+    """Generate MultiPoint geometry from a MultiPoint WKT representation.
+
+    :param wkt: MultiPoint WKT string column to generate from.
+    :type wkt: ColumnOrName
+    :param srid: SRID for the geometry
+    :type srid: ColumnOrNameOrNumber
+    :return: MultiPoint geometry generated from the wkt column.
+    :rtype: Column
+    """
+    args = (wkt) if srid is None else (wkt, srid)
+
+    return _call_constructor_function("ST_MPointFromText", args)
+
 @validate_argument_types
 def ST_GeomCollFromText(wkt: ColumnOrName, srid: 
Optional[ColumnOrNameOrNumber] = None) -> Column:
     """Generate GeometryCollection geometry from a GeometryCollection WKT 
representation.
diff --git a/python/tests/sql/test_constructor_test.py 
b/python/tests/sql/test_constructor_test.py
index 302cf5d1d..91ea7802e 100644
--- a/python/tests/sql/test_constructor_test.py
+++ b/python/tests/sql/test_constructor_test.py
@@ -191,6 +191,19 @@ class TestConstructors(TestBase):
         line_df = self.spark.sql("select ST_MPolyFromText(wkt) as geom from 
input_wkt")
         assert line_df.count() == 1
 
+    def test_mpoint_from_text(self):
+        baseDf = self.spark.sql("SELECT 'MULTIPOINT ((10 10), (20 20), (30 
30))' as geom, 4326 as srid")
+        actual = 
baseDf.selectExpr("ST_AsText(ST_MPointFromText(geom))").take(1)[0][0]
+        expected = 'MULTIPOINT ((10 10), (20 20), (30 30))'
+        assert expected == actual
+
+        actualGeom = baseDf.selectExpr("ST_MPointFromText(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
+
     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]
diff --git a/python/tests/sql/test_dataframe_api.py 
b/python/tests/sql/test_dataframe_api.py
index a1450c880..bdee4108b 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -60,10 +60,8 @@ test_configurations = [
     (stc.ST_MPolyFromText, ("mpoly", 4326), "constructor", "" , "MULTIPOLYGON 
(((0 0, 20 0, 20 20, 0 20, 0 0), (5 5, 5 7, 7 7, 7 5, 5 5)))"),
     (stc.ST_MLineFromText, ("mline", ), "constructor", "" , "MULTILINESTRING 
((1 2, 3 4), (4 5, 6 7))"),
     (stc.ST_MLineFromText, ("mline", 4326), "constructor", "" , 
"MULTILINESTRING ((1 2, 3 4), (4 5, 6 7))"),
-    (stc.ST_PointM, ("x", "y", "m", "srid"), "x_y_z_m_srid", 
"ST_AsEWKT(geom)", "SRID=4326;POINT ZM(1 2 0 100.9)"),
-    (stc.ST_PointZM, ("x", "y", "z", "m", "srid"), "x_y_z_m_srid", "", "POINT 
Z (1 2 3)"),
-    (stc.ST_PointFromGeoHash, ("geohash", 4), "constructor", 
"ST_ReducePrecision(geom, 2)", "POINT (0.88 0.97)"),
-    (stc.ST_PointFromGeoHash, ("geohash",), "constructor", 
"ST_ReducePrecision(geom, 2)", "POINT (1 1)"),
+    (stc.ST_MPointFromText, ("mpoint", ), "constructor", "" , "MULTIPOINT (10 
10, 20 20, 30 30)"),
+    (stc.ST_MPointFromText, ("mpoint", 4326), "constructor", "" , "MULTIPOINT 
(10 10, 20 20, 30 30)"),
     (stc.ST_PointFromText, ("single_point", lambda: f.lit(',')), 
"constructor", "", "POINT (0 1)"),
     (stc.ST_PointFromWKB, ("wkbPoint",), "constructor", "", "POINT (10 15)"),
     (stc.ST_MakePoint, ("x", "y", "z"), "constructor", "", "POINT Z (0 1 2)"),
@@ -264,6 +262,7 @@ wrong_type_configurations = [
     (stc.ST_PointFromText, (None, "")),
     (stc.ST_PointFromText, ("", None)),
     (stc.ST_PointFromWKB, (None,)),
+    (stc.ST_MPointFromText, (None,)),
     (stc.ST_PolygonFromEnvelope, (None, "", "", "")),
     (stc.ST_PolygonFromEnvelope, ("", None, "", "")),
     (stc.ST_PolygonFromEnvelope, ("", "", None, "")),
@@ -441,10 +440,12 @@ class TestDataFrameAPI(TestBase):
 
     @pytest.fixture
     def base_df(self, request):
-        mpoly = 'MULTIPOLYGON(((0 0 ,20 0 ,20 20 ,0 20 ,0 0 ),(5 5 ,5 7 ,7 7 
,7 5 ,5 5)))'
-        mline = 'MULTILINESTRING((1 2, 3 4), (4 5, 6 7))'
         wkbLine = 
'0102000000020000000000000084d600c00000000080b5d6bf00000060e1eff7bf00000080075de5bf'
         wkbPoint = '010100000000000000000024400000000000002e40'
+        wkb = 
'0102000000020000000000000084d600c00000000080b5d6bf00000060e1eff7bf00000080075de5bf'
+        mpoly = 'MULTIPOLYGON(((0 0 ,20 0 ,20 20 ,0 20 ,0 0 ),(5 5 ,5 7 ,7 7 
,7 5 ,5 5)))'
+        mline = 'MULTILINESTRING((1 2, 3 4), (4 5, 6 7))'
+        mpoint = 'MULTIPOINT ((10 10), (20 20), (30 30))'
         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>"
@@ -457,10 +458,12 @@ class TestDataFrameAPI(TestBase):
                 "2.0 AS z",
                 "'0.0,1.0' AS single_point",
                 "'0.0,0.0,1.0,0.0,1.0,1.0,0.0,0.0' AS multiple_point",
-                f"'{mpoly}' AS mpoly",
-                f"'{mline}' AS mline",
                 f"X'{wkbLine}' AS wkbLine",
                 f"X'{wkbPoint}' AS wkbPoint",
+                f"X'{wkb}' AS wkb",
+                f"'{mpoly}' AS mpoly",
+                f"'{mline}' AS mline",
+                f"'{mpoint}' AS mpoint",
                 f"'{geojson}' AS geojson",
                 "'s00twy01mt' AS geohash",
                 f"'{gml_string}' AS gml",
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 d8a4f7edb..c6b8b2ba1 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
@@ -201,6 +201,21 @@ public class TestConstructors extends TestBase{
         );
     }
 
+    @Test
+    public void test_ST_MPointFromText() {
+        registerUDF("ST_MPointFromText", String.class);
+        registerUDF("ST_SRID", byte[].class);
+        verifySqlSingleRes(
+                "select sedona.ST_AsText(sedona.ST_MPointFromText('MULTIPOINT 
((10 10), (20 20), (30 30))'))",
+                "MULTIPOINT ((10 10), (20 20), (30 30))"
+        );
+        registerUDF("ST_MPointFromText", String.class, int.class);
+        verifySqlSingleRes(
+                "select sedona.ST_SRID(sedona.ST_MPointFromText('MULTIPOINT 
((10 10), (20 20), (30 30))',4269))",
+                4269
+        );
+    }
+
     @Test
     public void test_ST_GeomCollFromText() {
         registerUDF("ST_GeomCollFromText", 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 b3e2570cd..fa498697a 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_MPointFromText(String wkt, int srid) throws 
ParseException {
+        return GeometrySerde.serialize(
+                Constructors.mPointFromText(wkt, srid)
+        );
+    }
+
+    @UDFAnnotations.ParamMeta(argNames = {"wkt"})
+    public static byte[] ST_MPointFromText(String wkt) throws ParseException {
+        return GeometrySerde.serialize(
+                Constructors.mPointFromText(wkt, 0)
+        );
+    }
+
     @UDFAnnotations.ParamMeta(argNames = {"wkt", "srid"})
     public static byte[] ST_GeomCollFromText(String wkt, int srid) throws 
ParseException {
         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 502ae1ace..42babb795 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
@@ -180,6 +180,7 @@ object Catalog {
     function[ST_CollectionExtract](defaultArgs = null),
     function[ST_Normalize](),
     function[ST_LineFromMultiPoint](),
+    function[ST_MPointFromText](0),
     function[ST_MPolyFromText](0),
     function[ST_MLineFromText](0),
     function[ST_GeomCollFromText](0),
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 45d9c3162..d192df654 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
@@ -455,6 +455,14 @@ case class ST_MLineFromText(inputExpressions: 
Seq[Expression])
   }
 }
 
+case class ST_MPointFromText(inputExpressions: Seq[Expression])
+  extends InferredExpression(Constructors.mPointFromText _) {
+
+  protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = 
{
+    copy(inputExpressions = newChildren)
+  }
+}
+
 case class ST_GeomCollFromText(inputExpressions: Seq[Expression])
   extends InferredExpression(Constructors.geomCollFromText _) {
 
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 b3a8f8500..6002e8c9a 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
@@ -166,4 +166,9 @@ object st_constructors extends DataFrameAPI {
   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)
+
+  def ST_MPointFromText(wkt: Column): Column = 
wrapExpression[ST_MPointFromText](wkt, 0)
+  def ST_MPointFromText(wkt: String): Column = 
wrapExpression[ST_MPointFromText](wkt, 0)
+  def ST_MPointFromText(wkt: Column, srid: Column): Column = 
wrapExpression[ST_MPointFromText](wkt, srid)
+  def ST_MPointFromText(wkt: String, srid: Int): Column = 
wrapExpression[ST_MPointFromText](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 aec9408f7..66a94dae6 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
@@ -424,6 +424,19 @@ class constructorTestScala extends TestBaseScala {
       assert(mLineDf.count() == 1)
     }
 
+    it("Passed ST_MPointFromText") {
+      val baseDf = sparkSession.sql("SELECT 'MULTIPOINT ((10 10), (20 20), (30 
30))' as geom, 4326 as srid")
+      var actual = 
baseDf.selectExpr("ST_MPointFromText(geom)").first().get(0).asInstanceOf[Geometry].toText
+      val expected = "MULTIPOINT ((10 10), (20 20), (30 30))"
+      assert(expected.equals(actual))
+
+      val actualGeom = baseDf.selectExpr("ST_MPointFromText(geom, 
srid)").first().get(0).asInstanceOf[Geometry]
+      actual = actualGeom.toText
+      assert(expected.equals(actual))
+      val actualSrid = actualGeom.getSRID
+      assert(4326 == actualSrid)
+    }
+
     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
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 5074707f6..94a2a6059 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_MPointFromText()") {
+      val df = sparkSession.sql("SELECT 'MULTIPOINT ((10 10), (20 20), (30 
30))' as geom")
+      var actual = 
df.select(ST_MPointFromText("geom")).first().get(0).asInstanceOf[Geometry].toText
+      val expected = "MULTIPOINT ((10 10), (20 20), (30 30))"
+      assert(expected == actual)
+
+      val actualGeom = df.select(ST_MPointFromText("geom", 
4326)).first().get(0).asInstanceOf[Geometry]
+      actual = actualGeom.toText
+      assert(actual == expected)
+      val actualSrid = actualGeom.getSRID
+      assert(4326 == actualSrid)
+    }
+
     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

Reply via email to