From 9ec20d4612eef18660ed2cb29b962f23c15c355a Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Tue, 18 Jun 2024 17:24:10 +0200
Subject: [PATCH 01/18] feat: initial support for geometry column

---
 app/es_embedded/es/mappings.json                |  3 +++
 .../elasticsearch/PhotonDocConverter.java       | 17 +++++++++++++++++
 .../photon/opensearch/PhotonDocSerializer.java  | 11 +++++++----
 buildSrc/shared.gradle                          |  1 +
 src/main/java/de/komoot/photon/PhotonDoc.java   | 16 +++++++++++++++-
 .../photon/nominatim/NominatimConnector.java    |  3 ++-
 .../photon/searcher/GeocodeJsonFormatter.java   |  8 +++++---
 .../de/komoot/photon/searcher/PhotonResult.java |  1 +
 8 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/app/es_embedded/es/mappings.json b/app/es_embedded/es/mappings.json
index 7085a49c1..39c4f7563 100644
--- a/app/es_embedded/es/mappings.json
+++ b/app/es_embedded/es/mappings.json
@@ -49,6 +49,9 @@
 			"coordinate": {
 				"type": "geo_point"
 			},
+			"geometry": {
+				"type": "geo_shape"
+			},
 			"country": {
 				"properties": {
 					"default": {
diff --git a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/PhotonDocConverter.java b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/PhotonDocConverter.java
index cc2688bd5..00d37a6e1 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/PhotonDocConverter.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/PhotonDocConverter.java
@@ -3,11 +3,17 @@
 import de.komoot.photon.Constants;
 import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.nominatim.model.AddressType;
+
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.json.JsonXContent;
 import org.locationtech.jts.geom.Envelope;
+import org.locationtech.jts.io.geojson.GeoJsonWriter;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -38,6 +44,17 @@ public static XContentBuilder convert(PhotonDoc doc, String[] languages, String[
                     .endObject();
         }
 
+        if (doc.getGeometry() != null) {
+            GeoJsonWriter g = new GeoJsonWriter();
+            
+            XContentParser parser = JsonXContent
+                .jsonXContent
+                .createParser(NamedXContentRegistry.EMPTY, g.write(doc.getGeometry()));
+
+            builder.field("geometry");
+            builder.copyCurrentStructure(parser);
+        }
+
         if (doc.getHouseNumber() != null) {
             builder.field("housenumber", doc.getHouseNumber());
         }
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
index 2ed731620..b0bd31f85 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
@@ -7,12 +7,10 @@
 import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.Utils;
 import org.locationtech.jts.geom.Envelope;
+import org.locationtech.jts.io.geojson.GeoJsonWriter;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 public class PhotonDocSerializer extends StdSerializer<PhotonDoc> {
     final private String[] languages;
@@ -48,6 +46,11 @@ public void serialize(PhotonDoc value, JsonGenerator gen, SerializerProvider pro
             gen.writeEndObject();
         }
 
+        if (value.getGeometry() != null) {
+            GeoJsonWriter g = new GeoJsonWriter();
+            gen.writeObjectField("geometry", g.write(value.getGeometry()));
+        }
+
         if (value.getHouseNumber() != null) {
             gen.writeStringField("housenumber", value.getHouseNumber());
         }
diff --git a/buildSrc/shared.gradle b/buildSrc/shared.gradle
index f0b4dd6cf..8c98eb9d1 100644
--- a/buildSrc/shared.gradle
+++ b/buildSrc/shared.gradle
@@ -52,6 +52,7 @@ dependencies {
         exclude(module: 'commons-logging')
     }
     implementation 'org.locationtech.jts:jts-core:1.19.0'
+    implementation 'org.locationtech.jts.io:jts-io-common:1.19.0'
     implementation 'com.sparkjava:spark-core:2.9.4'
     implementation 'net.postgis:postgis-jdbc:2023.1.0'
     implementation 'org.json:json:20240303'
diff --git a/src/main/java/de/komoot/photon/PhotonDoc.java b/src/main/java/de/komoot/photon/PhotonDoc.java
index 719c42617..a0c7fbf08 100644
--- a/src/main/java/de/komoot/photon/PhotonDoc.java
+++ b/src/main/java/de/komoot/photon/PhotonDoc.java
@@ -1,9 +1,10 @@
-package de.komoot.photon;
+    package de.komoot.photon;
 
 import org.locationtech.jts.geom.Envelope;
 import org.locationtech.jts.geom.Geometry;
 import org.locationtech.jts.geom.Point;
 import de.komoot.photon.nominatim.model.AddressType;
+import org.locationtech.jts.geom.Polygon;
 import org.slf4j.Logger;
 
 import java.util.*;
@@ -34,6 +35,7 @@ public class PhotonDoc {
     private Set<Map<String, String>> context = new HashSet<>();
     private String houseNumber = null;
     private Point centroid = null;
+    private Geometry geometry = null;
 
     public PhotonDoc(long placeId, String osmType, long osmId, String tagKey, String tagValue) {
         this.placeId = placeId;
@@ -62,6 +64,7 @@ public PhotonDoc(PhotonDoc other) {
         this.rankAddress = other.rankAddress;
         this.addressParts = other.addressParts;
         this.context = other.context;
+        this.geometry = other.geometry;
     }
 
     public PhotonDoc names(Map<String, String> names) {
@@ -86,6 +89,14 @@ public PhotonDoc centroid(Geometry centroid) {
         return this;
     }
 
+    public PhotonDoc geometry(Geometry polygon) {
+        // if (polygon.getGeometryType().equals("Polygon")) {
+            this.geometry = (Geometry) polygon;
+        // }
+        return this;
+
+    }
+
     public PhotonDoc countryCode(String countryCode) {
         if (countryCode != null) {
             this.countryCode = countryCode.toUpperCase();
@@ -312,4 +323,7 @@ public String getHouseNumber() {
     public Point getCentroid() {
         return this.centroid;
     }
+    public Geometry getGeometry() {
+        return this.geometry;
+    }
 }
diff --git a/src/main/java/de/komoot/photon/nominatim/NominatimConnector.java b/src/main/java/de/komoot/photon/nominatim/NominatimConnector.java
index eebe9ab37..5243687ca 100644
--- a/src/main/java/de/komoot/photon/nominatim/NominatimConnector.java
+++ b/src/main/java/de/komoot/photon/nominatim/NominatimConnector.java
@@ -24,7 +24,7 @@
 public class NominatimConnector {
     private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(NominatimConnector.class);
 
-    private static final String SELECT_COLS_PLACEX = "SELECT place_id, osm_type, osm_id, class, type, name, postcode, address, extratags, ST_Envelope(geometry) AS bbox, parent_place_id, linked_place_id, rank_address, rank_search, importance, country_code, centroid";
+    private static final String SELECT_COLS_PLACEX = "SELECT place_id, osm_type, osm_id, class, type, name, postcode, address, extratags, ST_Envelope(geometry) AS bbox, parent_place_id, linked_place_id, rank_address, rank_search, importance, country_code, centroid, geometry";
     private static final String SELECT_COLS_ADDRESS = "SELECT p.name, p.class, p.type, p.rank_address";
 
     private final DBDataAdapter dbutils;
@@ -58,6 +58,7 @@ public NominatimResult mapRow(ResultSet rs, int rowNum) throws SQLException {
                     .parentPlaceId(rs.getLong("parent_place_id"))
                     .countryCode(rs.getString("country_code"))
                     .centroid(dbutils.extractGeometry(rs, "centroid"))
+                    .geometry(dbutils.extractGeometry(rs, "geometry"))
                     .linkedPlaceId(rs.getLong("linked_place_id"))
                     .rankAddress(rs.getInt("rank_address"))
                     .postcode(rs.getString("postcode"));
diff --git a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
index 8557c3d10..dc2d20bb1 100644
--- a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
+++ b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
@@ -31,9 +31,11 @@ public String convert(List<PhotonResult> results, String debugInfo) {
             features.put(new JSONObject()
                         .put("type", "Feature")
                         .put("properties", getResultProperties(result))
-                        .put("geometry", new JSONObject()
-                                .put("type", "Point")
-                                .put("coordinates", coordinates)));
+                        .put("geometry", result.get("geometry")));
+                        
+                        // .put("geometry", new JSONObject()
+                                // .put("type", "Point")
+                                // .put("coordinates", coordinates)));
         }
 
         final JSONObject out = new JSONObject();
diff --git a/src/main/java/de/komoot/photon/searcher/PhotonResult.java b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
index 946a9c0ba..f019b59bb 100644
--- a/src/main/java/de/komoot/photon/searcher/PhotonResult.java
+++ b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
@@ -22,6 +22,7 @@ public interface PhotonResult {
     Map<String, String> getMap(String key);
 
     double[] getCoordinates();
+    
     double[] getExtent();
 
     double getScore();

From 5a7fb1a7eb170b70d5f3900273c8e745fd1f414f Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Tue, 9 Jul 2024 15:56:17 +0200
Subject: [PATCH 02/18] feat: add unit test

---
 src/main/java/de/komoot/photon/PhotonDoc.java |  5 +-
 .../searcher/GeocodeJsonFormatterTest.java    | 48 ++++++++++++++++---
 2 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/src/main/java/de/komoot/photon/PhotonDoc.java b/src/main/java/de/komoot/photon/PhotonDoc.java
index a0c7fbf08..17afeeda5 100644
--- a/src/main/java/de/komoot/photon/PhotonDoc.java
+++ b/src/main/java/de/komoot/photon/PhotonDoc.java
@@ -90,11 +90,8 @@ public PhotonDoc centroid(Geometry centroid) {
     }
 
     public PhotonDoc geometry(Geometry polygon) {
-        // if (polygon.getGeometryType().equals("Polygon")) {
-            this.geometry = (Geometry) polygon;
-        // }
+        this.geometry = (Geometry) polygon;
         return this;
-
     }
 
     public PhotonDoc countryCode(String countryCode) {
diff --git a/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java b/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
index eaa8e6333..2ea134a0f 100644
--- a/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
+++ b/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
@@ -15,11 +15,16 @@ class GeocodeJsonFormatterTest {
     @Test
     void testConvertToGeojson() {
         GeocodeJsonFormatter formatter = new GeocodeJsonFormatter(false, "en");
-        List<PhotonResult> allResults = new ArrayList<>();
-        allResults.add(createDummyResult("99999", "Park Foo", "leisure", "park"));
-        allResults.add(createDummyResult("88888", "Bar Park", "leisure", "park"));
+        List<PhotonResult> allPointResults = new ArrayList<>();
+        allPointResults.add(createDummyPointResult("99999", "Park Foo", "leisure", "park"));
+        allPointResults.add(createDummyPointResult("88888", "Bar Park", "leisure", "park"));
 
-        String geojsonString = formatter.convert(allResults, null);
+        List<PhotonResult> allPolygonResults = new ArrayList<>();
+        allPolygonResults.add(createDummyPolygonResult("99999", "Park Foo", "leisure", "park"));
+        allPolygonResults.add(createDummyPolygonResult("88888", "Bar Park", "leisure", "park"));
+
+        // Test Points
+        String geojsonString = formatter.convert(allPointResults, null);
         JSONObject jsonObj = new JSONObject(geojsonString);
         assertEquals("FeatureCollection", jsonObj.getString("type"));
         JSONArray features = jsonObj.getJSONArray("features");
@@ -31,15 +36,44 @@ void testConvertToGeojson() {
             assertEquals("leisure", feature.getJSONObject("properties").getString(Constants.OSM_KEY));
             assertEquals("park", feature.getJSONObject("properties").getString(Constants.OSM_VALUE));
         }
+
+        // Test Polygon
+        geojsonString = formatter.convert(allPolygonResults, null);
+        jsonObj = new JSONObject(geojsonString);
+        assertEquals("FeatureCollection", jsonObj.getString("type"));
+        features = jsonObj.getJSONArray("features");
+        assertEquals(2, features.length());
+        for (int i = 0; i < features.length(); i++) {
+            JSONObject feature = features.getJSONObject(i);
+            assertEquals("Feature", feature.getString("type"));
+            assertEquals("Polygon", feature.getJSONObject("geometry").getString("type"));
+            assertEquals("leisure", feature.getJSONObject("properties").getString(Constants.OSM_KEY));
+            assertEquals("park", feature.getJSONObject("properties").getString(Constants.OSM_VALUE));
+        }
     }
     
-    private PhotonResult createDummyResult(String postCode, String name, String osmKey,
-                    String osmValue) {
+    private PhotonResult createDummyPointResult(String postCode, String name, String osmKey,
+                                                String osmValue) {
+        return new MockPhotonResult()
+                .put(Constants.POSTCODE, postCode)
+                .putLocalized(Constants.NAME, "en", name)
+                .put(Constants.OSM_KEY, osmKey)
+                .put(Constants.OSM_VALUE, osmValue)
+                .put("geometry", new JSONObject()
+                    .put("type", "Point")
+                    .put("coordinates", new double[]{42, 21}));
+    }
+
+    private PhotonResult createDummyPolygonResult(String postCode, String name, String osmKey,
+                                                String osmValue) {
         return new MockPhotonResult()
                 .put(Constants.POSTCODE, postCode)
                 .putLocalized(Constants.NAME, "en", name)
                 .put(Constants.OSM_KEY, osmKey)
-                .put(Constants.OSM_VALUE, osmValue);
+                .put(Constants.OSM_VALUE, osmValue)
+                .put("geometry", new JSONObject()
+                        .put("type", "Polygon")
+                        .put("coordinates", new double[][]{{100.0, 0.0}, {101.0, 0.0}, {101.0, 1.0}, {100.0, 1.0}, {100.0, 0.0}}));
     }
 
 }

From 31e2111ac5a24258c310eb197003318db7e21c2f Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Thu, 11 Jul 2024 08:46:23 +0200
Subject: [PATCH 03/18] feat: add geometry column as an commanline argument

---
 src/main/java/de/komoot/photon/App.java       | 12 +++++-----
 .../de/komoot/photon/CommandLineArgs.java     |  7 ++++++
 .../photon/ReverseSearchRequestHandler.java   |  8 ++++---
 .../photon/nominatim/NominatimConnector.java  | 14 +++++++----
 .../photon/nominatim/NominatimUpdater.java    |  8 +++----
 .../photon/query/ReverseRequestFactory.java   |  2 +-
 .../photon/searcher/GeocodeJsonFormatter.java | 23 ++++++++++++-------
 .../nominatim/NominatimUpdaterDBTest.java     |  2 +-
 .../query/ReverseRequestFactoryTest.java      | 20 ++++++++--------
 9 files changed, 59 insertions(+), 37 deletions(-)

diff --git a/src/main/java/de/komoot/photon/App.java b/src/main/java/de/komoot/photon/App.java
index af7815be7..5325e61b3 100644
--- a/src/main/java/de/komoot/photon/App.java
+++ b/src/main/java/de/komoot/photon/App.java
@@ -101,7 +101,7 @@ private static void startJsonDump(CommandLineArgs args) {
         try {
             final String filename = args.getJsonDump();
             final JsonDumper jsonDumper = new JsonDumper(filename, args.getLanguages(), args.getExtraTags());
-            NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword());
+            NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.isUseGeometryColumn());
             nominatimConnector.setImporter(jsonDumper);
             nominatimConnector.readEntireDatabase(args.getCountryCodes());
             LOGGER.info("Json dump was created: {}", filename);
@@ -116,7 +116,7 @@ private static void startJsonDump(CommandLineArgs args) {
      */
     private static void startNominatimImport(CommandLineArgs args, Server esServer) {
         DatabaseProperties dbProperties;
-        NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword());
+        NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.isUseGeometryColumn());
         Date importDate = nominatimConnector.getLastImportDate();
         try {
             dbProperties = esServer.recreateIndex(args.getLanguages(), importDate); // clear out previous data
@@ -132,7 +132,7 @@ private static void startNominatimImport(CommandLineArgs args, Server esServer)
     }
 
     private static void startNominatimUpdateInit(CommandLineArgs args) {
-        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword());
+        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.isUseGeometryColumn());
         nominatimUpdater.initUpdates(args.getNominatimUpdateInit());
     }
 
@@ -159,7 +159,7 @@ private static NominatimUpdater setupNominatimUpdater(CommandLineArgs args, Serv
         DatabaseProperties dbProperties = new DatabaseProperties();
         server.loadFromDatabase(dbProperties);
 
-        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword());
+        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.isUseGeometryColumn());
         nominatimUpdater.setUpdater(server.createUpdater(dbProperties.getLanguages(), args.getExtraTags()));
         return nominatimUpdater;
     }
@@ -195,9 +195,9 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
 
         ReverseHandler reverseHandler = server.createReverseHandler(args.getQueryTimeout());
         get("reverse", new ReverseSearchRequestHandler("reverse", reverseHandler, dbProperties.getLanguages(),
-                args.getDefaultLanguage(), args.getMaxReverseResults()));
+                args.getDefaultLanguage(), args.getMaxReverseResults(), args.isUseGeometryColumn()));
         get("reverse/", new ReverseSearchRequestHandler("reverse/", reverseHandler, dbProperties.getLanguages(),
-                args.getDefaultLanguage(), args.getMaxReverseResults()));
+                args.getDefaultLanguage(), args.getMaxReverseResults(), args.isUseGeometryColumn()));
         
         get("status", new StatusRequestHandler("status", server));
         get("status/", new StatusRequestHandler("status/", server));
diff --git a/src/main/java/de/komoot/photon/CommandLineArgs.java b/src/main/java/de/komoot/photon/CommandLineArgs.java
index 3a05d46a1..24e84f48f 100644
--- a/src/main/java/de/komoot/photon/CommandLineArgs.java
+++ b/src/main/java/de/komoot/photon/CommandLineArgs.java
@@ -88,6 +88,9 @@ public class CommandLineArgs {
     @Parameter(names = "-max-reverse-results", description = "The maximum possible 'limit' parameter for reverse geocoding searches")
     private int maxReverseResults = 50;
 
+    @Parameter(names = "-use-geometry-column", description = "Use the 'geometry' column from Nominatim instead of the 'centroid' column on import and serving (i.e. get Polygons for cities). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
+    private boolean useGeometryColumn = false;
+
     public String[] getLanguages(boolean useDefaultIfEmpty) {
         if (useDefaultIfEmpty && languages.length == 0) {
             return new String[]{"en", "de", "fr", "it"};
@@ -199,5 +202,9 @@ public int getMaxReverseResults() {
     public int getMaxResults() {
         return maxResults;
     }
+
+    public boolean isUseGeometryColumn() {
+        return useGeometryColumn;
+    }
 }
 
diff --git a/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java b/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
index e34bb61fe..066e31b9d 100644
--- a/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
@@ -22,11 +22,13 @@
 public class ReverseSearchRequestHandler extends RouteImpl {
     private final ReverseRequestFactory reverseRequestFactory;
     private final ReverseHandler requestHandler;
+    private final boolean useGeometryColumn;
 
-    ReverseSearchRequestHandler(String path, ReverseHandler dbHandler, String[] languages, String defaultLanguage, int maxResults) {
+    ReverseSearchRequestHandler(String path, ReverseHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean useGeometryColumn) {
         super(path);
+        this.useGeometryColumn = useGeometryColumn;
         List<String> supportedLanguages = Arrays.asList(languages);
-        this.reverseRequestFactory = new ReverseRequestFactory(supportedLanguages, defaultLanguage, maxResults);
+        this.reverseRequestFactory = new ReverseRequestFactory(supportedLanguages, defaultLanguage, maxResults, useGeometryColumn);
         this.requestHandler = dbHandler;
     }
 
@@ -53,6 +55,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
 
-        return new GeocodeJsonFormatter(false, photonRequest.getLanguage()).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(false, photonRequest.getLanguage(), useGeometryColumn).convert(results, debugInfo);
     }
 }
diff --git a/src/main/java/de/komoot/photon/nominatim/NominatimConnector.java b/src/main/java/de/komoot/photon/nominatim/NominatimConnector.java
index 5243687ca..acfa9de32 100644
--- a/src/main/java/de/komoot/photon/nominatim/NominatimConnector.java
+++ b/src/main/java/de/komoot/photon/nominatim/NominatimConnector.java
@@ -40,6 +40,7 @@ public class NominatimConnector {
     private final String selectOsmlineSql;
     private Importer importer;
 
+    private final boolean useGeometryColumn;
 
     /**
      * Maps a placex row in nominatim to a photon doc.
@@ -58,11 +59,14 @@ public NominatimResult mapRow(ResultSet rs, int rowNum) throws SQLException {
                     .parentPlaceId(rs.getLong("parent_place_id"))
                     .countryCode(rs.getString("country_code"))
                     .centroid(dbutils.extractGeometry(rs, "centroid"))
-                    .geometry(dbutils.extractGeometry(rs, "geometry"))
                     .linkedPlaceId(rs.getLong("linked_place_id"))
                     .rankAddress(rs.getInt("rank_address"))
                     .postcode(rs.getString("postcode"));
 
+            if (useGeometryColumn) {
+                doc.geometry(dbutils.extractGeometry(rs, "geometry"));
+            }
+
             double importance = rs.getDouble("importance");
             doc.importance(rs.wasNull() ? (0.75 - rs.getInt("rank_search") / 40d) : importance);
 
@@ -88,11 +92,11 @@ public NominatimResult mapRow(ResultSet rs, int rowNum) throws SQLException {
      * @param username db username
      * @param password db username's password
      */
-    public NominatimConnector(String host, int port, String database, String username, String password) {
-        this(host, port, database, username, password, new PostgisDataAdapter());
+    public NominatimConnector(String host, int port, String database, String username, String password, boolean useGeometryColumn) {
+        this(host, port, database, username, password, new PostgisDataAdapter(), useGeometryColumn);
     }
 
-    public NominatimConnector(String host, int port, String database, String username, String password, DBDataAdapter dataAdapter) {
+    public NominatimConnector(String host, int port, String database, String username, String password, DBDataAdapter dataAdapter, boolean useGeometryColumn) {
         BasicDataSource dataSource = buildDataSource(host, port, database, username, password, false);
 
         template = new JdbcTemplate(dataSource);
@@ -100,6 +104,8 @@ public NominatimConnector(String host, int port, String database, String usernam
 
         dbutils = dataAdapter;
 
+        this.useGeometryColumn = useGeometryColumn;
+
         // Setup handling of interpolation table. There are two different formats depending on the Nominatim version.
         if (dbutils.hasColumn(template, "location_property_osmline", "step")) {
             // new-style interpolations
diff --git a/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java b/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
index 3e97ab0ea..417ab6d2b 100644
--- a/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
+++ b/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
@@ -199,14 +199,14 @@ private List<UpdateRow> getPlaces(String table) {
      * @param username Nominatim database username
      * @param password Nominatim database password
      */
-    public NominatimUpdater(String host, int port, String database, String username, String password, DBDataAdapter dataAdapter) {
+    public NominatimUpdater(String host, int port, String database, String username, String password, DBDataAdapter dataAdapter, boolean useGeometryColumn) {
         BasicDataSource dataSource = NominatimConnector.buildDataSource(host, port, database, username, password, true);
 
-        exporter = new NominatimConnector(host, port, database, username, password, dataAdapter);
+        exporter = new NominatimConnector(host, port, database, username, password, dataAdapter, useGeometryColumn);
         template = new JdbcTemplate(dataSource);
     }
 
-    public NominatimUpdater(String host, int port, String database, String username, String password) {
-        this(host, port, database, username, password, new PostgisDataAdapter());
+    public NominatimUpdater(String host, int port, String database, String username, String password, boolean useGeometryColumn) {
+        this(host, port, database, username, password, new PostgisDataAdapter(), useGeometryColumn);
     }
 }
diff --git a/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java b/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
index e539fe127..fe65b162d 100644
--- a/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
@@ -23,7 +23,7 @@ public class ReverseRequestFactory {
     private final LayerParamValidator layerParamValidator;
     private final int maxResults;
 
-    public ReverseRequestFactory(List<String> supportedLanguages, String defaultLanguage, int maxResults) {
+    public ReverseRequestFactory(List<String> supportedLanguages, String defaultLanguage, int maxResults, boolean useGeometryColumn) {
         this.languageResolver = new RequestLanguageResolver(supportedLanguages, defaultLanguage);
         this.layerParamValidator = new LayerParamValidator();
         this.maxResults = maxResults;
diff --git a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
index dc2d20bb1..1cc8ee722 100644
--- a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
+++ b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
@@ -15,10 +15,12 @@ public class GeocodeJsonFormatter implements ResultFormatter {
 
     private final boolean addDebugInfo;
     private final String language;
+    private final boolean useGeometryColumn;
 
-    public GeocodeJsonFormatter(boolean addDebugInfo, String language) {
+    public GeocodeJsonFormatter(boolean addDebugInfo, String language, boolean useGeometryColumn) {
         this.addDebugInfo = addDebugInfo;
         this.language = language;
+        this.useGeometryColumn = useGeometryColumn;
     }
 
     @Override
@@ -26,16 +28,21 @@ public String convert(List<PhotonResult> results, String debugInfo) {
         final JSONArray features = new JSONArray(results.size());
 
         for (PhotonResult result : results) {
-            final double[] coordinates = result.getCoordinates();
-
-            features.put(new JSONObject()
+            if (useGeometryColumn) {
+                features.put(new JSONObject()
                         .put("type", "Feature")
                         .put("properties", getResultProperties(result))
                         .put("geometry", result.get("geometry")));
-                        
-                        // .put("geometry", new JSONObject()
-                                // .put("type", "Point")
-                                // .put("coordinates", coordinates)));
+            } else {
+                final double[] coordinates = result.getCoordinates();
+
+                features.put(new JSONObject()
+                        .put("type", "Feature")
+                        .put("properties", getResultProperties(result))
+                        .put("geometry", new JSONObject()
+                                .put("type", "Point")
+                                .put("coordinates", coordinates)));
+            }
         }
 
         final JSONObject out = new JSONObject();
diff --git a/src/test/java/de/komoot/photon/nominatim/NominatimUpdaterDBTest.java b/src/test/java/de/komoot/photon/nominatim/NominatimUpdaterDBTest.java
index 23d55f014..1d5bdee3c 100644
--- a/src/test/java/de/komoot/photon/nominatim/NominatimUpdaterDBTest.java
+++ b/src/test/java/de/komoot/photon/nominatim/NominatimUpdaterDBTest.java
@@ -26,7 +26,7 @@ void setup() {
                 .build();
 
 
-        connector = new NominatimUpdater(null, 0, null, null, null, new H2DataAdapter());
+        connector = new NominatimUpdater(null, 0, null, null, null, new H2DataAdapter(), false);
         updater = new CollectingUpdater();
         connector.setUpdater(updater);
 
diff --git a/src/test/java/de/komoot/photon/query/ReverseRequestFactoryTest.java b/src/test/java/de/komoot/photon/query/ReverseRequestFactoryTest.java
index 1e302e0f6..5683836e8 100644
--- a/src/test/java/de/komoot/photon/query/ReverseRequestFactoryTest.java
+++ b/src/test/java/de/komoot/photon/query/ReverseRequestFactoryTest.java
@@ -56,7 +56,7 @@ private void requestWithLayers(Request mockRequest, String... layers) {
     @Test
     void testWithLocation() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(-87, reverseRequest.getLocation().getX(), 0);
         assertEquals(41, reverseRequest.getLocation().getY(), 0);
@@ -66,7 +66,7 @@ void testWithLocation() throws Exception {
 
     private void assertBadRequest(Request mockRequest, String expectedMessage) {
         try {
-            ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+            ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
             reverseRequest = reverseRequestFactory.create(mockRequest);
             fail();
         } catch (BadRequestException e) {
@@ -155,7 +155,7 @@ void testWithBadRadius() throws Exception {
     void testHighRadius() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         Mockito.when(mockRequest.queryParams("radius")).thenReturn("5.1");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(5.1d, reverseRequest.getRadius(), 0);
         Mockito.verify(mockRequest, Mockito.times(1)).queryParams("radius");
@@ -180,7 +180,7 @@ void testWithBadLimit() throws Exception {
     void testHighLimit() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         Mockito.when(mockRequest.queryParams("limit")).thenReturn("51");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 50);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 50, false);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(50, reverseRequest.getLimit());
         Mockito.verify(mockRequest, Mockito.times(1)).queryParams("limit");
@@ -189,7 +189,7 @@ void testHighLimit() throws Exception {
     @Test
     void testDistanceSortDefault() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         Mockito.verify(mockRequest, Mockito.times(1)).queryParamOrDefault("distance_sort", "true");
         assertEquals(true, reverseRequest.getLocationDistanceSort());
@@ -199,7 +199,7 @@ void testDistanceSortDefault() throws Exception {
     void testWithLayersFilters() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         requestWithLayers(mockRequest, "city", "locality");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(new HashSet<>(Arrays.asList("city", "locality")), reverseRequest.getLayerFilters());
     }
@@ -208,7 +208,7 @@ void testWithLayersFilters() throws Exception {
     void testWithDuplicatedLayerFilters() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         requestWithLayers(mockRequest, "city", "locality", "city");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(new HashSet<>(Arrays.asList("city", "locality")), reverseRequest.getLayerFilters());
     }
@@ -225,7 +225,7 @@ void testWithBadLayerFilters() {
     void testTagFilters() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         requestWithOsmFilters(mockRequest, "foo", ":!bar");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
         reverseRequest = reverseRequestFactory.create(mockRequest);
 
         List<TagFilter> result = reverseRequest.getOsmTagFilters();
@@ -242,7 +242,7 @@ void testTagFilters() throws Exception {
     void testBadTagFilters() {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         requestWithOsmFilters(mockRequest, "good", "bad:bad:bad");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
 
         assertThrows(BadRequestException.class, () -> reverseRequestFactory.create(mockRequest));
     }
@@ -252,7 +252,7 @@ void testWithDebug() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         Mockito.when(mockRequest.queryParams("debug")).thenReturn("1");
 
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
         reverseRequest = reverseRequestFactory.create(mockRequest);
 
         assertTrue(reverseRequest.getDebug());

From 031d96263e59f0b59172d3c5c0b95c568d2822c7 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Thu, 11 Jul 2024 08:54:47 +0200
Subject: [PATCH 04/18] bugfix: undo intellij magic

---
 .../de/komoot/photon/opensearch/PhotonDocSerializer.java     | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
index b0bd31f85..936a6e9a5 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
@@ -10,7 +10,10 @@
 import org.locationtech.jts.io.geojson.GeoJsonWriter;
 
 import java.io.IOException;
-import java.util.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 public class PhotonDocSerializer extends StdSerializer<PhotonDoc> {
     final private String[] languages;

From 152c2d1fb30f8288243e6df6ca649e4b00b2a6d4 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Thu, 11 Jul 2024 09:08:47 +0200
Subject: [PATCH 05/18] bugfix: minor build bugs

---
 src/main/java/de/komoot/photon/App.java       |  8 +++----
 .../komoot/photon/SearchRequestHandler.java   |  6 +++--
 .../StructuredSearchRequestHandler.java       |  6 +++--
 .../nominatim/NominatimConnectorDBTest.java   |  2 +-
 .../searcher/GeocodeJsonFormatterTest.java    | 23 +++++++++++--------
 5 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/src/main/java/de/komoot/photon/App.java b/src/main/java/de/komoot/photon/App.java
index 2792a6d21..640893738 100644
--- a/src/main/java/de/komoot/photon/App.java
+++ b/src/main/java/de/komoot/photon/App.java
@@ -191,13 +191,13 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
         String[] langs = dbProperties.getLanguages();
 
         SearchHandler searchHandler = server.createSearchHandler(langs, args.getQueryTimeout());
-        get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults()));
-        get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults()));
+        get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), args.isUseGeometryColumn()));
+        get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), args.isUseGeometryColumn()));
 
         if (dbProperties.getSupportStructuredQueries()) {
             StructuredSearchHandler structured = server.createStructuredSearchHandler(langs, args.getQueryTimeout());
-            get("structured", new StructuredSearchRequestHandler("structured", structured, langs, args.getDefaultLanguage(), args.getMaxResults()));
-            get("structured/", new StructuredSearchRequestHandler("structured/", structured, langs, args.getDefaultLanguage(), args.getMaxResults()));
+            get("structured", new StructuredSearchRequestHandler("structured", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), args.isUseGeometryColumn()));
+            get("structured/", new StructuredSearchRequestHandler("structured/", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), args.isUseGeometryColumn()));
         }
 
         ReverseHandler reverseHandler = server.createReverseHandler(args.getQueryTimeout());
diff --git a/src/main/java/de/komoot/photon/SearchRequestHandler.java b/src/main/java/de/komoot/photon/SearchRequestHandler.java
index 5f11578dd..6391a0978 100644
--- a/src/main/java/de/komoot/photon/SearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/SearchRequestHandler.java
@@ -21,10 +21,12 @@ public class SearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final SearchHandler requestHandler;
     private final int maxResults;
+    private final boolean useGeometryColumn;
 
-    SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults) {
+    SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean useGeometryColumn) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
+        this.useGeometryColumn = useGeometryColumn;
         this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults);
         this.requestHandler = dbHandler;
         this.maxResults = maxResults;
@@ -56,6 +58,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
 
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage()).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), useGeometryColumn).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
index 805c25560..cef36329d 100644
--- a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
@@ -17,10 +17,12 @@
 public class StructuredSearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final StructuredSearchHandler requestHandler;
+    private final boolean useGeometryColumn;
 
-    StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults) {
+    StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean useGeometryColumn) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
+        this.useGeometryColumn = useGeometryColumn;
         this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults);
         this.requestHandler = dbHandler;
     }
@@ -51,6 +53,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
  */
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage()).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), useGeometryColumn).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java b/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
index 37c793931..5c75580f9 100644
--- a/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
+++ b/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
@@ -35,7 +35,7 @@ void setup() {
                 .build();
 
 
-        connector = new NominatimConnector(null, 0, null, null, null, new H2DataAdapter());
+        connector = new NominatimConnector(null, 0, null, null, null, new H2DataAdapter(), false);
         importer = new CollectingImporter();
         connector.setImporter(importer);
 
diff --git a/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java b/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
index 2ea134a0f..c311c15e8 100644
--- a/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
+++ b/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
@@ -13,16 +13,12 @@
 class GeocodeJsonFormatterTest {
 
     @Test
-    void testConvertToGeojson() {
-        GeocodeJsonFormatter formatter = new GeocodeJsonFormatter(false, "en");
+    void testConvertPointToGeojson() {
+        GeocodeJsonFormatter formatter = new GeocodeJsonFormatter(false, "en", false);
         List<PhotonResult> allPointResults = new ArrayList<>();
         allPointResults.add(createDummyPointResult("99999", "Park Foo", "leisure", "park"));
         allPointResults.add(createDummyPointResult("88888", "Bar Park", "leisure", "park"));
 
-        List<PhotonResult> allPolygonResults = new ArrayList<>();
-        allPolygonResults.add(createDummyPolygonResult("99999", "Park Foo", "leisure", "park"));
-        allPolygonResults.add(createDummyPolygonResult("88888", "Bar Park", "leisure", "park"));
-
         // Test Points
         String geojsonString = formatter.convert(allPointResults, null);
         JSONObject jsonObj = new JSONObject(geojsonString);
@@ -36,12 +32,21 @@ void testConvertToGeojson() {
             assertEquals("leisure", feature.getJSONObject("properties").getString(Constants.OSM_KEY));
             assertEquals("park", feature.getJSONObject("properties").getString(Constants.OSM_VALUE));
         }
+    }
+
+    @Test
+    void testConvertPolygonToGeojson() {
+        GeocodeJsonFormatter formatter = new GeocodeJsonFormatter(false, "en", true);
+
+        List<PhotonResult> allPolygonResults = new ArrayList<>();
+        allPolygonResults.add(createDummyPolygonResult("99999", "Park Foo", "leisure", "park"));
+        allPolygonResults.add(createDummyPolygonResult("88888", "Bar Park", "leisure", "park"));
 
         // Test Polygon
-        geojsonString = formatter.convert(allPolygonResults, null);
-        jsonObj = new JSONObject(geojsonString);
+        String geojsonString = formatter.convert(allPolygonResults, null);
+        JSONObject jsonObj = new JSONObject(geojsonString);
         assertEquals("FeatureCollection", jsonObj.getString("type"));
-        features = jsonObj.getJSONArray("features");
+        JSONArray features = jsonObj.getJSONArray("features");
         assertEquals(2, features.length());
         for (int i = 0; i < features.length(); i++) {
             JSONObject feature = features.getJSONObject(i);

From 5d1b854b58667b84fc2c22088a84b6c9459187a6 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Thu, 11 Jul 2024 10:16:56 +0200
Subject: [PATCH 06/18] feat: add polygon as an api request instead of a
 default

---
 src/main/java/de/komoot/photon/App.java       | 12 +++++------
 .../de/komoot/photon/CommandLineArgs.java     |  2 +-
 .../photon/ReverseSearchRequestHandler.java   |  8 +++-----
 .../komoot/photon/SearchRequestHandler.java   |  6 ++----
 .../StructuredSearchRequestHandler.java       |  6 ++----
 .../photon/query/PhotonRequestBase.java       |  7 +++++++
 .../photon/query/PhotonRequestFactory.java    |  5 ++++-
 .../komoot/photon/query/ReverseRequest.java   |  8 +++++++-
 .../photon/query/ReverseRequestFactory.java   |  6 +++---
 .../photon/searcher/GeocodeJsonFormatter.java |  2 +-
 .../query/QueryReverseFilterLayerTest.java    |  2 +-
 .../query/QueryReverseFilterTagValueTest.java |  2 +-
 .../komoot/photon/query/QueryReverseTest.java |  2 +-
 .../query/ReverseRequestFactoryTest.java      | 20 +++++++++----------
 14 files changed, 49 insertions(+), 39 deletions(-)

diff --git a/src/main/java/de/komoot/photon/App.java b/src/main/java/de/komoot/photon/App.java
index 640893738..a823110bb 100644
--- a/src/main/java/de/komoot/photon/App.java
+++ b/src/main/java/de/komoot/photon/App.java
@@ -191,20 +191,20 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
         String[] langs = dbProperties.getLanguages();
 
         SearchHandler searchHandler = server.createSearchHandler(langs, args.getQueryTimeout());
-        get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), args.isUseGeometryColumn()));
-        get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), args.isUseGeometryColumn()));
+        get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults()));
+        get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults()));
 
         if (dbProperties.getSupportStructuredQueries()) {
             StructuredSearchHandler structured = server.createStructuredSearchHandler(langs, args.getQueryTimeout());
-            get("structured", new StructuredSearchRequestHandler("structured", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), args.isUseGeometryColumn()));
-            get("structured/", new StructuredSearchRequestHandler("structured/", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), args.isUseGeometryColumn()));
+            get("structured", new StructuredSearchRequestHandler("structured", structured, langs, args.getDefaultLanguage(), args.getMaxResults()));
+            get("structured/", new StructuredSearchRequestHandler("structured/", structured, langs, args.getDefaultLanguage(), args.getMaxResults()));
         }
 
         ReverseHandler reverseHandler = server.createReverseHandler(args.getQueryTimeout());
         get("reverse", new ReverseSearchRequestHandler("reverse", reverseHandler, dbProperties.getLanguages(),
-                args.getDefaultLanguage(), args.getMaxReverseResults(), args.isUseGeometryColumn()));
+                args.getDefaultLanguage(), args.getMaxReverseResults()));
         get("reverse/", new ReverseSearchRequestHandler("reverse/", reverseHandler, dbProperties.getLanguages(),
-                args.getDefaultLanguage(), args.getMaxReverseResults(), args.isUseGeometryColumn()));
+                args.getDefaultLanguage(), args.getMaxReverseResults()));
         
         get("status", new StatusRequestHandler("status", server));
         get("status/", new StatusRequestHandler("status/", server));
diff --git a/src/main/java/de/komoot/photon/CommandLineArgs.java b/src/main/java/de/komoot/photon/CommandLineArgs.java
index 5d8520d8b..b4bb93324 100644
--- a/src/main/java/de/komoot/photon/CommandLineArgs.java
+++ b/src/main/java/de/komoot/photon/CommandLineArgs.java
@@ -91,7 +91,7 @@ public class CommandLineArgs {
     @Parameter(names = "-max-reverse-results", description = "The maximum possible 'limit' parameter for reverse geocoding searches")
     private int maxReverseResults = 50;
 
-    @Parameter(names = "-use-geometry-column", description = "Use the 'geometry' column from Nominatim instead of the 'centroid' column on import and serving (i.e. get Polygons for cities). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
+    @Parameter(names = "-use-geometry-column", description = "[import-only] Add the 'geometry' column from Nominatim on import (i.e. add Polygons for cities). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
     private boolean useGeometryColumn = false;
 
     public String[] getLanguages(boolean useDefaultIfEmpty) {
diff --git a/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java b/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
index 066e31b9d..3416bd25b 100644
--- a/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
@@ -22,13 +22,11 @@
 public class ReverseSearchRequestHandler extends RouteImpl {
     private final ReverseRequestFactory reverseRequestFactory;
     private final ReverseHandler requestHandler;
-    private final boolean useGeometryColumn;
 
-    ReverseSearchRequestHandler(String path, ReverseHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean useGeometryColumn) {
+    ReverseSearchRequestHandler(String path, ReverseHandler dbHandler, String[] languages, String defaultLanguage, int maxResults) {
         super(path);
-        this.useGeometryColumn = useGeometryColumn;
         List<String> supportedLanguages = Arrays.asList(languages);
-        this.reverseRequestFactory = new ReverseRequestFactory(supportedLanguages, defaultLanguage, maxResults, useGeometryColumn);
+        this.reverseRequestFactory = new ReverseRequestFactory(supportedLanguages, defaultLanguage, maxResults);
         this.requestHandler = dbHandler;
     }
 
@@ -55,6 +53,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
 
-        return new GeocodeJsonFormatter(false, photonRequest.getLanguage(), useGeometryColumn).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(false, photonRequest.getLanguage(), photonRequest.getPolygon()).convert(results, debugInfo);
     }
 }
diff --git a/src/main/java/de/komoot/photon/SearchRequestHandler.java b/src/main/java/de/komoot/photon/SearchRequestHandler.java
index 6391a0978..909029245 100644
--- a/src/main/java/de/komoot/photon/SearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/SearchRequestHandler.java
@@ -21,12 +21,10 @@ public class SearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final SearchHandler requestHandler;
     private final int maxResults;
-    private final boolean useGeometryColumn;
 
-    SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean useGeometryColumn) {
+    SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
-        this.useGeometryColumn = useGeometryColumn;
         this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults);
         this.requestHandler = dbHandler;
         this.maxResults = maxResults;
@@ -58,6 +56,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
 
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), useGeometryColumn).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getPolygon()).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
index cef36329d..e8aeafd36 100644
--- a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
@@ -17,12 +17,10 @@
 public class StructuredSearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final StructuredSearchHandler requestHandler;
-    private final boolean useGeometryColumn;
 
-    StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean useGeometryColumn) {
+    StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
-        this.useGeometryColumn = useGeometryColumn;
         this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults);
         this.requestHandler = dbHandler;
     }
@@ -53,6 +51,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
  */
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), useGeometryColumn).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getPolygon()).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestBase.java b/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
index 720686e49..5f5f9c99a 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
@@ -18,6 +18,7 @@ public class PhotonRequestBase
     private int zoom = 14;
     private Envelope bbox = null;
     private boolean debug = false;
+    private boolean polygon = false;
 
     private final List<TagFilter> osmTagFilters = new ArrayList<>(1);
     private Set<String> layerFilters = new HashSet<>(1);
@@ -53,6 +54,8 @@ public String getLanguage() {
 
     public boolean getDebug() { return debug; }
 
+    public boolean getPolygon() { return polygon; }
+
     public List<TagFilter> getOsmTagFilters() {
         return osmTagFilters;
     }
@@ -100,4 +103,8 @@ void setBbox(Envelope bbox) {
     void enableDebug() {
         this.debug = true;
     }
+
+    public void setPolygon(boolean polygon) {
+        this.polygon = polygon;
+    }
 }
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
index 081244d94..5fb5886d8 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
@@ -19,7 +19,7 @@ public class PhotonRequestFactory {
     private final int maxResults;
 
     private static final HashSet<String> REQUEST_QUERY_PARAMS = new HashSet<>(Arrays.asList("lang", "q", "lon", "lat",
-            "limit", "osm_tag", "location_bias_scale", "bbox", "debug", "zoom", "layer"));
+            "limit", "osm_tag", "location_bias_scale", "bbox", "debug", "zoom", "layer", "polygon"));
 
     private static final HashSet<String> STRUCTURED_ADDRESS_FIELDS = new HashSet<>(Arrays.asList("countrycode", "state", "county", "city",
             "postcode", "district", "housenumber", "street"));
@@ -59,6 +59,7 @@ public StructuredPhotonRequest createStructured(Request webRequest) throws BadRe
         result.setStreet(webRequest.queryParams("street"));
         result.setHouseNumber(webRequest.queryParams("housenumber"));
 
+
         addCommonParameters(webRequest, result);
 
         return result;
@@ -110,6 +111,8 @@ private void addCommonParameters(Request webRequest, PhotonRequestBase request)
         if (layerFiltersQueryMap.hasValue()) {
             request.setLayerFilter(layerParamValidator.validate(layerFiltersQueryMap.values()));
         }
+
+        request.setPolygon(Boolean.parseBoolean(webRequest.queryParams("polygon")));
     }
 
     private Integer parseInt(Request webRequest, String param) throws BadRequestException {
diff --git a/src/main/java/de/komoot/photon/query/ReverseRequest.java b/src/main/java/de/komoot/photon/query/ReverseRequest.java
index cb8c78cde..5fabf0cb0 100644
--- a/src/main/java/de/komoot/photon/query/ReverseRequest.java
+++ b/src/main/java/de/komoot/photon/query/ReverseRequest.java
@@ -20,9 +20,10 @@ public class ReverseRequest implements Serializable {
     private final Set<String> layerFilters;
     private final List<TagFilter> osmTagFilters = new ArrayList<>(1);
     private final boolean debug;
+    private final boolean polygon;
 
     public ReverseRequest(Point location, String language, double radius, String queryStringFilter, int limit,
-                          boolean locationDistanceSort, Set<String> layerFilter, boolean debug) {
+                          boolean locationDistanceSort, Set<String> layerFilter, boolean debug, boolean polygon) {
         this.location = location;
         this.language = language;
         this.radius = radius;
@@ -31,6 +32,7 @@ public ReverseRequest(Point location, String language, double radius, String que
         this.locationDistanceSort = locationDistanceSort;
         this.layerFilters = layerFilter;
         this.debug = debug;
+        this.polygon = polygon;
     }
 
     public Point getLocation() {
@@ -69,6 +71,10 @@ public boolean getDebug() {
         return debug;
     }
 
+    public boolean getPolygon() {
+        return polygon;
+    }
+
     ReverseRequest addOsmTagFilter(TagFilter filter) {
         osmTagFilters.add(filter);
         return this;
diff --git a/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java b/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
index fe65b162d..d3ae421dc 100644
--- a/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
@@ -16,14 +16,14 @@
 public class ReverseRequestFactory {
 
     private static final HashSet<String> REQUEST_QUERY_PARAMS = new HashSet<>(Arrays.asList("lang", "lon", "lat", "radius",
-            "query_string_filter", "distance_sort", "limit", "layer", "osm_tag", "debug"));
+            "query_string_filter", "distance_sort", "limit", "layer", "osm_tag", "debug", "polygon"));
     private static final LocationParamConverter mandatoryLocationParamConverter = new LocationParamConverter(true);
 
     private final RequestLanguageResolver languageResolver;
     private final LayerParamValidator layerParamValidator;
     private final int maxResults;
 
-    public ReverseRequestFactory(List<String> supportedLanguages, String defaultLanguage, int maxResults, boolean useGeometryColumn) {
+    public ReverseRequestFactory(List<String> supportedLanguages, String defaultLanguage, int maxResults) {
         this.languageResolver = new RequestLanguageResolver(supportedLanguages, defaultLanguage);
         this.layerParamValidator = new LayerParamValidator();
         this.maxResults = maxResults;
@@ -86,7 +86,7 @@ public ReverseRequest create(Request webRequest) throws BadRequestException {
         }
 
         String queryStringFilter = webRequest.queryParams("query_string_filter");
-        ReverseRequest request = new ReverseRequest(location, language, radius, queryStringFilter, limit, locationDistanceSort, layerFilter, enableDebug);
+        ReverseRequest request = new ReverseRequest(location, language, radius, queryStringFilter, limit, locationDistanceSort, layerFilter, enableDebug, Boolean.parseBoolean(webRequest.queryParams("polygon")));
 
         QueryParamsMap tagFiltersQueryMap = webRequest.queryMap("osm_tag");
         if (tagFiltersQueryMap.hasValue()) {
diff --git a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
index 1cc8ee722..677775e04 100644
--- a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
+++ b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
@@ -28,7 +28,7 @@ public String convert(List<PhotonResult> results, String debugInfo) {
         final JSONArray features = new JSONArray(results.size());
 
         for (PhotonResult result : results) {
-            if (useGeometryColumn) {
+            if (useGeometryColumn && result.get("geometry") != null) {
                 features.put(new JSONObject()
                         .put("type", "Feature")
                         .put("properties", getResultProperties(result))
diff --git a/src/test/java/de/komoot/photon/query/QueryReverseFilterLayerTest.java b/src/test/java/de/komoot/photon/query/QueryReverseFilterLayerTest.java
index 5efac0bbc..c649fddf4 100644
--- a/src/test/java/de/komoot/photon/query/QueryReverseFilterLayerTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryReverseFilterLayerTest.java
@@ -52,7 +52,7 @@ private List<PhotonResult> reverse(String... layers) {
         Point pt = FACTORY.createPoint(new Coordinate(10, 10));
 
         Set<String> layerSet = Arrays.stream(layers).collect(Collectors.toSet());
-        ReverseRequest request = new ReverseRequest(pt, "en", 1.0, "", 10, true, layerSet, false);
+        ReverseRequest request = new ReverseRequest(pt, "en", 1.0, "", 10, true, layerSet, false, false);
 
         return getServer().createReverseHandler(1).reverse(request);
     }
diff --git a/src/test/java/de/komoot/photon/query/QueryReverseFilterTagValueTest.java b/src/test/java/de/komoot/photon/query/QueryReverseFilterTagValueTest.java
index 4f4a46fe0..6fb8b5274 100644
--- a/src/test/java/de/komoot/photon/query/QueryReverseFilterTagValueTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryReverseFilterTagValueTest.java
@@ -68,7 +68,7 @@ public void tearDown() throws IOException {
 
     private List<PhotonResult> reverseWithTags(String[] params) {
         Point pt = FACTORY.createPoint(new Coordinate(13.38886, 52.51704));
-        ReverseRequest request = new ReverseRequest(pt, "en", 1.0, "", 50, true, new HashSet<>(), false);
+        ReverseRequest request = new ReverseRequest(pt, "en", 1.0, "", 50, true, new HashSet<>(), false, false);
         for (String param : params) {
             request.addOsmTagFilter(TagFilter.buildOsmTagFilter(param));
         }
diff --git a/src/test/java/de/komoot/photon/query/QueryReverseTest.java b/src/test/java/de/komoot/photon/query/QueryReverseTest.java
index 7d96ff781..0210bdae9 100644
--- a/src/test/java/de/komoot/photon/query/QueryReverseTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryReverseTest.java
@@ -48,7 +48,7 @@ private List<PhotonResult> reverse(double lon, double lat, double radius, int li
         Point pt = FACTORY.createPoint(new Coordinate(lon, lat));
 
         return getServer().createReverseHandler(1).reverse(
-            new ReverseRequest(pt, "en", radius, "", limit, true, new HashSet<>(), false)
+            new ReverseRequest(pt, "en", radius, "", limit, true, new HashSet<>(), false, false)
         );
     }
 
diff --git a/src/test/java/de/komoot/photon/query/ReverseRequestFactoryTest.java b/src/test/java/de/komoot/photon/query/ReverseRequestFactoryTest.java
index 5683836e8..1e302e0f6 100644
--- a/src/test/java/de/komoot/photon/query/ReverseRequestFactoryTest.java
+++ b/src/test/java/de/komoot/photon/query/ReverseRequestFactoryTest.java
@@ -56,7 +56,7 @@ private void requestWithLayers(Request mockRequest, String... layers) {
     @Test
     void testWithLocation() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(-87, reverseRequest.getLocation().getX(), 0);
         assertEquals(41, reverseRequest.getLocation().getY(), 0);
@@ -66,7 +66,7 @@ void testWithLocation() throws Exception {
 
     private void assertBadRequest(Request mockRequest, String expectedMessage) {
         try {
-            ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+            ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
             reverseRequest = reverseRequestFactory.create(mockRequest);
             fail();
         } catch (BadRequestException e) {
@@ -155,7 +155,7 @@ void testWithBadRadius() throws Exception {
     void testHighRadius() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         Mockito.when(mockRequest.queryParams("radius")).thenReturn("5.1");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(5.1d, reverseRequest.getRadius(), 0);
         Mockito.verify(mockRequest, Mockito.times(1)).queryParams("radius");
@@ -180,7 +180,7 @@ void testWithBadLimit() throws Exception {
     void testHighLimit() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         Mockito.when(mockRequest.queryParams("limit")).thenReturn("51");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 50, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 50);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(50, reverseRequest.getLimit());
         Mockito.verify(mockRequest, Mockito.times(1)).queryParams("limit");
@@ -189,7 +189,7 @@ void testHighLimit() throws Exception {
     @Test
     void testDistanceSortDefault() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         Mockito.verify(mockRequest, Mockito.times(1)).queryParamOrDefault("distance_sort", "true");
         assertEquals(true, reverseRequest.getLocationDistanceSort());
@@ -199,7 +199,7 @@ void testDistanceSortDefault() throws Exception {
     void testWithLayersFilters() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         requestWithLayers(mockRequest, "city", "locality");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(new HashSet<>(Arrays.asList("city", "locality")), reverseRequest.getLayerFilters());
     }
@@ -208,7 +208,7 @@ void testWithLayersFilters() throws Exception {
     void testWithDuplicatedLayerFilters() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         requestWithLayers(mockRequest, "city", "locality", "city");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
         reverseRequest = reverseRequestFactory.create(mockRequest);
         assertEquals(new HashSet<>(Arrays.asList("city", "locality")), reverseRequest.getLayerFilters());
     }
@@ -225,7 +225,7 @@ void testWithBadLayerFilters() {
     void testTagFilters() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         requestWithOsmFilters(mockRequest, "foo", ":!bar");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
         reverseRequest = reverseRequestFactory.create(mockRequest);
 
         List<TagFilter> result = reverseRequest.getOsmTagFilters();
@@ -242,7 +242,7 @@ void testTagFilters() throws Exception {
     void testBadTagFilters() {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         requestWithOsmFilters(mockRequest, "good", "bad:bad:bad");
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
 
         assertThrows(BadRequestException.class, () -> reverseRequestFactory.create(mockRequest));
     }
@@ -252,7 +252,7 @@ void testWithDebug() throws Exception {
         Request mockRequest = createRequestWithLongitudeLatitude(-87d, 41d);
         Mockito.when(mockRequest.queryParams("debug")).thenReturn("1");
 
-        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10, false);
+        ReverseRequestFactory reverseRequestFactory = new ReverseRequestFactory(Collections.singletonList("en"), "en", 10);
         reverseRequest = reverseRequestFactory.create(mockRequest);
 
         assertTrue(reverseRequest.getDebug());

From d544bb380ddb037cdb694f5d1ac38543f3d01ee1 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Thu, 5 Sep 2024 20:52:00 +0200
Subject: [PATCH 07/18] feat: add unit tests and process remarks of @lonvia

---
 .../main/java/de/komoot/photon/Server.java    | 12 +++-
 .../java/de/komoot/photon/ESBaseTester.java   | 16 +++--
 .../elasticsearch/ElasticResultTest.java      |  2 +-
 .../main/java/de/komoot/photon/Server.java    |  6 +-
 .../photon/opensearch/DBPropertyEntry.java    |  2 +
 .../photon/opensearch/IndexMapping.java       |  1 +
 .../java/de/komoot/photon/ESBaseTester.java   | 14 +++--
 buildSrc/shared.gradle                        |  2 +
 src/main/java/de/komoot/photon/App.java       | 22 ++++---
 .../de/komoot/photon/CommandLineArgs.java     |  4 +-
 .../de/komoot/photon/DatabaseProperties.java  | 21 +++++++
 src/main/java/de/komoot/photon/PhotonDoc.java |  9 +++
 .../komoot/photon/SearchRequestHandler.java   | 17 +++++-
 .../StructuredSearchRequestHandler.java       |  2 +-
 .../photon/query/PhotonRequestBase.java       | 17 ++++--
 .../photon/query/PhotonRequestFactory.java    |  5 +-
 .../de/komoot/photon/ApiIntegrationTest.java  | 23 +++++++-
 .../komoot/photon/api/ApiLanguagesTest.java   |  2 +-
 .../nominatim/NominatimConnectorDBTest.java   | 16 ++++-
 .../nominatim/testdb/PlacexTestRow.java       |  2 +
 .../query/PhotonRequestFactoryTest.java       |  8 +++
 .../photon/query/QueryByLanguageTest.java     |  2 +-
 .../photon/query/QueryFilterLayerTest.java    |  2 +-
 .../photon/query/QueryFilterTagValueTest.java |  2 +-
 .../komoot/photon/query/QueryPolygonTest.java | 58 +++++++++++++++++++
 .../query/QueryReverseFilterLayerTest.java    |  2 +-
 .../query/QueryReverseFilterTagValueTest.java |  5 +-
 .../komoot/photon/query/QueryReverseTest.java |  5 +-
 28 files changed, 234 insertions(+), 45 deletions(-)
 create mode 100644 src/test/java/de/komoot/photon/query/QueryPolygonTest.java

diff --git a/app/es_embedded/src/main/java/de/komoot/photon/Server.java b/app/es_embedded/src/main/java/de/komoot/photon/Server.java
index c0e5c3359..bd983b3fc 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/Server.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/Server.java
@@ -48,6 +48,7 @@ public class Server {
     private static final String FIELD_VERSION = "database_version";
     private static final String FIELD_LANGUAGES = "indexed_languages";
     private static final String FIELD_IMPORT_DATE = "import_date";
+    private static final String FIELD_SUPPORT_POLYGONS = "support_polygons";
 
     private Node esNode;
 
@@ -169,7 +170,7 @@ private void setupDirectories(URL directoryName) throws IOException, URISyntaxEx
 
     }
 
-    public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries) throws IOException {
+    public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportPolygons) throws IOException {
         deleteIndex();
 
         loadIndexSettings().createIndex(esClient, PhotonIndex.NAME);
@@ -178,7 +179,10 @@ public DatabaseProperties recreateIndex(String[] languages, Date importDate, boo
 
         DatabaseProperties dbProperties = new DatabaseProperties()
             .setLanguages(languages)
-            .setImportDate(importDate);
+            .setImportDate(importDate)
+            .setSupportPolygons(supportPolygons);
+
+        LOGGER.info(dbProperties.toString());
         saveToDatabase(dbProperties);
 
         return dbProperties;
@@ -234,6 +238,7 @@ public void saveToDatabase(DatabaseProperties dbProperties) throws IOException
                         .field(FIELD_VERSION, DatabaseProperties.DATABASE_VERSION)
                         .field(FIELD_LANGUAGES, String.join(",", dbProperties.getLanguages()))
                         .field(FIELD_IMPORT_DATE, dbProperties.getImportDate() instanceof Date ? dbProperties.getImportDate().toInstant() : null)
+                        .field(FIELD_SUPPORT_POLYGONS, Boolean.toString(dbProperties.getSupportPolygons()))
                         .endObject().endObject();
 
         esClient.prepareIndex(PhotonIndex.NAME, PhotonIndex.TYPE).
@@ -274,6 +279,9 @@ public void loadFromDatabase(DatabaseProperties dbProperties) {
 
         String importDateString = properties.get(FIELD_IMPORT_DATE);
         dbProperties.setImportDate(importDateString == null ? null : Date.from(Instant.parse(importDateString)));
+
+        String supportPolygons = properties.get(FIELD_SUPPORT_POLYGONS);
+        dbProperties.setSupportPolygons(supportPolygons == null ? null : Boolean.parseBoolean(supportPolygons));
     }
 
     public Importer createImporter(String[] languages, String[] extraTags) {
diff --git a/app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java b/app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java
index 5b2e5008c..676bd949b 100644
--- a/app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java
+++ b/app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java
@@ -7,6 +7,8 @@
 import de.komoot.photon.searcher.PhotonResult;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.io.TempDir;
+import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKTReader;
 
 import java.io.IOException;
 import java.nio.file.Path;
@@ -25,9 +27,9 @@ public class ESBaseTester {
 
     private ElasticTestServer server;
 
-    protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String key, String value) {
+    protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String key, String value) throws ParseException {
         Point location = FACTORY.createPoint(new Coordinate(lon, lat));
-        return new PhotonDoc(id, "W", osmId, key, value).names(Collections.singletonMap("name", "berlin")).centroid(location);
+        return new PhotonDoc(id, "W", osmId, key, value).names(Collections.singletonMap("name", "berlin")).centroid(location).geometry(new WKTReader().read("POLYGON ((6.4440619 52.1969454, 6.4441094 52.1969158, 6.4441408 52.1969347, 6.4441138 52.1969516, 6.4440933 52.1969643, 6.4440619 52.1969454))"));
     }
 
     protected PhotonResult getById(int id) {
@@ -45,17 +47,21 @@ public void tearDown() throws IOException {
     }
 
     public void setUpES() throws IOException {
-        setUpES(dataDirectory, "en");
+        setUpES(dataDirectory, false,"en");
+    }
+
+    public void setUpESWithPolygons() throws IOException {
+        setUpES(dataDirectory, true,"en");
     }
     /**
      * Setup the ES server
      *
      * @throws IOException
      */
-    public void setUpES(Path test_directory, String... languages) throws IOException {
+    public void setUpES(Path test_directory, boolean supportPolygons, String... languages) throws IOException {
         server = new ElasticTestServer(test_directory.toString());
         server.start(TEST_CLUSTER_NAME, new String[]{});
-        server.recreateIndex(languages, new Date(), false);
+        server.recreateIndex(languages, new Date(), false, supportPolygons);
         refresh();
     }
 
diff --git a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticResultTest.java b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticResultTest.java
index db51d985e..58e5ce73d 100644
--- a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticResultTest.java
+++ b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticResultTest.java
@@ -44,7 +44,7 @@ protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String
 
     @BeforeAll
     void setUp() throws Exception {
-        setUpES(instanceTestDirectory, "en", "de", "fr", "it");
+        setUpES(instanceTestDirectory, false, "en", "de", "fr", "it");
         Importer instance = getServer().createImporter(new String[]{"en", "de", "fr", "it"},
                  new String[]{"population",  "capital"});
 
diff --git a/app/opensearch/src/main/java/de/komoot/photon/Server.java b/app/opensearch/src/main/java/de/komoot/photon/Server.java
index ab7456269..3ecf08ab5 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/Server.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/Server.java
@@ -98,7 +98,7 @@ public void shutdown() {
         }
     }
 
-    public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries) throws IOException {
+    public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportPolygons) throws IOException {
         // delete any existing data
         if (client.indices().exists(e -> e.index(PhotonIndex.NAME)).value()) {
             client.indices().delete(d -> d.index(PhotonIndex.NAME));
@@ -111,7 +111,8 @@ public DatabaseProperties recreateIndex(String[] languages, Date importDate, boo
         var dbProperties = new DatabaseProperties()
                 .setLanguages(languages)
                 .setSupportStructuredQueries(supportStructuredQueries)
-                .setImportDate(importDate);
+                .setImportDate(importDate)
+                .setSupportPolygons(supportPolygons);
         saveToDatabase(dbProperties);
 
         return dbProperties;
@@ -157,6 +158,7 @@ public void loadFromDatabase(DatabaseProperties dbProperties) throws IOException
         dbProperties.setLanguages(dbEntry.source().languages);
         dbProperties.setImportDate(dbEntry.source().importDate);
         dbProperties.setSupportStructuredQueries(dbEntry.source().supportStructuredQueries);
+        dbProperties.setSupportPolygons(dbEntry.source().supportPolygons);
     }
 
     public Importer createImporter(String[] languages, String[] extraTags) {
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/DBPropertyEntry.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/DBPropertyEntry.java
index fa96a1d3e..27ed1050d 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/DBPropertyEntry.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/DBPropertyEntry.java
@@ -9,6 +9,7 @@ public class DBPropertyEntry {
     public Date importDate;
     public String[] languages;
     public boolean supportStructuredQueries;
+    public boolean supportPolygons;
 
     public DBPropertyEntry() {}
 
@@ -17,5 +18,6 @@ public DBPropertyEntry(DatabaseProperties props) {
         importDate = props.getImportDate();
         languages = props.getLanguages();
         supportStructuredQueries = props.getSupportStructuredQueries();
+        supportPolygons = props.getSupportPolygons();
     }
 }
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/IndexMapping.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/IndexMapping.java
index 2c81d76a7..fd8e2920c 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/IndexMapping.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/IndexMapping.java
@@ -79,6 +79,7 @@ private void setupBaseMappings() {
         }
 
         mappings.properties("coordinate", b -> b.geoPoint(p -> p));
+        mappings.properties("geometry", b -> b.geoShape(p -> p));
         mappings.properties("countrycode", b -> b.keyword(p -> p.index(true)));
         mappings.properties("importance", b -> b.float_(p -> p.index(false)));
 
diff --git a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
index e8d9eec9f..9a7241f9b 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
@@ -1,6 +1,8 @@
 package de.komoot.photon;
 
+import de.komoot.photon.opensearch.Importer;
 import de.komoot.photon.opensearch.OpenSearchTestServer;
+import de.komoot.photon.opensearch.Updater;
 import de.komoot.photon.searcher.PhotonResult;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.io.TempDir;
@@ -49,28 +51,28 @@ public void setUpES() throws IOException {
     public void setUpES(Path test_directory, String... languages) throws IOException {
         server = new OpenSearchTestServer(test_directory.toString());
         server.startTestServer(TEST_CLUSTER_NAME);
-        server.recreateIndex(languages, new Date(), true);
+        server.recreateIndex(languages, new Date(), true, true);
         server.refreshIndexes();
     }
 
     protected Importer makeImporter() {
-        return server.createImporter(new String[]{"en"}, new String[]{});
+        return (Importer) server.createImporter(new String[]{"en"}, new String[]{});
     }
 
     protected Importer makeImporterWithExtra(String... extraTags) {
-        return server.createImporter(new String[]{"en"}, extraTags);
+        return (Importer) server.createImporter(new String[]{"en"}, extraTags);
     }
 
     protected Importer makeImporterWithLanguages(String... languages) {
-        return server.createImporter(languages, new String[]{});
+        return (Importer) server.createImporter(languages, new String[]{});
     }
 
     protected Updater makeUpdater() {
-        return server.createUpdater(new String[]{"en"}, new String[]{});
+        return (Updater) server.createUpdater(new String[]{"en"}, new String[]{});
     }
 
     protected Updater makeUpdaterWithExtra(String... extraTags) {
-        return server.createUpdater(new String[]{"en"}, extraTags);
+        return (Updater) server.createUpdater(new String[]{"en"}, extraTags);
     }
 
     protected Server getServer() {
diff --git a/buildSrc/shared.gradle b/buildSrc/shared.gradle
index 8c98eb9d1..ff77bf08b 100644
--- a/buildSrc/shared.gradle
+++ b/buildSrc/shared.gradle
@@ -13,6 +13,8 @@ application {
 java {
     sourceCompatibility = JavaVersion.VERSION_11
     targetCompatibility = JavaVersion.VERSION_11
+    compileJava.options.encoding = "UTF-8"
+    compileTestJava.options.encoding = "UTF-8"
 }
 
 repositories {
diff --git a/src/main/java/de/komoot/photon/App.java b/src/main/java/de/komoot/photon/App.java
index a823110bb..00aea759c 100644
--- a/src/main/java/de/komoot/photon/App.java
+++ b/src/main/java/de/komoot/photon/App.java
@@ -102,7 +102,7 @@ private static void startJsonDump(CommandLineArgs args) {
         try {
             final String filename = args.getJsonDump();
             final JsonDumper jsonDumper = new JsonDumper(filename, args.getLanguages(), args.getExtraTags());
-            NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.isUseGeometryColumn());
+            NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getUseGeometryColumn());
             nominatimConnector.setImporter(jsonDumper);
             nominatimConnector.readEntireDatabase(args.getCountryCodes());
             LOGGER.info("Json dump was created: {}", filename);
@@ -117,10 +117,14 @@ private static void startJsonDump(CommandLineArgs args) {
      */
     private static void startNominatimImport(CommandLineArgs args, Server esServer) {
         DatabaseProperties dbProperties;
-        NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.isUseGeometryColumn());
+        NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getUseGeometryColumn());
         Date importDate = nominatimConnector.getLastImportDate();
+        LOGGER.info("Starting import with the following settings: " +
+                "\n Languages: {} \n Import Date: {} \n Support Structured Queries: {} \n Support Polygons: {}",
+                args.getLanguages(), importDate, args.getSupportStructuredQueries(), args.getUseGeometryColumn());
+
         try {
-            dbProperties = esServer.recreateIndex(args.getLanguages(), importDate, args.getSupportStructuredQueries()); // clear out previous data
+            dbProperties = esServer.recreateIndex(args.getLanguages(), importDate, args.getSupportStructuredQueries(), args.getUseGeometryColumn()); // clear out previous data
         } catch (IOException e) {
             throw new RuntimeException("Cannot setup index, elastic search config files not readable", e);
         }
@@ -133,7 +137,7 @@ private static void startNominatimImport(CommandLineArgs args, Server esServer)
     }
 
     private static void startNominatimUpdateInit(CommandLineArgs args) {
-        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.isUseGeometryColumn());
+        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getUseGeometryColumn());
         nominatimUpdater.initUpdates(args.getNominatimUpdateInit());
     }
 
@@ -160,7 +164,7 @@ private static NominatimUpdater setupNominatimUpdater(CommandLineArgs args, Serv
         DatabaseProperties dbProperties = new DatabaseProperties();
         server.loadFromDatabase(dbProperties);
 
-        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.isUseGeometryColumn());
+        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getUseGeometryColumn());
         nominatimUpdater.setUpdater(server.createUpdater(dbProperties.getLanguages(), args.getExtraTags()));
         return nominatimUpdater;
     }
@@ -176,6 +180,10 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
             dbProperties.restrictLanguages(args.getLanguages());
         }
 
+        LOGGER.info("Starting API with the following settings: " +
+                        "\n Languages: {} \n Import Date: {} \n Support Structured Queries: {} \n Support Polygons: {}",
+                dbProperties.getLanguages(), dbProperties.getImportDate(), dbProperties.getSupportStructuredQueries(), dbProperties.getSupportPolygons());
+
         port(args.getListenPort());
         ipAddress(args.getListenIp());
 
@@ -191,8 +199,8 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
         String[] langs = dbProperties.getLanguages();
 
         SearchHandler searchHandler = server.createSearchHandler(langs, args.getQueryTimeout());
-        get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults()));
-        get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults()));
+        get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
+        get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
 
         if (dbProperties.getSupportStructuredQueries()) {
             StructuredSearchHandler structured = server.createStructuredSearchHandler(langs, args.getQueryTimeout());
diff --git a/src/main/java/de/komoot/photon/CommandLineArgs.java b/src/main/java/de/komoot/photon/CommandLineArgs.java
index b4bb93324..c2b383518 100644
--- a/src/main/java/de/komoot/photon/CommandLineArgs.java
+++ b/src/main/java/de/komoot/photon/CommandLineArgs.java
@@ -91,7 +91,7 @@ public class CommandLineArgs {
     @Parameter(names = "-max-reverse-results", description = "The maximum possible 'limit' parameter for reverse geocoding searches")
     private int maxReverseResults = 50;
 
-    @Parameter(names = "-use-geometry-column", description = "[import-only] Add the 'geometry' column from Nominatim on import (i.e. add Polygons for cities). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
+    @Parameter(names = "-use-geometry-column", description = "[import-only] Add the 'geometry' column from Nominatim on import (i.e. add Polygons for cities, countries etc.). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
     private boolean useGeometryColumn = false;
 
     public String[] getLanguages(boolean useDefaultIfEmpty) {
@@ -208,7 +208,7 @@ public int getMaxResults() {
         return maxResults;
     }
 
-    public boolean isUseGeometryColumn() {
+    public boolean getUseGeometryColumn() {
         return useGeometryColumn;
     }
 }
diff --git a/src/main/java/de/komoot/photon/DatabaseProperties.java b/src/main/java/de/komoot/photon/DatabaseProperties.java
index 5ebfd4ee7..a10340e1d 100644
--- a/src/main/java/de/komoot/photon/DatabaseProperties.java
+++ b/src/main/java/de/komoot/photon/DatabaseProperties.java
@@ -28,6 +28,8 @@ public class DatabaseProperties {
 
     private boolean supportStructuredQueries;
 
+    private boolean supportPolygons;
+
     /**
      * Return the list of languages for which the database is configured.
      * @return
@@ -100,4 +102,23 @@ public DatabaseProperties setSupportStructuredQueries(boolean supportStructuredQ
         this.supportStructuredQueries = supportStructuredQueries;
         return this;
     }
+
+    public boolean getSupportPolygons() {
+        return supportPolygons;
+    }
+
+    public DatabaseProperties setSupportPolygons(boolean supportPolygons) {
+        this.supportPolygons = supportPolygons;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return "DatabaseProperties{" +
+                "languages=" + Arrays.toString(languages) +
+                ", importDate=" + importDate +
+                ", supportStructuredQueries=" + supportStructuredQueries +
+                ", supportPolygons=" + supportPolygons +
+                '}';
+    }
 }
diff --git a/src/main/java/de/komoot/photon/PhotonDoc.java b/src/main/java/de/komoot/photon/PhotonDoc.java
index 17afeeda5..aa8c4c28a 100644
--- a/src/main/java/de/komoot/photon/PhotonDoc.java
+++ b/src/main/java/de/komoot/photon/PhotonDoc.java
@@ -45,6 +45,15 @@ public PhotonDoc(long placeId, String osmType, long osmId, String tagKey, String
         this.tagValue = tagValue;
     }
 
+    public PhotonDoc(long placeId, String osmType, long osmId, String tagKey, String tagValue, Geometry geometry) {
+        this.placeId = placeId;
+        this.osmType = osmType;
+        this.osmId = osmId;
+        this.tagKey = tagKey;
+        this.tagValue = tagValue;
+        this.geometry = geometry;
+    }
+
     public PhotonDoc(PhotonDoc other) {
         this.placeId = other.placeId;
         this.osmType = other.osmType;
diff --git a/src/main/java/de/komoot/photon/SearchRequestHandler.java b/src/main/java/de/komoot/photon/SearchRequestHandler.java
index 909029245..0a96dd41e 100644
--- a/src/main/java/de/komoot/photon/SearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/SearchRequestHandler.java
@@ -21,17 +21,19 @@ public class SearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final SearchHandler requestHandler;
     private final int maxResults;
+    private final boolean supportPolygons;
 
-    SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults) {
+    SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean supportPolygons) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
         this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults);
         this.requestHandler = dbHandler;
         this.maxResults = maxResults;
+        this.supportPolygons = supportPolygons;
     }
 
     @Override
-    public String handle(Request request, Response response) {
+    public String handle(Request request, Response response) throws BadRequestException {
         PhotonRequest photonRequest = null;
         try {
             photonRequest = photonRequestFactory.create(request);
@@ -56,6 +58,15 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
 
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getPolygon()).convert(results, debugInfo);
+        boolean returnPolygon = supportPolygons;
+        if (photonRequest.isPolygonRequest()) {
+            returnPolygon = photonRequest.getReturnPolygon();
+        }
+
+        if (!supportPolygons && (photonRequest.isPolygonRequest() && photonRequest.getReturnPolygon())) {
+            throw new BadRequestException(400, "You're requesting a polygon, but polygons are not imported!");
+        }
+
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), returnPolygon).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
index e8aeafd36..a8b4bc7b6 100644
--- a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
@@ -51,6 +51,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
  */
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getPolygon()).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getReturnPolygon()).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestBase.java b/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
index 5f5f9c99a..1e559be10 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
@@ -18,7 +18,8 @@ public class PhotonRequestBase
     private int zoom = 14;
     private Envelope bbox = null;
     private boolean debug = false;
-    private boolean polygon = false;
+    private boolean returnPolygon = true;
+    private boolean polygonRequest = false;
 
     private final List<TagFilter> osmTagFilters = new ArrayList<>(1);
     private Set<String> layerFilters = new HashSet<>(1);
@@ -54,7 +55,7 @@ public String getLanguage() {
 
     public boolean getDebug() { return debug; }
 
-    public boolean getPolygon() { return polygon; }
+    public boolean getReturnPolygon() { return returnPolygon; }
 
     public List<TagFilter> getOsmTagFilters() {
         return osmTagFilters;
@@ -104,7 +105,15 @@ void enableDebug() {
         this.debug = true;
     }
 
-    public void setPolygon(boolean polygon) {
-        this.polygon = polygon;
+    void setReturnPolygon(boolean returnPolygon) {
+        this.returnPolygon = returnPolygon;
+    }
+
+    void setPolygonRequest(boolean polygonRequest) {
+        this.polygonRequest = polygonRequest;
+    }
+
+    public boolean isPolygonRequest() {
+        return polygonRequest;
     }
 }
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
index 5fb5886d8..d1ea41036 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
@@ -112,7 +112,10 @@ private void addCommonParameters(Request webRequest, PhotonRequestBase request)
             request.setLayerFilter(layerParamValidator.validate(layerFiltersQueryMap.values()));
         }
 
-        request.setPolygon(Boolean.parseBoolean(webRequest.queryParams("polygon")));
+        if (webRequest.queryParams("polygon") != null) {
+            request.setPolygonRequest(true);
+            request.setReturnPolygon(Boolean.parseBoolean(webRequest.queryParams("polygon")));
+        }
     }
 
     private Integer parseInt(Request webRequest, String param) throws BadRequestException {
diff --git a/src/test/java/de/komoot/photon/ApiIntegrationTest.java b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
index ec9b224b1..00f5200f9 100644
--- a/src/test/java/de/komoot/photon/ApiIntegrationTest.java
+++ b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
@@ -23,7 +23,7 @@ class ApiIntegrationTest extends ESBaseTester {
 
     @BeforeEach
     void setUp() throws Exception {
-        setUpES();
+        setUpESWithPolygons();
         Importer instance = makeImporter();
         instance.add(createDoc(13.38886, 52.51704, 1000, 1000, "place", "city").importance(0.6), 0);
         instance.add(createDoc(13.39026, 52.54714, 1001, 1001, "place", "town").importance(0.3), 0);
@@ -163,4 +163,25 @@ public void testApiStatus() throws Exception {
         assertEquals("Ok", json.getString("status"));
         assertEquals(prop.getImportDate().toInstant().toString(), json.getString("import_date"));
     }
+
+    @Test
+    void testSearchAndGetPolygon() throws Exception {
+        App.main(new String[]{"-cluster", TEST_CLUSTER_NAME, "-listen-port", Integer.toString(LISTEN_PORT), "-transport-addresses", "127.0.0.1", "-use-geometry-column"});
+        awaitInitialization();
+        HttpURLConnection connection = (HttpURLConnection) new URL("http://127.0.0.1:" + port() + "/api?q=berlin&limit=1").openConnection();
+        JSONObject json = new JSONObject(
+                new BufferedReader(new InputStreamReader(connection.getInputStream())).lines().collect(Collectors.joining("\n")));
+        JSONArray features = json.getJSONArray("features");
+        assertEquals(1, features.length());
+        JSONObject feature = features.getJSONObject(0);
+
+        JSONObject geometry = feature.getJSONObject("geometry");
+        assertEquals("Polygon", geometry.getString("type"));
+
+        JSONObject properties = feature.getJSONObject("properties");
+        assertEquals("W", properties.getString("osm_type"));
+        assertEquals("place", properties.getString("osm_key"));
+        assertEquals("city", properties.getString("osm_value"));
+        assertEquals("berlin", properties.getString("name"));
+    }
 }
diff --git a/src/test/java/de/komoot/photon/api/ApiLanguagesTest.java b/src/test/java/de/komoot/photon/api/ApiLanguagesTest.java
index 9e821fe9f..91242b92d 100644
--- a/src/test/java/de/komoot/photon/api/ApiLanguagesTest.java
+++ b/src/test/java/de/komoot/photon/api/ApiLanguagesTest.java
@@ -48,7 +48,7 @@ protected PhotonDoc createDoc(int id, String key, String value, String... names)
     }
 
     private void importPlaces(String... languages) throws Exception {
-        setUpES(dataDirectory, languages);
+        setUpES(dataDirectory, false, languages);
         Importer instance = makeImporterWithLanguages(languages);
         instance.add(createDoc(1000, "place", "city",
                 "name:en", "thething", "name:fr", "letruc", "name:ch", "dasding"), 0);
diff --git a/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java b/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
index 5c75580f9..0011d0b1b 100644
--- a/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
+++ b/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
@@ -35,7 +35,7 @@ void setup() {
                 .build();
 
 
-        connector = new NominatimConnector(null, 0, null, null, null, new H2DataAdapter(), false);
+        connector = new NominatimConnector(null, 0, null, null, null, new H2DataAdapter(), true);
         importer = new CollectingImporter();
         connector.setImporter(importer);
 
@@ -336,6 +336,20 @@ void testNoCountry() {
         assertNull(importer.get(place).getCountryCode());
     }
 
+    /**
+     * Places without a country can be imported.
+     */
+    @Test
+    void testGeometry() {
+        PlacexTestRow place = new PlacexTestRow("building", "yes").name("Oosterbroek Zuivel").country("nl").add(jdbc);
+
+        connector.readEntireDatabase();
+
+        assertEquals(1, importer.size());
+
+        assertNull(importer.get(place).getGeometry());
+    }
+
     @Test
     public void testGetImportDate() {
         Date importDate = connector.getLastImportDate();
diff --git a/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java b/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
index a72d6ee0c..36ffc68e7 100644
--- a/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
+++ b/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
@@ -24,6 +24,7 @@ public class PlacexTestRow {
     private Integer rankAddress = 30;
     private Integer rankSearch = 30;
     private String centroid;
+    private String geometry;
     private String countryCode = "us";
     private Double importance = null;
 
@@ -33,6 +34,7 @@ public PlacexTestRow(String key, String value) {
         this.value = value;
         osmId = placeId;
         centroid = "POINT (1.0 34.0)";
+        geometry = "POLYGON ((6.4440619 52.1969454, 6.4441094 52.1969158, 6.4441408 52.1969347, 6.4441138 52.1969516, 6.4440933 52.1969643, 6.4440619 52.1969454))";
     }
 
     public static PlacexTestRow make_street(String name) {
diff --git a/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java b/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
index 93a6ba85b..1afc529d4 100644
--- a/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
+++ b/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
@@ -211,4 +211,12 @@ void testWithBadLayerFilters() throws Exception {
         assertTrue(exception.getMessage().contains(expectedMessageFragment),
                 String.format("Error message doesn not contain '%s': %s", expectedMessageFragment, exception.getMessage()));
     }
+
+    @Test
+    void testWithoutPolygon() throws Exception {
+        Request mockRequest = createRequestWithQueryParams("q", "berlin", "polygon", "false");
+        PhotonRequest photonRequest = createPhotonRequest(mockRequest);
+
+        assertFalse(photonRequest.getReturnPolygon());
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/de/komoot/photon/query/QueryByLanguageTest.java b/src/test/java/de/komoot/photon/query/QueryByLanguageTest.java
index 33bae735c..acce52e76 100644
--- a/src/test/java/de/komoot/photon/query/QueryByLanguageTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryByLanguageTest.java
@@ -25,7 +25,7 @@ class QueryByLanguageTest extends ESBaseTester {
 
     private Importer setup(String... languages) throws IOException {
         languageList = languages;
-        setUpES(dataDirectory, languages);
+        setUpES(dataDirectory, false, languages);
         return makeImporterWithLanguages(languages);
     }
 
diff --git a/src/test/java/de/komoot/photon/query/QueryFilterLayerTest.java b/src/test/java/de/komoot/photon/query/QueryFilterLayerTest.java
index bff0a3373..5ad8d9380 100644
--- a/src/test/java/de/komoot/photon/query/QueryFilterLayerTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryFilterLayerTest.java
@@ -26,7 +26,7 @@ class QueryFilterLayerTest extends ESBaseTester {
 
     @BeforeAll
     void setUp() throws Exception {
-        setUpES(instanceTestDirectory, "en", "de", "fr");
+        setUpES(instanceTestDirectory, false, "en", "de", "fr");
         Importer instance = makeImporter();
 
         int id = 0;
diff --git a/src/test/java/de/komoot/photon/query/QueryFilterTagValueTest.java b/src/test/java/de/komoot/photon/query/QueryFilterTagValueTest.java
index ea3859d4e..1bd2641bd 100644
--- a/src/test/java/de/komoot/photon/query/QueryFilterTagValueTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryFilterTagValueTest.java
@@ -36,7 +36,7 @@ class QueryFilterTagValueTest extends ESBaseTester {
 
     @BeforeAll
     void setUp() throws Exception {
-        setUpES(instanceTestDirectory, "en", "de", "fr");
+        setUpES(instanceTestDirectory, false, "en", "de", "fr");
         Importer instance = makeImporter();
         double lon = 13.38886;
         double lat = 52.51704;
diff --git a/src/test/java/de/komoot/photon/query/QueryPolygonTest.java b/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
new file mode 100644
index 000000000..3350d023f
--- /dev/null
+++ b/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
@@ -0,0 +1,58 @@
+package de.komoot.photon.query;
+
+import de.komoot.photon.ESBaseTester;
+import de.komoot.photon.Importer;
+import de.komoot.photon.PhotonDoc;
+import de.komoot.photon.searcher.PhotonResult;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKTReader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * Tests that the database backend produces queries which can find all
+ * expected results. These tests do not check relevance.
+ */
+class QueryPolygonTest extends ESBaseTester {
+    private int testDocId = 10000;
+
+    @BeforeEach
+    void setup() throws IOException {
+        setUpESWithPolygons();
+    }
+
+    private PhotonDoc createDoc(String... names) throws ParseException {
+        Map<String, String> nameMap = new HashMap<>();
+
+        for (int i = 0; i < names.length - 1; i += 2) {
+            nameMap.put(names[i], names[i+1]);
+        }
+
+        ++testDocId;
+        return new PhotonDoc(testDocId, "N", testDocId, "place", "city", new WKTReader().read("POLYGON ((1 1, 1 2, 2 1, 1 1))")).names(nameMap);
+    }
+
+    private List<PhotonResult> search(String query) {
+        return getServer().createSearchHandler(new String[]{"en"}, 1).search(new PhotonRequest(query, "en"));
+    }
+
+
+    @Test
+    void testSearchGetPolygon() throws IOException, ParseException {
+        Importer instance = makeImporter();
+        instance.add(createDoc("name", "Muffle Flu"), 0);
+        instance.finish();
+        refresh();
+        assertNotNull(search("muffle flu").get(0).get("geometry"));
+    }
+}
diff --git a/src/test/java/de/komoot/photon/query/QueryReverseFilterLayerTest.java b/src/test/java/de/komoot/photon/query/QueryReverseFilterLayerTest.java
index c649fddf4..883dc8a3b 100644
--- a/src/test/java/de/komoot/photon/query/QueryReverseFilterLayerTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryReverseFilterLayerTest.java
@@ -28,7 +28,7 @@ class QueryReverseFilterLayerTest extends ESBaseTester {
 
     @BeforeAll
     void setup() throws IOException {
-        setUpES(instanceTestDirectory, "en");
+        setUpES(instanceTestDirectory, false,"en");
 
         Importer instance = makeImporter();
 
diff --git a/src/test/java/de/komoot/photon/query/QueryReverseFilterTagValueTest.java b/src/test/java/de/komoot/photon/query/QueryReverseFilterTagValueTest.java
index 6fb8b5274..0dd82932f 100644
--- a/src/test/java/de/komoot/photon/query/QueryReverseFilterTagValueTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryReverseFilterTagValueTest.java
@@ -22,6 +22,7 @@
 import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.searcher.PhotonResult;
 import de.komoot.photon.searcher.TagFilter;
+import org.locationtech.jts.io.ParseException;
 
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 class QueryReverseFilterTagValueTest extends ESBaseTester {
@@ -39,8 +40,8 @@ class QueryReverseFilterTagValueTest extends ESBaseTester {
                                                       "railway", "station"};
 
     @BeforeAll
-    void setup() throws IOException {
-        setUpES(instanceTestDirectory, "en", "de", "fr");
+    void setup() throws IOException, ParseException {
+        setUpES(instanceTestDirectory, false, "en", "de", "fr");
         Importer instance = makeImporter();
         double lon = 13.38886;
         double lat = 52.51704;
diff --git a/src/test/java/de/komoot/photon/query/QueryReverseTest.java b/src/test/java/de/komoot/photon/query/QueryReverseTest.java
index 0210bdae9..0c841bdcf 100644
--- a/src/test/java/de/komoot/photon/query/QueryReverseTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryReverseTest.java
@@ -12,6 +12,7 @@
 import org.junit.jupiter.api.io.TempDir;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
+import org.locationtech.jts.io.ParseException;
 
 import java.io.IOException;
 import java.nio.file.Path;
@@ -26,8 +27,8 @@ class QueryReverseTest extends ESBaseTester {
     private static Path instanceTestDirectory;
 
     @BeforeAll
-    void setup() throws IOException {
-        setUpES(instanceTestDirectory, "en");
+    void setup() throws IOException, ParseException {
+        setUpES(instanceTestDirectory, false, "en");
 
         Importer instance = makeImporter();
         instance.add(createDoc(10,10, 100, 100, "place", "house"), 0);

From 41c20c420862b06b104859894fe98e165083f69e Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Thu, 5 Sep 2024 21:03:04 +0200
Subject: [PATCH 08/18] bugfix: minor fixes

---
 .../src/main/java/de/komoot/photon/Server.java       |  1 -
 src/main/java/de/komoot/photon/App.java              | 12 ++++++------
 src/main/java/de/komoot/photon/CommandLineArgs.java  |  8 ++++----
 .../photon/nominatim/NominatimConnectorDBTest.java   | 10 ++--------
 .../photon/nominatim/testdb/PlacexTestRow.java       |  6 +++---
 5 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/app/es_embedded/src/main/java/de/komoot/photon/Server.java b/app/es_embedded/src/main/java/de/komoot/photon/Server.java
index bd983b3fc..63555e14d 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/Server.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/Server.java
@@ -182,7 +182,6 @@ public DatabaseProperties recreateIndex(String[] languages, Date importDate, boo
             .setImportDate(importDate)
             .setSupportPolygons(supportPolygons);
 
-        LOGGER.info(dbProperties.toString());
         saveToDatabase(dbProperties);
 
         return dbProperties;
diff --git a/src/main/java/de/komoot/photon/App.java b/src/main/java/de/komoot/photon/App.java
index 00aea759c..576197f98 100644
--- a/src/main/java/de/komoot/photon/App.java
+++ b/src/main/java/de/komoot/photon/App.java
@@ -102,7 +102,7 @@ private static void startJsonDump(CommandLineArgs args) {
         try {
             final String filename = args.getJsonDump();
             final JsonDumper jsonDumper = new JsonDumper(filename, args.getLanguages(), args.getExtraTags());
-            NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getUseGeometryColumn());
+            NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getImportGeometryColumn());
             nominatimConnector.setImporter(jsonDumper);
             nominatimConnector.readEntireDatabase(args.getCountryCodes());
             LOGGER.info("Json dump was created: {}", filename);
@@ -117,14 +117,14 @@ private static void startJsonDump(CommandLineArgs args) {
      */
     private static void startNominatimImport(CommandLineArgs args, Server esServer) {
         DatabaseProperties dbProperties;
-        NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getUseGeometryColumn());
+        NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getImportGeometryColumn());
         Date importDate = nominatimConnector.getLastImportDate();
         LOGGER.info("Starting import with the following settings: " +
                 "\n Languages: {} \n Import Date: {} \n Support Structured Queries: {} \n Support Polygons: {}",
-                args.getLanguages(), importDate, args.getSupportStructuredQueries(), args.getUseGeometryColumn());
+                args.getLanguages(), importDate, args.getSupportStructuredQueries(), args.getImportGeometryColumn());
 
         try {
-            dbProperties = esServer.recreateIndex(args.getLanguages(), importDate, args.getSupportStructuredQueries(), args.getUseGeometryColumn()); // clear out previous data
+            dbProperties = esServer.recreateIndex(args.getLanguages(), importDate, args.getSupportStructuredQueries(), args.getImportGeometryColumn()); // clear out previous data
         } catch (IOException e) {
             throw new RuntimeException("Cannot setup index, elastic search config files not readable", e);
         }
@@ -137,7 +137,7 @@ private static void startNominatimImport(CommandLineArgs args, Server esServer)
     }
 
     private static void startNominatimUpdateInit(CommandLineArgs args) {
-        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getUseGeometryColumn());
+        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getImportGeometryColumn());
         nominatimUpdater.initUpdates(args.getNominatimUpdateInit());
     }
 
@@ -164,7 +164,7 @@ private static NominatimUpdater setupNominatimUpdater(CommandLineArgs args, Serv
         DatabaseProperties dbProperties = new DatabaseProperties();
         server.loadFromDatabase(dbProperties);
 
-        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getUseGeometryColumn());
+        NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getImportGeometryColumn());
         nominatimUpdater.setUpdater(server.createUpdater(dbProperties.getLanguages(), args.getExtraTags()));
         return nominatimUpdater;
     }
diff --git a/src/main/java/de/komoot/photon/CommandLineArgs.java b/src/main/java/de/komoot/photon/CommandLineArgs.java
index c2b383518..41ae5386e 100644
--- a/src/main/java/de/komoot/photon/CommandLineArgs.java
+++ b/src/main/java/de/komoot/photon/CommandLineArgs.java
@@ -91,8 +91,8 @@ public class CommandLineArgs {
     @Parameter(names = "-max-reverse-results", description = "The maximum possible 'limit' parameter for reverse geocoding searches")
     private int maxReverseResults = 50;
 
-    @Parameter(names = "-use-geometry-column", description = "[import-only] Add the 'geometry' column from Nominatim on import (i.e. add Polygons for cities, countries etc.). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
-    private boolean useGeometryColumn = false;
+    @Parameter(names = "-import-geometry-column", description = "[import-only] Add the 'geometry' column from Nominatim on import (i.e. add Polygons for cities, countries etc.). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
+    private boolean importGeometryColumn = false;
 
     public String[] getLanguages(boolean useDefaultIfEmpty) {
         if (useDefaultIfEmpty && languages.length == 0) {
@@ -208,8 +208,8 @@ public int getMaxResults() {
         return maxResults;
     }
 
-    public boolean getUseGeometryColumn() {
-        return useGeometryColumn;
+    public boolean getImportGeometryColumn() {
+        return importGeometryColumn;
     }
 }
 
diff --git a/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java b/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
index 0011d0b1b..49fa4abe1 100644
--- a/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
+++ b/src/test/java/de/komoot/photon/nominatim/NominatimConnectorDBTest.java
@@ -335,19 +335,13 @@ void testNoCountry() {
 
         assertNull(importer.get(place).getCountryCode());
     }
-
-    /**
-     * Places without a country can be imported.
-     */
+    
     @Test
     void testGeometry() {
         PlacexTestRow place = new PlacexTestRow("building", "yes").name("Oosterbroek Zuivel").country("nl").add(jdbc);
-
         connector.readEntireDatabase();
-
         assertEquals(1, importer.size());
-
-        assertNull(importer.get(place).getGeometry());
+        assertNotNull(importer.get(place).getGeometry());
     }
 
     @Test
diff --git a/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java b/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
index 36ffc68e7..92dd0d134 100644
--- a/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
+++ b/src/test/java/de/komoot/photon/nominatim/testdb/PlacexTestRow.java
@@ -114,9 +114,9 @@ public PlacexTestRow parent(PlacexTestRow row) {
 
     public PlacexTestRow add(JdbcTemplate jdbc) {
         jdbc.update("INSERT INTO placex (place_id, parent_place_id, osm_type, osm_id, class, type, rank_search, rank_address,"
-                        + " centroid, name, country_code, importance, address, indexed_status)"
-                        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ? FORMAT JSON, ?, ?, ? FORMAT JSON, 0)",
-                placeId, parentPlaceId, osmType, osmId, key, value, rankSearch, rankAddress, centroid,
+                        + " centroid, geometry, name, country_code, importance, address, indexed_status)"
+                        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? FORMAT JSON, ?, ?, ? FORMAT JSON, 0)",
+                placeId, parentPlaceId, osmType, osmId, key, value, rankSearch, rankAddress, centroid, geometry,
                 asJson(names), countryCode, importance, asJson(address));
 
         return this;

From cef09d7d967f0c3d708a225640b71a783d431871 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Thu, 5 Sep 2024 21:06:37 +0200
Subject: [PATCH 09/18] bugfix: typo

---
 src/test/java/de/komoot/photon/ApiIntegrationTest.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/java/de/komoot/photon/ApiIntegrationTest.java b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
index 00f5200f9..5a89d0758 100644
--- a/src/test/java/de/komoot/photon/ApiIntegrationTest.java
+++ b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
@@ -166,7 +166,7 @@ public void testApiStatus() throws Exception {
 
     @Test
     void testSearchAndGetPolygon() throws Exception {
-        App.main(new String[]{"-cluster", TEST_CLUSTER_NAME, "-listen-port", Integer.toString(LISTEN_PORT), "-transport-addresses", "127.0.0.1", "-use-geometry-column"});
+        App.main(new String[]{"-cluster", TEST_CLUSTER_NAME, "-listen-port", Integer.toString(LISTEN_PORT), "-transport-addresses", "127.0.0.1", "-import-geometry-column"});
         awaitInitialization();
         HttpURLConnection connection = (HttpURLConnection) new URL("http://127.0.0.1:" + port() + "/api?q=berlin&limit=1").openConnection();
         JSONObject json = new JSONObject(

From 161c9674863b6010e37688984444e503eec63cff Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Sat, 16 Nov 2024 14:42:43 +0100
Subject: [PATCH 10/18] fix: OpenSearch implementation of Geometry column

---
 .../src/test/java/de/komoot/photon/ESBaseTester.java   | 10 +++++++---
 .../src/test/java/de/komoot/photon/ServerTest.java     |  3 ++-
 .../komoot/photon/opensearch/StructuredQueryTest.java  |  2 +-
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
index 572c747cd..4a722f101 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
@@ -45,13 +45,17 @@ protected PhotonResult getById(String id) {
     }
 
     public void setUpES() throws IOException {
-        setUpES(dataDirectory, "en");
+        setUpES(dataDirectory, false,"en");
     }
 
-    public void setUpES(Path testDirectory, String... languages) throws IOException {
+    public void setUpESWithPolygons() throws IOException {
+        setUpES(dataDirectory, true,"en");
+    }
+
+    public void setUpES(Path testDirectory, boolean supportPolygons, String... languages) throws IOException {
         server = new OpenSearchTestServer(testDirectory.toString());
         server.startTestServer(TEST_CLUSTER_NAME);
-        server.recreateIndex(languages, new Date(), true, true);
+        server.recreateIndex(languages, new Date(), true, supportPolygons);
         server.refreshIndexes();
     }
 
diff --git a/app/opensearch/src/test/java/de/komoot/photon/ServerTest.java b/app/opensearch/src/test/java/de/komoot/photon/ServerTest.java
index ac14173f0..abace3cf6 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/ServerTest.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/ServerTest.java
@@ -16,7 +16,8 @@ void testSaveAndLoadFromDatabase() throws IOException {
         Date now = new Date();
         DatabaseProperties prop = new DatabaseProperties(new String[]{"en", "de", "fr"},
                                                          now,
-                                   false);
+                                   false,
+                                            false);
         getServer().saveToDatabase(prop);
 
         prop = getServer().loadFromDatabase();
diff --git a/app/opensearch/src/test/java/de/komoot/photon/opensearch/StructuredQueryTest.java b/app/opensearch/src/test/java/de/komoot/photon/opensearch/StructuredQueryTest.java
index b4c96cafc..335e7eb46 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/opensearch/StructuredQueryTest.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/opensearch/StructuredQueryTest.java
@@ -45,7 +45,7 @@ private static int getRank(AddressType type) {
 
     @BeforeEach
     void setUp() throws Exception {
-        setUpES(instanceTestDirectory, LANGUAGE, "de", "fr");
+        setUpES(instanceTestDirectory, false, LANGUAGE, "de", "fr");
         Importer instance = makeImporter();
 
         var country = new PhotonDoc(0, "R", 0, "place", "country")

From 583d575046a04493671342a62265d386d586ac51 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Sat, 16 Nov 2024 14:57:13 +0100
Subject: [PATCH 11/18] fix: remarks of lonvia

---
 src/main/java/de/komoot/photon/App.java       |  4 +--
 .../komoot/photon/SearchRequestHandler.java   | 17 +++++-------
 .../StructuredSearchRequestHandler.java       | 11 +++++++-
 .../photon/nominatim/NominatimImporter.java   | 27 +++++++++++++------
 .../photon/nominatim/NominatimUpdater.java    | 10 +++++--
 .../photon/query/PhotonRequestFactory.java    | 17 +++++++++++-
 6 files changed, 62 insertions(+), 24 deletions(-)

diff --git a/src/main/java/de/komoot/photon/App.java b/src/main/java/de/komoot/photon/App.java
index 8bf3b2663..5258bf69c 100644
--- a/src/main/java/de/komoot/photon/App.java
+++ b/src/main/java/de/komoot/photon/App.java
@@ -276,8 +276,8 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
 
         if (dbProperties.getSupportStructuredQueries()) {
             StructuredSearchHandler structured = server.createStructuredSearchHandler(langs, args.getQueryTimeout());
-            get("structured", new StructuredSearchRequestHandler("structured", structured, langs, args.getDefaultLanguage(), args.getMaxResults()));
-            get("structured/", new StructuredSearchRequestHandler("structured/", structured, langs, args.getDefaultLanguage(), args.getMaxResults()));
+            get("structured", new StructuredSearchRequestHandler("structured", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
+            get("structured/", new StructuredSearchRequestHandler("structured/", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
         }
 
         ReverseHandler reverseHandler = server.createReverseHandler(args.getQueryTimeout());
diff --git a/src/main/java/de/komoot/photon/SearchRequestHandler.java b/src/main/java/de/komoot/photon/SearchRequestHandler.java
index 0a96dd41e..82dbaa85d 100644
--- a/src/main/java/de/komoot/photon/SearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/SearchRequestHandler.java
@@ -43,6 +43,12 @@ public String handle(Request request, Response response) throws BadRequestExcept
             throw halt(e.getHttpStatus(), json.toString());
         }
 
+        if (!supportPolygons && (photonRequest.isPolygonRequest() && photonRequest.getReturnPolygon())) {
+            JSONObject json = new JSONObject();
+            json.put("message", "You're requesting a polygon, but polygons are not imported!");
+            throw halt(400, json.toString());
+        }
+
         List<PhotonResult> results = requestHandler.search(photonRequest);
 
         // Further filtering
@@ -58,15 +64,6 @@ public String handle(Request request, Response response) throws BadRequestExcept
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
 
-        boolean returnPolygon = supportPolygons;
-        if (photonRequest.isPolygonRequest()) {
-            returnPolygon = photonRequest.getReturnPolygon();
-        }
-
-        if (!supportPolygons && (photonRequest.isPolygonRequest() && photonRequest.getReturnPolygon())) {
-            throw new BadRequestException(400, "You're requesting a polygon, but polygons are not imported!");
-        }
-
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), returnPolygon).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getReturnPolygon()).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
index 293c3dc5f..6b066acc6 100644
--- a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
@@ -17,12 +17,14 @@
 public class StructuredSearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final StructuredSearchHandler requestHandler;
+    private final boolean supportPolygons;
 
-    StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults) {
+    StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean supportPolygons) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
         this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults);
         this.requestHandler = dbHandler;
+        this.supportPolygons = supportPolygons;
     }
 
     @Override
@@ -36,6 +38,12 @@ public String handle(Request request, Response response) {
             throw halt(e.getHttpStatus(), json.toString());
         }
 
+        if (!supportPolygons && (photonRequest.isPolygonRequest() && photonRequest.getReturnPolygon())) {
+            JSONObject json = new JSONObject();
+            json.put("message", "You're requesting a polygon, but polygons are not imported!");
+            throw halt(400, json.toString());
+        }
+
         List<PhotonResult> results = requestHandler.search(photonRequest);
 
         // Further filtering
@@ -46,6 +54,7 @@ public String handle(Request request, Response response) {
             results = results.subList(0, photonRequest.getLimit());
         }
 
+
         String debugInfo = null;
      /*   if (photonRequest.getDebug()) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
diff --git a/src/main/java/de/komoot/photon/nominatim/NominatimImporter.java b/src/main/java/de/komoot/photon/nominatim/NominatimImporter.java
index d7ba5990f..be661adc9 100644
--- a/src/main/java/de/komoot/photon/nominatim/NominatimImporter.java
+++ b/src/main/java/de/komoot/photon/nominatim/NominatimImporter.java
@@ -56,11 +56,17 @@ public void readCountry(String countryCode, ImportThread importThread) {
         addressCache.loadCountryAddresses(template, dbutils, countryCode);
 
         final PlaceRowMapper placeRowMapper = new PlaceRowMapper(dbutils, useGeometryColumn);
+        String query = "SELECT place_id, osm_type, osm_id, class, type, name, postcode," +
+                "       address, extratags, ST_Envelope(geometry) AS bbox, parent_place_id," +
+                "       linked_place_id, rank_address, rank_search, importance, country_code, centroid, ";
+
+        if (useGeometryColumn) {
+            query += "geometry,";
+        }
+
         // First read ranks below 30, independent places
         template.query(
-                "SELECT place_id, osm_type, osm_id, class, type, name, postcode," +
-                        "       address, extratags, ST_Envelope(geometry) AS bbox, parent_place_id," +
-                        "       linked_place_id, rank_address, rank_search, importance, country_code, centroid, geometry," +
+                query +
                         dbutils.jsonArrayFromSelect(
                                 "address_place_id",
                                 "FROM place_addressline pa " +
@@ -88,12 +94,17 @@ public void readCountry(String countryCode, ImportThread importThread) {
                 });
 
         // Next get all POIs/housenumbers.
+        query = "SELECT p.place_id, p.osm_type, p.osm_id, p.class, p.type, p.name, p.postcode," +
+                "       p.address, p.extratags, ST_Envelope(p.geometry) AS bbox, p.parent_place_id," +
+                "       p.linked_place_id, p.rank_address, p.rank_search, p.importance, p.country_code, p.centroid, " +
+                "       parent.class as parent_class, parent.type as parent_type," +
+                "       parent.rank_address as parent_rank_address, parent.name as parent_name, ";
+
+        if (useGeometryColumn) {
+            query += "p.geometry, ";
+        }
         template.query(
-                "SELECT p.place_id, p.osm_type, p.osm_id, p.class, p.type, p.name, p.postcode," +
-                        "       p.address, p.extratags, ST_Envelope(p.geometry) AS bbox, p.parent_place_id," +
-                        "       p.linked_place_id, p.rank_address, p.rank_search, p.importance, p.country_code, p.centroid, p.geometry," +
-                        "       parent.class as parent_class, parent.type as parent_type," +
-                        "       parent.rank_address as parent_rank_address, parent.name as parent_name, " +
+                 query +
                         dbutils.jsonArrayFromSelect(
                                 "address_place_id",
                                 "FROM place_addressline pa " +
diff --git a/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java b/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
index 9472974fe..25f06d023 100644
--- a/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
+++ b/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
@@ -17,7 +17,7 @@
 public class NominatimUpdater extends NominatimConnector {
     private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(NominatimUpdater.class);
 
-    private static final String SELECT_COLS_PLACEX = "SELECT place_id, osm_type, osm_id, class, type, name, postcode, address, extratags, ST_Envelope(geometry) AS bbox, parent_place_id, linked_place_id, rank_address, rank_search, importance, country_code, centroid, geometry";
+    private static final String SELECT_COLS_PLACEX = "SELECT place_id, osm_type, osm_id, class, type, name, postcode, address, extratags, ST_Envelope(geometry) AS bbox, parent_place_id, linked_place_id, rank_address, rank_search, importance, country_code, centroid";
     private static final String SELECT_COLS_ADDRESS = "SELECT p.name, p.class, p.type, p.rank_address";
     private static final String SELECT_OSMLINE_OLD_STYLE = "SELECT place_id, osm_id, parent_place_id, startnumber, endnumber, interpolationtype, postcode, country_code, linegeo";
     private static final String SELECT_OSMLINE_NEW_STYLE = "SELECT place_id, osm_id, parent_place_id, startnumber, endnumber, step, postcode, country_code, linegeo";
@@ -267,8 +267,14 @@ private List<UpdateRow> getPlaces(String table) {
 
 
     public List<PhotonDoc> getByPlaceId(long placeId) {
+        String query = SELECT_COLS_PLACEX + " FROM placex WHERE place_id = ? and indexed_status = 0";
+
+        if (useGeometryColumn) {
+            query += ", geometry";
+        }
+
         List<NominatimResult> result = template.query(
-                SELECT_COLS_PLACEX + " FROM placex WHERE place_id = ? and indexed_status = 0",
+                query,
                 placeToNominatimResult, placeId);
 
         return result.isEmpty() ? null : result.get(0).getDocsWithHousenumber();
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
index d1ea41036..80dbc41b7 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
@@ -114,7 +114,7 @@ private void addCommonParameters(Request webRequest, PhotonRequestBase request)
 
         if (webRequest.queryParams("polygon") != null) {
             request.setPolygonRequest(true);
-            request.setReturnPolygon(Boolean.parseBoolean(webRequest.queryParams("polygon")));
+            request.setReturnPolygon(parseBoolean(webRequest, webRequest.queryParams("polygon")));
         }
     }
 
@@ -151,4 +151,19 @@ private Double parseDouble(Request webRequest, String param) throws BadRequestEx
 
         return outVal;
     }
+
+    private Boolean parseBoolean(Request webRequest, String param) throws BadRequestException {
+        Boolean booleanVal = null;
+        String value = webRequest.queryParams(param);
+
+        if (value != null && !value.isEmpty()) {
+            try {
+                booleanVal = Boolean.valueOf(value);
+            } catch (NumberFormatException e) {
+                throw new BadRequestException(400, String.format("Invalid parameter '%s': must be a boolean", param));
+            }
+        }
+
+        return booleanVal;
+    }
 }

From 0abb0b4007f5dceffde0e6ceeb1bc37d8f3bbbb7 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Sat, 16 Nov 2024 15:13:59 +0100
Subject: [PATCH 12/18] fix: unit tests

---
 .../java/de/komoot/photon/nominatim/NominatimUpdater.java | 4 +++-
 .../java/de/komoot/photon/query/PhotonRequestFactory.java | 8 ++------
 .../komoot/photon/nominatim/NominatimUpdaterDBTest.java   | 2 +-
 3 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java b/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
index 25f06d023..1c591656a 100644
--- a/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
+++ b/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
@@ -267,12 +267,14 @@ private List<UpdateRow> getPlaces(String table) {
 
 
     public List<PhotonDoc> getByPlaceId(long placeId) {
-        String query = SELECT_COLS_PLACEX + " FROM placex WHERE place_id = ? and indexed_status = 0";
+        String query = SELECT_COLS_PLACEX;
 
         if (useGeometryColumn) {
             query += ", geometry";
         }
 
+        query += " FROM placex WHERE place_id = ? and indexed_status = 0";
+
         List<NominatimResult> result = template.query(
                 query,
                 placeToNominatimResult, placeId);
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
index 80dbc41b7..434de8b29 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
@@ -114,7 +114,7 @@ private void addCommonParameters(Request webRequest, PhotonRequestBase request)
 
         if (webRequest.queryParams("polygon") != null) {
             request.setPolygonRequest(true);
-            request.setReturnPolygon(parseBoolean(webRequest, webRequest.queryParams("polygon")));
+            request.setReturnPolygon(parseBoolean(webRequest, "polygon"));
         }
     }
 
@@ -157,11 +157,7 @@ private Boolean parseBoolean(Request webRequest, String param) throws BadRequest
         String value = webRequest.queryParams(param);
 
         if (value != null && !value.isEmpty()) {
-            try {
-                booleanVal = Boolean.valueOf(value);
-            } catch (NumberFormatException e) {
-                throw new BadRequestException(400, String.format("Invalid parameter '%s': must be a boolean", param));
-            }
+            booleanVal = Boolean.valueOf(value);
         }
 
         return booleanVal;
diff --git a/src/test/java/de/komoot/photon/nominatim/NominatimUpdaterDBTest.java b/src/test/java/de/komoot/photon/nominatim/NominatimUpdaterDBTest.java
index 354151075..228fb476f 100644
--- a/src/test/java/de/komoot/photon/nominatim/NominatimUpdaterDBTest.java
+++ b/src/test/java/de/komoot/photon/nominatim/NominatimUpdaterDBTest.java
@@ -29,7 +29,7 @@ void setup() {
                 .build();
 
 
-        connector = new NominatimUpdater(null, 0, null, null, null, new H2DataAdapter(), true);
+        connector = new NominatimUpdater(null, 0, null, null, null, new H2DataAdapter(), false);
         updater = new CollectingUpdater();
         connector.setUpdater(updater);
 

From db58e9a33a7d456319bc4f4ddfa84ec664db4336 Mon Sep 17 00:00:00 2001
From: red-fenix <red-fenix@xor.nu>
Date: Sat, 14 Dec 2024 12:00:31 +0100
Subject: [PATCH 13/18] fix: opensearch implementation

---
 .../photon/elasticsearch/ElasticResult.java   |  5 +++
 .../elasticsearch/ElasticGetIdResult.java     |  4 +++
 app/opensearch/build.gradle                   |  2 +-
 .../main/java/de/komoot/photon/Server.java    |  5 ++-
 .../photon/opensearch/OpenSearchResult.java   |  8 ++++-
 .../OpenSearchResultDeserializer.java         | 17 ++++++++-
 .../opensearch/PhotonDocSerializer.java       | 35 +++++++++++++++++--
 .../java/de/komoot/photon/ESBaseTester.java   |  8 +++--
 .../photon/opensearch/ImporterTest.java       |  8 +++--
 src/main/java/de/komoot/photon/PhotonDoc.java |  2 ++
 .../photon/searcher/GeocodeJsonFormatter.java | 18 +++++++---
 .../komoot/photon/searcher/PhotonResult.java  |  5 ++-
 .../de/komoot/photon/ApiIntegrationTest.java  |  4 +--
 .../komoot/photon/query/QueryPolygonTest.java | 11 +++---
 .../photon/searcher/MockPhotonResult.java     | 11 ++++++
 15 files changed, 120 insertions(+), 23 deletions(-)

diff --git a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
index 55b8ed5cf..4e2d6e588 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
@@ -66,6 +66,11 @@ public double[] getCoordinates() {
         return new double[]{coordinate.get(Constants.LON), coordinate.get(Constants.LAT)};
     }
 
+    @Override
+    public double[][] getGeometry() {
+        return null;
+    }
+
     @Override
     public double[] getExtent() {
         final Map<String, Object> extent = (Map<String, Object>) result.getSource().get("extent");
diff --git a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
index a7579cd40..891c062b5 100644
--- a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
+++ b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
@@ -34,6 +34,10 @@ public double[] getCoordinates() {
         throw new NotImplementedException();
     }
 
+    public double[][] getGeometry() {
+        throw new NotImplementedException();
+    }
+
     @Override
     public double[] getExtent() {
         throw new NotImplementedException();
diff --git a/app/opensearch/build.gradle b/app/opensearch/build.gradle
index 344457b36..2be69292f 100644
--- a/app/opensearch/build.gradle
+++ b/app/opensearch/build.gradle
@@ -22,7 +22,7 @@ dependencies {
     implementation 'org.apache.httpcomponents.client5:httpclient5:5.4.1'
     implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.2'
 
-    implementation('org.codelibs.opensearch:opensearch-runner:2.18.0.0') {
+    implementation('org.codelibs.opensearch:opensearch-runner:2.18.0.1') {
         exclude(module: 'repository-url')
         exclude(module: 'reindex-client')
         exclude(module: 'rank-eval-client')
diff --git a/app/opensearch/src/main/java/de/komoot/photon/Server.java b/app/opensearch/src/main/java/de/komoot/photon/Server.java
index 485a024df..554ca6600 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/Server.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/Server.java
@@ -35,7 +35,9 @@ public class Server {
 
     public static final String OPENSEARCH_MODULES =
             "org.opensearch.transport.Netty4Plugin,"
-            + "org.opensearch.analysis.common.CommonAnalysisPlugin";
+            + "org.opensearch.analysis.common.CommonAnalysisPlugin,"
+            + "org.opensearch.geo.GeoModulePlugin,"
+            + "org.opensearch.geospatial.plugin.GeospatialPlugin";
 
     protected OpenSearchClient client;
     private OpenSearchRunner runner = null;
@@ -87,6 +89,7 @@ private HttpHost[] startInternal(String clusterName) {
                 .clusterName(clusterName)
                 .numOfNode(1)
                 .moduleTypes(OPENSEARCH_MODULES)
+                .pluginTypes(OPENSEARCH_MODULES)
         );
 
         runner.ensureYellow();
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
index 3cbf95069..2a2fab4bb 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
@@ -11,14 +11,16 @@ public class OpenSearchResult implements PhotonResult {
     private double score = 0.0;
     private final double[] extent;
     private final double[] coordinates;
+    private final double[][] geometry;
     private final Map<String, Object> infos;
     private final Map<String, Map<String, String>> localeTags;
 
-    OpenSearchResult(double[] extent, double[] coordinates, Map<String, Object> infos, Map<String, Map<String, String>> localeTags) {
+    OpenSearchResult(double[] extent, double[] coordinates, Map<String, Object> infos, Map<String, Map<String, String>> localeTags, double[][] geometry) {
         this.extent = extent;
         this.coordinates = coordinates;
         this.infos = infos;
         this.localeTags = localeTags;
+        this.geometry = geometry;
     }
 
     public OpenSearchResult setScore(double score) {
@@ -61,6 +63,10 @@ public double[] getCoordinates() {
         return coordinates;
     }
 
+    public double[][] getGeometry() {
+        return geometry;
+    }
+
     @Override
     public double[] getExtent() {
         return extent;
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
index 1573aa393..a51f24e87 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
@@ -3,6 +3,7 @@
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -28,6 +29,7 @@ public OpenSearchResult deserialize(JsonParser p, DeserializationContext ctxt) t
 
         final Map<String, Object> tags = new HashMap<>();
         final Map<String, Map<String, String>> localeTags = new HashMap<>();
+        double[][] geometry = extractGeometry((ObjectNode) node.get("geometry"));
 
         var fields = node.fields();
         while (fields.hasNext()) {
@@ -55,7 +57,7 @@ public OpenSearchResult deserialize(JsonParser p, DeserializationContext ctxt) t
             }
         }
 
-        return new OpenSearchResult(extent, coordinates, tags, localeTags);
+        return new OpenSearchResult(extent, coordinates, tags, localeTags, geometry);
     }
 
     private double[] extractExtent(ObjectNode node) {
@@ -79,4 +81,17 @@ private double[] extractCoordinate(ObjectNode node) {
         return new double[]{node.get(Constants.LON).doubleValue(), node.get(Constants.LAT).doubleValue()};
     }
 
+    private double[][] extractGeometry(ObjectNode node) {
+        if (node == null) {
+            return PhotonResult.INVALID_GEOMETRY;
+        }
+
+        double[][] coordinates = new double[node.get("coordinates").get(0).size()][];
+        for(int i=0; i<node.get("coordinates").get(0).size(); i++) {
+            double[] coordinate = new double[] {node.get("coordinates").get(0).get(i).get(0).doubleValue(), node.get("coordinates").get(0).get(i).get(1).doubleValue()};
+            coordinates[i] = coordinate;
+        }
+
+        return coordinates;
+    }
 }
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
index 3c9792593..5710d868a 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
@@ -6,10 +6,12 @@
 import de.komoot.photon.Constants;
 import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.Utils;
+import org.locationtech.jts.geom.Coordinate;
 import org.locationtech.jts.geom.Envelope;
 import org.locationtech.jts.io.geojson.GeoJsonWriter;
 
 import java.io.IOException;
+import java.io.StringWriter;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -50,8 +52,37 @@ public void serialize(PhotonDoc value, JsonGenerator gen, SerializerProvider pro
         }
 
         if (value.getGeometry() != null) {
-            GeoJsonWriter g = new GeoJsonWriter();
-            gen.writeObjectField("geometry", g.write(value.getGeometry()));
+//            gen.writeStringField("geometry", g.write(value.getGeometry()));
+
+            gen.writeObjectFieldStart("geometry");
+                gen.writeStringField("type", "Polygon");
+
+            gen.writeArrayFieldStart("coordinates");
+
+            gen.writeStartArray();
+
+            for (Coordinate c: value.getGeometry().getCoordinates()) {
+                gen.writeStartArray();
+                gen.writeNumber(c.x);
+                gen.writeNumber(c.y);
+                gen.writeEndArray();
+            }
+            gen.writeEndArray();
+
+//            gen.writeStartArray();
+//            gen.writeNumber(bbox.getMaxX());
+//            gen.writeNumber(bbox.getMinY());
+//            gen.writeEndArray();
+
+            gen.writeEndArray();
+            gen.writeEndObject();
+
+//                gen.writeObjectFieldStart("crs");
+//                gen.writeStringField("type", "name");
+//                gen.writeObjectFieldStart("properties");
+//                gen.writeStringField("name", "EPSG:0");
+//                gen.writeEndObject();
+//            gen.writeEndObject();
         }
 
         if (value.getHouseNumber() != null) {
diff --git a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
index 4a722f101..ff2652ce1 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
@@ -9,12 +9,15 @@
 import org.locationtech.jts.geom.Coordinate;
 import org.locationtech.jts.geom.GeometryFactory;
 import org.locationtech.jts.geom.PrecisionModel;
+import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKTReader;
 
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collections;
 import java.util.Date;
 
+
 public class ESBaseTester {
     public static final String TEST_CLUSTER_NAME = "photon-test";
     protected static final GeometryFactory FACTORY = new GeometryFactory(new PrecisionModel(), 4326);
@@ -24,11 +27,12 @@ public class ESBaseTester {
 
     private OpenSearchTestServer server;
 
-    protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String key, String value) {
+    protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String key, String value) throws ParseException {
         final var location = FACTORY.createPoint(new Coordinate(lon, lat));
         return new PhotonDoc(id, "W", osmId, key, value)
                 .names(Collections.singletonMap("name", "berlin"))
-                .centroid(location);
+                .centroid(location)
+                .geometry(new WKTReader().read("POLYGON ((6.4440619 52.1969454, 6.4441094 52.1969158, 6.4441408 52.1969347, 6.4441138 52.1969516, 6.4440933 52.1969643, 6.4440619 52.1969454))"));
     }
 
     @AfterEach
diff --git a/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java b/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
index f1b2a8687..221efc7fc 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
@@ -6,6 +6,8 @@
 import de.komoot.photon.searcher.PhotonResult;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKTReader;
 
 import java.io.IOException;
 import java.util.Collections;
@@ -18,14 +20,14 @@ class ImporterTest extends ESBaseTester {
 
     @BeforeEach
     public void setUp() throws IOException {
-        setUpES();
+        setUpESWithPolygons();
     }
 
     @Test
-    void testAddSimpleDoc() {
+    void testAddSimpleDoc() throws ParseException {
         Importer instance = makeImporterWithExtra("");
 
-        instance.add(new PhotonDoc(1234, "N", 1000, "place", "city")
+        instance.add(new PhotonDoc(1234, "N", 1000, "place", "city", new WKTReader().read("POLYGON ((1 1, 1 2, 2 1, 1 1))"))
                 .extraTags(Collections.singletonMap("maxspeed", "100")), 0);
         instance.finish();
 
diff --git a/src/main/java/de/komoot/photon/PhotonDoc.java b/src/main/java/de/komoot/photon/PhotonDoc.java
index 2114cd0e3..cbf1bc606 100644
--- a/src/main/java/de/komoot/photon/PhotonDoc.java
+++ b/src/main/java/de/komoot/photon/PhotonDoc.java
@@ -6,6 +6,7 @@
 import org.locationtech.jts.geom.Point;
 import de.komoot.photon.nominatim.model.AddressType;
 import org.locationtech.jts.geom.Polygon;
+import org.locationtech.spatial4j.shape.ShapeFactory;
 import org.slf4j.Logger;
 
 import java.util.*;
@@ -357,6 +358,7 @@ public String getHouseNumber() {
     public Point getCentroid() {
         return this.centroid;
     }
+
     public Geometry getGeometry() {
         return this.geometry;
     }
diff --git a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
index 243571870..f7568852a 100644
--- a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
+++ b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
@@ -28,11 +28,19 @@ public String convert(List<PhotonResult> results, String debugInfo) {
         final JSONArray features = new JSONArray(results.size());
 
         for (PhotonResult result : results) {
-            if (useGeometryColumn && result.get("geometry") != null) {
-                features.put(new JSONObject()
-                        .put("type", "Feature")
-                        .put("properties", getResultProperties(result))
-                        .put("geometry", result.get("geometry")));
+            if (useGeometryColumn && (result.get("geometry") != null || result.getGeometry() != null)) {
+                if (result.get("geometry") != null) {
+                    features.put(new JSONObject()
+                            .put("type", "Feature")
+                            .put("properties", getResultProperties(result))
+                            .put("geometry", result.get("geometry")));
+                } else {
+                    var geom = new JSONObject().put("type", "Polygon").put("coordinates", result.getGeometry());
+                    features.put(new JSONObject()
+                            .put("type", "Feature")
+                            .put("properties", getResultProperties(result))
+                            .put("geometry", geom));
+                }
             } else {
                 final double[] coordinates = result.getCoordinates();
 
diff --git a/src/main/java/de/komoot/photon/searcher/PhotonResult.java b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
index d14e20cce..5064a96a2 100644
--- a/src/main/java/de/komoot/photon/searcher/PhotonResult.java
+++ b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
@@ -9,6 +9,7 @@
  */
 public interface PhotonResult {
     final double[] INVALID_COORDINATES = new double[]{0, 0};
+    final double[][] INVALID_GEOMETRY = new double[][]{{0, 0}};
 
     /**
      * Get the value for the given field.
@@ -24,7 +25,9 @@ public interface PhotonResult {
     Map<String, String> getMap(String key);
 
     double[] getCoordinates();
-    
+
+    double[][] getGeometry();
+
     double[] getExtent();
 
     double getScore();
diff --git a/src/test/java/de/komoot/photon/ApiIntegrationTest.java b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
index ce9f2132d..f434d2808 100644
--- a/src/test/java/de/komoot/photon/ApiIntegrationTest.java
+++ b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
@@ -26,7 +26,7 @@ class ApiIntegrationTest extends ESBaseTester {
 
     @BeforeEach
     void setUp() throws Exception {
-        setUpESWithPolygons();
+        setUpES();
         Importer instance = makeImporter();
         instance.add(createDoc(13.38886, 52.51704, 1000, 1000, "place", "city").importance(0.6), 0);
         instance.add(createDoc(13.39026, 52.54714, 1001, 1001, "place", "town").importance(0.3), 0);
@@ -149,7 +149,7 @@ void testApiStatus() throws Exception {
 
     @Test
     void testSearchAndGetPolygon() throws Exception {
-        App.main(new String[]{"-cluster", TEST_CLUSTER_NAME, "-listen-port", Integer.toString(LISTEN_PORT), "-transport-addresses", "127.0.0.1", "-import-geometry-column"});
+        App.main(new String[]{"-cluster", TEST_CLUSTER_NAME, "-listen-port", Integer.toString(LISTEN_PORT), "-transport-addresses", "127.0.0.1"});
         awaitInitialization();
         HttpURLConnection connection = (HttpURLConnection) new URL("http://127.0.0.1:" + port() + "/api?q=berlin&limit=1").openConnection();
         JSONObject json = new JSONObject(
diff --git a/src/test/java/de/komoot/photon/query/QueryPolygonTest.java b/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
index 3350d023f..ffd31b197 100644
--- a/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
@@ -10,13 +10,10 @@
 import org.locationtech.jts.io.WKTReader;
 
 import java.io.IOException;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 /**
@@ -53,6 +50,12 @@ void testSearchGetPolygon() throws IOException, ParseException {
         instance.add(createDoc("name", "Muffle Flu"), 0);
         instance.finish();
         refresh();
-        assertNotNull(search("muffle flu").get(0).get("geometry"));
+        List<PhotonResult> s = search("muffle flu");
+
+        if (s.get(0).getClass().getName().equals("de.komoot.photon.opensearch.OpenSearchResult")) {
+            assertNotNull(s.get(0).getGeometry());
+        } else {
+            assertNotNull(s.get(0).get("geometry"));
+        }
     }
 }
diff --git a/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java b/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
index 02efcc581..649528cde 100644
--- a/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
+++ b/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
@@ -9,6 +9,7 @@ public class MockPhotonResult implements PhotonResult {
 
     final Map<String, Object> data = new HashMap<>();
     final double[] coordinates = new double[]{42, 21};
+    final double[][] geometry = {{6.4440619,52.1969454},{6.4441094,52.1969158},{6.4441408,52.1969347},{6.4441138,52.1969516},{6.4440933,52.1969643},{6.4440619,52.1969454}};
     final double[] extent = new double[]{0, 1, 2, 3};
     final Map<String, String> localized = new HashMap<>();
 
@@ -32,6 +33,16 @@ public double[] getCoordinates() {
         return coordinates;
     }
 
+    @Override
+    public double[][] getGeometry() {
+        return geometry;
+    }
+
+//    @Override
+//    public double[][] getGeometry() {
+//        return geometry;
+//    }
+
     @Override
     public double[] getExtent() {
         return extent;

From 17c2c0ddcfecb86785b6d4f0510b478deafd62ef Mon Sep 17 00:00:00 2001
From: red-fenix <red-fenix@xor.nu>
Date: Sun, 12 Jan 2025 11:04:55 +0100
Subject: [PATCH 14/18] fix: latest remarks of lonvia

---
 .../main/java/de/komoot/photon/Server.java    |  2 +-
 .../photon/elasticsearch/ElasticResult.java   | 11 ++++++
 .../elasticsearch/ElasticGetIdResult.java     |  6 ++++
 .../main/java/de/komoot/photon/Server.java    | 12 +++----
 .../de/komoot/photon/opensearch/Importer.java |  2 ++
 .../photon/opensearch/OpenSearchResult.java   | 10 +++++-
 .../OpenSearchResultDeserializer.java         | 34 ++++++++++++++++---
 .../opensearch/PhotonDocSerializer.java       | 28 +++++----------
 .../java/de/komoot/photon/ESBaseTester.java   |  5 ++-
 .../opensearch/OpenSearchTestServer.java      |  3 +-
 src/main/java/de/komoot/photon/PhotonDoc.java |  2 --
 .../komoot/photon/SearchRequestHandler.java   |  8 ++---
 .../StructuredSearchRequestHandler.java       |  4 +--
 .../photon/nominatim/NominatimUpdater.java    |  4 +--
 .../photon/query/PhotonRequestBase.java       | 10 +-----
 .../photon/query/PhotonRequestFactory.java    | 15 +++++---
 .../photon/searcher/GeocodeJsonFormatter.java |  2 +-
 .../komoot/photon/searcher/GeometryType.java  | 17 ++++++++++
 .../komoot/photon/searcher/PhotonResult.java  |  2 ++
 .../de/komoot/photon/ApiIntegrationTest.java  | 27 ++++++++++++++-
 .../query/PhotonRequestFactoryTest.java       | 10 +++++-
 .../komoot/photon/query/QueryPolygonTest.java | 25 ++++++++++++--
 .../photon/searcher/MockPhotonResult.java     |  9 ++---
 23 files changed, 177 insertions(+), 71 deletions(-)
 create mode 100644 src/main/java/de/komoot/photon/searcher/GeometryType.java

diff --git a/app/es_embedded/src/main/java/de/komoot/photon/Server.java b/app/es_embedded/src/main/java/de/komoot/photon/Server.java
index dfb06f903..22582f22a 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/Server.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/Server.java
@@ -290,7 +290,7 @@ public DatabaseProperties loadFromDatabase() {
         return new DatabaseProperties(langString == null ? null : langString.split(","),
                 importDateString == null ? null : Date.from(Instant.parse(importDateString)),
                 false,
-                supportPolygons == null ? null : Boolean.parseBoolean(supportPolygons));
+                Boolean.parseBoolean(supportPolygons));
     }
 
     public Importer createImporter(String[] languages, String[] extraTags) {
diff --git a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
index 4e2d6e588..9145f303a 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
@@ -1,6 +1,7 @@
 package de.komoot.photon.elasticsearch;
 
 import de.komoot.photon.Constants;
+import de.komoot.photon.searcher.GeometryType;
 import de.komoot.photon.searcher.PhotonResult;
 import org.elasticsearch.search.SearchHit;
 import org.slf4j.Logger;
@@ -66,8 +67,18 @@ public double[] getCoordinates() {
         return new double[]{coordinate.get(Constants.LON), coordinate.get(Constants.LAT)};
     }
 
+    @Override
+    public GeometryType getGeometryType() {
+        final Map<String, Object> geometry = (Map<String, Object>) result.getSource().get("geometry");
+
+        return GeometryType.valueOf((String) geometry.get("type"));
+    }
+
     @Override
     public double[][] getGeometry() {
+        final Map<String, Object> geometry = (Map<String, Object>) result.getSource().get("geometry");
+        final List<List<Double>> coords = (List<List<Double>>) geometry.get("coordinates");
+
         return null;
     }
 
diff --git a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
index 891c062b5..73ffbb10d 100644
--- a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
+++ b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
@@ -1,5 +1,6 @@
 package de.komoot.photon.elasticsearch;
 
+import de.komoot.photon.searcher.GeometryType;
 import de.komoot.photon.searcher.PhotonResult;
 import org.apache.commons.lang3.NotImplementedException;
 import org.elasticsearch.action.get.GetResponse;
@@ -34,6 +35,11 @@ public double[] getCoordinates() {
         throw new NotImplementedException();
     }
 
+    @Override
+    public GeometryType getGeometryType() {
+        throw new NotImplementedException();
+    }
+
     public double[][] getGeometry() {
         throw new NotImplementedException();
     }
diff --git a/app/opensearch/src/main/java/de/komoot/photon/Server.java b/app/opensearch/src/main/java/de/komoot/photon/Server.java
index 554ca6600..d753a84ed 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/Server.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/Server.java
@@ -33,11 +33,11 @@ public class Server {
 
     private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Server.class);
 
-    public static final String OPENSEARCH_MODULES =
-            "org.opensearch.transport.Netty4Plugin,"
-            + "org.opensearch.analysis.common.CommonAnalysisPlugin,"
-            + "org.opensearch.geo.GeoModulePlugin,"
-            + "org.opensearch.geospatial.plugin.GeospatialPlugin";
+//    public static final String OPENSEARCH_MODULES =
+//            "org.opensearch.transport.Netty4Plugin,"
+//            + "org.opensearch.analysis.common.CommonAnalysisPlugin,"
+//            + "org.opensearch.geo.GeoModulePlugin,"
+//            + "org.opensearch.geospatial.plugin.GeospatialPlugin";
 
     protected OpenSearchClient client;
     private OpenSearchRunner runner = null;
@@ -88,8 +88,6 @@ private HttpHost[] startInternal(String clusterName) {
                 .basePath(dataDirectory)
                 .clusterName(clusterName)
                 .numOfNode(1)
-                .moduleTypes(OPENSEARCH_MODULES)
-                .pluginTypes(OPENSEARCH_MODULES)
         );
 
         runner.ensureYellow();
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/Importer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/Importer.java
index c3e7b31bf..00616e85a 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/Importer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/Importer.java
@@ -4,6 +4,8 @@
 import org.opensearch.client.opensearch.OpenSearchClient;
 import org.opensearch.client.opensearch._types.Time;
 import org.opensearch.client.opensearch.core.BulkRequest;
+import org.opensearch.client.opensearch.core.bulk.BulkOperation;
+import org.opensearch.client.opensearch.core.bulk.BulkResponseItem;
 import org.slf4j.Logger;
 
 import java.io.IOException;
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
index 2a2fab4bb..74a36149f 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
@@ -1,5 +1,6 @@
 package de.komoot.photon.opensearch;
 
+import de.komoot.photon.searcher.GeometryType;
 import de.komoot.photon.searcher.PhotonResult;
 import org.json.JSONObject;
 
@@ -12,15 +13,17 @@ public class OpenSearchResult implements PhotonResult {
     private final double[] extent;
     private final double[] coordinates;
     private final double[][] geometry;
+    private final GeometryType geometryType;
     private final Map<String, Object> infos;
     private final Map<String, Map<String, String>> localeTags;
 
-    OpenSearchResult(double[] extent, double[] coordinates, Map<String, Object> infos, Map<String, Map<String, String>> localeTags, double[][] geometry) {
+    OpenSearchResult(double[] extent, double[] coordinates, Map<String, Object> infos, Map<String, Map<String, String>> localeTags, double[][] geometry, GeometryType geometryType) {
         this.extent = extent;
         this.coordinates = coordinates;
         this.infos = infos;
         this.localeTags = localeTags;
         this.geometry = geometry;
+        this.geometryType = geometryType;
     }
 
     public OpenSearchResult setScore(double score) {
@@ -63,6 +66,11 @@ public double[] getCoordinates() {
         return coordinates;
     }
 
+    @Override
+    public GeometryType getGeometryType() {
+        return geometryType;
+    }
+
     public double[][] getGeometry() {
         return geometry;
     }
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
index a51f24e87..26431173c 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
@@ -3,11 +3,11 @@
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import de.komoot.photon.Constants;
+import de.komoot.photon.searcher.GeometryType;
 import de.komoot.photon.searcher.PhotonResult;
 
 import java.io.IOException;
@@ -29,7 +29,19 @@ public OpenSearchResult deserialize(JsonParser p, DeserializationContext ctxt) t
 
         final Map<String, Object> tags = new HashMap<>();
         final Map<String, Map<String, String>> localeTags = new HashMap<>();
-        double[][] geometry = extractGeometry((ObjectNode) node.get("geometry"));
+
+        double[][] geometry = new double[0][];
+        GeometryType geometryType = GeometryType.UNKNOWN;
+
+        if (node.get("geometry") != null && node.get("geometry").get("type") != null) {
+            if (node.get("geometry").get("type").asText().equals("Polygon")) {
+                geometry = extractPolygon((ObjectNode) node.get("geometry"));
+                geometryType = GeometryType.POLYGON;
+            } else if (node.get("geometry").get("type").asText().equals("LineString")) {
+                geometry = extractLineString((ObjectNode) node.get("geometry"));
+                geometryType = GeometryType.LINESTRING;
+            }
+        }
 
         var fields = node.fields();
         while (fields.hasNext()) {
@@ -57,7 +69,7 @@ public OpenSearchResult deserialize(JsonParser p, DeserializationContext ctxt) t
             }
         }
 
-        return new OpenSearchResult(extent, coordinates, tags, localeTags, geometry);
+        return new OpenSearchResult(extent, coordinates, tags, localeTags, geometry, geometryType);
     }
 
     private double[] extractExtent(ObjectNode node) {
@@ -81,7 +93,7 @@ private double[] extractCoordinate(ObjectNode node) {
         return new double[]{node.get(Constants.LON).doubleValue(), node.get(Constants.LAT).doubleValue()};
     }
 
-    private double[][] extractGeometry(ObjectNode node) {
+    private double[][] extractPolygon(ObjectNode node) {
         if (node == null) {
             return PhotonResult.INVALID_GEOMETRY;
         }
@@ -94,4 +106,18 @@ private double[][] extractGeometry(ObjectNode node) {
 
         return coordinates;
     }
+
+    private double[][] extractLineString(ObjectNode node) {
+        if (node == null) {
+            return PhotonResult.INVALID_GEOMETRY;
+        }
+
+        double[][] coordinates = new double[node.get("coordinates").size()][];
+        for(int i=0; i<node.get("coordinates").size(); i++) {
+            double[] coordinate = new double[] {node.get("coordinates").get(i).get(0).doubleValue(), node.get("coordinates").get(i).get(1).doubleValue()};
+            coordinates[i] = coordinate;
+        }
+
+        return coordinates;
+    }
 }
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
index 5710d868a..903fd3998 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
@@ -52,14 +52,14 @@ public void serialize(PhotonDoc value, JsonGenerator gen, SerializerProvider pro
         }
 
         if (value.getGeometry() != null) {
-//            gen.writeStringField("geometry", g.write(value.getGeometry()));
-
             gen.writeObjectFieldStart("geometry");
-                gen.writeStringField("type", "Polygon");
+            gen.writeStringField("type", value.getGeometry().getGeometryType());
 
             gen.writeArrayFieldStart("coordinates");
 
-            gen.writeStartArray();
+            if (value.getGeometry().getGeometryType().equals("Polygon")) {
+                gen.writeStartArray();
+            }
 
             for (Coordinate c: value.getGeometry().getCoordinates()) {
                 gen.writeStartArray();
@@ -67,22 +67,12 @@ public void serialize(PhotonDoc value, JsonGenerator gen, SerializerProvider pro
                 gen.writeNumber(c.y);
                 gen.writeEndArray();
             }
-            gen.writeEndArray();
-
-//            gen.writeStartArray();
-//            gen.writeNumber(bbox.getMaxX());
-//            gen.writeNumber(bbox.getMinY());
-//            gen.writeEndArray();
-
-            gen.writeEndArray();
-            gen.writeEndObject();
+            if (value.getGeometry().getGeometryType().equals("Polygon")) {
+                gen.writeEndArray();
+            }
 
-//                gen.writeObjectFieldStart("crs");
-//                gen.writeStringField("type", "name");
-//                gen.writeObjectFieldStart("properties");
-//                gen.writeStringField("name", "EPSG:0");
-//                gen.writeEndObject();
-//            gen.writeEndObject();
+            gen.writeEndArray(); // end 'coordinates'
+            gen.writeEndObject(); // end 'geometry'
         }
 
         if (value.getHouseNumber() != null) {
diff --git a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
index ff2652ce1..7b531e77e 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
@@ -2,7 +2,6 @@
 
 import de.komoot.photon.opensearch.Importer;
 import de.komoot.photon.opensearch.OpenSearchTestServer;
-import de.komoot.photon.opensearch.Updater;
 import de.komoot.photon.searcher.PhotonResult;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.io.TempDir;
@@ -49,11 +48,11 @@ protected PhotonResult getById(String id) {
     }
 
     public void setUpES() throws IOException {
-        setUpES(dataDirectory, false,"en");
+        setUpES(dataDirectory, false, "en");
     }
 
     public void setUpESWithPolygons() throws IOException {
-        setUpES(dataDirectory, true,"en");
+        setUpES(dataDirectory, true, "en");
     }
 
     public void setUpES(Path testDirectory, boolean supportPolygons, String... languages) throws IOException {
diff --git a/app/opensearch/src/test/java/de/komoot/photon/opensearch/OpenSearchTestServer.java b/app/opensearch/src/test/java/de/komoot/photon/opensearch/OpenSearchTestServer.java
index 161f60715..6c65537a8 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/opensearch/OpenSearchTestServer.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/opensearch/OpenSearchTestServer.java
@@ -38,8 +38,7 @@ public void build(final int number, final Settings.Builder settingsBuilder) {
                 .basePath(instanceDir)
                 .clusterName(clusterName)
                 .numOfNode(1)
-                .baseHttpPort(9200)
-                .moduleTypes(OPENSEARCH_MODULES));
+                .baseHttpPort(9200));
 
         // wait for yellow status
         runner.ensureYellow();
diff --git a/src/main/java/de/komoot/photon/PhotonDoc.java b/src/main/java/de/komoot/photon/PhotonDoc.java
index cbf1bc606..37f91dcb0 100644
--- a/src/main/java/de/komoot/photon/PhotonDoc.java
+++ b/src/main/java/de/komoot/photon/PhotonDoc.java
@@ -5,8 +5,6 @@
 import org.locationtech.jts.geom.Geometry;
 import org.locationtech.jts.geom.Point;
 import de.komoot.photon.nominatim.model.AddressType;
-import org.locationtech.jts.geom.Polygon;
-import org.locationtech.spatial4j.shape.ShapeFactory;
 import org.slf4j.Logger;
 
 import java.util.*;
diff --git a/src/main/java/de/komoot/photon/SearchRequestHandler.java b/src/main/java/de/komoot/photon/SearchRequestHandler.java
index 82dbaa85d..041e96567 100644
--- a/src/main/java/de/komoot/photon/SearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/SearchRequestHandler.java
@@ -20,15 +20,13 @@
 public class SearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final SearchHandler requestHandler;
-    private final int maxResults;
     private final boolean supportPolygons;
 
     SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean supportPolygons) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
-        this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults);
+        this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults, supportPolygons);
         this.requestHandler = dbHandler;
-        this.maxResults = maxResults;
         this.supportPolygons = supportPolygons;
     }
 
@@ -43,9 +41,9 @@ public String handle(Request request, Response response) throws BadRequestExcept
             throw halt(e.getHttpStatus(), json.toString());
         }
 
-        if (!supportPolygons && (photonRequest.isPolygonRequest() && photonRequest.getReturnPolygon())) {
+        if (!supportPolygons && photonRequest.getReturnPolygon()) {
             JSONObject json = new JSONObject();
-            json.put("message", "You're requesting a polygon, but polygons are not imported!");
+            json.put("message", "You're explicitly requesting a polygon, but polygons are not imported!");
             throw halt(400, json.toString());
         }
 
diff --git a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
index 6b066acc6..ec5e99ab5 100644
--- a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
@@ -22,7 +22,7 @@ public class StructuredSearchRequestHandler extends RouteImpl {
     StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean supportPolygons) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
-        this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults);
+        this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults, supportPolygons);
         this.requestHandler = dbHandler;
         this.supportPolygons = supportPolygons;
     }
@@ -38,7 +38,7 @@ public String handle(Request request, Response response) {
             throw halt(e.getHttpStatus(), json.toString());
         }
 
-        if (!supportPolygons && (photonRequest.isPolygonRequest() && photonRequest.getReturnPolygon())) {
+        if (!supportPolygons && photonRequest.getReturnPolygon()) {
             JSONObject json = new JSONObject();
             json.put("message", "You're requesting a polygon, but polygons are not imported!");
             throw halt(400, json.toString());
diff --git a/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java b/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
index 1c591656a..9e278a416 100644
--- a/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
+++ b/src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java
@@ -78,8 +78,8 @@ public class NominatimUpdater extends NominatimConnector {
     private boolean useGeometryColumn;
 
 
-    public NominatimUpdater(String host, int port, String database, String username, String passwordboolean, boolean useGeometryColumn) {
-        this(host, port, database, username, passwordboolean, new PostgisDataAdapter(), useGeometryColumn);
+    public NominatimUpdater(String host, int port, String database, String username, String password, boolean useGeometryColumn) {
+        this(host, port, database, username, password, new PostgisDataAdapter(), useGeometryColumn);
     }
 
     public NominatimUpdater(String host, int port, String database, String username, String password, DBDataAdapter dataAdapter, boolean useGeometryColumn) {
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestBase.java b/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
index 1e559be10..c8ba8aeae 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
@@ -18,8 +18,7 @@ public class PhotonRequestBase
     private int zoom = 14;
     private Envelope bbox = null;
     private boolean debug = false;
-    private boolean returnPolygon = true;
-    private boolean polygonRequest = false;
+    private boolean returnPolygon = false;
 
     private final List<TagFilter> osmTagFilters = new ArrayList<>(1);
     private Set<String> layerFilters = new HashSet<>(1);
@@ -109,11 +108,4 @@ void setReturnPolygon(boolean returnPolygon) {
         this.returnPolygon = returnPolygon;
     }
 
-    void setPolygonRequest(boolean polygonRequest) {
-        this.polygonRequest = polygonRequest;
-    }
-
-    public boolean isPolygonRequest() {
-        return polygonRequest;
-    }
 }
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
index 434de8b29..2c265b88c 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
@@ -17,6 +17,7 @@ public class PhotonRequestFactory {
     private final BoundingBoxParamConverter bboxParamConverter;
     private final LayerParamValidator layerParamValidator;
     private final int maxResults;
+    private final boolean supportPolygons;
 
     private static final HashSet<String> REQUEST_QUERY_PARAMS = new HashSet<>(Arrays.asList("lang", "q", "lon", "lat",
             "limit", "osm_tag", "location_bias_scale", "bbox", "debug", "zoom", "layer", "polygon"));
@@ -28,11 +29,12 @@ public class PhotonRequestFactory {
             "countrycode", "state", "county", "city", "postcode", "district", "housenumber", "street"));
 
 
-    public PhotonRequestFactory(List<String> supportedLanguages, String defaultLanguage, int maxResults) {
+    public PhotonRequestFactory(List<String> supportedLanguages, String defaultLanguage, int maxResults, boolean supportPolygons) {
         this.languageResolver = new RequestLanguageResolver(supportedLanguages, defaultLanguage);
         this.bboxParamConverter = new BoundingBoxParamConverter();
         this.layerParamValidator = new LayerParamValidator();
         this.maxResults = maxResults;
+        this.supportPolygons = supportPolygons;
     }
 
     public StructuredPhotonRequest createStructured(Request webRequest) throws BadRequestException {
@@ -112,8 +114,11 @@ private void addCommonParameters(Request webRequest, PhotonRequestBase request)
             request.setLayerFilter(layerParamValidator.validate(layerFiltersQueryMap.values()));
         }
 
+        // If the database supports polygons, return them by default.
+        request.setReturnPolygon(supportPolygons);
+
+        // Check if the user explicitly doesn't want a polygon.
         if (webRequest.queryParams("polygon") != null) {
-            request.setPolygonRequest(true);
             request.setReturnPolygon(parseBoolean(webRequest, "polygon"));
         }
     }
@@ -152,12 +157,12 @@ private Double parseDouble(Request webRequest, String param) throws BadRequestEx
         return outVal;
     }
 
-    private Boolean parseBoolean(Request webRequest, String param) throws BadRequestException {
-        Boolean booleanVal = null;
+    private Boolean parseBoolean(Request webRequest, String param) {
+        boolean booleanVal = false;
         String value = webRequest.queryParams(param);
 
         if (value != null && !value.isEmpty()) {
-            booleanVal = Boolean.valueOf(value);
+            booleanVal = Boolean.parseBoolean(value);
         }
 
         return booleanVal;
diff --git a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
index f7568852a..467436aea 100644
--- a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
+++ b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
@@ -35,7 +35,7 @@ public String convert(List<PhotonResult> results, String debugInfo) {
                             .put("properties", getResultProperties(result))
                             .put("geometry", result.get("geometry")));
                 } else {
-                    var geom = new JSONObject().put("type", "Polygon").put("coordinates", result.getGeometry());
+                    var geom = new JSONObject().put("type", result.getGeometryType().getName()).put("coordinates", result.getGeometry());
                     features.put(new JSONObject()
                             .put("type", "Feature")
                             .put("properties", getResultProperties(result))
diff --git a/src/main/java/de/komoot/photon/searcher/GeometryType.java b/src/main/java/de/komoot/photon/searcher/GeometryType.java
new file mode 100644
index 000000000..c508deba2
--- /dev/null
+++ b/src/main/java/de/komoot/photon/searcher/GeometryType.java
@@ -0,0 +1,17 @@
+package de.komoot.photon.searcher;
+
+public enum GeometryType {
+    UNKNOWN("unknown"),
+    POLYGON("Polygon"),
+    LINESTRING("LineString");
+
+    private final String name;
+
+    GeometryType(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+}
diff --git a/src/main/java/de/komoot/photon/searcher/PhotonResult.java b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
index 5064a96a2..2e02bec08 100644
--- a/src/main/java/de/komoot/photon/searcher/PhotonResult.java
+++ b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
@@ -26,6 +26,8 @@ public interface PhotonResult {
 
     double[] getCoordinates();
 
+    GeometryType getGeometryType();
+
     double[][] getGeometry();
 
     double[] getExtent();
diff --git a/src/test/java/de/komoot/photon/ApiIntegrationTest.java b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
index f434d2808..4eaceb109 100644
--- a/src/test/java/de/komoot/photon/ApiIntegrationTest.java
+++ b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
@@ -7,12 +7,14 @@
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.CsvSource;
+import org.locationtech.jts.io.WKTReader;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLConnection;
+import java.util.Collections;
 import java.util.stream.Collectors;
 
 import static org.junit.jupiter.api.Assertions.*;
@@ -26,10 +28,11 @@ class ApiIntegrationTest extends ESBaseTester {
 
     @BeforeEach
     void setUp() throws Exception {
-        setUpES();
+        setUpESWithPolygons();
         Importer instance = makeImporter();
         instance.add(createDoc(13.38886, 52.51704, 1000, 1000, "place", "city").importance(0.6), 0);
         instance.add(createDoc(13.39026, 52.54714, 1001, 1001, "place", "town").importance(0.3), 0);
+        instance.add(createDoc(13.39026, 52.54714, 1002, 1002, "place", "city").importance(0.3).names(Collections.singletonMap("name", "linestring")).geometry(new WKTReader().read("LINESTRING (30 10, 10 30, 40 40)")), 0);
         instance.finish();
         refresh();
     }
@@ -167,4 +170,26 @@ void testSearchAndGetPolygon() throws Exception {
         assertEquals("city", properties.getString("osm_value"));
         assertEquals("berlin", properties.getString("name"));
     }
+
+    @Test
+    void testSearchAndGetLineString() throws Exception {
+        App.main(new String[]{"-cluster", TEST_CLUSTER_NAME, "-listen-port", Integer.toString(LISTEN_PORT), "-transport-addresses", "127.0.0.1"});
+        awaitInitialization();
+        HttpURLConnection connection = (HttpURLConnection) new URL("http://127.0.0.1:" + port() + "/api?q=linestring&limit=1").openConnection();
+        JSONObject json = new JSONObject(
+                new BufferedReader(new InputStreamReader(connection.getInputStream())).lines().collect(Collectors.joining("\n")));
+        JSONArray features = json.getJSONArray("features");
+        assertEquals(1, features.length());
+        JSONObject feature = features.getJSONObject(0);
+
+        JSONObject geometry = feature.getJSONObject("geometry");
+        assertEquals("LineString", geometry.getString("type"));
+        assertEquals("[[30,10],[10,30],[40,40]]", geometry.getJSONArray("coordinates").toString());
+
+        JSONObject properties = feature.getJSONObject("properties");
+        assertEquals("W", properties.getString("osm_type"));
+        assertEquals("place", properties.getString("osm_key"));
+        assertEquals("city", properties.getString("osm_value"));
+        assertEquals("linestring", properties.getString("name"));
+    }
 }
diff --git a/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java b/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
index fbfa009ac..00760695c 100644
--- a/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
+++ b/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
@@ -56,7 +56,7 @@ private void requestWithLayers(Request mockRequest, String... layers) {
     }
 
     private PhotonRequest createPhotonRequest(Request mockRequest) throws BadRequestException {
-        PhotonRequestFactory factory = new PhotonRequestFactory(Collections.singletonList("en"), "en", 10);
+        PhotonRequestFactory factory = new PhotonRequestFactory(Collections.singletonList("en"), "en", 10, true);
         return factory.create(mockRequest);
     }
 
@@ -211,6 +211,14 @@ void testWithBadLayerFilters() {
                 String.format("Error message doesn not contain '%s': %s", expectedMessageFragment, exception.getMessage()));
     }
 
+    @Test
+    void testWithPolygon() throws Exception {
+        Request mockRequest = createRequestWithQueryParams("q", "berlin");
+        PhotonRequest photonRequest = createPhotonRequest(mockRequest);
+
+        assertTrue(photonRequest.getReturnPolygon());
+    }
+
     @Test
     void testWithoutPolygon() throws Exception {
         Request mockRequest = createRequestWithQueryParams("q", "berlin", "polygon", "false");
diff --git a/src/test/java/de/komoot/photon/query/QueryPolygonTest.java b/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
index ffd31b197..3bcfe0021 100644
--- a/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
@@ -6,6 +6,8 @@
 import de.komoot.photon.searcher.PhotonResult;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Point;
 import org.locationtech.jts.io.ParseException;
 import org.locationtech.jts.io.WKTReader;
 
@@ -36,7 +38,7 @@ private PhotonDoc createDoc(String... names) throws ParseException {
         }
 
         ++testDocId;
-        return new PhotonDoc(testDocId, "N", testDocId, "place", "city", new WKTReader().read("POLYGON ((1 1, 1 2, 2 1, 1 1))")).names(nameMap);
+        return new PhotonDoc(testDocId, "N", testDocId, "place", "city").names(nameMap);
     }
 
     private List<PhotonResult> search(String query) {
@@ -47,7 +49,26 @@ private List<PhotonResult> search(String query) {
     @Test
     void testSearchGetPolygon() throws IOException, ParseException {
         Importer instance = makeImporter();
-        instance.add(createDoc("name", "Muffle Flu"), 0);
+        Point location = FACTORY.createPoint(new Coordinate(1.0, 2.34));
+        PhotonDoc doc = createDoc("name", "Muffle Flu").geometry(new WKTReader().read("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))")).centroid(location);
+        instance.add(doc, 0);
+        instance.finish();
+        refresh();
+        List<PhotonResult> s = search("muffle flu");
+
+        if (s.get(0).getClass().getName().equals("de.komoot.photon.opensearch.OpenSearchResult")) {
+            assertNotNull(s.get(0).getGeometry());
+        } else {
+            assertNotNull(s.get(0).get("geometry"));
+        }
+    }
+
+    @Test
+    void testSearchGetLineString() throws IOException, ParseException {
+        Importer instance = makeImporter();
+        Point location = FACTORY.createPoint(new Coordinate(1.0, 2.34));
+        PhotonDoc doc = createDoc("name", "Muffle Flu").geometry(new WKTReader().read("LINESTRING (30 10, 10 30, 40 40)")).centroid(location);
+        instance.add(doc, 0);
         instance.finish();
         refresh();
         List<PhotonResult> s = search("muffle flu");
diff --git a/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java b/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
index 649528cde..b63f9c3ce 100644
--- a/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
+++ b/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
@@ -10,6 +10,7 @@ public class MockPhotonResult implements PhotonResult {
     final Map<String, Object> data = new HashMap<>();
     final double[] coordinates = new double[]{42, 21};
     final double[][] geometry = {{6.4440619,52.1969454},{6.4441094,52.1969158},{6.4441408,52.1969347},{6.4441138,52.1969516},{6.4440933,52.1969643},{6.4440619,52.1969454}};
+    final GeometryType geometryType = GeometryType.POLYGON;
     final double[] extent = new double[]{0, 1, 2, 3};
     final Map<String, String> localized = new HashMap<>();
 
@@ -38,10 +39,10 @@ public double[][] getGeometry() {
         return geometry;
     }
 
-//    @Override
-//    public double[][] getGeometry() {
-//        return geometry;
-//    }
+    @Override
+    public GeometryType getGeometryType() {
+        return geometryType;
+    }
 
     @Override
     public double[] getExtent() {

From eff3b06d00eea965b0743be7598badd28a2e7dda Mon Sep 17 00:00:00 2001
From: red-fenix <red-fenix@xor.nu>
Date: Sun, 23 Feb 2025 11:05:58 +0100
Subject: [PATCH 15/18] feat: add support for all polygon types

---
 .../photon/elasticsearch/ElasticResult.java   | 15 +------
 .../elasticsearch/PhotonDocConverter.java     |  8 +---
 .../elasticsearch/ElasticGetIdResult.java     |  8 +---
 .../de/komoot/photon/opensearch/Importer.java |  9 +++-
 .../photon/opensearch/OpenSearchResult.java   | 14 ++----
 .../OpenSearchResultDeserializer.java         | 45 ++-----------------
 .../opensearch/PhotonDocSerializer.java       | 31 +++----------
 .../photon/opensearch/ImporterTest.java       |  2 +-
 src/main/java/de/komoot/photon/Constants.java |  1 +
 src/main/java/de/komoot/photon/PhotonDoc.java | 25 +++++++++++
 .../photon/nominatim/NominatimImporter.java   |  2 +-
 .../photon/nominatim/PostgisDataAdapter.java  |  1 +
 .../nominatim/model/PlaceRowMapper.java       |  6 ++-
 .../photon/searcher/GeocodeJsonFormatter.java |  9 ++--
 .../komoot/photon/searcher/GeometryType.java  | 17 -------
 .../komoot/photon/searcher/PhotonResult.java  |  5 +--
 .../searcher/GeocodeJsonFormatterTest.java    |  6 +--
 .../photon/searcher/MockPhotonResult.java     | 10 +----
 18 files changed, 72 insertions(+), 142 deletions(-)
 delete mode 100644 src/main/java/de/komoot/photon/searcher/GeometryType.java

diff --git a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
index 9145f303a..d92a38d30 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/ElasticResult.java
@@ -1,7 +1,6 @@
 package de.komoot.photon.elasticsearch;
 
 import de.komoot.photon.Constants;
-import de.komoot.photon.searcher.GeometryType;
 import de.komoot.photon.searcher.PhotonResult;
 import org.elasticsearch.search.SearchHit;
 import org.slf4j.Logger;
@@ -68,18 +67,8 @@ public double[] getCoordinates() {
     }
 
     @Override
-    public GeometryType getGeometryType() {
-        final Map<String, Object> geometry = (Map<String, Object>) result.getSource().get("geometry");
-
-        return GeometryType.valueOf((String) geometry.get("type"));
-    }
-
-    @Override
-    public double[][] getGeometry() {
-        final Map<String, Object> geometry = (Map<String, Object>) result.getSource().get("geometry");
-        final List<List<Double>> coords = (List<List<Double>>) geometry.get("coordinates");
-
-        return null;
+    public String getGeometry() {
+        return (String) result.getSource().get("geometry");
     }
 
     @Override
diff --git a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/PhotonDocConverter.java b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/PhotonDocConverter.java
index 00d37a6e1..f5580d9f9 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/PhotonDocConverter.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/elasticsearch/PhotonDocConverter.java
@@ -4,16 +4,12 @@
 import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.nominatim.model.AddressType;
 
-import org.elasticsearch.common.xcontent.NamedXContentRegistry;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentFactory;
-import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.*;
 import org.elasticsearch.common.xcontent.json.JsonXContent;
 import org.locationtech.jts.geom.Envelope;
 import org.locationtech.jts.io.geojson.GeoJsonWriter;
 
 import java.io.IOException;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -46,7 +42,7 @@ public static XContentBuilder convert(PhotonDoc doc, String[] languages, String[
 
         if (doc.getGeometry() != null) {
             GeoJsonWriter g = new GeoJsonWriter();
-            
+
             XContentParser parser = JsonXContent
                 .jsonXContent
                 .createParser(NamedXContentRegistry.EMPTY, g.write(doc.getGeometry()));
diff --git a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
index 73ffbb10d..6a4fb487c 100644
--- a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
+++ b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ElasticGetIdResult.java
@@ -1,6 +1,5 @@
 package de.komoot.photon.elasticsearch;
 
-import de.komoot.photon.searcher.GeometryType;
 import de.komoot.photon.searcher.PhotonResult;
 import org.apache.commons.lang3.NotImplementedException;
 import org.elasticsearch.action.get.GetResponse;
@@ -35,12 +34,7 @@ public double[] getCoordinates() {
         throw new NotImplementedException();
     }
 
-    @Override
-    public GeometryType getGeometryType() {
-        throw new NotImplementedException();
-    }
-
-    public double[][] getGeometry() {
+    public String getGeometry() {
         throw new NotImplementedException();
     }
 
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/Importer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/Importer.java
index 00616e85a..dc488cbc2 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/Importer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/Importer.java
@@ -56,7 +56,14 @@ private void saveDocuments() {
             var response = client.bulk(bulkRequest.build());
 
             if (response.errors()) {
-                LOGGER.error("Error during bulk import.");
+                for (BulkResponseItem bri: response.items()) {
+                    LOGGER.error("Error during bulk import.");
+                    if (bri.error() != null) {
+                        LOGGER.error(bri.error().reason());
+                        LOGGER.error(bri.error().type());
+                        LOGGER.error(bri.error().stackTrace());
+                    }
+                }
             }
         } catch (IOException e) {
             LOGGER.error("Error during bulk import", e);
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
index 74a36149f..0bfeba686 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResult.java
@@ -1,6 +1,5 @@
 package de.komoot.photon.opensearch;
 
-import de.komoot.photon.searcher.GeometryType;
 import de.komoot.photon.searcher.PhotonResult;
 import org.json.JSONObject;
 
@@ -12,18 +11,16 @@ public class OpenSearchResult implements PhotonResult {
     private double score = 0.0;
     private final double[] extent;
     private final double[] coordinates;
-    private final double[][] geometry;
-    private final GeometryType geometryType;
+    private final String geometry;
     private final Map<String, Object> infos;
     private final Map<String, Map<String, String>> localeTags;
 
-    OpenSearchResult(double[] extent, double[] coordinates, Map<String, Object> infos, Map<String, Map<String, String>> localeTags, double[][] geometry, GeometryType geometryType) {
+    OpenSearchResult(double[] extent, double[] coordinates, Map<String, Object> infos, Map<String, Map<String, String>> localeTags, String geometry) {
         this.extent = extent;
         this.coordinates = coordinates;
         this.infos = infos;
         this.localeTags = localeTags;
         this.geometry = geometry;
-        this.geometryType = geometryType;
     }
 
     public OpenSearchResult setScore(double score) {
@@ -66,12 +63,7 @@ public double[] getCoordinates() {
         return coordinates;
     }
 
-    @Override
-    public GeometryType getGeometryType() {
-        return geometryType;
-    }
-
-    public double[][] getGeometry() {
+    public String getGeometry() {
         return geometry;
     }
 
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
index 26431173c..7f822f365 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/OpenSearchResultDeserializer.java
@@ -7,7 +7,6 @@
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import de.komoot.photon.Constants;
-import de.komoot.photon.searcher.GeometryType;
 import de.komoot.photon.searcher.PhotonResult;
 
 import java.io.IOException;
@@ -30,17 +29,9 @@ public OpenSearchResult deserialize(JsonParser p, DeserializationContext ctxt) t
         final Map<String, Object> tags = new HashMap<>();
         final Map<String, Map<String, String>> localeTags = new HashMap<>();
 
-        double[][] geometry = new double[0][];
-        GeometryType geometryType = GeometryType.UNKNOWN;
-
-        if (node.get("geometry") != null && node.get("geometry").get("type") != null) {
-            if (node.get("geometry").get("type").asText().equals("Polygon")) {
-                geometry = extractPolygon((ObjectNode) node.get("geometry"));
-                geometryType = GeometryType.POLYGON;
-            } else if (node.get("geometry").get("type").asText().equals("LineString")) {
-                geometry = extractLineString((ObjectNode) node.get("geometry"));
-                geometryType = GeometryType.LINESTRING;
-            }
+        String geometry = null;
+        if (node.get("geometry") != null) {
+            geometry = node.get("geometry").toString();
         }
 
         var fields = node.fields();
@@ -69,7 +60,7 @@ public OpenSearchResult deserialize(JsonParser p, DeserializationContext ctxt) t
             }
         }
 
-        return new OpenSearchResult(extent, coordinates, tags, localeTags, geometry, geometryType);
+        return new OpenSearchResult(extent, coordinates, tags, localeTags, geometry);
     }
 
     private double[] extractExtent(ObjectNode node) {
@@ -92,32 +83,4 @@ private double[] extractCoordinate(ObjectNode node) {
 
         return new double[]{node.get(Constants.LON).doubleValue(), node.get(Constants.LAT).doubleValue()};
     }
-
-    private double[][] extractPolygon(ObjectNode node) {
-        if (node == null) {
-            return PhotonResult.INVALID_GEOMETRY;
-        }
-
-        double[][] coordinates = new double[node.get("coordinates").get(0).size()][];
-        for(int i=0; i<node.get("coordinates").get(0).size(); i++) {
-            double[] coordinate = new double[] {node.get("coordinates").get(0).get(i).get(0).doubleValue(), node.get("coordinates").get(0).get(i).get(1).doubleValue()};
-            coordinates[i] = coordinate;
-        }
-
-        return coordinates;
-    }
-
-    private double[][] extractLineString(ObjectNode node) {
-        if (node == null) {
-            return PhotonResult.INVALID_GEOMETRY;
-        }
-
-        double[][] coordinates = new double[node.get("coordinates").size()][];
-        for(int i=0; i<node.get("coordinates").size(); i++) {
-            double[] coordinate = new double[] {node.get("coordinates").get(i).get(0).doubleValue(), node.get("coordinates").get(i).get(1).doubleValue()};
-            coordinates[i] = coordinate;
-        }
-
-        return coordinates;
-    }
 }
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
index 903fd3998..73e511793 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/PhotonDocSerializer.java
@@ -6,12 +6,10 @@
 import de.komoot.photon.Constants;
 import de.komoot.photon.PhotonDoc;
 import de.komoot.photon.Utils;
-import org.locationtech.jts.geom.Coordinate;
 import org.locationtech.jts.geom.Envelope;
 import org.locationtech.jts.io.geojson.GeoJsonWriter;
 
 import java.io.IOException;
-import java.io.StringWriter;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -51,28 +49,13 @@ public void serialize(PhotonDoc value, JsonGenerator gen, SerializerProvider pro
             gen.writeEndObject();
         }
 
-        if (value.getGeometry() != null) {
-            gen.writeObjectFieldStart("geometry");
-            gen.writeStringField("type", value.getGeometry().getGeometryType());
+        if (value.getGeometry() != null && !value.getGeometry().getGeometryType().equals("Point")) {
+            // Convert JTS Geometry to GeoJSON
+            GeoJsonWriter geoJsonWriter = new GeoJsonWriter();
+            String geoJson = geoJsonWriter.write(value.getGeometry());
 
-            gen.writeArrayFieldStart("coordinates");
-
-            if (value.getGeometry().getGeometryType().equals("Polygon")) {
-                gen.writeStartArray();
-            }
-
-            for (Coordinate c: value.getGeometry().getCoordinates()) {
-                gen.writeStartArray();
-                gen.writeNumber(c.x);
-                gen.writeNumber(c.y);
-                gen.writeEndArray();
-            }
-            if (value.getGeometry().getGeometryType().equals("Polygon")) {
-                gen.writeEndArray();
-            }
-
-            gen.writeEndArray(); // end 'coordinates'
-            gen.writeEndObject(); // end 'geometry'
+            gen.writeFieldName("geometry");
+            gen.writeRawValue(geoJson);
         }
 
         if (value.getHouseNumber() != null) {
@@ -109,7 +92,7 @@ public void serialize(PhotonDoc value, JsonGenerator gen, SerializerProvider pro
         gen.writeEndObject();
     }
 
-        private void writeName(JsonGenerator gen, PhotonDoc doc, String[] languages) throws IOException {
+    private void writeName(JsonGenerator gen, PhotonDoc doc, String[] languages) throws IOException {
         Map<String, String> fNames = new HashMap<>();
 
         doc.copyName(fNames, "default", "name");
diff --git a/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java b/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
index 221efc7fc..418ac741a 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
@@ -27,7 +27,7 @@ public void setUp() throws IOException {
     void testAddSimpleDoc() throws ParseException {
         Importer instance = makeImporterWithExtra("");
 
-        instance.add(new PhotonDoc(1234, "N", 1000, "place", "city", new WKTReader().read("POLYGON ((1 1, 1 2, 2 1, 1 1))"))
+        instance.add(new PhotonDoc(1234, "N", 1000, "place", "city", new WKTReader().read("MULTIPOLYGON (((6.111933 51.2659309, 6.1119417 51.2659247, 6.1119554 51.2659249, 6.1119868 51.2659432, 6.111964 51.2659591, 6.1119333 51.2659391, 6.111933 51.2659309)))"))
                 .extraTags(Collections.singletonMap("maxspeed", "100")), 0);
         instance.finish();
 
diff --git a/src/main/java/de/komoot/photon/Constants.java b/src/main/java/de/komoot/photon/Constants.java
index 50957da07..fc3a9f268 100644
--- a/src/main/java/de/komoot/photon/Constants.java
+++ b/src/main/java/de/komoot/photon/Constants.java
@@ -24,4 +24,5 @@ public class Constants {
     public static final String OSM_VALUE = "osm_value";
     public static final String OBJECT_TYPE = "type";
     public static final String CLASSIFICATION = "classification";
+    public static final String GEOMETRY = "geometry";
 }
diff --git a/src/main/java/de/komoot/photon/PhotonDoc.java b/src/main/java/de/komoot/photon/PhotonDoc.java
index 37f91dcb0..a9eda8978 100644
--- a/src/main/java/de/komoot/photon/PhotonDoc.java
+++ b/src/main/java/de/komoot/photon/PhotonDoc.java
@@ -360,4 +360,29 @@ public Point getCentroid() {
     public Geometry getGeometry() {
         return this.geometry;
     }
+
+    @Override
+    public String toString() {
+        return "PhotonDoc{" +
+                "placeId=" + placeId +
+                ", osmType='" + osmType + '\'' +
+                ", osmId=" + osmId +
+                ", tagKey='" + tagKey + '\'' +
+                ", tagValue='" + tagValue + '\'' +
+                ", name=" + name +
+                ", postcode='" + postcode + '\'' +
+                ", extratags=" + extratags +
+                ", bbox=" + bbox +
+                ", parentPlaceId=" + parentPlaceId +
+                ", importance=" + importance +
+                ", countryCode='" + countryCode + '\'' +
+                ", linkedPlaceId=" + linkedPlaceId +
+                ", rankAddress=" + rankAddress +
+                ", addressParts=" + addressParts +
+                ", context=" + context +
+                ", houseNumber='" + houseNumber + '\'' +
+                ", centroid=" + centroid +
+                ", geometry=" + geometry +
+                '}';
+    }
 }
diff --git a/src/main/java/de/komoot/photon/nominatim/NominatimImporter.java b/src/main/java/de/komoot/photon/nominatim/NominatimImporter.java
index be661adc9..1d48b2034 100644
--- a/src/main/java/de/komoot/photon/nominatim/NominatimImporter.java
+++ b/src/main/java/de/komoot/photon/nominatim/NominatimImporter.java
@@ -101,7 +101,7 @@ public void readCountry(String countryCode, ImportThread importThread) {
                 "       parent.rank_address as parent_rank_address, parent.name as parent_name, ";
 
         if (useGeometryColumn) {
-            query += "p.geometry, ";
+            query += "p.geometry as geometry, ";
         }
         template.query(
                  query +
diff --git a/src/main/java/de/komoot/photon/nominatim/PostgisDataAdapter.java b/src/main/java/de/komoot/photon/nominatim/PostgisDataAdapter.java
index 37e6718fc..051d9cc47 100644
--- a/src/main/java/de/komoot/photon/nominatim/PostgisDataAdapter.java
+++ b/src/main/java/de/komoot/photon/nominatim/PostgisDataAdapter.java
@@ -37,6 +37,7 @@ public Geometry extractGeometry(ResultSet rs, String columnName) throws SQLExcep
                 return new WKTReader().read(sb.toString());
             } catch (ParseException e) {
                 // ignore
+                System.out.println(e);
             }
         }
 
diff --git a/src/main/java/de/komoot/photon/nominatim/model/PlaceRowMapper.java b/src/main/java/de/komoot/photon/nominatim/model/PlaceRowMapper.java
index 191b27888..543b3cef7 100644
--- a/src/main/java/de/komoot/photon/nominatim/model/PlaceRowMapper.java
+++ b/src/main/java/de/komoot/photon/nominatim/model/PlaceRowMapper.java
@@ -43,7 +43,11 @@ public PhotonDoc mapRow(ResultSet rs, int rowNum) throws SQLException {
                 .postcode(rs.getString("postcode"));
 
         if (useGeometryColumn) {
-            doc.geometry(dbutils.extractGeometry(rs, "geometry"));
+            try {
+                doc.geometry(dbutils.extractGeometry(rs, "geometry"));
+            } catch (IllegalArgumentException e) {
+                System.out.println("Could not get Geometry: " + e);
+            }
         }
 
         double importance = rs.getDouble("importance");
diff --git a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
index 467436aea..cce1e9178 100644
--- a/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
+++ b/src/main/java/de/komoot/photon/searcher/GeocodeJsonFormatter.java
@@ -34,12 +34,15 @@ public String convert(List<PhotonResult> results, String debugInfo) {
                             .put("type", "Feature")
                             .put("properties", getResultProperties(result))
                             .put("geometry", result.get("geometry")));
-                } else {
-                    var geom = new JSONObject().put("type", result.getGeometryType().getName()).put("coordinates", result.getGeometry());
+                }
+                else {
+                    // We need to un-escape the JSON String first
+                    JSONObject jsonObject = new JSONObject(result.getGeometry());
+
                     features.put(new JSONObject()
                             .put("type", "Feature")
                             .put("properties", getResultProperties(result))
-                            .put("geometry", geom));
+                            .put("geometry", jsonObject));
                 }
             } else {
                 final double[] coordinates = result.getCoordinates();
diff --git a/src/main/java/de/komoot/photon/searcher/GeometryType.java b/src/main/java/de/komoot/photon/searcher/GeometryType.java
deleted file mode 100644
index c508deba2..000000000
--- a/src/main/java/de/komoot/photon/searcher/GeometryType.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package de.komoot.photon.searcher;
-
-public enum GeometryType {
-    UNKNOWN("unknown"),
-    POLYGON("Polygon"),
-    LINESTRING("LineString");
-
-    private final String name;
-
-    GeometryType(String name) {
-        this.name = name;
-    }
-
-    public String getName() {
-        return name;
-    }
-}
diff --git a/src/main/java/de/komoot/photon/searcher/PhotonResult.java b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
index 2e02bec08..ffbcefd26 100644
--- a/src/main/java/de/komoot/photon/searcher/PhotonResult.java
+++ b/src/main/java/de/komoot/photon/searcher/PhotonResult.java
@@ -9,7 +9,6 @@
  */
 public interface PhotonResult {
     final double[] INVALID_COORDINATES = new double[]{0, 0};
-    final double[][] INVALID_GEOMETRY = new double[][]{{0, 0}};
 
     /**
      * Get the value for the given field.
@@ -26,9 +25,7 @@ public interface PhotonResult {
 
     double[] getCoordinates();
 
-    GeometryType getGeometryType();
-
-    double[][] getGeometry();
+    String getGeometry();
 
     double[] getExtent();
 
diff --git a/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java b/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
index c311c15e8..46519499d 100644
--- a/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
+++ b/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
@@ -51,7 +51,7 @@ void testConvertPolygonToGeojson() {
         for (int i = 0; i < features.length(); i++) {
             JSONObject feature = features.getJSONObject(i);
             assertEquals("Feature", feature.getString("type"));
-            assertEquals("Polygon", feature.getJSONObject("geometry").getString("type"));
+            assertEquals("MultiPolygon", feature.getJSONObject("geometry").getString("type"));
             assertEquals("leisure", feature.getJSONObject("properties").getString(Constants.OSM_KEY));
             assertEquals("park", feature.getJSONObject("properties").getString(Constants.OSM_VALUE));
         }
@@ -76,9 +76,7 @@ private PhotonResult createDummyPolygonResult(String postCode, String name, Stri
                 .putLocalized(Constants.NAME, "en", name)
                 .put(Constants.OSM_KEY, osmKey)
                 .put(Constants.OSM_VALUE, osmValue)
-                .put("geometry", new JSONObject()
-                        .put("type", "Polygon")
-                        .put("coordinates", new double[][]{{100.0, 0.0}, {101.0, 0.0}, {101.0, 1.0}, {100.0, 1.0}, {100.0, 0.0}}));
+                .put(Constants.GEOMETRY, new JSONObject("{\"type\":\"MultiPolygon\",\"coordinates\":[[[[-100.0,40.0],[-100.0,45.0],[-90.0,45.0],[-90.0,40.0],[-100.0,40.0]]],[[[-80.0,35.0],[-80.0,40.0],[-70.0,40.0],[-70.0,35.0],[-80.0,35.0]]]]}"));
     }
 
 }
diff --git a/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java b/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
index b63f9c3ce..613f92947 100644
--- a/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
+++ b/src/test/java/de/komoot/photon/searcher/MockPhotonResult.java
@@ -9,8 +9,7 @@ public class MockPhotonResult implements PhotonResult {
 
     final Map<String, Object> data = new HashMap<>();
     final double[] coordinates = new double[]{42, 21};
-    final double[][] geometry = {{6.4440619,52.1969454},{6.4441094,52.1969158},{6.4441408,52.1969347},{6.4441138,52.1969516},{6.4440933,52.1969643},{6.4440619,52.1969454}};
-    final GeometryType geometryType = GeometryType.POLYGON;
+    final String geometry = "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[-100.0,40.0],[-100.0,45.0],[-90.0,45.0],[-90.0,40.0],[-100.0,40.0]]],[[[-80.0,35.0],[-80.0,40.0],[-70.0,40.0],[-70.0,35.0],[-80.0,35.0]]]]}";
     final double[] extent = new double[]{0, 1, 2, 3};
     final Map<String, String> localized = new HashMap<>();
 
@@ -35,15 +34,10 @@ public double[] getCoordinates() {
     }
 
     @Override
-    public double[][] getGeometry() {
+    public String getGeometry() {
         return geometry;
     }
 
-    @Override
-    public GeometryType getGeometryType() {
-        return geometryType;
-    }
-
     @Override
     public double[] getExtent() {
         return extent;

From a5ac9b4acd11e8ec8108bbaf74afa80715035b35 Mon Sep 17 00:00:00 2001
From: red-fenix <red-fenix@xor.nu>
Date: Tue, 11 Mar 2025 20:59:00 +0100
Subject: [PATCH 16/18] bugfix: rename all "polygon" references to "geometry"

---
 .../src/main/java/de/komoot/photon/Server.java | 12 ++++++------
 .../java/de/komoot/photon/ESBaseTester.java    |  6 +++---
 .../src/main/java/de/komoot/photon/Server.java |  6 +++---
 .../photon/opensearch/DBPropertyEntry.java     |  4 ++--
 .../java/de/komoot/photon/ESBaseTester.java    |  6 +++---
 .../komoot/photon/opensearch/ImporterTest.java |  2 +-
 src/main/java/de/komoot/photon/App.java        | 12 ++++++------
 .../java/de/komoot/photon/CommandLineArgs.java |  2 +-
 .../de/komoot/photon/DatabaseProperties.java   | 16 ++++++++--------
 src/main/java/de/komoot/photon/PhotonDoc.java  |  4 ++--
 .../photon/ReverseSearchRequestHandler.java    |  2 +-
 .../de/komoot/photon/SearchRequestHandler.java | 14 +++++++-------
 .../photon/StructuredSearchRequestHandler.java | 14 +++++++-------
 .../komoot/photon/query/PhotonRequestBase.java |  8 ++++----
 .../photon/query/PhotonRequestFactory.java     | 18 +++++++++---------
 .../de/komoot/photon/query/ReverseRequest.java | 10 +++++-----
 .../photon/query/ReverseRequestFactory.java    |  4 ++--
 .../de/komoot/photon/ApiIntegrationTest.java   |  4 ++--
 .../photon/query/PhotonRequestFactoryTest.java | 10 +++++-----
 ...PolygonTest.java => QueryGeometryTest.java} |  4 ++--
 .../searcher/GeocodeJsonFormatterTest.java     | 16 ++++++++--------
 21 files changed, 87 insertions(+), 87 deletions(-)
 rename src/test/java/de/komoot/photon/query/{QueryPolygonTest.java => QueryGeometryTest.java} (97%)

diff --git a/app/es_embedded/src/main/java/de/komoot/photon/Server.java b/app/es_embedded/src/main/java/de/komoot/photon/Server.java
index 22582f22a..a52907891 100644
--- a/app/es_embedded/src/main/java/de/komoot/photon/Server.java
+++ b/app/es_embedded/src/main/java/de/komoot/photon/Server.java
@@ -56,7 +56,7 @@ public class Server {
     private static final String FIELD_VERSION = "database_version";
     private static final String FIELD_LANGUAGES = "indexed_languages";
     private static final String FIELD_IMPORT_DATE = "import_date";
-    private static final String FIELD_SUPPORT_POLYGONS = "support_polygons";
+    private static final String FIELD_SUPPORT_GEOMETRIES = "support_geometries";
 
     private Node esNode;
 
@@ -178,7 +178,7 @@ private void setupDirectories(URL directoryName) throws IOException, URISyntaxEx
 
     }
 
-    public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportPolygons) throws IOException {
+    public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportGeometries) throws IOException {
         deleteIndex();
 
         loadIndexSettings().createIndex(esClient, PhotonIndex.NAME);
@@ -188,7 +188,7 @@ public DatabaseProperties recreateIndex(String[] languages, Date importDate, boo
         DatabaseProperties dbProperties = new DatabaseProperties()
             .setLanguages(languages)
             .setImportDate(importDate)
-            .setSupportPolygons(supportPolygons);
+            .setSupportGeometries(supportGeometries);
 
         saveToDatabase(dbProperties);
 
@@ -244,7 +244,7 @@ public void saveToDatabase(DatabaseProperties dbProperties) throws IOException
                         .field(FIELD_VERSION, DATABASE_VERSION)
                         .field(FIELD_LANGUAGES, String.join(",", dbProperties.getLanguages()))
                         .field(FIELD_IMPORT_DATE, dbProperties.getImportDate() instanceof Date ? dbProperties.getImportDate().toInstant() : null)
-                        .field(FIELD_SUPPORT_POLYGONS, Boolean.toString(dbProperties.getSupportPolygons()))
+                        .field(FIELD_SUPPORT_GEOMETRIES, Boolean.toString(dbProperties.getSupportGeometries()))
                         .endObject().endObject();
 
         esClient.prepareIndex(PhotonIndex.NAME, PhotonIndex.TYPE).
@@ -285,12 +285,12 @@ public DatabaseProperties loadFromDatabase() {
 
         String importDateString = properties.get(FIELD_IMPORT_DATE);
 
-        String supportPolygons = properties.get(FIELD_SUPPORT_POLYGONS);
+        String supportGeometries = properties.get(FIELD_SUPPORT_GEOMETRIES);
 
         return new DatabaseProperties(langString == null ? null : langString.split(","),
                 importDateString == null ? null : Date.from(Instant.parse(importDateString)),
                 false,
-                Boolean.parseBoolean(supportPolygons));
+                Boolean.parseBoolean(supportGeometries));
     }
 
     public Importer createImporter(String[] languages, String[] extraTags) {
diff --git a/app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java b/app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java
index dff5bdcd6..1ea9bd62a 100644
--- a/app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java
+++ b/app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java
@@ -50,7 +50,7 @@ public void setUpES() throws IOException {
         setUpES(dataDirectory, false,"en");
     }
 
-    public void setUpESWithPolygons() throws IOException {
+    public void setUpESWithGeometry() throws IOException {
         setUpES(dataDirectory, true,"en");
     }
     /**
@@ -58,10 +58,10 @@ public void setUpESWithPolygons() throws IOException {
      *
      * @throws IOException
      */
-    public void setUpES(Path testDirectory, boolean supportPolygons, String... languages) throws IOException {
+    public void setUpES(Path testDirectory, boolean supportGeometries, String... languages) throws IOException {
         server = new ElasticTestServer(testDirectory.toString());
         server.start(TEST_CLUSTER_NAME, new String[]{});
-        server.recreateIndex(languages, new Date(), false, supportPolygons);
+        server.recreateIndex(languages, new Date(), false, supportGeometries);
         refresh();
     }
 
diff --git a/app/opensearch/src/main/java/de/komoot/photon/Server.java b/app/opensearch/src/main/java/de/komoot/photon/Server.java
index d753a84ed..fe555dd35 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/Server.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/Server.java
@@ -120,7 +120,7 @@ public void shutdown() {
         }
     }
 
-    public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportPolygons) throws IOException {
+    public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportGeometries) throws IOException {
         // delete any existing data
         if (client.indices().exists(e -> e.index(PhotonIndex.NAME)).value()) {
             client.indices().delete(d -> d.index(PhotonIndex.NAME));
@@ -130,7 +130,7 @@ public DatabaseProperties recreateIndex(String[] languages, Date importDate, boo
 
         (new IndexMapping(supportStructuredQueries)).addLanguages(languages).putMapping(client, PhotonIndex.NAME);
 
-        var dbProperties = new DatabaseProperties(languages, importDate, supportStructuredQueries, supportPolygons);
+        var dbProperties = new DatabaseProperties(languages, importDate, supportStructuredQueries, supportGeometries);
         saveToDatabase(dbProperties);
 
         return dbProperties;
@@ -182,7 +182,7 @@ public DatabaseProperties loadFromDatabase() throws IOException {
         return new DatabaseProperties(dbEntry.source().languages,
                                       dbEntry.source().importDate,
                                       dbEntry.source().supportStructuredQueries,
-                                      dbEntry.source().supportPolygons);
+                                      dbEntry.source().supportGeometries);
     }
 
     public Importer createImporter(String[] languages, String[] extraTags) {
diff --git a/app/opensearch/src/main/java/de/komoot/photon/opensearch/DBPropertyEntry.java b/app/opensearch/src/main/java/de/komoot/photon/opensearch/DBPropertyEntry.java
index 795234dbe..21679cab3 100644
--- a/app/opensearch/src/main/java/de/komoot/photon/opensearch/DBPropertyEntry.java
+++ b/app/opensearch/src/main/java/de/komoot/photon/opensearch/DBPropertyEntry.java
@@ -9,7 +9,7 @@ public class DBPropertyEntry {
     public Date importDate;
     public String[] languages;
     public boolean supportStructuredQueries;
-    public boolean supportPolygons;
+    public boolean supportGeometries;
 
     public DBPropertyEntry() {}
 
@@ -18,6 +18,6 @@ public DBPropertyEntry(DatabaseProperties props, String databaseVersion) {
         importDate = props.getImportDate();
         languages = props.getLanguages();
         supportStructuredQueries = props.getSupportStructuredQueries();
-        supportPolygons = props.getSupportPolygons();
+        supportGeometries = props.getSupportGeometries();
     }
 }
diff --git a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
index 7b531e77e..98bf0979d 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
@@ -51,14 +51,14 @@ public void setUpES() throws IOException {
         setUpES(dataDirectory, false, "en");
     }
 
-    public void setUpESWithPolygons() throws IOException {
+    public void setUpESWithGeometry() throws IOException {
         setUpES(dataDirectory, true, "en");
     }
 
-    public void setUpES(Path testDirectory, boolean supportPolygons, String... languages) throws IOException {
+    public void setUpES(Path testDirectory, boolean supportGeometries, String... languages) throws IOException {
         server = new OpenSearchTestServer(testDirectory.toString());
         server.startTestServer(TEST_CLUSTER_NAME);
-        server.recreateIndex(languages, new Date(), true, supportPolygons);
+        server.recreateIndex(languages, new Date(), true, supportGeometries);
         server.refreshIndexes();
     }
 
diff --git a/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java b/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
index 418ac741a..3ffcf1a64 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
@@ -20,7 +20,7 @@ class ImporterTest extends ESBaseTester {
 
     @BeforeEach
     public void setUp() throws IOException {
-        setUpESWithPolygons();
+        setUpESWithGeometry();
     }
 
     @Test
diff --git a/src/main/java/de/komoot/photon/App.java b/src/main/java/de/komoot/photon/App.java
index 5258bf69c..604fb20a0 100644
--- a/src/main/java/de/komoot/photon/App.java
+++ b/src/main/java/de/komoot/photon/App.java
@@ -253,8 +253,8 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
         }
 
         LOGGER.info("Starting API with the following settings: " +
-                        "\n Languages: {} \n Import Date: {} \n Support Structured Queries: {} \n Support Polygons: {}",
-                dbProperties.getLanguages(), dbProperties.getImportDate(), dbProperties.getSupportStructuredQueries(), dbProperties.getSupportPolygons());
+                        "\n Languages: {} \n Import Date: {} \n Support Structured Queries: {} \n Support Geometries: {}",
+                dbProperties.getLanguages(), dbProperties.getImportDate(), dbProperties.getSupportStructuredQueries(), dbProperties.getSupportGeometries());
 
         port(args.getListenPort());
         ipAddress(args.getListenIp());
@@ -271,13 +271,13 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
         String[] langs = dbProperties.getLanguages();
 
         SearchHandler searchHandler = server.createSearchHandler(langs, args.getQueryTimeout());
-        get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
-        get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
+        get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportGeometries()));
+        get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportGeometries()));
 
         if (dbProperties.getSupportStructuredQueries()) {
             StructuredSearchHandler structured = server.createStructuredSearchHandler(langs, args.getQueryTimeout());
-            get("structured", new StructuredSearchRequestHandler("structured", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
-            get("structured/", new StructuredSearchRequestHandler("structured/", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
+            get("structured", new StructuredSearchRequestHandler("structured", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportGeometries()));
+            get("structured/", new StructuredSearchRequestHandler("structured/", structured, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportGeometries()));
         }
 
         ReverseHandler reverseHandler = server.createReverseHandler(args.getQueryTimeout());
diff --git a/src/main/java/de/komoot/photon/CommandLineArgs.java b/src/main/java/de/komoot/photon/CommandLineArgs.java
index 1428d4f41..38df37a39 100644
--- a/src/main/java/de/komoot/photon/CommandLineArgs.java
+++ b/src/main/java/de/komoot/photon/CommandLineArgs.java
@@ -98,7 +98,7 @@ public class CommandLineArgs {
     @Parameter(names = "-max-reverse-results", description = "The maximum possible 'limit' parameter for reverse geocoding searches")
     private int maxReverseResults = 50;
 
-    @Parameter(names = "-import-geometry-column", description = "[import-only] Add the 'geometry' column from Nominatim on import (i.e. add Polygons for cities, countries etc.). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
+    @Parameter(names = "-import-geometry-column", description = "[import-only] Add the 'geometry' column from Nominatim on import (i.e. add Polygons/Linestrings/Multipolygons etc. for cities, countries etc.). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
     private boolean importGeometryColumn = false;
 
     public String[] getLanguages(boolean useDefaultIfEmpty) {
diff --git a/src/main/java/de/komoot/photon/DatabaseProperties.java b/src/main/java/de/komoot/photon/DatabaseProperties.java
index ca599648a..875cd1917 100644
--- a/src/main/java/de/komoot/photon/DatabaseProperties.java
+++ b/src/main/java/de/komoot/photon/DatabaseProperties.java
@@ -11,13 +11,13 @@ public class DatabaseProperties {
     private String[] languages;
     private Date importDate;
     private boolean supportStructuredQueries;
-    private boolean supportPolygons;
+    private boolean supportGeometries;
 
-    public DatabaseProperties(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportPolygons) {
+    public DatabaseProperties(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportGeometries) {
         this.languages = languages;
         this.importDate = importDate;
         this.supportStructuredQueries = supportStructuredQueries;
-        this.supportPolygons = supportPolygons;
+        this.supportGeometries = supportGeometries;
     }
 
     public DatabaseProperties() {
@@ -100,12 +100,12 @@ public DatabaseProperties setSupportStructuredQueries(boolean supportStructuredQ
         return this;
     }
 
-    public boolean getSupportPolygons() {
-        return supportPolygons;
+    public boolean getSupportGeometries() {
+        return supportGeometries;
     }
 
-    public DatabaseProperties setSupportPolygons(boolean supportPolygons) {
-        this.supportPolygons = supportPolygons;
+    public DatabaseProperties setSupportGeometries(boolean supportGeometries) {
+        this.supportGeometries = supportGeometries;
         return this;
     }
 
@@ -115,7 +115,7 @@ public String toString() {
                 "languages=" + Arrays.toString(languages) +
                 ", importDate=" + importDate +
                 ", supportStructuredQueries=" + supportStructuredQueries +
-                ", supportPolygons=" + supportPolygons +
+                ", supportGeometries=" + supportGeometries +
                 '}';
     }
 }
diff --git a/src/main/java/de/komoot/photon/PhotonDoc.java b/src/main/java/de/komoot/photon/PhotonDoc.java
index a9eda8978..8403c9f82 100644
--- a/src/main/java/de/komoot/photon/PhotonDoc.java
+++ b/src/main/java/de/komoot/photon/PhotonDoc.java
@@ -98,8 +98,8 @@ public PhotonDoc centroid(Geometry centroid) {
         return this;
     }
 
-    public PhotonDoc geometry(Geometry polygon) {
-        this.geometry = (Geometry) polygon;
+    public PhotonDoc geometry(Geometry geometry) {
+        this.geometry = (Geometry) geometry;
         return this;
     }
 
diff --git a/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java b/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
index 3416bd25b..e6cda6d63 100644
--- a/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/ReverseSearchRequestHandler.java
@@ -53,6 +53,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
 
-        return new GeocodeJsonFormatter(false, photonRequest.getLanguage(), photonRequest.getPolygon()).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(false, photonRequest.getLanguage(), photonRequest.getGeometry()).convert(results, debugInfo);
     }
 }
diff --git a/src/main/java/de/komoot/photon/SearchRequestHandler.java b/src/main/java/de/komoot/photon/SearchRequestHandler.java
index 041e96567..5a5d07bb1 100644
--- a/src/main/java/de/komoot/photon/SearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/SearchRequestHandler.java
@@ -20,14 +20,14 @@
 public class SearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final SearchHandler requestHandler;
-    private final boolean supportPolygons;
+    private final boolean supportGeometries;
 
-    SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean supportPolygons) {
+    SearchRequestHandler(String path, SearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean supportGeometries) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
-        this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults, supportPolygons);
+        this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults, supportGeometries);
         this.requestHandler = dbHandler;
-        this.supportPolygons = supportPolygons;
+        this.supportGeometries = supportGeometries;
     }
 
     @Override
@@ -41,9 +41,9 @@ public String handle(Request request, Response response) throws BadRequestExcept
             throw halt(e.getHttpStatus(), json.toString());
         }
 
-        if (!supportPolygons && photonRequest.getReturnPolygon()) {
+        if (!supportGeometries && photonRequest.getReturnGeometry()) {
             JSONObject json = new JSONObject();
-            json.put("message", "You're explicitly requesting a polygon, but polygons are not imported!");
+            json.put("message", "You're explicitly requesting a geometry, but geometries are not imported!");
             throw halt(400, json.toString());
         }
 
@@ -62,6 +62,6 @@ public String handle(Request request, Response response) throws BadRequestExcept
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
 
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getReturnPolygon()).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getReturnGeometry()).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
index ec5e99ab5..2c3a63853 100644
--- a/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
+++ b/src/main/java/de/komoot/photon/StructuredSearchRequestHandler.java
@@ -17,14 +17,14 @@
 public class StructuredSearchRequestHandler extends RouteImpl {
     private final PhotonRequestFactory photonRequestFactory;
     private final StructuredSearchHandler requestHandler;
-    private final boolean supportPolygons;
+    private final boolean supportGeometries;
 
-    StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean supportPolygons) {
+    StructuredSearchRequestHandler(String path, StructuredSearchHandler dbHandler, String[] languages, String defaultLanguage, int maxResults, boolean supportGeometries) {
         super(path);
         List<String> supportedLanguages = Arrays.asList(languages);
-        this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults, supportPolygons);
+        this.photonRequestFactory = new PhotonRequestFactory(supportedLanguages, defaultLanguage, maxResults, supportGeometries);
         this.requestHandler = dbHandler;
-        this.supportPolygons = supportPolygons;
+        this.supportGeometries = supportGeometries;
     }
 
     @Override
@@ -38,9 +38,9 @@ public String handle(Request request, Response response) {
             throw halt(e.getHttpStatus(), json.toString());
         }
 
-        if (!supportPolygons && photonRequest.getReturnPolygon()) {
+        if (!supportGeometries && photonRequest.getReturnGeometry()) {
             JSONObject json = new JSONObject();
-            json.put("message", "You're requesting a polygon, but polygons are not imported!");
+            json.put("message", "You're requesting a Geometry, but Geometries are not imported!");
             throw halt(400, json.toString());
         }
 
@@ -60,6 +60,6 @@ public String handle(Request request, Response response) {
             debugInfo = requestHandler.dumpQuery(photonRequest);
         }
  */
-        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getReturnPolygon()).convert(results, debugInfo);
+        return new GeocodeJsonFormatter(photonRequest.getDebug(), photonRequest.getLanguage(), photonRequest.getReturnGeometry()).convert(results, debugInfo);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestBase.java b/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
index c8ba8aeae..9b7803dee 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestBase.java
@@ -18,7 +18,7 @@ public class PhotonRequestBase
     private int zoom = 14;
     private Envelope bbox = null;
     private boolean debug = false;
-    private boolean returnPolygon = false;
+    private boolean returnGeometry = false;
 
     private final List<TagFilter> osmTagFilters = new ArrayList<>(1);
     private Set<String> layerFilters = new HashSet<>(1);
@@ -54,7 +54,7 @@ public String getLanguage() {
 
     public boolean getDebug() { return debug; }
 
-    public boolean getReturnPolygon() { return returnPolygon; }
+    public boolean getReturnGeometry() { return returnGeometry; }
 
     public List<TagFilter> getOsmTagFilters() {
         return osmTagFilters;
@@ -104,8 +104,8 @@ void enableDebug() {
         this.debug = true;
     }
 
-    void setReturnPolygon(boolean returnPolygon) {
-        this.returnPolygon = returnPolygon;
+    void setReturnGeometry(boolean returnGeometry) {
+        this.returnGeometry = returnGeometry;
     }
 
 }
diff --git a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
index 2c265b88c..cb369384b 100644
--- a/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/PhotonRequestFactory.java
@@ -17,10 +17,10 @@ public class PhotonRequestFactory {
     private final BoundingBoxParamConverter bboxParamConverter;
     private final LayerParamValidator layerParamValidator;
     private final int maxResults;
-    private final boolean supportPolygons;
+    private final boolean supportGeometries;
 
     private static final HashSet<String> REQUEST_QUERY_PARAMS = new HashSet<>(Arrays.asList("lang", "q", "lon", "lat",
-            "limit", "osm_tag", "location_bias_scale", "bbox", "debug", "zoom", "layer", "polygon"));
+            "limit", "osm_tag", "location_bias_scale", "bbox", "debug", "zoom", "layer", "geometry"));
 
     private static final HashSet<String> STRUCTURED_ADDRESS_FIELDS = new HashSet<>(Arrays.asList("countrycode", "state", "county", "city",
             "postcode", "district", "housenumber", "street"));
@@ -29,12 +29,12 @@ public class PhotonRequestFactory {
             "countrycode", "state", "county", "city", "postcode", "district", "housenumber", "street"));
 
 
-    public PhotonRequestFactory(List<String> supportedLanguages, String defaultLanguage, int maxResults, boolean supportPolygons) {
+    public PhotonRequestFactory(List<String> supportedLanguages, String defaultLanguage, int maxResults, boolean supportGeometries) {
         this.languageResolver = new RequestLanguageResolver(supportedLanguages, defaultLanguage);
         this.bboxParamConverter = new BoundingBoxParamConverter();
         this.layerParamValidator = new LayerParamValidator();
         this.maxResults = maxResults;
-        this.supportPolygons = supportPolygons;
+        this.supportGeometries = supportGeometries;
     }
 
     public StructuredPhotonRequest createStructured(Request webRequest) throws BadRequestException {
@@ -114,12 +114,12 @@ private void addCommonParameters(Request webRequest, PhotonRequestBase request)
             request.setLayerFilter(layerParamValidator.validate(layerFiltersQueryMap.values()));
         }
 
-        // If the database supports polygons, return them by default.
-        request.setReturnPolygon(supportPolygons);
+        // If the database supports geometries, return them by default.
+        request.setReturnGeometry(supportGeometries);
 
-        // Check if the user explicitly doesn't want a polygon.
-        if (webRequest.queryParams("polygon") != null) {
-            request.setReturnPolygon(parseBoolean(webRequest, "polygon"));
+        // Check if the user explicitly doesn't want a geometry.
+        if (webRequest.queryParams("geometry") != null) {
+            request.setReturnGeometry(parseBoolean(webRequest, "geometry"));
         }
     }
 
diff --git a/src/main/java/de/komoot/photon/query/ReverseRequest.java b/src/main/java/de/komoot/photon/query/ReverseRequest.java
index 5fabf0cb0..217b63dfd 100644
--- a/src/main/java/de/komoot/photon/query/ReverseRequest.java
+++ b/src/main/java/de/komoot/photon/query/ReverseRequest.java
@@ -20,10 +20,10 @@ public class ReverseRequest implements Serializable {
     private final Set<String> layerFilters;
     private final List<TagFilter> osmTagFilters = new ArrayList<>(1);
     private final boolean debug;
-    private final boolean polygon;
+    private final boolean geometry;
 
     public ReverseRequest(Point location, String language, double radius, String queryStringFilter, int limit,
-                          boolean locationDistanceSort, Set<String> layerFilter, boolean debug, boolean polygon) {
+                          boolean locationDistanceSort, Set<String> layerFilter, boolean debug, boolean geometry) {
         this.location = location;
         this.language = language;
         this.radius = radius;
@@ -32,7 +32,7 @@ public ReverseRequest(Point location, String language, double radius, String que
         this.locationDistanceSort = locationDistanceSort;
         this.layerFilters = layerFilter;
         this.debug = debug;
-        this.polygon = polygon;
+        this.geometry = geometry;
     }
 
     public Point getLocation() {
@@ -71,8 +71,8 @@ public boolean getDebug() {
         return debug;
     }
 
-    public boolean getPolygon() {
-        return polygon;
+    public boolean getGeometry() {
+        return geometry;
     }
 
     ReverseRequest addOsmTagFilter(TagFilter filter) {
diff --git a/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java b/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
index d3ae421dc..70a5c2fb4 100644
--- a/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
+++ b/src/main/java/de/komoot/photon/query/ReverseRequestFactory.java
@@ -16,7 +16,7 @@
 public class ReverseRequestFactory {
 
     private static final HashSet<String> REQUEST_QUERY_PARAMS = new HashSet<>(Arrays.asList("lang", "lon", "lat", "radius",
-            "query_string_filter", "distance_sort", "limit", "layer", "osm_tag", "debug", "polygon"));
+            "query_string_filter", "distance_sort", "limit", "layer", "osm_tag", "debug", "geometry"));
     private static final LocationParamConverter mandatoryLocationParamConverter = new LocationParamConverter(true);
 
     private final RequestLanguageResolver languageResolver;
@@ -86,7 +86,7 @@ public ReverseRequest create(Request webRequest) throws BadRequestException {
         }
 
         String queryStringFilter = webRequest.queryParams("query_string_filter");
-        ReverseRequest request = new ReverseRequest(location, language, radius, queryStringFilter, limit, locationDistanceSort, layerFilter, enableDebug, Boolean.parseBoolean(webRequest.queryParams("polygon")));
+        ReverseRequest request = new ReverseRequest(location, language, radius, queryStringFilter, limit, locationDistanceSort, layerFilter, enableDebug, Boolean.parseBoolean(webRequest.queryParams("geometry")));
 
         QueryParamsMap tagFiltersQueryMap = webRequest.queryMap("osm_tag");
         if (tagFiltersQueryMap.hasValue()) {
diff --git a/src/test/java/de/komoot/photon/ApiIntegrationTest.java b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
index 4eaceb109..589dc9f8d 100644
--- a/src/test/java/de/komoot/photon/ApiIntegrationTest.java
+++ b/src/test/java/de/komoot/photon/ApiIntegrationTest.java
@@ -28,7 +28,7 @@ class ApiIntegrationTest extends ESBaseTester {
 
     @BeforeEach
     void setUp() throws Exception {
-        setUpESWithPolygons();
+        setUpESWithGeometry();
         Importer instance = makeImporter();
         instance.add(createDoc(13.38886, 52.51704, 1000, 1000, "place", "city").importance(0.6), 0);
         instance.add(createDoc(13.39026, 52.54714, 1001, 1001, "place", "town").importance(0.3), 0);
@@ -151,7 +151,7 @@ void testApiStatus() throws Exception {
     }
 
     @Test
-    void testSearchAndGetPolygon() throws Exception {
+    void testSearchAndGetGeometry() throws Exception {
         App.main(new String[]{"-cluster", TEST_CLUSTER_NAME, "-listen-port", Integer.toString(LISTEN_PORT), "-transport-addresses", "127.0.0.1"});
         awaitInitialization();
         HttpURLConnection connection = (HttpURLConnection) new URL("http://127.0.0.1:" + port() + "/api?q=berlin&limit=1").openConnection();
diff --git a/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java b/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
index 00760695c..8eff8e9aa 100644
--- a/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
+++ b/src/test/java/de/komoot/photon/query/PhotonRequestFactoryTest.java
@@ -212,18 +212,18 @@ void testWithBadLayerFilters() {
     }
 
     @Test
-    void testWithPolygon() throws Exception {
+    void testWithGeometry() throws Exception {
         Request mockRequest = createRequestWithQueryParams("q", "berlin");
         PhotonRequest photonRequest = createPhotonRequest(mockRequest);
 
-        assertTrue(photonRequest.getReturnPolygon());
+        assertTrue(photonRequest.getReturnGeometry());
     }
 
     @Test
-    void testWithoutPolygon() throws Exception {
-        Request mockRequest = createRequestWithQueryParams("q", "berlin", "polygon", "false");
+    void testWithoutGeometry() throws Exception {
+        Request mockRequest = createRequestWithQueryParams("q", "berlin", "geometry", "false");
         PhotonRequest photonRequest = createPhotonRequest(mockRequest);
 
-        assertFalse(photonRequest.getReturnPolygon());
+        assertFalse(photonRequest.getReturnGeometry());
     }
 }
\ No newline at end of file
diff --git a/src/test/java/de/komoot/photon/query/QueryPolygonTest.java b/src/test/java/de/komoot/photon/query/QueryGeometryTest.java
similarity index 97%
rename from src/test/java/de/komoot/photon/query/QueryPolygonTest.java
rename to src/test/java/de/komoot/photon/query/QueryGeometryTest.java
index 3bcfe0021..cff061e6a 100644
--- a/src/test/java/de/komoot/photon/query/QueryPolygonTest.java
+++ b/src/test/java/de/komoot/photon/query/QueryGeometryTest.java
@@ -22,12 +22,12 @@
  * Tests that the database backend produces queries which can find all
  * expected results. These tests do not check relevance.
  */
-class QueryPolygonTest extends ESBaseTester {
+class QueryGeometryTest extends ESBaseTester {
     private int testDocId = 10000;
 
     @BeforeEach
     void setup() throws IOException {
-        setUpESWithPolygons();
+        setUpESWithGeometry();
     }
 
     private PhotonDoc createDoc(String... names) throws ParseException {
diff --git a/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java b/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
index 46519499d..71851aa17 100644
--- a/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
+++ b/src/test/java/de/komoot/photon/searcher/GeocodeJsonFormatterTest.java
@@ -35,15 +35,15 @@ void testConvertPointToGeojson() {
     }
 
     @Test
-    void testConvertPolygonToGeojson() {
+    void testConvertGeometryToGeojson() {
         GeocodeJsonFormatter formatter = new GeocodeJsonFormatter(false, "en", true);
 
-        List<PhotonResult> allPolygonResults = new ArrayList<>();
-        allPolygonResults.add(createDummyPolygonResult("99999", "Park Foo", "leisure", "park"));
-        allPolygonResults.add(createDummyPolygonResult("88888", "Bar Park", "leisure", "park"));
+        List<PhotonResult> allResults = new ArrayList<>();
+        allResults.add(createDummyGeometryResult("99999", "Park Foo", "leisure", "park"));
+        allResults.add(createDummyGeometryResult("88888", "Bar Park", "leisure", "park"));
 
-        // Test Polygon
-        String geojsonString = formatter.convert(allPolygonResults, null);
+        // Test Geometry
+        String geojsonString = formatter.convert(allResults, null);
         JSONObject jsonObj = new JSONObject(geojsonString);
         assertEquals("FeatureCollection", jsonObj.getString("type"));
         JSONArray features = jsonObj.getJSONArray("features");
@@ -69,8 +69,8 @@ private PhotonResult createDummyPointResult(String postCode, String name, String
                     .put("coordinates", new double[]{42, 21}));
     }
 
-    private PhotonResult createDummyPolygonResult(String postCode, String name, String osmKey,
-                                                String osmValue) {
+    private PhotonResult createDummyGeometryResult(String postCode, String name, String osmKey,
+                                                   String osmValue) {
         return new MockPhotonResult()
                 .put(Constants.POSTCODE, postCode)
                 .putLocalized(Constants.NAME, "en", name)

From e6570c536813e5ca3f62a3b3b22270afadddffe5 Mon Sep 17 00:00:00 2001
From: red-fenix <red-fenix@xor.nu>
Date: Wed, 12 Mar 2025 07:37:21 +0100
Subject: [PATCH 17/18] bugfix: set correct crs/srid on geometry import

---
 .../java/de/komoot/photon/nominatim/PostgisDataAdapter.java  | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/main/java/de/komoot/photon/nominatim/PostgisDataAdapter.java b/src/main/java/de/komoot/photon/nominatim/PostgisDataAdapter.java
index 051d9cc47..bb3a24708 100644
--- a/src/main/java/de/komoot/photon/nominatim/PostgisDataAdapter.java
+++ b/src/main/java/de/komoot/photon/nominatim/PostgisDataAdapter.java
@@ -34,7 +34,10 @@ public Geometry extractGeometry(ResultSet rs, String columnName) throws SQLExcep
             try {
                 StringBuffer sb = new StringBuffer();
                 wkt.getGeometry().outerWKT(sb);
-                return new WKTReader().read(sb.toString());
+
+                Geometry geometry = new WKTReader().read(sb.toString());
+                geometry.setSRID(4326);
+                return geometry;
             } catch (ParseException e) {
                 // ignore
                 System.out.println(e);

From 9aa111794705c369dc507cab54c265fe5bdfff5e Mon Sep 17 00:00:00 2001
From: red-fenix <red-fenix@xor.nu>
Date: Wed, 12 Mar 2025 18:02:49 +0100
Subject: [PATCH 18/18] bugfix: fix Photondoc constructors

---
 .../de/komoot/photon/elasticsearch/ImporterTest.java     | 5 ++++-
 .../java/de/komoot/photon/opensearch/ImporterTest.java   | 3 ++-
 src/main/java/de/komoot/photon/PhotonDoc.java            | 9 ---------
 3 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ImporterTest.java b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ImporterTest.java
index c5fafc91e..5fc6801d2 100644
--- a/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ImporterTest.java
+++ b/app/es_embedded/src/test/java/de/komoot/photon/elasticsearch/ImporterTest.java
@@ -6,6 +6,8 @@
 import de.komoot.photon.searcher.PhotonResult;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.locationtech.jts.io.ParseException;
+import org.locationtech.jts.io.WKTReader;
 
 import java.io.IOException;
 import java.util.Collections;
@@ -22,10 +24,11 @@ public void setUp() throws IOException {
     }
 
     @Test
-    void testAddSimpleDoc() {
+    void testAddSimpleDoc() throws ParseException {
         Importer instance = makeImporterWithExtra("");
 
         instance.add(new PhotonDoc(1234, "N", 1000, "place", "city")
+                .geometry(new WKTReader().read("MULTIPOLYGON (((6.111933 51.2659309, 6.1119417 51.2659247, 6.1119554 51.2659249, 6.1119868 51.2659432, 6.111964 51.2659591, 6.1119333 51.2659391, 6.111933 51.2659309)))"))
                 .extraTags(Collections.singletonMap("maxspeed", "100")), 0);
         instance.finish();
         refresh();
diff --git a/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java b/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
index 3ffcf1a64..1fd9d1448 100644
--- a/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
+++ b/app/opensearch/src/test/java/de/komoot/photon/opensearch/ImporterTest.java
@@ -27,7 +27,8 @@ public void setUp() throws IOException {
     void testAddSimpleDoc() throws ParseException {
         Importer instance = makeImporterWithExtra("");
 
-        instance.add(new PhotonDoc(1234, "N", 1000, "place", "city", new WKTReader().read("MULTIPOLYGON (((6.111933 51.2659309, 6.1119417 51.2659247, 6.1119554 51.2659249, 6.1119868 51.2659432, 6.111964 51.2659591, 6.1119333 51.2659391, 6.111933 51.2659309)))"))
+        instance.add(new PhotonDoc(1234, "N", 1000, "place", "city")
+                .geometry(new WKTReader().read("MULTIPOLYGON (((6.111933 51.2659309, 6.1119417 51.2659247, 6.1119554 51.2659249, 6.1119868 51.2659432, 6.111964 51.2659591, 6.1119333 51.2659391, 6.111933 51.2659309)))"))
                 .extraTags(Collections.singletonMap("maxspeed", "100")), 0);
         instance.finish();
 
diff --git a/src/main/java/de/komoot/photon/PhotonDoc.java b/src/main/java/de/komoot/photon/PhotonDoc.java
index 8403c9f82..ed834d66c 100644
--- a/src/main/java/de/komoot/photon/PhotonDoc.java
+++ b/src/main/java/de/komoot/photon/PhotonDoc.java
@@ -45,15 +45,6 @@ public PhotonDoc(long placeId, String osmType, long osmId, String tagKey, String
         this.tagValue = tagValue;
     }
 
-    public PhotonDoc(long placeId, String osmType, long osmId, String tagKey, String tagValue, Geometry geometry) {
-        this.placeId = placeId;
-        this.osmType = osmType;
-        this.osmId = osmId;
-        this.tagKey = tagKey;
-        this.tagValue = tagValue;
-        this.geometry = geometry;
-    }
-
     public PhotonDoc(PhotonDoc other) {
         this.placeId = other.placeId;
         this.osmType = other.osmType;