How can one create a table for relation member nodes?

I’m importing relations into Postgres using the “flex” output format. I’d like to have a table, say, relation_member_nodes, which will store label and admin_center nodes for relations which specify such members. In particular, I’d like columns for (1) the ID of the relation; (2) the ID of the node; (3) a string, either label or admin_center indicating the member role; and (4) the point as a geometry column.

I can identify such members in process_relation, like so:

function osm2pgsql.process_relation(object)
  for i, member in ipairs(object.members) do
    if member.type == 'n' and (member.role == 'label' or member.role == 'admin_center') then
      -- `member` is a node I wish to keep.
    end
  end

  -- ...other processing...
end

However, there doesn’t seem to be much I can do with this since member is a flat table with keys type, role, and ref. I tried to turn it into a “node” by assigning it the metatable of node, but this does not work:

local node_metatable = nil

function osm2pgsql.process_node(object)
  node_metatable = getmetatable(object)
end

function osm2pgsql.process_relation(object)
  for i, member in ipairs(object.members) do
    if member.type == 'n' and (member.role == 'label' or member.role == 'admin_center') then
      local fakenode = {
        type = "node",
        id = member.ref,
      }
      setmetatable(fakenode, node_metatable)

      label_node = fakenode:as_point() -- Error in 'as_point': The function as_point() can only be called from the process_node() function.
    end
  end

  -- ...other processing...
end

So: is there some way to get ahold of the underlying point in process_relation? I considered creating a global table to store points, but with over 9 billion nodes in a full planet file, that feels irresponsible. I’ve also considered omitting --drop and then issuing a query post-import to copy points from planet_osm_nodes into my table, but I’d really rather have the import process definined entirely in Lua.

4 Likes