diff --git a/lib/geo/json/decoder.ex b/lib/geo/json/decoder.ex index 7bb183e..d15089b 100644 --- a/lib/geo/json/decoder.ex +++ b/lib/geo/json/decoder.ex @@ -30,8 +30,11 @@ defmodule Geo.JSON.Decoder do @doc """ Takes a map representing GeoJSON and returns a Geometry. + + Feature objects with null geometries will be stripped from a FeatureCollection, + and a standalone Feature object with null geometry will be decoded to nil. """ - @spec decode!(map()) :: Geo.geometry() + @spec decode!(map()) :: Geo.geometry() | nil def decode!(geo_json) do cond do Map.has_key?(geo_json, "geometries") -> @@ -72,7 +75,8 @@ defmodule Geo.JSON.Decoder do Map.get(geo_json, "type") == "FeatureCollection" -> geometries = - Enum.map(Map.get(geo_json, "features"), fn x -> + Map.get(geo_json, "features") + |> Enum.map(fn x -> do_decode( Map.get(x, "type"), Map.get(x, "geometry"), @@ -80,6 +84,7 @@ defmodule Geo.JSON.Decoder do Map.get(x, "id", "") ) end) + |> Enum.reject(&is_nil/1) %GeometryCollection{ geometries: geometries, @@ -94,7 +99,7 @@ defmodule Geo.JSON.Decoder do @doc """ Takes a map representing GeoJSON and returns a Geometry. """ - @spec decode(map()) :: {:ok, Geo.geometry()} | {:error, DecodeError.t()} + @spec decode(map()) :: {:ok, Geo.geometry() | nil} | {:error, DecodeError.t()} def decode(geo_json) do {:ok, decode!(geo_json)} rescue @@ -168,6 +173,8 @@ defmodule Geo.JSON.Decoder do %MultiPolygonZ{coordinates: coordinates, srid: get_srid(crs), properties: properties} end + defp do_decode("Feature", nil, _properties, _id), do: nil + defp do_decode("Feature", geometry, properties, _id) do do_decode(Map.get(geometry, "type"), Map.get(geometry, "coordinates"), properties, nil) end diff --git a/test/geo/json_test.exs b/test/geo/json_test.exs index fe51a9e..c8f661e 100644 --- a/test/geo/json_test.exs +++ b/test/geo/json_test.exs @@ -301,6 +301,43 @@ defmodule Geo.JSON.Test do assert geom1.properties["label"] == "8 Boulevard du Port 80000 Amiens" end + test "Decode feature with null geometry" do + json = """ + { + "properties": { + "context": "80, Somme, Picardie", + "housenumber": "8" + }, + "geometry": null, + "type": "Feature" + } + """ + + geom = Jason.decode!(json) |> Geo.JSON.decode!() + assert is_nil(geom) + end + + test "Decode feature in a feature collection with null geometry" do + json = """ + { + "type": "FeatureCollection", + "features": [ + { + "properties": { + "context": "80, Somme, Picardie", + "housenumber": "8" + }, + "geometry": null, + "type": "Feature" + } + ] + } + """ + + geom = Jason.decode!(json) |> Geo.JSON.decode!() + assert geom.geometries == [] + end + property "encodes and decodes back to the correct Point struct" do check all x <- float(), y <- float() do