defmodule DecodeFeature do
# TODO: This is not working yet, to be fixed in a future release
def decode(%Geobuf.Data{data_type: {:feature_collection, feature_collection}}) do
%{
"type" => "FeatureCollection",
"features" => Enum.map(feature_collection.features, &decode/1)
}
end
def decode(%Geobuf.Data{data_type: {:feature, feature}} = data) do
%{
"properties" => decode_properties(feature.properties, feature.values, data.keys),
"type" => "Feature",
"geometry" => decode_geometry(feature.geometry, data.precision, data.dimensions)
}
|> maybe_add_id(feature.id_type)
end
def decode(%Geobuf.Data{data_type: {:geometry, geometry}} = data) do
decode_geometry(geometry, data.precision, data.dimensions)
end
defp maybe_add_id(feature, id) do
if id != nil do
Map.put(feature, "id", decode_id(id))
else
feature
end
end
defp decode_id(nil), do: nil
defp decode_id({:id, id}), do: id
defp decode_properties(properties, values, keys) do
Enum.chunk_every(properties, 2)
|> Enum.map(fn [key_idx, val_idx] ->
{keys |> Enum.at(key_idx), values |> Enum.at(val_idx) |> decode_value()}
end)
|> Enum.into(%{})
end
defp decode_geometry(geo, precision, dimensions) do
DecodeGeometry.decode(geo, precision, dimensions)
end
defp decode_value(%Geobuf.Data.Value{value_type: {type, value}}) do
case type do
:bool_value -> value
:double_value -> value
:string_value -> value
:pos_int_value -> value
:neg_int_value -> -value
:json_value -> decode_json(value)
_ -> nil
end
end
defp decode_json(json_value) do
case Jason.decode(json_value) do
{:ok, m} -> m
{:error, _} -> raise "Failed to decode JSON"
end
end
end