Skip to content

Commit 82e572b

Browse files
committed
feat: custom spatial value mapping/process
1 parent 01f41a9 commit 82e572b

File tree

2 files changed

+60
-35
lines changed

2 files changed

+60
-35
lines changed

ckanext/spatial/plugin.py

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -69,39 +69,9 @@ def after_dataset_update(self, context, data_dict):
6969
self.check_spatial_extra(data_dict, update=True)
7070

7171
def check_spatial_extra(self, dataset_dict, update=False):
72-
'''
73-
For a given dataset, looks at the spatial extent (as given in the
74-
"spatial" field/extra in GeoJSON format) and stores it in the database.
75-
'''
76-
77-
dataset_id = dataset_dict["id"]
78-
geometry = dataset_dict.get("spatial")
79-
80-
if not geometry:
81-
# Check extras
82-
for extra in dataset_dict.get("extras", []):
83-
if extra["key"] == "spatial":
84-
geometry = extra["value"]
85-
86-
if not geometry:
87-
return
88-
89-
# Check valid JSON
90-
try:
91-
log.debug("Received geometry: {}".format(geometry))
92-
93-
geometry = geojson.loads(str(geometry))
94-
except ValueError as e:
95-
error_dict = {
96-
"spatial": ["Error decoding JSON object: {}".format(str(e))]}
97-
raise tk.ValidationError(error_dict)
98-
99-
if not hasattr(geometry, "is_valid") or not geometry.is_valid:
100-
msg = "Error: Wrong GeoJSON object"
101-
if hasattr(geometry, "errors"):
102-
msg = msg + ": {}".format(geometry.errors())
103-
error_dict = {"spatial": [msg]}
104-
raise tk.ValidationError(error_dict)
72+
# no need to validate spatial as validation already done in scheming
73+
pass
74+
10575

10676
# ITemplateHelpers
10777

ckanext/spatial/search/__init__.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,54 @@
1919
class SpatialSearchBackend:
2020
"""Base class for all datastore backends."""
2121

22+
def process_spatial_field(self, geom_from_metadata):
23+
"""Process spatial field based on its format (dict with spatial_type or GeoJSON string)"""
24+
# if string then convert to dict
25+
if isinstance(geom_from_metadata, str):
26+
geom_from_metadata = dict(json.loads(geom_from_metadata))
27+
28+
# Handle dict format with spatial_type
29+
if isinstance(geom_from_metadata, dict):
30+
spatial_type = geom_from_metadata.get("spatial_type")
31+
value = geom_from_metadata.get("value")
32+
33+
if spatial_type == "bbox" and value:
34+
# Convert bbox array to GeoJSON polygon
35+
# bbox format: [Northernmost latitude, Southernmost latitude, Easternmost longitude, Westernmost longitude]
36+
if len(value) == 4:
37+
maxy, miny, maxx, minx = value
38+
geometry = {
39+
"type": "Polygon",
40+
"coordinates": [[
41+
[minx, miny],
42+
[maxx, miny],
43+
[maxx, maxy],
44+
[minx, maxy],
45+
[minx, miny]
46+
]]
47+
}
48+
return geometry
49+
else:
50+
log.error("Invalid bbox format, expected 4 values, not indexing :: {}".format(value))
51+
return None
52+
53+
elif spatial_type == "wkt" and value:
54+
# Convert WKT to GeoJSON using shapely
55+
try:
56+
from shapely import wkt as shapely_wkt
57+
shape = shapely_wkt.loads(value.strip())
58+
# Convert shapely geometry to GeoJSON-like dict
59+
geometry = shapely.geometry.mapping(shape)
60+
return geometry
61+
except Exception as e:
62+
log.error("Failed to parse WKT geometry: {}, not indexing :: {}".format(e, value[:100]))
63+
return None
64+
else:
65+
log.error("Unknown spatial_type or missing value: {}".format(spatial_type))
66+
return None
67+
# Handle existing GeoJSON string format
68+
return self.parse_geojson(geom_from_metadata)
69+
2270
def parse_geojson(self, geom_from_metadata):
2371

2472
try:
@@ -51,10 +99,15 @@ def index_dataset(self, dataset_dict):
5199
"""
52100

53101
geom_from_metadata = dataset_dict.get("spatial")
102+
54103
if not geom_from_metadata:
55104
return dataset_dict
56105

57-
geometry = self.parse_geojson(geom_from_metadata)
106+
geometry = self.process_spatial_field(geom_from_metadata)
107+
108+
if not geometry:
109+
return dataset_dict
110+
58111
shape = self.shape_from_geometry(geometry)
59112

60113
if not shape:
@@ -134,10 +187,12 @@ class SolrSpatialFieldSearchBackend(SpatialSearchBackend):
134187
def index_dataset(self, dataset_dict):
135188
wkt = None
136189
geom_from_metadata = dataset_dict.get("spatial")
190+
137191
if not geom_from_metadata:
138192
return dataset_dict
139193

140-
geometry = self.parse_geojson(geom_from_metadata)
194+
geometry = self.process_spatial_field(geom_from_metadata)
195+
141196
if not geometry:
142197
return dataset_dict
143198

0 commit comments

Comments
 (0)