diff --git a/apps/transport/lib/registry/engine.ex b/apps/transport/lib/registry/engine.ex index 190d724d5e..a677c36c48 100644 --- a/apps/transport/lib/registry/engine.ex +++ b/apps/transport/lib/registry/engine.ex @@ -4,6 +4,7 @@ defmodule Transport.Registry.Engine do """ alias Transport.Registry.GTFS + alias Transport.Registry.NeTEx alias Transport.Registry.Model.Stop alias Transport.Registry.Result @@ -46,6 +47,7 @@ defmodule Transport.Registry.Engine do def prepare_extractor(%DB.Resource{} = resource) do case resource.format do "GTFS" -> {:ok, {GTFS, resource.url}} + "NeTEx" -> {:ok, {NeTEx, resource.url}} _ -> {:error, "Unsupported format"} end end diff --git a/apps/transport/lib/registry/model/stop.ex b/apps/transport/lib/registry/model/stop.ex index 89a1076b17..3e9c9b84d4 100644 --- a/apps/transport/lib/registry/model/stop.ex +++ b/apps/transport/lib/registry/model/stop.ex @@ -15,6 +15,8 @@ defmodule Transport.Registry.Model.StopIdentifier do @type identifier_type :: :main | :private_code | :stop_code | :other + def main(id), do: %__MODULE__{type: :main, id: id} + @doc """ iex> to_field(%Transport.Registry.Model.StopIdentifier{id: "stop1", type: :main}) "main:stop1" diff --git a/apps/transport/lib/registry/netex.ex b/apps/transport/lib/registry/netex.ex new file mode 100644 index 0000000000..248c4619f7 --- /dev/null +++ b/apps/transport/lib/registry/netex.ex @@ -0,0 +1,58 @@ +defmodule Transport.Registry.NeTEx do + @moduledoc """ + Implementation of a stop extractor for NeTEx resources. + """ + + alias Transport.Registry.Model.Stop + alias Transport.Registry.Model.StopIdentifier + alias Transport.Registry.Result + + require Logger + + @behaviour Transport.Registry.Extractor + @doc """ + Extract stops from a NeTEx archive. + """ + def extract_from_archive(archive) do + # FIXME: propagate some context + data_source_id = nil + + archive + |> Transport.NeTEx.read_all_stop_places() + |> Enum.flat_map(&process_stop_places(data_source_id, &1)) + |> Result.ok() + end + + defp process_stop_places(data_source_id, {_filename, {:ok, stop_places}}) do + stop_places |> Enum.map(&to_stop(data_source_id, &1)) |> Result.cat_results() + end + + defp process_stop_places(_data_source_id, {filename, {:error, message}}) do + Logger.error("Processing of #{filename}, error: #{message}") + [] + end + + defp to_stop(data_source_id, %{id: id, name: name, latitude: latitude, longitude: longitude}) do + %Stop{ + main_id: StopIdentifier.main(id), + display_name: name, + latitude: latitude, + longitude: longitude, + data_source_format: :netex, + data_source_id: data_source_id + } + |> Result.ok() + end + + defp to_stop(_data_source_id, incomplete_record) do + expected_keys = MapSet.new(~w(id name latitude longitude)) + keys = MapSet.new(Map.keys(incomplete_record)) + + missing_keys = MapSet.difference(expected_keys, keys) |> Enum.to_list() + + message = "Can't build stop, missing keys: #{inspect(missing_keys)}" + + Logger.error(message) + Result.error(message) + end +end