~ihabunek/triglav

726b46ec90c0b14a0c128d8464c45299e08d1123 — Ivan Habunek a month ago 5b8cb18 public-transport
Separate route and route_master mappings

This is helpful when preloading relation members, we only want to
preload members on masters to be able to draw a hierarchy, and not on
routes.
M lib/triglav/public_transport/mappings.ex => lib/triglav/public_transport/mappings.ex +22 -5
@@ 111,17 111,34 @@ defmodule Triglav.PublicTransport.Mappings do
        join: relation in Relation,
        on:
          tag(relation, "operator") == operator.ref and
            lower(tag(relation, "ref")) == lower(route.ref),
            lower(tag(relation, "ref")) == lower(route.ref) and
            tag(relation, "type") in ["route", "route_master"],
        select: %{
          feed_id: feed.id,
          route_id: route.id,
          relation_id: relation.id
          relation_id: relation.id,
          type: tag(relation, "type")
        }
      )
      |> Repo.all()

    Repo.delete_all(where("pt_route_mapped_relations", feed_id: ^feed_id))
    {count, nil} = Repo.insert_all("pt_route_mapped_relations", mappings)
    Logger.info("Created #{count} route mappings")
    routes =
      mappings
      |> Enum.filter(&(&1.type == "route"))
      |> Enum.map(&Map.drop(&1, [:type]))

    route_masters =
      mappings
      |> Enum.filter(&(&1.type == "route_master"))
      |> Enum.map(&Map.drop(&1, [:type]))

    Repo.delete_all(where("pt_route_mapped_route_relations", feed_id: ^feed_id))
    Repo.delete_all(where("pt_route_mapped_route_master_relations", feed_id: ^feed_id))

    {c1, nil} = Repo.insert_all("pt_route_mapped_route_relations", routes)
    {c2, nil} = Repo.insert_all("pt_route_mapped_route_master_relations", route_masters)

    Logger.info("Created #{c1} route mappings")
    Logger.info("Created #{c2} route master mappings")
  end
end

M lib/triglav/public_transport/schemas/route.ex => lib/triglav/public_transport/schemas/route.ex +7 -1
@@ 17,6 17,12 @@ defmodule Triglav.PublicTransport.Schemas.Route do

    has_many :variants, RouteVariant

    many_to_many :mapped_relations, Relation, join_through: "pt_route_mapped_relations"
    # Relates to OSM relations of type="route" matched by ref
    many_to_many :mapped_route_relations, Relation,
      join_through: "pt_route_mapped_route_relations"

    # Relates to OSM relations of type="route_master" matched by ref
    many_to_many :mapped_route_master_relations, Relation,
      join_through: "pt_route_mapped_route_master_relations"
  end
end

M lib/triglav_web/controllers/public_transport_controller.ex => lib/triglav_web/controllers/public_transport_controller.ex +24 -20
@@ 16,22 16,21 @@ defmodule TriglavWeb.PublicTransportController do
  def feed(conn, %{"id" => id}) do
    osm_state = Geofabrik.get_local_state()
    feed = Repo.get!(Feed, id) |> Repo.preload(:operator)
    routes = Repo.all(from Route, where: [feed_id: ^feed.id], order_by: :ref)

    osm_routes =
      Osm.list_relations(operator: feed.operator.ref, type: "route")
      |> Enum.group_by(& &1.tags["ref"])

    osm_masters =
      Osm.list_relations(operator: feed.operator.ref, type: "route_master")
      |> Repo.preload(:members)
      |> Enum.group_by(& &1.tags["ref"])
    routes =
      Repo.all(
        from Route,
          where: [feed_id: ^feed.id],
          order_by: :ref,
          preload: [
            :mapped_route_relations,
            [mapped_route_master_relations: :members]
          ]
      )

    render(conn, "feed.html",
      feed: feed,
      routes: routes,
      osm_masters: osm_masters,
      osm_routes: osm_routes,
      osm_state: osm_state
    )
  end


@@ 55,21 54,26 @@ defmodule TriglavWeb.PublicTransportController do

  def route(conn, %{"id" => id}) do
    osm_state = Geofabrik.get_local_state()
    route = Repo.get!(Route, id) |> Repo.preload([:variants, feed: :operator])
    variants = Repo.preload(route.variants, platforms: :platform) |> Enum.group_by(& &1.direction)
    osm_relations = Osm.list_relations(operator: route.feed.operator.ref, ref: route.ref)

    {osm_masters, osm_routes} =
      Enum.split_with(osm_relations, &(&1.tags["type"] == "route_master"))
    route =
      Route
      |> Repo.get!(id)
      |> Repo.preload([
        :variants,
        :mapped_route_relations,
        [
          feed: :operator,
          mapped_route_master_relations: :members,
          variants: [platforms: :platform]
        ]
      ])

    osm_masters = Repo.preload(osm_masters, :members)
    variants = Enum.group_by(route.variants, & &1.direction)

    render(conn, "route.html",
      route: route,
      variants: variants,
      osm_masters: osm_masters,
      osm_relations: osm_relations,
      osm_routes: osm_routes,
      osm_relations: Enum.concat(route.mapped_route_master_relations, route.mapped_route_relations),
      osm_state: osm_state
    )
  end

M lib/triglav_web/templates/public_transport/feed.html.heex => lib/triglav_web/templates/public_transport/feed.html.heex +2 -2
@@ 70,8 70,8 @@
          </td>
          <td>
            <%= route_hierarchy(
              Map.get(@osm_masters, route.ref, []),
              Map.get(@osm_routes, route.ref, [])
              route.mapped_route_master_relations,
              route.mapped_route_relations
            ) %>
          </td>
        </tr>

M lib/triglav_web/templates/public_transport/route.html.heex => lib/triglav_web/templates/public_transport/route.html.heex +1 -1
@@ 10,7 10,7 @@

  <%= if length(@osm_relations) > 0 do %>
    <h3>OSM Relations</h3>
    <%= route_hierarchy(@osm_masters, @osm_routes) %>
    <%= route_hierarchy(@route.mapped_route_master_relations, @route.mapped_route_relations) %>
    <div class="my-4"><%= josm_load_objects(@osm_relations) %></div>
  <% else %>
    <p class="text-red-900"><span class="text-xl">⚠</span> No OSM relations found.</p>

M priv/repo/migrations/20220616114253_create_public_transport_mapping_tables.exs => priv/repo/migrations/20220616114253_create_public_transport_mapping_tables.exs +7 -1
@@ 12,7 12,13 @@ defmodule Triglav.Repo.Migrations.CreatePublicTransportMappingTables do

    create unique_index(:pt_platform_mappings, [:feed_id, :platform_id])

    create table("pt_route_mapped_relations", primary_key: false) do
    create table("pt_route_mapped_route_relations", primary_key: false) do
      add :feed_id, references("pt_feeds"), null: false
      add :route_id, references("pt_routes"), null: false, primary_key: true
      add :relation_id, :bigint, null: false, primary_key: true
    end

    create table("pt_route_mapped_route_master_relations", primary_key: false) do
      add :feed_id, references("pt_feeds"), null: false
      add :route_id, references("pt_routes"), null: false, primary_key: true
      add :relation_id, :bigint, null: false, primary_key: true