-- osm2pgsql Flex output script for Transportationer -- Maps OSM tags to the 5 POI categories -- Write to a per-city staging table so osm2pgsql can freely drop/recreate it -- in create mode without touching other cities' rows in raw_pois. -- extract-pois.ts merges the staging data into raw_pois after the import. local city_slug = os.getenv('CITY_SLUG') or 'unknown' local staging_name = 'raw_pois_import_' .. city_slug:gsub('[^%w]', '_') local pois = osm2pgsql.define_table({ name = staging_name, ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' }, columns = { { column = 'city_slug', type = 'text' }, { column = 'category', type = 'text' }, { column = 'subcategory', type = 'text' }, { column = 'name', type = 'text' }, { column = 'tags', type = 'jsonb' }, { column = 'geom', type = 'point', projection = 4326 }, } }) -- Tag → {category, subcategory} mapping local tag_map = { amenity = { -- service_trade pharmacy = { 'service_trade', 'pharmacy' }, bank = { 'service_trade', 'bank' }, atm = { 'service_trade', 'atm' }, cafe = { 'service_trade', 'cafe' }, restaurant = { 'service_trade', 'restaurant' }, fast_food = { 'service_trade', 'restaurant' }, post_office = { 'service_trade', 'post_office' }, marketplace = { 'service_trade', 'market' }, -- transport bicycle_rental = { 'transport', 'bike_share' }, car_sharing = { 'transport', 'car_share' }, ferry_terminal = { 'transport', 'ferry' }, bus_station = { 'transport', 'bus_stop' }, -- work_school kindergarten = { 'work_school', 'kindergarten' }, childcare = { 'work_school', 'kindergarten' }, school = { 'work_school', 'school' }, university = { 'work_school', 'university' }, college = { 'work_school', 'university' }, driving_school = { 'work_school', 'driving_school' }, -- culture_community library = { 'culture_community', 'library' }, theatre = { 'culture_community', 'theatre' }, cinema = { 'culture_community', 'theatre' }, community_centre= { 'culture_community', 'community_center' }, place_of_worship= { 'culture_community', 'place_of_worship' }, hospital = { 'culture_community', 'hospital' }, clinic = { 'culture_community', 'clinic' }, doctors = { 'culture_community', 'clinic' }, social_facility = { 'culture_community', 'social_services' }, townhall = { 'culture_community', 'government' }, police = { 'culture_community', 'government' }, -- recreation swimming_pool = { 'recreation', 'swimming_pool' }, }, shop = { supermarket = { 'service_trade', 'supermarket' }, wholesale = { 'service_trade', 'supermarket' }, convenience = { 'service_trade', 'convenience' }, bakery = { 'service_trade', 'cafe' }, pharmacy = { 'service_trade', 'pharmacy' }, laundry = { 'service_trade', 'laundry' }, dry_cleaning = { 'service_trade', 'laundry' }, greengrocer = { 'service_trade', 'market' }, butcher = { 'service_trade', 'market' }, department_store= { 'service_trade', 'market' }, mall = { 'service_trade', 'market' }, }, highway = { bus_stop = { 'transport', 'bus_stop' }, }, railway = { station = { 'transport', 'train_station' }, halt = { 'transport', 'train_station' }, tram_stop = { 'transport', 'tram_stop' }, subway_entrance = { 'transport', 'metro' }, subway_station = { 'transport', 'metro' }, }, -- public_transport stop_position/platform intentionally excluded: -- they duplicate highway=bus_stop / railway=tram_stop nodes at the same -- physical location and would double-count those stops in scoring. office = { coworking = { 'work_school', 'coworking' }, }, tourism = { museum = { 'culture_community', 'museum' }, }, leisure = { park = { 'recreation', 'park' }, playground = { 'recreation', 'playground' }, sports_centre = { 'recreation', 'sports_facility' }, fitness_centre = { 'recreation', 'gym' }, swimming_pool = { 'recreation', 'swimming_pool' }, garden = { 'recreation', 'park' }, nature_reserve = { 'recreation', 'green_space' }, golf_course = { 'recreation', 'green_space' }, pitch = { 'recreation', 'sports_facility' }, arts_centre = { 'culture_community', 'community_center' }, }, landuse = { recreation_ground = { 'recreation', 'green_space' }, grass = { 'recreation', 'green_space' }, meadow = { 'recreation', 'green_space' }, forest = { 'recreation', 'green_space' }, }, } local CITY_SLUG = city_slug local function classify(tags) for key, values in pairs(tag_map) do local val = tags[key] if val and values[val] then return values[val][1], values[val][2] end end return nil, nil end local function get_centroid(object) if object.type == 'node' then return object:as_point() elseif object.type == 'way' then local geom = object:as_linestring() if geom then return geom:centroid() end else local geom = object:as_multipolygon() if geom then return geom:centroid() end end return nil end local function process(object) local category, subcategory = classify(object.tags) if not category then return end local geom = get_centroid(object) if not geom then return end pois:insert({ city_slug = CITY_SLUG, category = category, subcategory = subcategory, name = object.tags.name, tags = object.tags, geom = geom, }) end function osm2pgsql.process_node(object) process(object) end function osm2pgsql.process_way(object) process(object) end function osm2pgsql.process_relation(object) process(object) end