From 9e125aee02b2193f1c246c69eafbd242eeeb070a Mon Sep 17 00:00:00 2001 From: Oliver Tonnhofer Date: Tue, 25 Aug 2015 14:52:09 +0200 Subject: [PATCH] add new enumerate type to replace zorder --- docs/mapping.rst | 27 +++++++- example-mapping.json | 122 +++++++++++++++++----------------- mapping/fields.go | 38 +++++++++++ mapping/fields_test.go | 74 +++++++++++++++++++++ test/complete_db.osm | 32 +++++++++ test/complete_db_mapping.json | 85 ++++++++--------------- test/complete_db_test.py | 7 ++ 7 files changed, 266 insertions(+), 119 deletions(-) diff --git a/docs/mapping.rst b/docs/mapping.rst index 93c759d..7b1670e 100644 --- a/docs/mapping.rst +++ b/docs/mapping.rst @@ -205,6 +205,32 @@ Convert ``true``, ``yes`` and ``1`` to the numeric ``1``, ``-1`` values to ``-1` Convert values to an integer number. Other values will not be inserted. Useful for ``admin_levels`` for example. +``enumerate`` +^^^^^^^^^^^^^ + +Enumerates a list of values and stores tag values as an integer. + +The following `enum` column will contain ``1`` for ``landuse=forest``, ``4`` for ``landuse=grass`` and ``0`` for undefined values. + +.. code-block:: javascript + + { + "args": { + "values": [ + "forest", + "park", + "cemetery", + "grass" + ] + }, + "type": "enumerate", + "name": "enum", + "key": "landuse" + } + +``mapping_value`` will be used when ``key`` is not set or ``null``. + + Element types ~~~~~~~~~~~~~ @@ -255,7 +281,6 @@ Area of polygon geometries in square meters. This area is calculated in the webm Calculate the z-order of an OSM highway or railway. Returns a numeric value that represents the importance of a way where ``motorway`` is the most important (9), and ``path`` or ``track`` are least important (0). ``bridge`` and ``tunnel`` will modify the value by -10/+10. ``layer`` will be multiplied by ten and added to the value. E.g. ``highway=motorway``, ``bridge=yes`` and ``layer=2`` will return 39 (9+10+2*10). - ``hstore_tags`` ^^^^^^^^^^^^^^^ diff --git a/example-mapping.json b/example-mapping.json index 9a7d604..cc5d876 100644 --- a/example-mapping.json +++ b/example-mapping.json @@ -71,58 +71,57 @@ }, { "args": { - "ranks": [ - "pedestrian", - "footway", - "playground", - "park", - "forest", - "cemetery", - "farmyard", - "farm", - "farmland", - "wood", - "meadow", - "grass", - "wetland", - "village_green", - "recreation_ground", - "garden", - "sports_centre", - "pitch", - "common", - "allotments", - "golf_course", - "university", - "school", - "college", - "library", - "baracks", - "fuel", - "parking", - "nature_reserve", - "cinema", - "theatre", - "place_of_worship", - "hospital", - "scrub", - "orchard", - "vineyard", - "zoo", - "quarry", - "residential", - "retail", - "commercial", - "industrial", - "railway", - "heath", + "values": [ + "land", "island", - "land" + "heath", + "railway", + "industrial", + "commercial", + "retail", + "residential", + "quarry", + "zoo", + "vineyard", + "orchard", + "scrub", + "hospital", + "place_of_worship", + "theatre", + "cinema", + "nature_reserve", + "parking", + "fuel", + "baracks", + "library", + "college", + "school", + "university", + "golf_course", + "allotments", + "common", + "pitch", + "sports_centre", + "garden", + "recreation_ground", + "village_green", + "wetland", + "grass", + "meadow", + "wood", + "farmland", + "farm", + "farmyard", + "cemetery", + "forest", + "park", + "playground", + "footway", + "pedestrian" ] }, - "type": "zorder", - "name": "z_order", - "key": "z_order" + "type": "enumerate", + "name": "z_order" } ], "type": "polygon", @@ -258,22 +257,21 @@ }, { "args": { - "ranks": [ - "country", - "state", - "region", - "county", - "city", - "town", - "village", - "hamlet", + "values": [ + "locality", "suburb", - "locality" + "hamlet", + "village", + "town", + "city", + "county", + "region", + "state", + "country" ] }, - "type": "zorder", - "name": "z_order", - "key": "z_order" + "type": "enumerate", + "name": "z_order" }, { "type": "integer", diff --git a/mapping/fields.go b/mapping/fields.go index 21436a7..7407797 100644 --- a/mapping/fields.go +++ b/mapping/fields.go @@ -31,6 +31,7 @@ func init() { "wayzorder": {"wayzorder", "int32", WayZOrder, nil}, "pseudoarea": {"pseudoarea", "float32", PseudoArea, nil}, "zorder": {"zorder", "int32", nil, MakeZOrder}, + "enumerate": {"enumerate", "int32", nil, MakeEnumerate}, "string_suffixreplace": {"string_suffixreplace", "string", nil, MakeSuffixReplace}, } } @@ -224,6 +225,7 @@ func WayZOrder(val string, elem *element.OSMElem, geom *geom.Geometry, match Mat } func MakeZOrder(fieldName string, fieldType FieldType, field Field) (MakeValue, error) { + log.Print("warn: zorder type is deprecated and will be removed. See enumerate type.") _rankList, ok := field.Args["ranks"] if !ok { return nil, errors.New("missing ranks in args for zorder") @@ -269,6 +271,42 @@ func MakeZOrder(fieldName string, fieldType FieldType, field Field) (MakeValue, return zOrder, nil } +func MakeEnumerate(fieldName string, fieldType FieldType, field Field) (MakeValue, error) { + _valuesList, ok := field.Args["values"] + if !ok { + return nil, errors.New("missing values in args for enumerate") + } + + valuesList, ok := _valuesList.([]interface{}) + if !ok { + return nil, errors.New("values in args for enumerate not a list") + } + + values := make(map[string]int) + for i, value := range valuesList { + valueName, ok := value.(string) + if !ok { + return nil, errors.New("value in values not a string") + } + + values[valueName] = i + 1 + } + enumerate := func(val string, elem *element.OSMElem, geom *geom.Geometry, match Match) interface{} { + if field.Key != "" { + if r, ok := values[val]; ok { + return r + } + return 0 + } + if r, ok := values[match.Value]; ok { + return r + } + return 0 + } + + return enumerate, nil +} + func MakeSuffixReplace(fieldName string, fieldType FieldType, field Field) (MakeValue, error) { _changes, ok := field.Args["suffixes"] if !ok { diff --git a/mapping/fields_test.go b/mapping/fields_test.go index aff33ed..b29b50a 100644 --- a/mapping/fields_test.go +++ b/mapping/fields_test.go @@ -107,6 +107,80 @@ func TestZOrder(t *testing.T) { } } +func TestEnumerate_Match(t *testing.T) { + // test enumerate by matched mapping key + match := Match{} + + zOrder, err := MakeEnumerate("enumerate", + AvailableFieldTypes["enumerate"], + Field{ + Name: "enumerate", + Key: "", + Type: "enumerate", + Args: map[string]interface{}{"values": []interface{}{"AA", "CC", "FF", "ZZ"}}, + }, + ) + if err != nil { + t.Fatal(err) + } + elem := &element.OSMElem{} + + elem.Tags = element.Tags{} // missing + if v := zOrder("", elem, nil, match); v != 0 { + t.Errorf(" -> %v", v) + } + match.Value = "ABCD" // unknown + if v := zOrder("", elem, nil, match); v != 0 { + t.Errorf(" -> %v", v) + } + match.Value = "AA" + if v := zOrder("", elem, nil, match); v != 1 { + t.Errorf(" -> %v", v) + } + match.Value = "CC" + if v := zOrder("", elem, nil, match); v != 2 { + t.Errorf(" -> %v", v) + } + match.Value = "ZZ" + if v := zOrder("", elem, nil, match); v != 4 { + t.Errorf(" -> %v", v) + } +} + +func TestEnumerate_Key(t *testing.T) { + // test enumerate by key + match := Match{} + + zOrder, err := MakeEnumerate("enumerate", + AvailableFieldTypes["enumerate"], + Field{ + Name: "enumerate", + Key: "fips", + Type: "enumerate", + Args: map[string]interface{}{"values": []interface{}{"AA", "CC", "FF", "ZZ"}}, + }, + ) + if err != nil { + t.Fatal(err) + } + elem := &element.OSMElem{} + if v := zOrder("", elem, nil, match); v != 0 { + t.Errorf(" -> %v", v) + } + if v := zOrder("ABCD", elem, nil, match); v != 0 { + t.Errorf(" -> %v", v) + } + if v := zOrder("AA", elem, nil, match); v != 1 { + t.Errorf(" -> %v", v) + } + if v := zOrder("CC", elem, nil, match); v != 2 { + t.Errorf(" -> %v", v) + } + if v := zOrder("ZZ", elem, nil, match); v != 4 { + t.Errorf(" -> %v", v) + } +} + func TestMakeSuffixReplace(t *testing.T) { field := Field{ Name: "name", Key: "name", Type: "string_suffixreplace", diff --git a/test/complete_db.osm b/test/complete_db.osm index ce3c6eb..6327832 100644 --- a/test/complete_db.osm +++ b/test/complete_db.osm @@ -1021,4 +1021,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/complete_db_mapping.json b/test/complete_db_mapping.json index 201ff38..637b06c 100644 --- a/test/complete_db_mapping.json +++ b/test/complete_db_mapping.json @@ -71,58 +71,32 @@ }, { "args": { - "ranks": [ - "pedestrian", - "footway", - "playground", + "values": [ "park", "forest", - "cemetery", - "farmyard", - "farm", - "farmland", - "wood", - "meadow", - "grass", - "wetland", - "village_green", - "recreation_ground", - "garden", - "sports_centre", - "pitch", - "common", - "allotments", - "golf_course", - "university", - "school", - "college", - "library", - "baracks", - "fuel", - "parking", - "nature_reserve", - "cinema", - "theatre", - "place_of_worship", - "hospital", - "scrub", - "orchard", - "vineyard", - "zoo", - "quarry", "residential", "retail", "commercial", "industrial", "railway", - "heath", - "island", - "land" + "cemetery", + "grass", + "farmyard", + "farm", + "farmland", + "orchard", + "vineyard", + "wood", + "meadow", + "village_green", + "recreation_ground", + "allotments", + "quarry" ] }, - "type": "zorder", - "name": "z_order", - "key": "z_order" + "type": "enumerate", + "name": "enum", + "key": "enum_test" } ], "type": "polygon", @@ -258,22 +232,21 @@ }, { "args": { - "ranks": [ - "country", - "state", - "region", - "county", - "city", - "town", - "village", - "hamlet", + "values": [ + "locality", "suburb", - "locality" + "hamlet", + "village", + "town", + "city", + "county", + "region", + "state", + "country" ] }, - "type": "zorder", - "name": "z_order", - "key": "z_order" + "type": "enumerate", + "name": "z_order" }, { "type": "integer", diff --git a/test/complete_db_test.py b/test/complete_db_test.py index 0129982..6ab1e9f 100644 --- a/test/complete_db_test.py +++ b/test/complete_db_test.py @@ -298,6 +298,13 @@ def test_update_node_to_coord_1(): assert t.query_row(t.db_conf, 'osm_amenities', 70001) assert not t.query_row(t.db_conf, 'osm_amenities', 70002) +def test_enumerate_key(): + """Enumerate from key.""" + assert t.query_row(t.db_conf, 'osm_landusages', 100001)['enum'] == 1 + assert t.query_row(t.db_conf, 'osm_landusages', 100002)['enum'] == 0 + assert t.query_row(t.db_conf, 'osm_landusages', 100003)['enum'] == 15 + + ####################################################################### def test_update(): """Diff import applies"""