From 1614a4656c91d671e45e910cf55fbfbae1e8f051 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sat, 26 Oct 2019 04:28:51 -0400 Subject: [PATCH] Manage field mapping in SQL declaratively Simplify some of the OSM->OMT field value mappings using declarative syntax. This approach is not for all cases, but in many it removes the need of storing the same field in both the .yaml and .sql files. TODO: support more complex AND/OR cases --- layers/aerodrome_label/aerodrome_label.yaml | 23 +++++-- layers/aerodrome_label/layer.sql | 22 +----- layers/landcover/landcover.sql | 10 +-- layers/landcover/landcover.yaml | 20 ++++-- layers/poi/class.sql | 37 ++-------- layers/poi/poi.yaml | 75 ++++++++++++++++++++- layers/transportation/class.sql | 18 ++--- layers/transportation/transportation.yaml | 58 ++++++++-------- layers/water/water.sql | 4 +- layers/water/water.yaml | 9 ++- 10 files changed, 156 insertions(+), 120 deletions(-) diff --git a/layers/aerodrome_label/aerodrome_label.yaml b/layers/aerodrome_label/aerodrome_label.yaml index 17b0fbe5..0be152dd 100644 --- a/layers/aerodrome_label/aerodrome_label.yaml +++ b/layers/aerodrome_label/aerodrome_label.yaml @@ -15,12 +15,23 @@ layer: [`aerodrome`](http://wiki.openstreetmap.org/wiki/Proposed_features/Aerodrome) and `aerodrome:type` tags. values: - - international - - public - - regional - - military - - private - - other + international: + aerodrome: 'international' + aerodrome_type: 'international' + public: + aerodrome: 'public' + aerodrome_type: ['%public%', 'civil'] + regional: + aerodrome: 'regional' + aerodrome_type: 'regional' + military: + aerodrome: 'military' + aerodrome_type: '%military%' + military: 'airfield' + private: + aerodrome: 'private' + aerodrome_type: 'private' + other: iata: 3-character code issued by the IATA. icao: 4-letter code issued by the ICAO. ele: Elevation (`ele`) in meters. diff --git a/layers/aerodrome_label/layer.sql b/layers/aerodrome_label/layer.sql index 8d5adfa1..4e91cc26 100644 --- a/layers/aerodrome_label/layer.sql +++ b/layers/aerodrome_label/layer.sql @@ -27,27 +27,7 @@ $$ COALESCE(NULLIF(name_de, ''), name, name_en) AS name_de, tags, CASE - WHEN aerodrome = 'international' - OR aerodrome_type = 'international' - THEN 'international' - WHEN - aerodrome = 'public' - OR aerodrome_type LIKE '%public%' - OR aerodrome_type = 'civil' - THEN 'public' - WHEN - aerodrome = 'regional' - OR aerodrome_type = 'regional' - THEN 'regional' - WHEN - aerodrome = 'military' - OR aerodrome_type LIKE '%military%' - OR military = 'airfield' - THEN 'military' - WHEN - aerodrome = 'private' - OR aerodrome_type = 'private' - THEN 'private' + %%FIELD_MAPPING: class %% ELSE 'other' END AS class, NULLIF(iata, '') AS iata, diff --git a/layers/landcover/landcover.sql b/layers/landcover/landcover.sql index 6d64b9aa..6b1f602c 100644 --- a/layers/landcover/landcover.sql +++ b/layers/landcover/landcover.sql @@ -11,15 +11,7 @@ CREATE OR REPLACE FUNCTION landcover_class(subclass VARCHAR) RETURNS TEXT AS $$ SELECT CASE - WHEN subclass IN ('farmland', 'farm', 'orchard', 'vineyard', 'plant_nursery') THEN 'farmland' - WHEN subclass IN ('glacier', 'ice_shelf') THEN 'ice' - WHEN subclass IN ('wood', 'forest') THEN 'wood' - WHEN subclass IN ('bare_rock', 'scree') THEN 'rock' - WHEN subclass IN ('fell', 'grassland', 'heath', 'scrub', 'tundra', 'grass', 'meadow', 'allotments', - 'park', 'village_green', 'recreation_ground', 'garden', 'golf_course') THEN 'grass' - WHEN subclass IN ('wetland', 'bog', 'swamp', 'wet_meadow', 'marsh', 'reedbed', - 'saltern', 'tidalflat', 'saltmarsh', 'mangrove') THEN 'wetland' - WHEN subclass IN ('beach', 'sand', 'dune') THEN 'sand' + %%FIELD_MAPPING: class %% ELSE NULL END; $$ LANGUAGE SQL IMMUTABLE; diff --git a/layers/landcover/landcover.yaml b/layers/landcover/landcover.yaml index 09e4e26f..6d51fe4f 100644 --- a/layers/landcover/landcover.yaml +++ b/layers/landcover/landcover.yaml @@ -10,12 +10,20 @@ layer: description: | Use the **class** to assign natural colors for **landcover**. values: - - farmland - - ice - - wood - - grass - - wetland - - sand + farmland: + subclass: ['farmland', 'farm', 'orchard', 'vineyard', 'plant_nursery'] + ice: + subclass: ['glacier', 'ice_shelf'] + wood: + subclass: ['wood', 'forest'] + rock: + subclass: ['bare_rock', 'scree'] + grass: + subclass: ['fell', 'grassland', 'heath', 'scrub', 'tundra', 'grass', 'meadow', 'allotments', 'park', 'village_green', 'recreation_ground', 'garden', 'golf_course'] + wetland: + subclass: ['wetland', 'bog', 'swamp', 'wet_meadow', 'marsh', 'reedbed', 'saltern', 'tidalflat', 'saltmarsh', 'mangrove'] + sand: + subclass: ['beach', 'sand', 'dune'] subclass: description: | Use **subclass** to do more precise styling. diff --git a/layers/poi/class.sql b/layers/poi/class.sql index c991d228..c81573ab 100644 --- a/layers/poi/class.sql +++ b/layers/poi/class.sql @@ -30,39 +30,10 @@ $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION poi_class(subclass TEXT, mapping_key TEXT) RETURNS TEXT AS $$ SELECT CASE - WHEN subclass IN ('accessories','antiques','beauty','bed','boutique','camera','carpet','charity','chemist','coffee','computer','convenience','copyshop','cosmetics','garden_centre','doityourself','erotic','electronics','fabric','florist','frozen_food','furniture','video_games','video','general','gift','hardware','hearing_aids','hifi','ice_cream','interior_decoration','jewelry','kiosk','lamps','mall','massage','motorcycle','mobile_phone','newsagent','optician','outdoor','perfumery','perfume','pet','photo','second_hand','shoes','sports','stationery','tailor','tattoo','ticket','tobacco','toys','travel_agency','watches','weapons','wholesale') THEN 'shop' - WHEN subclass IN ('townhall','public_building','courthouse','community_centre') THEN 'town_hall' - WHEN subclass IN ('golf','golf_course','miniature_golf') THEN 'golf' - WHEN subclass IN ('fast_food','food_court') THEN 'fast_food' - WHEN subclass IN ('park','bbq') THEN 'park' - WHEN subclass IN ('bus_stop','bus_station') THEN 'bus' - WHEN (subclass='station' AND mapping_key = 'railway') OR subclass IN ('halt', 'tram_stop', 'subway') THEN 'railway' - WHEN (subclass='station' AND mapping_key = 'aerialway') THEN 'aerialway' - WHEN subclass IN ('subway_entrance','train_station_entrance') THEN 'entrance' - WHEN subclass IN ('camp_site','caravan_site') THEN 'campsite' - WHEN subclass IN ('laundry','dry_cleaning') THEN 'laundry' - WHEN subclass IN ('supermarket','deli','delicatessen','department_store','greengrocer','marketplace') THEN 'grocery' - WHEN subclass IN ('books','library') THEN 'library' - WHEN subclass IN ('university','college') THEN 'college' - WHEN subclass IN ('hotel','motel','bed_and_breakfast','guest_house','hostel','chalet','alpine_hut','dormitory') THEN 'lodging' - WHEN subclass IN ('chocolate','confectionery') THEN 'ice_cream' - WHEN subclass IN ('post_box','post_office') THEN 'post' - WHEN subclass IN ('cafe') THEN 'cafe' - WHEN subclass IN ('school','kindergarten') THEN 'school' - WHEN subclass IN ('alcohol','beverages','wine') THEN 'alcohol_shop' - WHEN subclass IN ('bar','nightclub') THEN 'bar' - WHEN subclass IN ('marina','dock') THEN 'harbor' - WHEN subclass IN ('car','car_repair','taxi') THEN 'car' - WHEN subclass IN ('hospital','nursing_home', 'clinic') THEN 'hospital' - WHEN subclass IN ('grave_yard','cemetery') THEN 'cemetery' - WHEN subclass IN ('attraction','viewpoint') THEN 'attraction' - WHEN subclass IN ('biergarten','pub') THEN 'beer' - WHEN subclass IN ('music','musical_instrument') THEN 'music' - WHEN subclass IN ('american_football','stadium','soccer') THEN 'stadium' - WHEN subclass IN ('art','artwork','gallery','arts_centre') THEN 'art_gallery' - WHEN subclass IN ('bag','clothes') THEN 'clothing_store' - WHEN subclass IN ('swimming_area','swimming') THEN 'swimming' - WHEN subclass IN ('castle','ruins') THEN 'castle' + %%FIELD_MAPPING: class %% + WHEN (subclass = 'station' AND mapping_key = 'railway') + OR (subclass IN ('halt', 'tram_stop', 'subway')) THEN 'railway' + WHEN (subclass = 'station' AND mapping_key = 'aerialway') THEN 'aerialway' ELSE subclass END; $$ LANGUAGE SQL IMMUTABLE; diff --git a/layers/poi/poi.yaml b/layers/poi/poi.yaml index bd662857..8ed707d1 100644 --- a/layers/poi/poi.yaml +++ b/layers/poi/poi.yaml @@ -9,11 +9,84 @@ layer: name: The OSM [`name`](http://wiki.openstreetmap.org/wiki/Key:name) value of the POI. name_en: English name `name:en` if available, otherwise `name`. name_de: German name `name:de` if available, otherwise `name` or `name:en`. - class: | + class: + description: | More general classes of POIs. If there is no more general `class` for the `subclass` this field will contain the same value as `subclass`. But for example for schools you only need to style the class `school` to filter the subclasses `school` and `kindergarten`. Or use the class `shop` to style all shops. + values: + shop: + subclass: ['accessories', 'antiques', 'beauty', 'bed', 'boutique', 'camera', 'carpet', 'charity', 'chemist', + 'coffee', 'computer', 'convenience', 'copyshop', 'cosmetics', 'garden_centre', 'doityourself', + 'erotic', 'electronics', 'fabric', 'florist', 'frozen_food', 'furniture', 'video_games', 'video', + 'general', 'gift', 'hardware', 'hearing_aids', 'hifi', 'ice_cream', 'interior_decoration', + 'jewelry', 'kiosk', 'lamps', 'mall', 'massage', 'motorcycle', 'mobile_phone', 'newsagent', + 'optician', 'outdoor', 'perfumery', 'perfume', 'pet', 'photo', 'second_hand', 'shoes', 'sports', + 'stationery', 'tailor', 'tattoo', 'ticket', 'tobacco', 'toys', 'travel_agency', 'watches', + 'weapons', 'wholesale'] + town_hall: + subclass: ['townhall', 'public_building', 'courthouse', 'community_centre'] + golf: + subclass: ['golf', 'golf_course', 'miniature_golf'] + fast_food: + subclass: ['fast_food', 'food_court'] + park: + subclass: ['park', 'bbq'] + bus: + subclass: ['bus_stop', 'bus_station'] + railway: + aerialway: + entrance: + subclass: ['subway_entrance', 'train_station_entrance'] + campsite: + subclass: ['camp_site', 'caravan_site'] + laundry: + subclass: ['laundry', 'dry_cleaning'] + grocery: + subclass: ['supermarket', 'deli', 'delicatessen', 'department_store', 'greengrocer', 'marketplace'] + library: + subclass: ['books', 'library'] + college: + subclass: ['university', 'college'] + lodging: + subclass: ['hotel', 'motel', 'bed_and_breakfast', 'guest_house', 'hostel', 'chalet', 'alpine_hut', 'dormitory'] + ice_cream: + subclass: ['chocolate', 'confectionery'] + post: + subclass: ['post_box', 'post_office'] + cafe: + subclass: ['cafe'] + school: + subclass: ['school', 'kindergarten'] + alcohol_shop: + subclass: ['alcohol', 'beverages', 'wine'] + bar: + subclass: ['bar', 'nightclub'] + harbor: + subclass: ['marina', 'dock'] + car: + subclass: ['car', 'car_repair', 'taxi'] + hospital: + subclass: ['hospital', 'nursing_home', 'clinic'] + cemetery: + subclass: ['grave_yard', 'cemetery'] + attraction: + subclass: ['attraction', 'viewpoint'] + beer: + subclass: ['biergarten', 'pub'] + music: + subclass: ['music', 'musical_instrument'] + stadium: + subclass: ['american_football', 'stadium', 'soccer'] + art_gallery: + subclass: ['art', 'artwork', 'gallery', 'arts_centre'] + clothing_store: + subclass: ['bag', 'clothes'] + swimming: + subclass: ['swimming_area', 'swimming'] + castle: + subclass: ['castle', 'ruins'] subclass: description: | Original value of either the diff --git a/layers/transportation/class.sql b/layers/transportation/class.sql index 187b5f81..9f95412f 100644 --- a/layers/transportation/class.sql +++ b/layers/transportation/class.sql @@ -11,23 +11,19 @@ $$ LANGUAGE SQL IMMUTABLE STRICT; -- https://github.com/ClearTables/ClearTables/blob/master/transportation.lua CREATE OR REPLACE FUNCTION highway_class(highway TEXT, public_transport TEXT, construction TEXT) RETURNS TEXT AS $$ SELECT CASE - WHEN highway IN ('motorway', 'motorway_link') THEN 'motorway' - WHEN highway IN ('trunk', 'trunk_link') THEN 'trunk' - WHEN highway IN ('primary', 'primary_link') THEN 'primary' - WHEN highway IN ('secondary', 'secondary_link') THEN 'secondary' - WHEN highway IN ('tertiary', 'tertiary_link') THEN 'tertiary' - WHEN highway IN ('unclassified', 'residential', 'living_street', 'road') THEN 'minor' - WHEN highway IN ('pedestrian', 'path', 'footway', 'cycleway', 'steps', 'bridleway', 'corridor') OR public_transport IN ('platform') THEN 'path' - WHEN highway IN ('service', 'track', 'raceway') THEN highway + %%FIELD_MAPPING: class %% WHEN highway = 'construction' THEN CASE WHEN construction IN ('motorway', 'motorway_link') THEN 'motorway_construction' WHEN construction IN ('trunk', 'trunk_link') THEN 'trunk_construction' WHEN construction IN ('primary', 'primary_link') THEN 'primary_construction' WHEN construction IN ('secondary', 'secondary_link') THEN 'secondary_construction' WHEN construction IN ('tertiary', 'tertiary_link') THEN 'tertiary_construction' - WHEN construction = '' OR construction IN ('unclassified', 'residential', 'living_street', 'road') THEN 'minor_construction' - WHEN construction IN ('pedestrian', 'path', 'footway', 'cycleway', 'steps', 'bridleway', 'corridor') OR public_transport IN ('platform') THEN 'path_construction' - WHEN construction IN ('service', 'track', 'raceway') THEN CONCAT(highway, '_construction') + WHEN construction IN ('', 'unclassified', 'residential', 'living_street', 'road') THEN 'minor_construction' + WHEN construction IN ('pedestrian', 'path', 'footway', 'cycleway', 'steps', 'bridleway', 'corridor') + OR public_transport = 'platform' THEN 'path_construction' + WHEN construction = 'service' THEN 'service_construction' + WHEN construction = 'track' THEN 'track_construction' + WHEN construction = 'raceway' THEN 'raceway_construction' ELSE NULL END ELSE NULL diff --git a/layers/transportation/transportation.yaml b/layers/transportation/transportation.yaml index b92f6504..f4da3c34 100644 --- a/layers/transportation/transportation.yaml +++ b/layers/transportation/transportation.yaml @@ -24,33 +24,37 @@ layer: shipping ways), or [`man_made`](http://wiki.openstreetmap.org/wiki/Key:route). values: - - motorway - - trunk - - primary - - secondary - - tertiary - - minor - - service - - track - - path - - raceway - - motorway_construction - - trunk_construction - - primary_construction - - secondary_construction - - tertiary_construction - - minor_construction - - service_construction - - track_construction - - path_construction - - raceway_construction - - rail - - transit - - cable_car - - gondola - - ferry - - bridge - - pier + motorway: + highway: ['motorway', 'motorway_link'] + trunk: + highway: ['trunk', 'trunk_link'] + primary: + highway: ['primary', 'primary_link'] + secondary: + highway: ['secondary', 'secondary_link'] + tertiary: + highway: ['tertiary', 'tertiary_link'] + minor: + highway: ['unclassified', 'residential', 'living_street', 'road'] + path: + highway: ['pedestrian', 'path', 'footway', 'cycleway', 'steps', 'bridleway', 'corridor'] + public_transport: 'platform' + service: + highway: service + track: + highway: track + raceway: + highway: raceway + motorway_construction: + trunk_construction: + primary_construction: + secondary_construction: + tertiary_construction: + minor_construction: + path_construction: + service_construction: + track_construction: + raceway_construction: subclass: description: | Distinguish more specific classes of railway and path: diff --git a/layers/water/water.sql b/layers/water/water.sql index a7ca1f6b..3f3a9c60 100644 --- a/layers/water/water.sql +++ b/layers/water/water.sql @@ -1,8 +1,6 @@ CREATE OR REPLACE FUNCTION water_class(waterway TEXT) RETURNS TEXT AS $$ SELECT CASE - WHEN waterway='' THEN 'lake' - WHEN waterway='lake' THEN 'lake' - WHEN waterway='dock' THEN 'dock' + %%FIELD_MAPPING: class %% ELSE 'river' END; $$ LANGUAGE SQL IMMUTABLE; diff --git a/layers/water/water.yaml b/layers/water/water.yaml index 2e77b7b9..24ecabe5 100644 --- a/layers/water/water.yaml +++ b/layers/water/water.yaml @@ -14,9 +14,12 @@ layer: All water polygons from [OpenStreetMapData](http://osmdata.openstreetmap.de/) have the class `ocean`. Water bodies are classified as `lake` or `river` for water bodies with the [`waterway`](http://wiki.openstreetmap.org/wiki/Key:waterway) tag. values: - - ocean - - lake - - river + lake: + waterway: ['', 'lake'] + dock: + waterway: 'dock' + river: + ocean: intermittent: description: | Mark with `1` if it is an [intermittent](http://wiki.openstreetmap.org/wiki/Key:intermittent) water polygon.