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
This commit is contained in:
Yuri Astrakhan 2019-10-26 04:28:51 -04:00
parent f3667170f6
commit 1614a4656c
10 changed files with 156 additions and 120 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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;

View File

@ -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.

View File

@ -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'
%%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'
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'
ELSE subclass
END;
$$ LANGUAGE SQL IMMUTABLE;

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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;

View File

@ -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.