Skip to content

Commit cd99178

Browse files
committed
Refactor geometry addition methods to use Map<String, Object> for properties instead of String[] and Object[].
1 parent 63cff43 commit cd99178

File tree

12 files changed

+109
-117
lines changed

12 files changed

+109
-117
lines changed

server-plugin/src/main/java/org/neo4j/gis/spatial/DefaultLayer.java

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.Collections;
2323
import java.util.HashSet;
2424
import java.util.Iterator;
25-
import java.util.List;
2625
import java.util.Set;
2726
import javax.annotation.Nonnull;
2827
import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
@@ -72,33 +71,6 @@ public String getSignature() {
7271
return "Layer(name='" + getName() + "', encoder=" + getGeometryEncoder().getSignature() + ")";
7372
}
7473

75-
/**
76-
* Add the geometry encoded in the given Node. This causes the geometry to appear in the index.
77-
*/
78-
@Override
79-
public SpatialDatabaseRecord add(Transaction tx, Node geomNode) {
80-
Geometry geometry = getGeometryEncoder().decodeGeometry(geomNode);
81-
82-
// add BBOX to Node if it's missing
83-
getGeometryEncoder().ensureIndexable(geometry, geomNode);
84-
85-
indexWriter.add(tx, geomNode);
86-
return new SpatialDatabaseRecord(this, geomNode, geometry);
87-
}
88-
89-
@Override
90-
public int addAll(Transaction tx, List<Node> geomNodes) {
91-
GeometryEncoder geometryEncoder = getGeometryEncoder();
92-
93-
for (Node geomNode : geomNodes) {
94-
Geometry geometry = geometryEncoder.decodeGeometry(geomNode);
95-
// add BBOX to Node if it's missing
96-
geometryEncoder.encodeGeometry(tx, geometry, geomNode);
97-
}
98-
indexWriter.add(tx, geomNodes);
99-
return geomNodes.size();
100-
}
101-
10274
@Override
10375
public GeometryFactory getGeometryFactory() {
10476
return geometryFactory;

server-plugin/src/main/java/org/neo4j/gis/spatial/DynamicLayerConfig.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import java.io.File;
2323
import java.util.LinkedHashMap;
24-
import java.util.List;
2524
import java.util.Map;
2625
import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
2726
import org.geotools.filter.text.cql2.CQLException;
@@ -90,18 +89,6 @@ public String getQuery() {
9089
return query;
9190
}
9291

93-
@Override
94-
public SpatialDatabaseRecord add(Transaction tx, Node geomNode) {
95-
throw new SpatialDatabaseException(
96-
"Cannot add nodes to dynamic layers, add the node to the base layer instead");
97-
}
98-
99-
@Override
100-
public int addAll(Transaction tx, List<Node> geomNodes) {
101-
throw new SpatialDatabaseException(
102-
"Cannot add nodes to dynamic layers, add the node to the base layer instead");
103-
}
104-
10592
@Override
10693
public void delete(Transaction tx, Listener monitor) {
10794
throw new SpatialDatabaseException("Cannot delete dynamic layers, delete the base layer instead");

server-plugin/src/main/java/org/neo4j/gis/spatial/EditableLayer.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
*/
2020
package org.neo4j.gis.spatial;
2121

22+
import java.util.List;
23+
import java.util.Map;
2224
import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
2325
import org.locationtech.jts.geom.Geometry;
26+
import org.neo4j.graphdb.Node;
2427
import org.neo4j.graphdb.Transaction;
2528

2629
/**
@@ -33,6 +36,24 @@
3336
*/
3437
public interface EditableLayer extends Layer {
3538

39+
/**
40+
* This method adds existing geometries to the layer for indexing. After this method is called the geometry should
41+
* be searchable.
42+
*
43+
* @param geomNode the node containing the geometry to be added to the layer
44+
* @return SpatialDatabaseRecord representation of the geometry added to the database
45+
*/
46+
SpatialDatabaseRecord add(Transaction tx, Node geomNode);
47+
48+
/**
49+
* This method adds existing geometries to the layer for indexing in bulk. After this method is called the geometry
50+
* should be searchable.
51+
*
52+
* @param geomNodes the nodes containing the geometries to be added to the layer
53+
* @return the number of geometries added to the database
54+
*/
55+
int addAll(Transaction tx, List<Node> geomNodes);
56+
3657
/**
3758
* Add a new geometry to the layer. This will add the geometry to the index.
3859
*/
@@ -41,8 +62,7 @@ public interface EditableLayer extends Layer {
4162
/**
4263
* Add a new geometry to the layer. This will add the geometry to the index.
4364
*/
44-
//TODO: Rather use a HashMap of properties
45-
SpatialDatabaseRecord add(Transaction tx, Geometry geometry, String[] fieldsName, Object[] fields);
65+
SpatialDatabaseRecord add(Transaction tx, Geometry geometry, Map<String, Object> properties);
4666

4767
/**
4868
* Delete the geometry identified by the passed node id. This might be as simple as deleting the

server-plugin/src/main/java/org/neo4j/gis/spatial/EditableLayerImpl.java

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,55 @@
1919
*/
2020
package org.neo4j.gis.spatial;
2121

22+
import java.util.List;
23+
import java.util.Map;
2224
import org.locationtech.jts.geom.Geometry;
2325
import org.neo4j.graphdb.Node;
2426
import org.neo4j.graphdb.Transaction;
2527

2628
public class EditableLayerImpl extends DefaultLayer implements EditableLayer {
2729

30+
/**
31+
* Add the geometry encoded in the given Node. This causes the geometry to appear in the index.
32+
*/
33+
@Override
34+
public SpatialDatabaseRecord add(Transaction tx, Node geomNode) {
35+
Geometry geometry = getGeometryEncoder().decodeGeometry(geomNode);
36+
37+
// add BBOX to Node if it's missing
38+
getGeometryEncoder().ensureIndexable(geometry, geomNode);
39+
40+
indexWriter.add(tx, geomNode);
41+
return new SpatialDatabaseRecord(this, geomNode, geometry);
42+
}
43+
44+
@Override
45+
public int addAll(Transaction tx, List<Node> geomNodes) {
46+
GeometryEncoder geometryEncoder = getGeometryEncoder();
47+
48+
for (Node geomNode : geomNodes) {
49+
Geometry geometry = geometryEncoder.decodeGeometry(geomNode);
50+
// add BBOX to Node if it's missing
51+
geometryEncoder.encodeGeometry(tx, geometry, geomNode);
52+
}
53+
indexWriter.add(tx, geomNodes);
54+
return geomNodes.size();
55+
}
56+
2857
/**
2958
* Add a geometry to this layer.
3059
*/
3160
@Override
3261
public SpatialDatabaseRecord add(Transaction tx, Geometry geometry) {
33-
return add(tx, geometry, null, null);
62+
return add(tx, geometry, null);
3463
}
3564

3665
/**
3766
* Add a geometry to this layer, including properties.
3867
*/
3968
@Override
40-
public SpatialDatabaseRecord add(Transaction tx, Geometry geometry, String[] fieldsName, Object[] fields) {
41-
Node geomNode = addGeomNode(tx, geometry, fieldsName, fields);
69+
public SpatialDatabaseRecord add(Transaction tx, Geometry geometry, Map<String, Object> properties) {
70+
Node geomNode = addGeomNode(tx, geometry, properties);
4271
indexWriter.add(tx, geomNode);
4372
return new SpatialDatabaseRecord(this, geomNode, geometry);
4473
}
@@ -62,15 +91,10 @@ public void removeFromIndex(Transaction tx, String geomNodeId) {
6291
indexWriter.remove(tx, geomNodeId, deleteGeomNode, false);
6392
}
6493

65-
protected Node addGeomNode(Transaction tx, Geometry geom, String[] fieldsName, Object[] fields) {
94+
protected Node addGeomNode(Transaction tx, Geometry geom, Map<String, Object> properties) {
6695
Node geomNode = tx.createNode();
67-
// other properties
68-
if (fieldsName != null) {
69-
for (int i = 0; i < fieldsName.length; i++) {
70-
if (fieldsName[i] != null && fields[i] != null) {
71-
geomNode.setProperty(fieldsName[i], fields[i]);
72-
}
73-
}
96+
if (properties != null) {
97+
properties.forEach(geomNode::setProperty);
7498
}
7599
getGeometryEncoder().encodeGeometry(tx, geom, geomNode);
76100

server-plugin/src/main/java/org/neo4j/gis/spatial/Layer.java

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
*/
2020
package org.neo4j.gis.spatial;
2121

22-
import java.util.List;
2322
import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
2423
import org.locationtech.jts.geom.GeometryFactory;
2524
import org.neo4j.gis.spatial.attributes.PropertyMappingManager;
@@ -56,24 +55,6 @@ public interface Layer {
5655
*/
5756
LayerIndexReader getIndex();
5857

59-
/**
60-
* This method adds existing geometries to the layer for indexing. After this method is called the geometry should
61-
* be searchable.
62-
*
63-
* @param geomNode the node containing the geometry to be added to the layer
64-
* @return SpatialDatabaseRecord representation of the geometry added to the database
65-
*/
66-
SpatialDatabaseRecord add(Transaction tx, Node geomNode);
67-
68-
/**
69-
* This method adds existing geometries to the layer for indexing in bulk. After this method is called the geometry
70-
* should be searchable.
71-
*
72-
* @param geomNodes the nodes containing the geometries to be added to the layer
73-
* @return the number of geometries added to the database
74-
*/
75-
int addAll(Transaction tx, List<Node> geomNodes);
76-
7758
GeometryFactory getGeometryFactory();
7859

7960
/**

server-plugin/src/main/java/org/neo4j/gis/spatial/OrderedEditableLayer.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import static org.neo4j.gis.spatial.utilities.TraverserFactory.createTraverserInBackwardsCompatibleWay;
2323

24+
import java.util.Map;
2425
import org.locationtech.jts.geom.Geometry;
2526
import org.neo4j.graphdb.Direction;
2627
import org.neo4j.graphdb.Node;
@@ -51,8 +52,8 @@ enum OrderedRelationshipTypes implements RelationshipType {
5152
}
5253

5354
@Override
54-
protected Node addGeomNode(Transaction tx, Geometry geom, String[] fieldsName, Object[] fields) {
55-
Node geomNode = super.addGeomNode(tx, geom, fieldsName, fields);
55+
protected Node addGeomNode(Transaction tx, Geometry geom, Map<String, Object> properties) {
56+
Node geomNode = super.addGeomNode(tx, geom, properties);
5657
Node layerNode = getLayerNode(tx);
5758
if (previousGeomNode == null) {
5859
TraversalDescription traversalDescription = new MonoDirectionalTraversalDescription()

server-plugin/src/main/java/org/neo4j/gis/spatial/ShapefileImporter.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
import java.nio.charset.Charset;
2525
import java.nio.file.Path;
2626
import java.util.ArrayList;
27-
import java.util.Collections;
2827
import java.util.Date;
2928
import java.util.List;
29+
import java.util.TreeMap;
3030
import org.geotools.api.referencing.FactoryException;
3131
import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
3232
import org.geotools.data.PrjFileReader;
@@ -158,8 +158,6 @@ public List<Node> importFile(String dataset, EditableLayerImpl layer, Charset ch
158158
try {
159159
Record record;
160160
Geometry geometry;
161-
Object[] values;
162-
ArrayList<Object> fields = new ArrayList<>();
163161
int recordCounter = 0;
164162
int filterCounter = 0;
165163
while (shpReader.hasNext() && dbfReader.hasNext()) {
@@ -171,29 +169,30 @@ record = shpReader.nextRecord();
171169
recordCounter++;
172170
committedSinceLastNotification++;
173171
try {
174-
fields.clear();
175172
geometry = (Geometry) record.shape();
176173
if (filterEnvelope == null || filterEnvelope.intersects(
177174
geometry.getEnvelopeInternal())) {
178-
values = dbfReader.readEntry();
179-
180-
//convert Date to String
181-
//necessary because Neo4j doesn't support Date properties on nodes
182-
for (int k = 0; k < fieldsName.length - 1; k++) {
183-
if (values[k] instanceof Date aux) {
184-
values[k] = aux.toString();
175+
Object[] values = dbfReader.readEntry();
176+
177+
var properties = new TreeMap<String, Object>();
178+
for (int k = 0; k < fieldsName.length; k++) {
179+
String field = fieldsName[k];
180+
Object value = k == 0 ? recordCounter : values[k - 1];
181+
if (value instanceof Date aux) {
182+
//convert Date to String
183+
//necessary because Neo4j doesn't support Date properties on nodes
184+
value = aux.toString();
185185
}
186+
properties.put(field, value);
186187
}
187188

188-
fields.add(recordCounter);
189-
Collections.addAll(fields, values);
190189
if (geometry.isEmpty()) {
191190
log("warn | found empty geometry in record " + recordCounter);
192191
} else {
193192
// TODO check geometry.isValid()
194193
// ?
195194
SpatialDatabaseRecord spatial_record = layer.add(tx, geometry,
196-
fieldsName, fields.toArray(values));
195+
properties);
197196
added.add(spatial_record.getGeomNode());
198197
}
199198
} else {

server-plugin/src/main/java/org/neo4j/gis/spatial/SimplePointLayer.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.neo4j.gis.spatial;
2121

2222
import java.util.List;
23+
import java.util.Map;
2324
import org.locationtech.jts.geom.Coordinate;
2425
import org.neo4j.gis.spatial.pipes.GeoPipeFlow;
2526
import org.neo4j.gis.spatial.pipes.GeoPipeline;
@@ -31,19 +32,19 @@ public class SimplePointLayer extends EditableLayerImpl {
3132
public static final int LIMIT_RESULTS = 100;
3233

3334
public SpatialDatabaseRecord add(Transaction tx, Coordinate coordinate) {
34-
return add(tx, coordinate, null, null);
35+
return add(tx, coordinate, null);
3536
}
3637

37-
public SpatialDatabaseRecord add(Transaction tx, Coordinate coordinate, String[] fieldsName, Object[] fields) {
38-
return add(tx, getGeometryFactory().createPoint(coordinate), fieldsName, fields);
38+
public SpatialDatabaseRecord add(Transaction tx, Coordinate coordinate, Map<String, Object> properties) {
39+
return add(tx, getGeometryFactory().createPoint(coordinate), properties);
3940
}
4041

4142
public SpatialDatabaseRecord add(Transaction tx, double x, double y) {
42-
return add(tx, new Coordinate(x, y), null, null);
43+
return add(tx, new Coordinate(x, y), null);
4344
}
4445

45-
public SpatialDatabaseRecord add(Transaction tx, double x, double y, String[] fieldsName, Object[] fields) {
46-
return add(tx, new Coordinate(x, y), fieldsName, fields);
46+
public SpatialDatabaseRecord add(Transaction tx, double x, double y, Map<String, Object> properties) {
47+
return add(tx, new Coordinate(x, y), properties);
4748
}
4849

4950
public static Integer getGeometryType() {

server-plugin/src/test/java/org/neo4j/gis/spatial/OsmAnalysisTest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -384,11 +384,14 @@ private static SortedMap<String, Layer> exportPoints(Transaction tx, String laye
384384
l.add(tx, l.getGeometryFactory().createPoint(
385385
new Coordinate((Double) changedNode.getProperty("lon"), (Double) changedNode
386386
.getProperty("lat"))),
387-
new String[]{"user_id", "user_name", "year", "month",
388-
"dayOfMonth", "weekOfYear"},
389-
new Object[]{user.internalId, user.name, c.get(Calendar.YEAR),
390-
c.get(Calendar.MONTH),
391-
c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.WEEK_OF_YEAR)});
387+
Map.of(
388+
"user_id", user.internalId,
389+
"user_name", user.name,
390+
"year", c.get(Calendar.YEAR),
391+
"month", c.get(Calendar.MONTH),
392+
"dayOfMonth", c.get(Calendar.DAY_OF_MONTH),
393+
"weekOfYear", c.get(Calendar.WEEK_OF_YEAR)
394+
));
392395
}
393396
}
394397
}

server-plugin/src/test/java/org/neo4j/gis/spatial/TestSimplePointLayer.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ public void testIndexingExistingSimplePointNodes() {
204204

205205
Coordinate[] coords = makeCoordinateDataFromTextFile("NEO4J-SPATIAL.txt", testOrigin);
206206
inTx(tx -> {
207-
Layer layer = spatial.getLayer(tx, layerName);
207+
EditableLayer layer = (EditableLayer) spatial.getLayer(tx, layerName);
208208
for (Coordinate coordinate : coords) {
209209
Node n = tx.createNode();
210210
n.setProperty("x", coordinate.x);
@@ -226,7 +226,7 @@ public void testIndexingExistingNativePointNodes() {
226226

227227
Coordinate[] coords = makeCoordinateDataFromTextFile("NEO4J-SPATIAL.txt", testOrigin);
228228
inTx(tx -> {
229-
Layer layer = spatial.getLayer(tx, layerName);
229+
EditableLayer layer = (EditableLayer) spatial.getLayer(tx, layerName);
230230
for (Coordinate coordinate : coords) {
231231
Node n = tx.createNode();
232232
n.setProperty("x", coordinate.x);
@@ -257,9 +257,9 @@ public void testIndexingExistingPointNodesWithMultipleLocations() {
257257

258258
Coordinate[] coords = makeCoordinateDataFromTextFile("NEO4J-SPATIAL.txt", testOrigin);
259259
try (Transaction tx = db.beginTx()) {
260-
Layer layerA = spatial.getLayer(tx, layerNameA);
261-
Layer layerB = spatial.getLayer(tx, layerNameB);
262-
Layer layerC = spatial.getLayer(tx, layerNameC);
260+
EditableLayer layerA = (EditableLayer) spatial.getLayer(tx, layerNameA);
261+
EditableLayer layerB = (EditableLayer) spatial.getLayer(tx, layerNameB);
262+
EditableLayer layerC = (EditableLayer) spatial.getLayer(tx, layerNameC);
263263
for (Coordinate coordinate : coords) {
264264
Node n = tx.createNode();
265265
n.setProperty("xa", coordinate.x);

0 commit comments

Comments
 (0)