This is an automated email from the ASF dual-hosted git repository.

jiayu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sedona.git


The following commit(s) were added to refs/heads/master by this push:
     new 9ebdd5d96 [SEDONA-635] Allow ST_AsGeoJSON to return feature and 
featureCollection format GeoJSON (#1530)
9ebdd5d96 is described below

commit 9ebdd5d9683fc2d9f6ce3fb6ae9c1b6c68f3d254
Author: Pranav Toggi <[email protected]>
AuthorDate: Wed Jul 31 00:07:19 2024 -0400

    [SEDONA-635] Allow ST_AsGeoJSON to return feature and featureCollection 
format GeoJSON (#1530)
    
    * feat: add type parameter
    
    * update docs
    
    * update docs - add examples for features and featureCollections
    
    * fix typo
    
    * fix snowflake spotless error
    
    * fix python dataframe api
    
    * fix python dataframe api test
---
 .../java/org/apache/sedona/common/Functions.java   | 32 ++++++++-
 docs/api/flink/Function.md                         | 60 ++++++++++++++++-
 docs/api/snowflake/vector-data/Function.md         | 78 ++++++++++++++++++++--
 docs/api/sql/Function.md                           | 58 +++++++++++++++-
 .../apache/sedona/flink/expressions/Functions.java |  8 +++
 .../java/org/apache/sedona/flink/FunctionTest.java | 21 ++++++
 python/sedona/sql/st_functions.py                  |  5 +-
 python/tests/sql/test_dataframe_api.py             |  2 +
 .../sedona/snowflake/snowsql/TestFunctions.java    | 10 +++
 .../sedona/snowflake/snowsql/TestFunctionsV2.java  | 10 +++
 .../org/apache/sedona/snowflake/snowsql/UDFs.java  |  5 ++
 .../apache/sedona/snowflake/snowsql/UDFsV2.java    |  7 ++
 .../sql/sedona_sql/expressions/Functions.scala     |  4 +-
 .../sql/sedona_sql/expressions/st_functions.scala  |  5 ++
 .../apache/sedona/sql/dataFrameAPITestScala.scala  | 18 ++++-
 .../org/apache/sedona/sql/functionTestScala.scala  | 18 ++++-
 16 files changed, 322 insertions(+), 19 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 ce6dd4a20..4c9ce0a12 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -64,6 +64,8 @@ import 
org.locationtech.jts.simplify.TopologyPreservingSimplifier;
 import org.locationtech.jts.simplify.VWSimplifier;
 import org.locationtech.jts.triangulate.DelaunayTriangulationBuilder;
 import 
org.locationtech.jts.triangulate.polygon.ConstrainedDelaunayTriangulator;
+import org.wololo.geojson.Feature;
+import org.wololo.geojson.FeatureCollection;
 import org.wololo.jts2geojson.GeoJSONWriter;
 
 public class Functions {
@@ -664,11 +666,39 @@ public class Functions {
   }
 
   public static String asGeoJson(Geometry geometry) {
+    return asGeoJson(geometry, "simple");
+  }
+
+  public static String asGeoJson(Geometry geometry, String type) {
     if (geometry == null) {
       return null;
     }
+
     GeoJSONWriter writer = new GeoJSONWriter();
-    return writer.write(geometry).toString();
+    org.wololo.geojson.Geometry geoJson = writer.write(geometry);
+
+    switch (type.toLowerCase()) {
+      case "simple":
+        return geoJson.toString();
+
+      case "feature":
+        Map<String, Object> properties = new HashMap<>();
+        Feature feature = new Feature(geoJson, properties);
+        return feature.toString();
+
+      case "featurecollection":
+        List<Feature> features = new ArrayList<>();
+        features.add(new Feature(geoJson, new HashMap<>()));
+        FeatureCollection featureCollection =
+            new FeatureCollection(features.toArray(new Feature[0]));
+        return featureCollection.toString();
+
+      default:
+        throw new IllegalArgumentException(
+            "Unknown type: "
+                + type
+                + ". Valid types are: 'simple', 'feature', 
'featurecollection'.");
+    }
   }
 
   public static int nPoints(Geometry geometry) {
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index c188d6b84..3e56772e6 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -372,13 +372,23 @@ POINT ZM(1 1 1 1)
 
 ## ST_AsGeoJSON
 
-Introduction: Return the [GeoJSON](https://geojson.org/) string representation 
of a geometry
+Introduction: Return the [GeoJSON](https://geojson.org/) string representation 
of a geometry.
 
-Format: `ST_AsGeoJSON (A: Geometry)`
+The type parameter (Since: `v1.6.1`) takes the following options -
+
+- "Simple" (default): Returns a simple GeoJSON geometry.
+- "Feature": Wraps the geometry in a GeoJSON Feature.
+- "FeatureCollection": Wraps the Feature in a GeoJSON FeatureCollection.
+
+Format:
+
+`ST_AsGeoJSON (A: Geometry)`
+
+`ST_AsGeoJSON (A: Geometry, type: String)`
 
 Since: `v1.3.0`
 
-Example:
+SQL Example (Simple GeoJSON):
 
 ```sql
 SELECT ST_AsGeoJSON(ST_GeomFromWKT('POLYGON((1 1, 8 1, 8 8, 1 8, 1 1))'))
@@ -399,6 +409,50 @@ Output:
 }
 ```
 
+SQL Example (Feature GeoJSON):
+
+Output:
+
+```json
+{
+  "type":"Feature",
+  "geometry": {
+      "type":"Polygon",
+      "coordinates":[
+        [[1.0,1.0],
+          [8.0,1.0],
+          [8.0,8.0],
+          [1.0,8.0],
+          [1.0,1.0]]
+      ]
+  }
+}
+```
+
+SQL Example (FeatureCollection GeoJSON):
+
+Output:
+
+```json
+{
+  "type":"FeatureCollection",
+  "features": [{
+    "type":"Feature",
+    "geometry": {
+      "type":"Polygon",
+      "coordinates":[
+        [[1.0,1.0],
+          [8.0,1.0],
+          [8.0,8.0],
+          [1.0,8.0],
+          [1.0,1.0]]
+      ]
+    }
+  }
+  ]
+}
+```
+
 ## ST_AsGML
 
 Introduction: Return the [GML](https://www.ogc.org/standards/gml) string 
representation of a geometry
diff --git a/docs/api/snowflake/vector-data/Function.md 
b/docs/api/snowflake/vector-data/Function.md
index 0657b9413..11d6bbdb6 100644
--- a/docs/api/snowflake/vector-data/Function.md
+++ b/docs/api/snowflake/vector-data/Function.md
@@ -270,13 +270,81 @@ FROM polygondf
 
 Introduction: Return the [GeoJSON](https://geojson.org/) string representation 
of a geometry
 
-Format: `ST_AsGeoJSON (A:geometry)`
+The type parameter takes the following options -
 
-SQL example:
+- "Simple" (default): Returns a simple GeoJSON geometry.
+- "Feature": Wraps the geometry in a GeoJSON Feature.
+- "FeatureCollection": Wraps the Feature in a GeoJSON FeatureCollection.
 
-```SQL
-SELECT ST_AsGeoJSON(polygondf.countyshape)
-FROM polygondf
+Format:
+
+`ST_AsGeoJSON (A:geometry)`
+
+`ST_AsGeoJSON (A:geometry, type: String)`
+
+SQL Example (Simple GeoJSON):
+
+```sql
+SELECT ST_AsGeoJSON(ST_GeomFromWKT('POLYGON((1 1, 8 1, 8 8, 1 8, 1 1))'))
+```
+
+Output:
+
+```json
+{
+  "type":"Polygon",
+  "coordinates":[
+    [[1.0,1.0],
+      [8.0,1.0],
+      [8.0,8.0],
+      [1.0,8.0],
+      [1.0,1.0]]
+  ]
+}
+```
+
+SQL Example (Feature GeoJSON):
+
+Output:
+
+```json
+{
+  "type":"Feature",
+  "geometry": {
+      "type":"Polygon",
+      "coordinates":[
+        [[1.0,1.0],
+          [8.0,1.0],
+          [8.0,8.0],
+          [1.0,8.0],
+          [1.0,1.0]]
+      ]
+  }
+}
+```
+
+SQL Example (FeatureCollection GeoJSON):
+
+Output:
+
+```json
+{
+  "type":"FeatureCollection",
+  "features": [{
+      "type":"Feature",
+      "geometry": {
+          "type":"Polygon",
+          "coordinates":[
+            [[1.0,1.0],
+              [8.0,1.0],
+              [8.0,8.0],
+              [1.0,8.0],
+              [1.0,1.0]]
+          ]
+      }
+    }
+  ]
+}
 ```
 
 ## ST_AsGML
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index 6f4d1b18e..d1e86a21a 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -371,11 +371,21 @@ POINT ZM(1 1 1 1)
 
 Introduction: Return the [GeoJSON](https://geojson.org/) string representation 
of a geometry
 
-Format: `ST_AsGeoJSON (A: Geometry)`
+The type parameter (Since: `v1.6.1`) takes the following options -
+
+- "Simple" (default): Returns a simple GeoJSON geometry.
+- "Feature": Wraps the geometry in a GeoJSON Feature.
+- "FeatureCollection": Wraps the Feature in a GeoJSON FeatureCollection.
+
+Format:
+
+`ST_AsGeoJSON (A: Geometry)`
+
+`ST_AsGeoJSON (A: Geometry, type: String)`
 
 Since: `v1.0.0`
 
-SQL Example
+SQL Example (Simple GeoJSON):
 
 ```sql
 SELECT ST_AsGeoJSON(ST_GeomFromWKT('POLYGON((1 1, 8 1, 8 8, 1 8, 1 1))'))
@@ -396,6 +406,50 @@ Output:
 }
 ```
 
+SQL Example (Feature GeoJSON):
+
+Output:
+
+```json
+{
+  "type":"Feature",
+  "geometry": {
+      "type":"Polygon",
+      "coordinates":[
+        [[1.0,1.0],
+          [8.0,1.0],
+          [8.0,8.0],
+          [1.0,8.0],
+          [1.0,1.0]]
+      ]
+  }
+}
+```
+
+SQL Example (FeatureCollection GeoJSON):
+
+Output:
+
+```json
+{
+  "type":"FeatureCollection",
+  "features": [{
+      "type":"Feature",
+      "geometry": {
+          "type":"Polygon",
+          "coordinates":[
+            [[1.0,1.0],
+              [8.0,1.0],
+              [8.0,8.0],
+              [1.0,8.0],
+              [1.0,1.0]]
+          ]
+      }
+    }
+  ]
+}
+```
+
 ## ST_AsGML
 
 Introduction: Return the [GML](https://www.ogc.org/standards/gml) string 
representation of a geometry
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 e38def518..3e5d606ee 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
@@ -744,6 +744,14 @@ public class Functions {
       Geometry geom = (Geometry) o;
       return org.apache.sedona.common.Functions.asGeoJson(geom);
     }
+
+    @DataTypeHint("String")
+    public String eval(
+        @DataTypeHint(value = "RAW", bridgedTo = 
org.locationtech.jts.geom.Geometry.class) Object o,
+        String type) {
+      Geometry geom = (Geometry) o;
+      return org.apache.sedona.common.Functions.asGeoJson(geom, type);
+    }
   }
 
   public static class ST_AsGML extends ScalarFunction {
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 5f22124dd..1b6d1173f 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -1004,6 +1004,27 @@ public class FunctionTest extends TestBase {
     assertEquals(
         
"{\"type\":\"Polygon\",\"coordinates\":[[[-0.5,-0.5],[-0.5,0.5],[0.5,0.5],[0.5,-0.5],[-0.5,-0.5]]]}",
         result);
+
+    polygonTable = createPolygonTable(testDataSize);
+    polygonTable =
+        polygonTable.select(
+            call(Functions.ST_AsGeoJSON.class.getSimpleName(), 
$(polygonColNames[0]), "Feature"));
+    result = (String) first(polygonTable).getField(0);
+    assertEquals(
+        
"{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-0.5,-0.5],[-0.5,0.5],[0.5,0.5],[0.5,-0.5],[-0.5,-0.5]]]},\"properties\":{}}",
+        result);
+
+    polygonTable = createPolygonTable(testDataSize);
+    polygonTable =
+        polygonTable.select(
+            call(
+                Functions.ST_AsGeoJSON.class.getSimpleName(),
+                $(polygonColNames[0]),
+                "FeatureCollection"));
+    result = (String) first(polygonTable).getField(0);
+    assertEquals(
+        
"{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-0.5,-0.5],[-0.5,0.5],[0.5,0.5],[0.5,-0.5],[-0.5,-0.5]]]},\"properties\":{}}]}",
+        result);
   }
 
   @Test
diff --git a/python/sedona/sql/st_functions.py 
b/python/sedona/sql/st_functions.py
index 1f98b0331..e9d07f8f6 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -160,7 +160,7 @@ def ST_AsEWKT(geometry: ColumnOrName) -> Column:
 
 
 @validate_argument_types
-def ST_AsGeoJSON(geometry: ColumnOrName) -> Column:
+def ST_AsGeoJSON(geometry: ColumnOrName, type: Optional[Union[ColumnOrName, 
str]] = None) -> Column:
     """Generate the GeoJSON style representation of a geometry column.
 
     :param geometry: Geometry column to generate GeoJSON for.
@@ -168,7 +168,8 @@ def ST_AsGeoJSON(geometry: ColumnOrName) -> Column:
     :return: GeoJSON representation of geometry as a string column.
     :rtype: Column
     """
-    return _call_st_function("ST_AsGeoJSON", geometry)
+    args = (geometry) if type is None else (geometry, type)
+    return _call_st_function("ST_AsGeoJSON", args)
 
 
 @validate_argument_types
diff --git a/python/tests/sql/test_dataframe_api.py 
b/python/tests/sql/test_dataframe_api.py
index 0493ad527..448743f5c 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -92,6 +92,8 @@ test_configurations = [
     (stf.ST_AsHEXEWKB, ("point",), "point_geom", "", 
"01010000000000000000000000000000000000F03F"),
     (stf.ST_AsEWKT, (lambda: f.expr("ST_SetSRID(point, 4326)"),), 
"point_geom", "", "SRID=4326;POINT (0 1)"),
     (stf.ST_AsGeoJSON, ("point",), "point_geom", "", 
"{\"type\":\"Point\",\"coordinates\":[0.0,1.0]}"),
+    (stf.ST_AsGeoJSON, ("point", lambda: f.lit("feature")), "point_geom", "", 
"{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[0.0,1.0]},\"properties\":{}}"),
+    (stf.ST_AsGeoJSON, ("point", lambda: f.lit("featurecollection")), 
"point_geom", "", 
"{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[0.0,1.0]},\"properties\":{}}]}"),
     (stf.ST_AsGML, ("point",), "point_geom", "", "<gml:Point>\n  
<gml:coordinates>\n    0.0,1.0 \n  </gml:coordinates>\n</gml:Point>\n"),
     (stf.ST_AsKML, ("point",), "point_geom", "", "<Point>\n  
<coordinates>0.0,1.0</coordinates>\n</Point>\n"),
     (stf.ST_AsText, ("point",), "point_geom", "", "POINT (0 1)"),
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 7aec36c1e..de94fb3a5 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
@@ -154,6 +154,16 @@ public class TestFunctions extends TestBase {
     verifySqlSingleRes(
         "select sedona.ST_AsGeoJSON(sedona.ST_GeomFromText('POLYGON((1 1, 8 1, 
8 8, 1 8, 1 1))'))",
         
"{\"type\":\"Polygon\",\"coordinates\":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]}");
+
+    registerUDF("ST_AsGeoJSON", byte[].class, String.class);
+    verifySqlSingleRes(
+        "select sedona.ST_AsGeoJSON(sedona.ST_GeomFromText('POLYGON((1 1, 8 1, 
8 8, 1 8, 1 1))'), 'feature')",
+        
"{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]},\"properties\":{}}");
+
+    registerUDF("ST_AsGeoJSON", byte[].class, String.class);
+    verifySqlSingleRes(
+        "select sedona.ST_AsGeoJSON(sedona.ST_GeomFromText('POLYGON((1 1, 8 1, 
8 8, 1 8, 1 1))'), 'featurecollection')",
+        
"{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]},\"properties\":{}}]}");
   }
 
   @Test
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 ebb63e66a..5e80d8a46 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
@@ -149,6 +149,16 @@ public class TestFunctionsV2 extends TestBase {
     verifySqlSingleRes(
         "select sedona.ST_AsGeoJSON(ST_GeometryFromWKT('POLYGON((1 1, 8 1, 8 
8, 1 8, 1 1))'))",
         
"{\"type\":\"Polygon\",\"coordinates\":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]}");
+
+    registerUDFV2("ST_AsGeoJSON", String.class, String.class);
+    verifySqlSingleRes(
+        "select sedona.ST_AsGeoJSON(ST_GeometryFromWKT('POLYGON((1 1, 8 1, 8 
8, 1 8, 1 1))'), 'feature')",
+        
"{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]},\"properties\":{}}");
+
+    registerUDFV2("ST_AsGeoJSON", String.class, String.class);
+    verifySqlSingleRes(
+        "select sedona.ST_AsGeoJSON(ST_GeometryFromWKT('POLYGON((1 1, 8 1, 8 
8, 1 8, 1 1))'), 'featurecollection')",
+        
"{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]},\"properties\":{}}]}");
   }
 
   @Test
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 573933c8b..09c778cb2 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
@@ -144,6 +144,11 @@ public class UDFs {
     return Functions.asGeoJson(GeometrySerde.deserialize(geometry));
   }
 
+  @UDFAnnotations.ParamMeta(argNames = {"geometry", "type"})
+  public static String ST_AsGeoJSON(byte[] geometry, String type) {
+    return Functions.asGeoJson(GeometrySerde.deserialize(geometry), type);
+  }
+
   @UDFAnnotations.ParamMeta(argNames = {"geometry"})
   public static String ST_AsKML(byte[] geometry) {
     return Functions.asKML(GeometrySerde.deserialize(geometry));
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 063bd5515..a9a9bc208 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
@@ -185,6 +185,13 @@ public class UDFsV2 {
     return Functions.asGeoJson(GeometrySerde.deserGeoJson(geometry));
   }
 
+  @UDFAnnotations.ParamMeta(
+      argNames = {"geometry", "type"},
+      argTypes = {"Geometry", "String"})
+  public static String ST_AsGeoJSON(String geometry, String type) {
+    return Functions.asGeoJson(GeometrySerde.deserGeoJson(geometry), type);
+  }
+
   @UDFAnnotations.ParamMeta(
       argNames = {"geometry"},
       argTypes = {"Geometry"})
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 76db9bebb..852a9e5f6 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
@@ -466,7 +466,9 @@ case class ST_AsText(inputExpressions: Seq[Expression])
 }
 
 case class ST_AsGeoJSON(inputExpressions: Seq[Expression])
-    extends InferredExpression(Functions.asGeoJson _) {
+    extends InferredExpression(
+      inferrableFunction1(Functions.asGeoJson),
+      inferrableFunction2(Functions.asGeoJson)) {
 
   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_functions.scala
 
b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
index 81d00210c..fdf0aea1d 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
@@ -67,6 +67,11 @@ object st_functions extends DataFrameAPI {
   def ST_AsGeoJSON(geometry: Column): Column = 
wrapExpression[ST_AsGeoJSON](geometry)
   def ST_AsGeoJSON(geometry: String): Column = 
wrapExpression[ST_AsGeoJSON](geometry)
 
+  def ST_AsGeoJSON(geometry: Column, Type: Column): Column =
+    wrapExpression[ST_AsGeoJSON](geometry, Type)
+  def ST_AsGeoJSON(geometry: String, Type: String): Column =
+    wrapExpression[ST_AsGeoJSON](geometry, Type)
+
   def ST_AsGML(geometry: Column): Column = wrapExpression[ST_AsGML](geometry)
   def ST_AsGML(geometry: String): Column = wrapExpression[ST_AsGML](geometry)
 
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 307e5a9fe..4b114c08c 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
@@ -772,9 +772,21 @@ class dataFrameAPITestScala extends TestBaseScala {
 
     it("Passed ST_AsGeoJSON") {
       val pointDf = sparkSession.sql("SELECT ST_Point(0.0, 0.0) AS geom")
-      val df = pointDf.select(ST_AsGeoJSON("geom"))
-      val actualResult = df.take(1)(0).get(0).asInstanceOf[String]
-      val expectedResult = "{\"type\":\"Point\",\"coordinates\":[0.0,0.0]}"
+      var df = pointDf.select(ST_AsGeoJSON("geom"))
+      var actualResult = df.take(1)(0).get(0).asInstanceOf[String]
+      var expectedResult = "{\"type\":\"Point\",\"coordinates\":[0.0,0.0]}"
+      assert(actualResult == expectedResult)
+
+      df = pointDf.select(ST_AsGeoJSON(col("geom"), lit("feature")))
+      actualResult = df.take(1)(0).get(0).asInstanceOf[String]
+      expectedResult =
+        
"{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[0.0,0.0]},\"properties\":{}}"
+      assert(actualResult == expectedResult)
+
+      df = pointDf.select(ST_AsGeoJSON(col("geom"), lit("featureCollection")))
+      actualResult = df.take(1)(0).get(0).asInstanceOf[String]
+      expectedResult =
+        
"{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[0.0,0.0]},\"properties\":{}}]}"
       assert(actualResult == expectedResult)
     }
 
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 202115a2d..b231aa5b4 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
@@ -755,12 +755,26 @@ class functionTestScala
         sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON((1 1, 8 1, 8 8, 1 8, 
1 1))') AS polygon")
       df.createOrReplaceTempView("table")
 
-      val geojsonDf = sparkSession.sql("""select ST_AsGeoJSON(polygon) as 
geojson
+      var geojsonDf = sparkSession.sql("""select ST_AsGeoJSON(polygon) as 
geojson
           |from table""".stripMargin)
 
-      val expectedGeoJson =
+      var expectedGeoJson =
         
"""{"type":"Polygon","coordinates":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]}"""
       assert(geojsonDf.first().getString(0) === expectedGeoJson)
+
+      geojsonDf = sparkSession.sql("""select ST_AsGeoJSON(polygon, 'Feature') 
as geojson
+                                         |from table""".stripMargin)
+
+      expectedGeoJson =
+        
"""{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]},"properties":{}}"""
+      assert(geojsonDf.first().getString(0) === expectedGeoJson)
+
+      geojsonDf = sparkSession.sql("""select ST_AsGeoJSON(polygon, 
'FeatureCollection') as geojson
+                                     |from table""".stripMargin)
+
+      expectedGeoJson =
+        
"""{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[1.0,1.0],[8.0,1.0],[8.0,8.0],[1.0,8.0],[1.0,1.0]]]},"properties":{}}]}"""
+      assert(geojsonDf.first().getString(0) === expectedGeoJson)
     }
 
     it("Passed ST_AsBinary") {

Reply via email to