From 6c949b091967c8a2b3dabd99af7943d93613ca41 Mon Sep 17 00:00:00 2001 From: Jochen Topf Date: Wed, 27 Mar 2024 22:32:31 +0100 Subject: [PATCH] Remove gazetteer output and --with-forward-dependencies option --- man/osm2pgsql.1 | 11 +- man/osm2pgsql.md | 15 +- src/CMakeLists.txt | 2 - src/command-line-parser.cpp | 29 +- src/gazetteer-style.cpp | 576 ------------- src/gazetteer-style.hpp | 196 ----- src/middle-pgsql.cpp | 7 +- src/options.hpp | 6 - src/osm2pgsql.cpp | 7 +- src/osmdata.cpp | 5 +- src/osmdata.hpp | 1 - src/output-gazetteer.cpp | 221 ----- src/output-gazetteer.hpp | 108 --- src/output.cpp | 8 +- tests/CMakeLists.txt | 1 - .../regression/forward_dependencies.feature | 25 - tests/bdd/regression/gazetteer.feature | 60 -- tests/bdd/steps/steps_execute.py | 2 +- tests/common-import.hpp | 4 +- tests/common-options.hpp | 7 - tests/data/gazetteer-test.style | 237 ------ tests/test-db-copy-thread.cpp | 95 --- tests/test-options-parse.cpp | 16 - tests/test-output-gazetteer.cpp | 792 ------------------ 24 files changed, 17 insertions(+), 2414 deletions(-) delete mode 100644 src/gazetteer-style.cpp delete mode 100644 src/gazetteer-style.hpp delete mode 100644 src/output-gazetteer.cpp delete mode 100644 src/output-gazetteer.hpp delete mode 100644 tests/bdd/regression/gazetteer.feature delete mode 100644 tests/data/gazetteer-test.style delete mode 100644 tests/test-output-gazetteer.cpp diff --git a/man/osm2pgsql.1 b/man/osm2pgsql.1 index c04458ff7..9be357d18 100644 --- a/man/osm2pgsql.1 +++ b/man/osm2pgsql.1 @@ -224,14 +224,12 @@ too. .TP -O, --output=OUTPUT Specifies the output to use. -Currently osm2pgsql supports \f[B]pgsql\f[R], \f[B]flex\f[R], -\f[B]gazetteer\f[R] and \f[B]null\f[R]. +Currently osm2pgsql supports \f[B]pgsql\f[R], \f[B]flex\f[R], and +\f[B]null\f[R]. \f[B]pgsql\f[R] is the default output still available for backwards compatibility. New setups should use the \f[B]flex\f[R] output which allows for a much more flexible configuration. -The \f[B]gazetteer\f[R] output is intended for geocoding with Nominatim -only. The \f[B]null\f[R] output does not write anything and is only useful for testing or with \f[B]--slim\f[R] for creating slim tables. .TP @@ -346,11 +344,6 @@ index after the other. .TP --number-processes=THREADS Specifies the number of parallel threads used for certain operations. -.TP ---with-forward-dependencies=BOOL -Propagate changes from nodes to ways and node/way members to relations -(Default: \f[V]true\f[R]). -This option is deprecated. .SH SEE ALSO .IP \[bu] 2 osm2pgsql website (https://osm2pgsql.org) diff --git a/man/osm2pgsql.md b/man/osm2pgsql.md index abe510b2a..2fa096383 100644 --- a/man/osm2pgsql.md +++ b/man/osm2pgsql.md @@ -195,12 +195,11 @@ mandatory for short options too. -O, \--output=OUTPUT : Specifies the output to use. Currently osm2pgsql supports **pgsql**, - **flex**, **gazetteer** and **null**. **pgsql** is - the default output still available for backwards compatibility. New - setups should use the **flex** output which allows for a much more flexible - configuration. The **gazetteer** output is intended for geocoding with - Nominatim only. The **null** output does not write anything and is only - useful for testing or with **\--slim** for creating slim tables. + **flex**, and **null**. **pgsql** is the default output still available for + backwards compatibility. New setups should use the **flex** output which + allows for a much more flexible configuration. The **null** output does not + write anything and is only useful for testing or with **\--slim** for + creating slim tables. -S, \--style=FILE : The style file. This specifies how the data is imported into the database, @@ -307,10 +306,6 @@ mandatory for short options too. \--number-processes=THREADS : Specifies the number of parallel threads used for certain operations. -\--with-forward-dependencies=BOOL -: Propagate changes from nodes to ways and node/way members to relations - (Default: `true`). This option is deprecated. - # SEE ALSO * [osm2pgsql website](https://osm2pgsql.org) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ddf41219..ea1cfe979 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,6 @@ target_sources(osm2pgsql_lib PRIVATE dependency-manager.cpp expire-tiles.cpp expire-output.cpp - gazetteer-style.cpp geom.cpp geom-box.cpp geom-from-osm.cpp @@ -29,7 +28,6 @@ target_sources(osm2pgsql_lib PRIVATE node-persistent-cache.cpp ordered-index.cpp osmdata.cpp - output-gazetteer.cpp output-null.cpp output-pgsql.cpp output.cpp diff --git a/src/command-line-parser.cpp b/src/command-line-parser.cpp index d6a728ef5..370a2fc37 100644 --- a/src/command-line-parser.cpp +++ b/src/command-line-parser.cpp @@ -333,8 +333,7 @@ options_t parse_command_line(int argc, char *argv[]) // --output app.add_option("-O,--output", options.output_backend) - ->description("Set output ('pgsql' (default), 'flex', 'gazetteer' " - "(deprecated), 'null').") + ->description("Set output ('pgsql' (default), 'flex', 'null').") ->type_name("OUTPUT") ->group("Output options"); @@ -635,29 +634,6 @@ options_t parse_command_line(int argc, char *argv[]) ->option_text("TYPE") ->group("Deprecated options"); - // --with-forward-dependencies - app.add_option_function( - "--with-forward-dependencies", - [&](std::string const &arg) { - log_warn("The option --with-forward-dependencies is deprecated " - "and will soon be removed."); - if (arg == "false") { - options.with_forward_dependencies = false; - return; - } - if (arg == "true") { - options.with_forward_dependencies = true; - return; - } - throw fmt_error( - "Unknown value for --with-forward-dependencies option: {}", - arg); - }) - ->description("Propagate changes from nodes to ways and node/way " - "members to relations (default: true).") - ->option_text("BOOL") - ->group("Deprecated options"); - try { app.parse(argc, argv); } catch (...) { @@ -718,9 +694,6 @@ options_t parse_command_line(int argc, char *argv[]) if (options.output_backend == "flex") { check_options_output_flex(app); - } else if (options.output_backend == "gazetteer") { - log_warn( - "The 'gazetteer' output is deprecated and will soon be removed."); } else if (options.output_backend == "null") { check_options_output_null(app); } else if (options.output_backend == "pgsql" || diff --git a/src/gazetteer-style.cpp b/src/gazetteer-style.cpp deleted file mode 100644 index 47bdd9e2b..000000000 --- a/src/gazetteer-style.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/** - * SPDX-License-Identifier: GPL-2.0-or-later - * - * This file is part of osm2pgsql (https://osm2pgsql.org/). - * - * Copyright (C) 2006-2024 by the osm2pgsql developer community. - * For a full list of authors see the git log. - */ - -#include -#include -#include -#include - -#include -#include - -#include "domain-matcher.hpp" -#include "format.hpp" -#include "gazetteer-style.hpp" -#include "logging.hpp" -#include "pgsql.hpp" -#include "wkb.hpp" - -namespace pt = boost::property_tree; - -void db_deleter_place_t::delete_rows(std::string const &table, - std::string const &, pg_conn_t *conn) -{ - assert(!m_deletables.empty()); - - fmt::memory_buffer sql; - // Need a VALUES line for each deletable: type (3 bytes), id (15 bytes), - // class list (20 bytes), braces etc. (5 bytes). And additional space for - // the remainder of the SQL command. - sql.reserve(m_deletables.size() * 43 + 200); - - fmt::format_to(std::back_inserter(sql), "DELETE FROM {} p USING (VALUES ", - table); - - for (auto const &item : m_deletables) { - fmt::format_to(std::back_inserter(sql), "('{}',{},", item.osm_type, - item.osm_id); - if (item.classes.empty()) { - fmt::format_to(std::back_inserter(sql), "ARRAY[]::text[]),"); - } else { - fmt::format_to(std::back_inserter(sql), "ARRAY[{}]),", - item.classes); - } - } - - // remove the final comma - sql.resize(sql.size() - 1); - - fmt::format_to(std::back_inserter(sql), - ") AS t (osm_type, osm_id, classes) WHERE" - " p.osm_type = t.osm_type AND p.osm_id = t.osm_id" - " AND NOT p.class = ANY(t.classes)"); - - conn->exec(fmt::to_string(sql)); -} - -void gazetteer_style_t::clear() -{ - m_main.clear(); - m_names.clear(); - m_extra.clear(); - m_address.clear(); - m_operator = nullptr; - m_admin_level = MAX_ADMINLEVEL; -} - -std::string gazetteer_style_t::class_list() const -{ - fmt::memory_buffer buf; - - for (auto const &m : m_main) { - fmt::format_to(std::back_inserter(buf), FMT_STRING("'{}',"), - std::get<0>(m)); - } - - if (buf.size() > 0) { - buf.resize(buf.size() - 1); - } - - return fmt::to_string(buf); -} - -void gazetteer_style_t::load_style(std::string const &filename) -{ - log_info("Parsing gazetteer style file '{}'.", filename); - pt::ptree root; - - pt::read_json(filename, root); - - for (auto const &entry : root) { - for (auto const &tag : entry.second.get_child("keys")) { - for (auto const &value : entry.second.get_child("values")) { - add_style_entry(tag.second.data(), value.first, - parse_flags(value.second.data())); - } - } - } -} - -gazetteer_style_t::flag_t gazetteer_style_t::parse_flags(std::string const &str) -{ - flag_t out = 0; - - std::string::size_type start = 0; - - while (start != std::string::npos) { - auto const end = str.find(',', start); - - std::string item; - - if (end == std::string::npos) { - item = str.substr(start); - start = std::string::npos; - } else { - item = str.substr(start, end - start); - start = end + 1; - } - - if (item == "skip") { - return 0; - } - - if (item == "main") { - out |= SF_MAIN; - } else if (item == "with_name_key") { - out |= SF_MAIN_NAMED_KEY; - } else if (item == "with_name") { - out |= SF_MAIN_NAMED; - } else if (item == "fallback") { - out |= SF_MAIN_FALLBACK; - } else if (item == "operator") { - out |= SF_MAIN_OPERATOR; - m_any_operator_matches = true; - } else if (item == "name") { - out |= SF_NAME; - } else if (item == "ref") { - out |= SF_REF; - } else if (item == "address") { - out |= SF_ADDRESS; - } else if (item == "house") { - out |= SF_ADDRESS_POINT; - } else if (item == "postcode") { - out |= SF_POSTCODE; - } else if (item == "country") { - out |= SF_COUNTRY; - } else if (item == "extra") { - out |= SF_EXTRA; - } else if (item == "interpolation") { - out |= SF_INTERPOLATION; - } else { - throw std::runtime_error{"Unknown flag in style file."}; - } - } - - return out; -} - -bool gazetteer_style_t::add_metadata_style_entry(std::string const &key) -{ - if (key == "osm_version") { - m_metadata_fields.set_version(true); - } else if (key == "osm_timestamp") { - m_metadata_fields.set_timestamp(true); - } else if (key == "osm_changeset") { - m_metadata_fields.set_changeset(true); - } else if (key == "osm_uid") { - m_metadata_fields.set_uid(true); - } else if (key == "osm_user") { - m_metadata_fields.set_user(true); - } else { - return false; - } - return true; -} - -void gazetteer_style_t::add_style_entry(std::string const &key, - std::string const &value, - gazetteer_style_t::flag_t flags) -{ - if (key.empty()) { - if (value.empty()) { - m_default = flags; - } else { - m_matcher.emplace_back(value, flags, matcher_t::MT_VALUE); - } - return; - } - - // prefix: works on empty key only - if (key[key.size() - 1] == '*') { - if (key.size() == 1) { - throw std::runtime_error{"Style error. Ambiguous key '*'."}; - } - if (!value.empty()) { - throw std::runtime_error{ - "Style error. Prefix key can only be used with empty value."}; - } - m_matcher.emplace_back(key.substr(0, key.size() - 1), flags, - matcher_t::MT_PREFIX); - return; - } - - // suffix: dito - if (key[0] == '*') { - if (!value.empty()) { - throw std::runtime_error{ - "Style error. Suffix key can only be used with empty value."}; - } - m_matcher.emplace_back(key.substr(1), flags, matcher_t::MT_SUFFIX); - return; - } - - if (key == "boundary") { - if (value.empty() || value == "administrative") { - flags |= SF_BOUNDARY; - } - } - - if (add_metadata_style_entry(key)) { - if (!value.empty()) { - throw std::runtime_error{"Style error. Rules for OSM metadata " - "attributes must have an empty value."}; - } - if (flags != SF_EXTRA) { - throw std::runtime_error{"Style error. Rules for OSM metadata " - "attributes must have the style flag " - "\"extra\" and no other flag."}; - } - return; - } - if (value.empty()) { - m_matcher.emplace_back(key, flags, matcher_t::MT_KEY); - } else { - m_matcher.emplace_back(key + '\0' + value, flags, matcher_t::MT_FULL); - } -} - -gazetteer_style_t::flag_t gazetteer_style_t::find_flag(char const *k, - char const *v) const -{ - auto const klen = std::strlen(k); - auto const vlen = std::strlen(v); - - // full match - auto const fulllen = klen + vlen + 1U; - for (auto const &e : m_matcher) { - switch (e.type) { - case matcher_t::MT_FULL: - if (e.name.size() == fulllen && - std::strcmp(k, e.name.c_str()) == 0 && - std::memcmp(v, e.name.data() + klen + 1, vlen) == 0) { - return e.flag; - } - break; - case matcher_t::MT_KEY: - if (e.name.size() == klen && - std::memcmp(k, e.name.data(), klen) == 0) { - return e.flag; - } - break; - case matcher_t::MT_PREFIX: - if (e.name.size() < klen && - std::memcmp(k, e.name.data(), e.name.size()) == 0) { - return e.flag; - } - break; - case matcher_t::MT_SUFFIX: - if (e.name.size() < klen && - std::memcmp(k + klen - e.name.size(), e.name.data(), - e.name.size()) == 0) { - return e.flag; - } - break; - case matcher_t::MT_VALUE: - if (e.name.size() == vlen && - std::memcmp(v, e.name.data(), vlen) == 0) { - return e.flag; - } - break; - } - } - - return m_default; -} - -void gazetteer_style_t::process_tags(osmium::OSMObject const &o) -{ - clear(); - - bool has_postcode = false; - bool has_country = false; - char const *place = nullptr; - flag_t place_flag = 0; - bool address_point = false; - bool interpolation = false; - bool admin_boundary = false; - bool postcode_fallback = false; - bool is_named = false; - - for (auto const &item : o.tags()) { - char const *const k = item.key(); - char const *const v = item.value(); - - if (std::strcmp(k, "admin_level") == 0) { - char *endp = nullptr; - errno = 0; - auto const parsed = std::strtol(v, &endp, 10); - if (errno == 0 && *endp == '\0' && parsed > 0 && - parsed < MAX_ADMINLEVEL) { - m_admin_level = static_cast(parsed); - } else { - m_admin_level = MAX_ADMINLEVEL; - } - continue; - } - - if (m_any_operator_matches && std::strcmp(k, "operator") == 0) { - m_operator = v; - } - - flag_t const flag = find_flag(k, v); - - if (flag == 0) { - continue; - } - - if (flag & SF_MAIN) { - if (std::strcmp(k, "place") == 0) { - place = v; - place_flag = flag; - } else { - m_main.emplace_back(k, v, flag); - if ((flag & SF_BOUNDARY) && - std::strcmp(v, "administrative") == 0) { - admin_boundary = true; - } - } - } - - if (flag & static_cast(SF_NAME | SF_REF)) { - m_names.emplace_back(k, v); - if (flag & SF_NAME) { - is_named = true; - } - } - - if (flag & SF_ADDRESS) { - char const *addr_key = nullptr; - if (std::strncmp(k, "addr:", 5) == 0) { - addr_key = k + 5; - } else if (std::strncmp(k, "is_in:", 6) == 0) { - addr_key = k + 6; - } else { - addr_key = k; - } - - // country and postcode are handled specially, ignore them here - if (std::strcmp(addr_key, "country") != 0 && - std::strcmp(addr_key, "postcode") != 0) { - bool const first = std::none_of( - m_address.begin(), m_address.end(), [&](ptag_t const &t) { - return std::strcmp(t.first, addr_key) == 0; - }); - if (first) { - m_address.emplace_back(addr_key, v); - } - } - } - - if (flag & SF_ADDRESS_POINT) { - address_point = true; - is_named = true; - } - - if ((flag & SF_POSTCODE) && !has_postcode) { - has_postcode = true; - m_address.emplace_back("postcode", v); - if (flag & SF_MAIN_FALLBACK) { - postcode_fallback = true; - } - } - - if ((flag & SF_COUNTRY) && !has_country && std::strlen(v) == 2) { - has_country = true; - m_address.emplace_back("country", v); - } - - if (flag & SF_EXTRA) { - m_extra.emplace_back(k, v); - } - - if (flag & SF_INTERPOLATION) { - m_main.emplace_back("place", "houses", SF_MAIN); - interpolation = true; - } - } - - if (place) { - if (interpolation || (admin_boundary && std::strncmp(place, "isl", 3) != - 0)) { // island or islet - m_extra.emplace_back("place", place); - } else { - m_main.emplace_back("place", place, place_flag); - } - } - - filter_main_tags(is_named, o.tags()); - - if (m_main.empty()) { - if (address_point) { - m_main.emplace_back("place", "house", SF_MAIN | SF_MAIN_FALLBACK); - } else if (postcode_fallback && has_postcode) { - m_main.emplace_back("place", "postcode", - SF_MAIN | SF_MAIN_FALLBACK); - } - } -} - -void gazetteer_style_t::filter_main_tags(bool is_named, - osmium::TagList const &tags) -{ - // first throw away unnamed mains - auto mend = - std::remove_if(m_main.begin(), m_main.end(), [&](pmaintag_t const &t) { - auto const flags = std::get<2>(t); - - if (flags & SF_MAIN_NAMED) { - return !is_named; - } - - if (flags & SF_MAIN_NAMED_KEY) { - return !std::any_of(tags.begin(), tags.end(), - DomainMatcher{std::get<0>(t)}); - } - - return false; - }); - - // any non-fallback mains left? - bool const has_primary = - std::any_of(m_main.begin(), mend, [](pmaintag_t const &t) { - return !(std::get<2>(t) & SF_MAIN_FALLBACK); - }); - - if (has_primary) { - // remove all fallbacks - mend = std::remove_if(m_main.begin(), mend, [&](pmaintag_t const &t) { - return (std::get<2>(t) & SF_MAIN_FALLBACK); - }); - m_main.erase(mend, m_main.end()); - } else if (mend == m_main.begin()) { - m_main.clear(); - } else { - // remove everything except the first entry - m_main.resize(1); - } -} - -void gazetteer_style_t::copy_out(osmium::OSMObject const &o, - std::string const &geom, - copy_mgr_t *buffer) const -{ - for (auto const &tag : m_main) { - buffer->prepare(); - // osm_id - buffer->add_column(o.id()); - // osm_type - std::array const osm_type = { - (char)toupper(osmium::item_type_to_char(o.type())), '\0'}; - buffer->add_column(osm_type.data()); - // class - buffer->add_column(std::get<0>(tag)); - // type - buffer->add_column(std::get<1>(tag)); - // names - if (std::get<2>(tag) & SF_MAIN_NAMED_KEY) { - DomainMatcher const m{std::get<0>(tag)}; - buffer->new_hash(); - for (auto const &t : o.tags()) { - char const *const k = m(t); - if (k) { - buffer->add_hash_elem(k, t.value()); - } - } - buffer->finish_hash(); - } else { - bool first = true; - // operator will be ignored on anything but these classes - if (m_operator && (std::get<2>(tag) & SF_MAIN_OPERATOR)) { - buffer->new_hash(); - buffer->add_hash_elem("operator", m_operator); - first = false; - } - for (auto const &[key, value] : m_names) { - if (first) { - buffer->new_hash(); - first = false; - } - - buffer->add_hash_elem(key, value); - } - - if (first) { - buffer->add_null_column(); - } else { - buffer->finish_hash(); - } - } - // admin_level - buffer->add_column(m_admin_level); - // address - if (m_address.empty()) { - buffer->add_null_column(); - } else { - buffer->new_hash(); - for (auto const &[key, value] : m_address) { - if (std::strcmp(key, "tiger:county") == 0) { - std::string term; - auto const *const end = std::strchr(value, ','); - if (end) { - auto const len = - (std::string::size_type)(end - value); - term = std::string(value, len); - } else { - term = value; - } - term += " county"; - buffer->add_hash_elem(key, term); - } else { - buffer->add_hash_elem(key, value); - } - } - buffer->finish_hash(); - } - // extra tags - if (m_extra.empty() && m_metadata_fields.none()) { - buffer->add_null_column(); - } else { - buffer->new_hash(); - for (auto const &[key, value] : m_extra) { - buffer->add_hash_elem(key, value); - } - if (m_metadata_fields.version() && o.version()) { - buffer->add_hstore_num_noescape( - "osm_version", o.version()); - } - if (m_metadata_fields.uid() && o.uid()) { - buffer->add_hstore_num_noescape("osm_uid", - o.uid()); - } - if (m_metadata_fields.user() && o.user() && *(o.user()) != '\0') { - buffer->add_hash_elem("osm_user", o.user()); - } - if (m_metadata_fields.changeset() && o.changeset()) { - buffer->add_hstore_num_noescape( - "osm_changeset", o.changeset()); - } - if (m_metadata_fields.timestamp() && o.timestamp()) { - std::string const timestamp = o.timestamp().to_iso(); - buffer->add_hash_elem_noescape("osm_timestamp", - timestamp.c_str()); - } - buffer->finish_hash(); - } - // add the geometry - encoding it to hex along the way - buffer->add_hex_geom(geom); - - buffer->finish_line(); - } -} diff --git a/src/gazetteer-style.hpp b/src/gazetteer-style.hpp deleted file mode 100644 index ceb5832ea..000000000 --- a/src/gazetteer-style.hpp +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef OSM2PGSQL_GAZETTEER_STYLE_HPP -#define OSM2PGSQL_GAZETTEER_STYLE_HPP - -/** - * SPDX-License-Identifier: GPL-2.0-or-later - * - * This file is part of osm2pgsql (https://osm2pgsql.org/). - * - * Copyright (C) 2006-2024 by the osm2pgsql developer community. - * For a full list of authors see the git log. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "db-copy-mgr.hpp" - -/** - * Deleter which removes objects by osm_type, osm_id and class - * from a gazetteer place table. - * - * It deletes all object that have a given type and id and where the - * (comma-separated) list of classes does _not_ match. - */ -class db_deleter_place_t -{ - enum - { - // Deletion in the place table is fairly complex because of the - // compound primary key. It is better to start earlier with the - // deletion, so it can run in parallel with the file import. - Max_entries = 100000 - }; - - struct item_t - { - std::string classes; - osmid_t osm_id; - char osm_type; - - item_t(char t, osmid_t i, std::string c) - : classes(std::move(c)), osm_id(i), osm_type(t) - {} - - item_t(char t, osmid_t i) : osm_id(i), osm_type(t) {} - }; - -public: - bool has_data() const noexcept { return !m_deletables.empty(); } - - void add(char osm_type, osmid_t osm_id, std::string const &classes) - { - m_deletables.emplace_back(osm_type, osm_id, classes); - } - - void add(char osm_type, osmid_t osm_id) - { - m_deletables.emplace_back(osm_type, osm_id); - } - - void delete_rows(std::string const &table, std::string const &column, - pg_conn_t *conn); - - bool is_full() const noexcept { return m_deletables.size() > Max_entries; } - -private: - /// Vector with object to delete before copying - std::vector m_deletables; -}; - -/** - * Copy manager for the gazetteer place table only. - * - * Implicitly contains the table description. - */ -class gazetteer_copy_mgr_t : public db_copy_mgr_t -{ -public: - explicit gazetteer_copy_mgr_t( - std::shared_ptr const &processor) - : db_copy_mgr_t(processor), - m_table( - std::make_shared("public", "place", "place_id")) - { - } - - void prepare() { new_line(m_table); } - -private: - std::shared_ptr m_table; -}; - -enum : int -{ - MAX_ADMINLEVEL = 15 -}; - -class gazetteer_style_t -{ - using flag_t = uint16_t; - using ptag_t = std::pair; - using pmaintag_t = std::tuple; - - enum style_flags : uint16_t - { - SF_MAIN = 1U << 0U, - SF_MAIN_NAMED = 1U << 1U, - SF_MAIN_NAMED_KEY = 1U << 2U, - SF_MAIN_FALLBACK = 1U << 3U, - SF_MAIN_OPERATOR = 1U << 4U, - SF_NAME = 1U << 5U, - SF_REF = 1U << 6U, - SF_ADDRESS = 1U << 7U, - SF_ADDRESS_POINT = 1U << 8U, - SF_POSTCODE = 1U << 9U, - SF_COUNTRY = 1U << 10U, - SF_EXTRA = 1U << 11U, - SF_INTERPOLATION = 1U << 12U, - SF_BOUNDARY = 1U << 13U, // internal flag for boundaries - }; - - enum class matcher_t - { - MT_FULL, - MT_KEY, - MT_PREFIX, - MT_SUFFIX, - MT_VALUE - }; - - struct string_with_flag_t - { - std::string name; - flag_t flag; - matcher_t type; - - string_with_flag_t(std::string n, flag_t f, matcher_t t) - : name(std::move(n)), flag(f), type(t) - {} - }; - - using flag_list_t = std::vector; - -public: - using copy_mgr_t = gazetteer_copy_mgr_t; - - void load_style(std::string const &filename); - void process_tags(osmium::OSMObject const &o); - void copy_out(osmium::OSMObject const &o, std::string const &geom, - copy_mgr_t *buffer) const; - std::string class_list() const; - - bool has_data() const noexcept { return !m_main.empty(); } - -private: - bool add_metadata_style_entry(std::string const &key); - void add_style_entry(std::string const &key, std::string const &value, - flag_t flags); - flag_t parse_flags(std::string const &str); - flag_t find_flag(char const *k, char const *v) const; - void filter_main_tags(bool is_named, osmium::TagList const &tags); - - void clear(); - - // Style data. - flag_list_t m_matcher; - flag_t m_default{0}; - bool m_any_operator_matches{false}; - - // Cached OSM object data. - - /// class/type pairs to include - std::vector m_main; - /// name tags to include - std::vector m_names; - /// extratags to include - std::vector m_extra; - /// addresstags to include - std::vector m_address; - /// value of operator tag - char const *m_operator = nullptr; - /// admin level - int m_admin_level = MAX_ADMINLEVEL; - - /// which metadata fields of the OSM objects should be written to the output - osmium::metadata_options m_metadata_fields{"none"}; -}; - -#endif // OSM2PGSQL_GAZETTEER_STYLE_HPP diff --git a/src/middle-pgsql.cpp b/src/middle-pgsql.cpp index 2dafdfa92..f9759840e 100644 --- a/src/middle-pgsql.cpp +++ b/src/middle-pgsql.cpp @@ -134,9 +134,7 @@ middle_pgsql_t::table_desc::table_desc(options_t const &options, m_copy_target(std::make_shared( options.middle_dbschema, build_sql(options, ts.name), "id")) { - if (options.with_forward_dependencies) { - m_create_fw_dep_indexes = build_sql(options, ts.create_fw_dep_indexes); - } + m_create_fw_dep_indexes = build_sql(options, ts.create_fw_dep_indexes); } void middle_query_pgsql_t::exec_sql(std::string const &sql_cmd) const @@ -1681,8 +1679,7 @@ middle_pgsql_t::middle_pgsql_t(std::shared_ptr thread_pool, bool const has_bucket_index = check_bucket_index(&m_db_connection, options->prefix); - if (!has_bucket_index && options->append && - options->with_forward_dependencies) { + if (!has_bucket_index && options->append) { log_debug("You don't have a bucket index. See manual for details."); } diff --git a/src/options.hpp b/src/options.hpp index b518af60e..bf9655289 100644 --- a/src/options.hpp +++ b/src/options.hpp @@ -139,12 +139,6 @@ struct options_t bool keep_coastlines = false; bool droptemp = false; ///< drop slim mode temp tables after act - /** - * Should changes of objects be propagated forwards (from nodes to ways and - * from node/way members to parent relations)? - */ - bool with_forward_dependencies = true; - /// only copy rows that match an explicitly listed key bool hstore_match_only = false; diff --git a/src/osm2pgsql.cpp b/src/osm2pgsql.cpp index a8b113169..e9156e76d 100644 --- a/src/osm2pgsql.cpp +++ b/src/osm2pgsql.cpp @@ -61,9 +61,7 @@ static file_info run(options_t const &options) middle->set_requirements(output->get_requirements()); auto dependency_manager = - options.with_forward_dependencies - ? std::make_unique(middle) - : std::make_unique(); + std::make_unique(middle); osmdata_t osmdata{std::move(dependency_manager), middle, output, options}; @@ -339,8 +337,7 @@ static void set_option_defaults(options_t *options) } if (options->style.empty()) { - if (options->output_backend == "flex" || - options->output_backend == "gazetteer") { + if (options->output_backend == "flex") { throw std::runtime_error{"You have to set the config file " "with the -S|--style option."}; } diff --git a/src/osmdata.cpp b/src/osmdata.cpp index 30e623e22..8038364b7 100644 --- a/src/osmdata.cpp +++ b/src/osmdata.cpp @@ -33,8 +33,7 @@ osmdata_t::osmdata_t(std::unique_ptr dependency_manager, m_output(std::move(output)), m_connection_params(options.connection_params), m_bbox(options.bbox), m_num_procs(options.num_procs), m_append(options.append), m_droptemp(options.droptemp), - m_with_extra_attrs(options.extra_attributes), - m_with_forward_dependencies(options.with_forward_dependencies) + m_with_extra_attrs(options.extra_attributes) { assert(m_dependency_manager); assert(m_mid); @@ -407,7 +406,7 @@ void osmdata_t::postprocess_database() const void osmdata_t::stop() const { - if (m_append && m_with_forward_dependencies) { + if (m_append) { process_dependents(); } diff --git a/src/osmdata.hpp b/src/osmdata.hpp index f632cd4ee..6a66fc328 100644 --- a/src/osmdata.hpp +++ b/src/osmdata.hpp @@ -91,7 +91,6 @@ class osmdata_t : public osmium::handler::Handler bool m_append; bool m_droptemp; bool m_with_extra_attrs; - bool m_with_forward_dependencies; }; #endif // OSM2PGSQL_OSMDATA_HPP diff --git a/src/output-gazetteer.cpp b/src/output-gazetteer.cpp deleted file mode 100644 index bb7ebe356..000000000 --- a/src/output-gazetteer.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/** - * SPDX-License-Identifier: GPL-2.0-or-later - * - * This file is part of osm2pgsql (https://osm2pgsql.org/). - * - * Copyright (C) 2006-2024 by the osm2pgsql developer community. - * For a full list of authors see the git log. - */ - -#include "format.hpp" -#include "geom.hpp" -#include "geom-from-osm.hpp" -#include "geom-functions.hpp" -#include "middle.hpp" -#include "options.hpp" -#include "osmtypes.hpp" -#include "output-gazetteer.hpp" -#include "pgsql.hpp" - -#include -#include -#include - -output_gazetteer_t::~output_gazetteer_t() = default; - -void output_gazetteer_t::delete_unused_classes(char osm_type, osmid_t osm_id) -{ - if (get_options()->append) { - m_copy.prepare(); - - assert(m_style.has_data()); - - std::string const cls = m_style.class_list(); - m_copy.delete_object(osm_type, osm_id, cls); - } -} - -void output_gazetteer_t::delete_unused_full(char osm_type, osmid_t osm_id) -{ - if (get_options()->append) { - m_copy.prepare(); - m_copy.delete_object(osm_type, osm_id); - } -} - -void output_gazetteer_t::start() -{ - /* (Re)create the table unless we are appending */ - if (!get_options()->append) { - int const srid = get_options()->projection->target_srs(); - - pg_conn_t const conn{get_options()->connection_params, "out.gazetteer"}; - - /* Drop any existing table */ - conn.exec("DROP TABLE IF EXISTS place CASCADE"); - - /* Create the new table */ - - std::string const sql = - fmt::format("CREATE TABLE place (" - " osm_id int8 NOT NULL," - " osm_type char(1) NOT NULL," - " class text NOT NULL," - " type text NOT NULL," - " name hstore," - " admin_level smallint," - " address hstore," - " extratags hstore," - " geometry Geometry(Geometry,{}) NOT NULL)", - srid) + - tablespace_clause(get_options()->tblsmain_data); - - conn.exec(sql); - - std::string const index_sql = - "CREATE INDEX place_id_idx ON place" - " USING BTREE (osm_type, osm_id)" + - tablespace_clause(get_options()->tblsmain_index); - conn.exec(index_sql); - } -} - -void output_gazetteer_t::sync() { m_copy.sync(); } - -void output_gazetteer_t::node_add(osmium::Node const &node) -{ - if (!process_node(node)) { - delete_unused_full('N', node.id()); - } -} - -void output_gazetteer_t::node_modify(osmium::Node const &node) -{ - if (!process_node(node)) { - delete_unused_full('N', node.id()); - } -} - -bool output_gazetteer_t::process_node(osmium::Node const &node) -{ - m_style.process_tags(node); - - /* Are we interested in this item? */ - if (!m_style.has_data()) { - return false; - } - - auto const wkb = - geom_to_ewkb(geom::transform(geom::create_point(node), *m_proj)); - delete_unused_classes('N', node.id()); - m_style.copy_out(node, wkb, &m_copy); - - return true; -} - -void output_gazetteer_t::way_add(osmium::Way *way) -{ - if (!process_way(way)) { - delete_unused_full('W', way->id()); - } -} - -void output_gazetteer_t::way_modify(osmium::Way *way) -{ - if (!process_way(way)) { - delete_unused_full('W', way->id()); - } -} - -bool output_gazetteer_t::process_way(osmium::Way *way) -{ - m_style.process_tags(*way); - - if (!m_style.has_data()) { - return false; - } - - // Fetch the node details. - middle().nodes_get_list(&(way->nodes())); - - // Get the geometry of the object. - geom::geometry_t geom; - if (!way->nodes().empty() && way->is_closed()) { - geom = geom::transform(geom::create_polygon(*way), *m_proj); - } - if (geom.is_null()) { - geom = geom::transform(geom::create_linestring(*way), *m_proj); - if (geom.is_null()) { - return false; - } - } - - delete_unused_classes('W', way->id()); - m_style.copy_out(*way, geom_to_ewkb(geom), &m_copy); - - return true; -} - -void output_gazetteer_t::relation_add(osmium::Relation const &rel) -{ - if (!process_relation(rel)) { - delete_unused_full('R', rel.id()); - } -} - -void output_gazetteer_t::relation_modify(osmium::Relation const &rel) -{ - if (!process_relation(rel)) { - delete_unused_full('R', rel.id()); - } -} - -bool output_gazetteer_t::process_relation(osmium::Relation const &rel) -{ - char const *const type = rel.tags()["type"]; - if (!type) { - return false; - } - - bool const is_waterway = std::strcmp(type, "waterway") == 0; - - if (std::strcmp(type, "associatedStreet") == 0 || - !(std::strcmp(type, "boundary") == 0 || - std::strcmp(type, "multipolygon") == 0 || is_waterway)) { - return false; - } - - m_style.process_tags(rel); - - /* Are we interested in this item? */ - if (!m_style.has_data()) { - return false; - } - - /* get the boundary path (ways) */ - m_osmium_buffer.clear(); - auto const num_ways = middle().rel_members_get( - rel, &m_osmium_buffer, osmium::osm_entity_bits::way); - - if (num_ways == 0) { - return false; - } - - for (auto &w : m_osmium_buffer.select()) { - middle().nodes_get_list(&(w.nodes())); - } - - auto const geom = geom::transform( - is_waterway ? geom::create_multilinestring(m_osmium_buffer) - : geom::create_multipolygon(rel, m_osmium_buffer), - *m_proj); - - if (geom.is_null()) { - return false; - } - - delete_unused_classes('R', rel.id()); - m_style.copy_out(rel, geom_to_ewkb(geom), &m_copy); - - return true; -} diff --git a/src/output-gazetteer.hpp b/src/output-gazetteer.hpp deleted file mode 100644 index 6f427d6be..000000000 --- a/src/output-gazetteer.hpp +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef OSM2PGSQL_OUTPUT_GAZETTEER_HPP -#define OSM2PGSQL_OUTPUT_GAZETTEER_HPP - -/** - * SPDX-License-Identifier: GPL-2.0-or-later - * - * This file is part of osm2pgsql (https://osm2pgsql.org/). - * - * Copyright (C) 2006-2024 by the osm2pgsql developer community. - * For a full list of authors see the git log. - */ - -#include -#include - -#include - -#include "gazetteer-style.hpp" -#include "options.hpp" -#include "osmtypes.hpp" -#include "output.hpp" -#include "reprojection.hpp" -#include "wkb.hpp" - -class db_copy_thread_t; -class thread_pool_t; - -struct middle_query_t; - -class output_gazetteer_t : public output_t -{ -public: - /// Constructor for new objects - output_gazetteer_t(std::shared_ptr const &mid, - std::shared_ptr thread_pool, - options_t const &options) - : output_t(mid, std::move(thread_pool), options), - m_copy(std::make_shared(options.connection_params)), - m_proj(options.projection) - { - m_style.load_style(options.style); - } - - /// Constructor for cloned objects - output_gazetteer_t(output_gazetteer_t const *other, - std::shared_ptr const &mid, - std::shared_ptr const ©_thread) - : output_t(other, mid), m_copy(copy_thread), - m_proj(other->get_options()->projection) - {} - - output_gazetteer_t(output_gazetteer_t const &) = delete; - output_gazetteer_t &operator=(output_gazetteer_t const &) = delete; - - output_gazetteer_t(output_gazetteer_t &&) = delete; - output_gazetteer_t &operator=(output_gazetteer_t &&) = delete; - - ~output_gazetteer_t() override; - - std::shared_ptr - clone(std::shared_ptr const &mid, - std::shared_ptr const ©_thread) const override - { - return std::make_shared(this, mid, copy_thread); - } - - void start() override; - void stop() noexcept override {} - void sync() override; - - void pending_way(osmid_t) noexcept override {} - void pending_relation(osmid_t) noexcept override {} - - void node_add(osmium::Node const &node) override; - void way_add(osmium::Way *way) override; - void relation_add(osmium::Relation const &rel) override; - - void node_modify(osmium::Node const &node) override; - void way_modify(osmium::Way *way) override; - void relation_modify(osmium::Relation const &rel) override; - - void node_delete(osmid_t id) override { delete_unused_full('N', id); } - void way_delete(osmid_t id) override { delete_unused_full('W', id); } - void relation_delete(osmid_t id) override { delete_unused_full('R', id); } - -private: - enum - { - PLACE_BUFFER_SIZE = 4096 - }; - - /// Delete all places that are not covered by the current style results. - void delete_unused_classes(char osm_type, osmid_t osm_id); - /// Delete all places for the given OSM object. - void delete_unused_full(char osm_type, osmid_t osm_id); - bool process_node(osmium::Node const &node); - bool process_way(osmium::Way *way); - bool process_relation(osmium::Relation const &rel); - - gazetteer_copy_mgr_t m_copy; - gazetteer_style_t m_style; - - std::shared_ptr m_proj; - osmium::memory::Buffer m_osmium_buffer{ - PLACE_BUFFER_SIZE, osmium::memory::Buffer::auto_grow::yes}; -}; - -#endif // OSM2PGSQL_OUTPUT_GAZETTEER_HPP diff --git a/src/output.cpp b/src/output.cpp index 51a353da8..f4b50b417 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -12,7 +12,6 @@ #include "db-copy.hpp" #include "format.hpp" #include "options.hpp" -#include "output-gazetteer.hpp" #include "output-null.hpp" #include "output-pgsql.hpp" @@ -44,18 +43,13 @@ output_t::create_output(std::shared_ptr const &mid, } #endif - if (options.output_backend == "gazetteer") { - return std::make_shared(mid, std::move(thread_pool), - options); - } - if (options.output_backend == "null") { return std::make_shared(mid, std::move(thread_pool), options); } throw fmt_error("Output backend '{}' not recognised. Should be one of" - " [pgsql, {}gazetteer, null].", + " [pgsql, {}null].", options.output_backend, flex_backend); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5288cce41..6e293eb2b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -63,7 +63,6 @@ set_test(test-options-parse LABELS NoDB) set_test(test-options-projection) set_test(test-ordered-index LABELS NoDB) set_test(test-osm-file-parsing LABELS NoDB) -set_test(test-output-gazetteer) set_test(test-output-pgsql) set_test(test-output-pgsql-area) set_test(test-output-pgsql-hstore-match-only) diff --git a/tests/bdd/regression/forward_dependencies.feature b/tests/bdd/regression/forward_dependencies.feature index 77a7a74b8..8b48bbee2 100644 --- a/tests/bdd/regression/forward_dependencies.feature +++ b/tests/bdd/regression/forward_dependencies.feature @@ -42,28 +42,3 @@ Feature: Test forward propagation of changes Then table planet_osm_roads has 1 row Then table planet_osm_polygon has 1 row - - Scenario: Node changes are not forwarded when forwarding is disabled - When running osm2pgsql pgsql with parameters - | --slim | --latlong | - Given the OSM data - """ - n13 v2 x3.1 y3.0 - w23 v2 Nn16,n17 - """ - When running osm2pgsql pgsql with parameters - | --slim | -a | --latlong | --with-forward-dependencies=false | - - Then table planet_osm_point has 1 row - Then table planet_osm_line has 1 row - Then table planet_osm_line has 1 row with condition - """ - abs(ST_X(ST_StartPoint(way)) - 3.0) < 0.0001 - """ - Then table planet_osm_line has 0 rows with condition - """ - abs(ST_X(ST_StartPoint(way)) - 3.1) < 0.0001 - """ - Then table planet_osm_roads has 1 row - Then table planet_osm_polygon has 2 rows - diff --git a/tests/bdd/regression/gazetteer.feature b/tests/bdd/regression/gazetteer.feature deleted file mode 100644 index 1bda297cf..000000000 --- a/tests/bdd/regression/gazetteer.feature +++ /dev/null @@ -1,60 +0,0 @@ -Feature: Basic tests of the gazetter output - - Background: - Given the input file 'liechtenstein-2013-08-03.osm.pbf' - And the style file 'gazetteer-test.style' - - Scenario: - When running osm2pgsql gazetteer with parameters - | --slim| - - Then table place has 2836 rows - And table place has 759 rows with condition - """ - osm_type = 'N' - """ - And table place has 2059 rows with condition - """ - osm_type = 'W' - """ - And table place has 18 rows with condition - """ - osm_type = 'R' - """ - And table place has 199 rows with condition - """ - address ? 'housenumber' - """ - And table place has 319 rows with condition - """ - address is not null - """ - - Given the input file '000466354.osc.gz' - When running osm2pgsql gazetteer with parameters - | -a | - | --slim| - - - Then table place has 2877 rows - And table place has 764 rows with condition - """ - osm_type = 'N' - """ - And table place has 2095 rows with condition - """ - osm_type = 'W' - """ - And table place has 18 rows with condition - """ - osm_type = 'R' - """ - And table place has 199 rows with condition - """ - address ? 'housenumber' - """ - And table place has 319 rows with condition - """ - address is not null - """ - diff --git a/tests/bdd/steps/steps_execute.py b/tests/bdd/steps/steps_execute.py index f04ee3efa..68ea46cef 100644 --- a/tests/bdd/steps/steps_execute.py +++ b/tests/bdd/steps/steps_execute.py @@ -38,7 +38,7 @@ def get_import_file(context): def run_osm2pgsql(context, output): - assert output in ('flex', 'pgsql', 'gazetteer', 'null', 'nooutput') + assert output in ('flex', 'pgsql', 'null', 'nooutput') cmdline = [str(Path(context.config.userdata['BINARY']).resolve())] diff --git a/tests/common-import.hpp b/tests/common-import.hpp index 9fc7bb325..19f170449 100644 --- a/tests/common-import.hpp +++ b/tests/common-import.hpp @@ -146,9 +146,7 @@ class import_t middle->set_requirements(output->get_requirements()); auto dependency_manager = - options.with_forward_dependencies - ? std::make_unique(middle) - : std::make_unique(); + std::make_unique(middle); osmdata_t osmdata{std::move(dependency_manager), middle, output, options}; diff --git a/tests/common-options.hpp b/tests/common-options.hpp index ac9691ecb..adcc0bef3 100644 --- a/tests/common-options.hpp +++ b/tests/common-options.hpp @@ -56,13 +56,6 @@ class opt_t return *this; } - opt_t &gazetteer() - { - m_opt.output_backend = "gazetteer"; - m_opt.style = TESTDATA_DIR "gazetteer-test.style"; - return *this; - } - opt_t &flex(char const *style) { m_opt.output_backend = "flex"; diff --git a/tests/data/gazetteer-test.style b/tests/data/gazetteer-test.style deleted file mode 100644 index 0b0e14e89..000000000 --- a/tests/data/gazetteer-test.style +++ /dev/null @@ -1,237 +0,0 @@ -[ -{ - "keys" : ["*source"], - "values" : { - "" : "skip" - } -}, -{ - "keys" : ["name:prefix", "name:suffix", "name:botanical", "wikidata", - "*:wikidata"], - "values" : { - "" : "extra" - } -}, -{ - "keys" : ["ref", "int_ref", "nat_ref", "reg_ref", "loc_ref", "old_ref", - "iata", "icao", "pcode", "pcode:*"], - "values" : { - "" : "ref" - } -}, -{ - "keys" : ["name", "name:*", "int_name", "int_name:*", "nat_name", "nat_name:*", - "reg_name", "reg_name:*", "loc_name", "loc_name:*", - "old_name", "old_name:*", "alt_name", "alt_name:*", "alt_name_*", - "official_name", "official_name:*", "place_name", "place_name:*", - "short_name", "short_name:*", "brand"], - "values" : { - "" : "name" - } -}, -{ - "keys" : ["addr:housename"], - "values" : { - "" : "name,house" - } -}, -{ - "keys" : ["emergency"], - "values" : { - "fire_hydrant" : "skip", - "yes" : "skip", - "no" : "skip", - "" : "main" - } -}, -{ - "keys" : ["historic", "military"], - "values" : { - "no" : "skip", - "yes" : "skip", - "" : "main" - } -}, -{ - "keys" : ["natural"], - "values" : { - "yes" : "skip", - "no" : "skip", - "coastline" : "skip", - "" : "main,with_name" - } -}, -{ - "keys" : ["landuse"], - "values" : { - "cemetry" : "main,with_name", - "" : "main,fallback,with_name" - } -}, -{ - "keys" : ["highway"], - "values" : { - "no" : "skip", - "turning_circle" : "skip", - "mini_roundabout" : "skip", - "noexit" : "skip", - "crossing" : "skip", - "traffic_signals" : "main,with_name", - "service" : "main,with_name", - "cycleway" : "main,with_name", - "path" : "main,with_name", - "footway" : "main,with_name", - "steps" : "main,with_name", - "bridleway" : "main,with_name", - "track" : "main,with_name", - "byway": "main,with_name", - "motorway_link" : "main,with_name", - "trunk_link" : "main,with_name", - "primary_link" : "main,with_name", - "secondary_link" : "main,with_name", - "tertiary_link" : "main,with_name", - "" : "main" - } -}, -{ - "keys" : ["railway"], - "values" : { - "level_crossing" : "skip", - "no" : "skip", - "" : "main,with_name" - } -}, -{ - "keys" : ["man_made"], - "values" : { - "survey_point" : "skip", - "cutline" : "skip", - "" : "main" - } -}, -{ - "keys" : ["aerialway"], - "values" : { - "pylon" : "skip", - "no" : "skip", - "" : "main" - } -}, -{ - "keys" : ["boundary"], - "values" : { - "" : "main,with_name" - } -}, -{ - "keys" : ["amenity"], - "values" : { - "restaurant" : "main,operator", - "fuel" : "main,operator" - } -}, -{ - "keys" : ["aeroway", "amenity", "club", "craft", "leisure", - "office", "mountain_pass"], - "values" : { - "no" : "skip", - "" : "main" - } -}, -{ - "keys" : ["shop"], - "values" : { - "no" : "skip", - "" : "main,operator" - } -}, -{ - "keys" : ["tourism"], - "values" : { - "yes" : "skip", - "no" : "skip", - "" : "main,operator" - } -}, -{ - "keys" : ["bridge", "tunnel"], - "values" : { - "" : "main,with_name_key,extra" - } -}, -{ - "keys" : ["waterway"], - "values" : { - "riverbank" : "skip", - "" : "main,with_name" - } -}, -{ - "keys" : ["place"], - "values" : { - "" : "main" - } -}, -{ - "keys" : ["junction"], - "values" : { - "" : "main,fallback,with_name" - } -}, -{ - "keys" : ["postal_code", "postcode", "addr:postcode", - "tiger:zip_left", "tiger:zip_right"], - "values" : { - "" : "postcode,fallback" - } -}, -{ - "keys" : ["country_code", "ISO3166-1", "is_in:country_code", - "addr:country", "addr:country", "addr:country_code"], - "values" : { - "" : "country" - } -}, -{ - "keys" : ["addr:housenumber", "addr:conscriptionnumber", "addr:streetnumber"], - "values" : { - "" : "address,house" - } -}, -{ - "keys" : ["addr:interpolation"], - "values" : { - "" : "interpolation,address" - } -}, -{ - "keys" : ["addr:*", "is_in:*", "tiger:county", "is_in"], - "values" : { - "" : "address" - } -}, -{ - "keys" : ["building"], - "values" : { - "no" : "skip", - "" : "main,fallback,with_name" - } -}, -{ - "keys" : ["note", "note:*", "source", "source*", "attribution", - "comment", "fixme", "FIXME", "created_by", "tiger:*", "NHD:*", - "nhd:*", "gnis:*", "geobase:*", "KSJ2:*", "yh:*", - "osak:*", "naptan:*", "CLC:*", "import", "it:fvg:*", - "type", "lacounty:*", "ref:ruian:*", "building:ruian:type", - "ref:linz:*"], - "values" : { - "" : "skip" - } -}, -{ - "keys" : [""], - "values" : { - "" : "extra" - } -} -] diff --git a/tests/test-db-copy-thread.cpp b/tests/test-db-copy-thread.cpp index 9cfd30c61..3e6ed2d65 100644 --- a/tests/test-db-copy-thread.cpp +++ b/tests/test-db-copy-thread.cpp @@ -11,7 +11,6 @@ #include "common-pg.hpp" #include "db-copy.hpp" -#include "gazetteer-style.hpp" static testing::pg::tempdb_t db; @@ -146,97 +145,3 @@ TEST_CASE("db_copy_thread_t with db_deleter_by_id_t") REQUIRE(table_count(conn, "WHERE id = 12") == 1); } } - -TEST_CASE("db_copy_thread_t with db_deleter_place_t") -{ - auto const conn = db.connect(); - conn.exec("DROP TABLE IF EXISTS test_copy_thread"); - conn.exec("CREATE TABLE test_copy_thread (" - "osm_type char(1)," - "osm_id bigint," - "class text)"); - - auto table = std::make_shared( - "public", "test_copy_thread", "place_id"); - - db_copy_thread_t t{db.connection_params()}; - using cmd_copy_t = db_cmd_copy_delete_t; - auto cmd = std::make_unique(table); - - SECTION("simple delete") - { - cmd->buffer += "N\t42\tbuilding\n" - "N\t43\tbuilding\n" - "W\t42\thighway\n" - "R\t42\twaterway\n"; - - t.add_buffer(std::unique_ptr(cmd.release())); - t.sync_and_wait(); - - cmd = std::make_unique(table); - - SECTION("full delete of existing rows") - { - cmd->add_deletable('N', 42); - cmd->add_deletable('R', 42); - - t.add_buffer(std::unique_ptr(cmd.release())); - t.sync_and_wait(); - - REQUIRE(table_count(conn, "WHERE osm_type = 'N'" - " and osm_id = 42") == 0); - REQUIRE(table_count(conn, "WHERE osm_type = 'N'" - " and osm_id = 43") == 1); - REQUIRE(table_count(conn, "WHERE osm_type = 'W'" - " and osm_id = 42") == 1); - REQUIRE(table_count(conn, "WHERE osm_type = 'R'" - " and osm_id = 42") == 0); - } - - SECTION("partial delete of existing rows") - { - cmd->add_deletable('N', 42, "'road','building','amenity'"); - cmd->add_deletable('R', 42, "'road','building','amenity'"); - - t.add_buffer(std::unique_ptr(cmd.release())); - t.sync_and_wait(); - - REQUIRE(table_count(conn, "WHERE osm_type = 'N'" - " and osm_id = 42") == 1); - REQUIRE(table_count(conn, "WHERE osm_type = 'N'" - " and osm_id = 43") == 1); - REQUIRE(table_count(conn, "WHERE osm_type = 'W'" - " and osm_id = 42") == 1); - REQUIRE(table_count(conn, "WHERE osm_type = 'R'" - " and osm_id = 42") == 0); - } - - SECTION("delete one add another id") - { - cmd->add_deletable('R', 42); - cmd->buffer += "W\t43\tamenity\n"; - - t.add_buffer(std::unique_ptr(cmd.release())); - t.sync_and_wait(); - - REQUIRE(table_count(conn, "WHERE osm_type = 'R'" - " and osm_id = 42") == 0); - REQUIRE(table_count(conn, "WHERE osm_type = 'W'" - " and osm_id = 43") == 1); - } - - SECTION("delete one add another class type") - { - cmd->add_deletable('W', 42, "'amenity'"); - cmd->buffer += "W\t42\tamenity\n"; - - t.add_buffer(std::unique_ptr(cmd.release())); - t.sync_and_wait(); - - REQUIRE(table_count(conn, "WHERE osm_type = 'W' and osm_id = 42" - " and class = 'highway'") == 0); - REQUIRE(table_count(conn, "WHERE osm_type = 'W' and osm_id = 42" - " and class = 'amenity'") == 1); - } - } -} diff --git a/tests/test-options-parse.cpp b/tests/test-options-parse.cpp index 33518890e..be9b4971f 100644 --- a/tests/test-options-parse.cpp +++ b/tests/test-options-parse.cpp @@ -193,19 +193,3 @@ TEST_CASE("Parsing log-progress fails for unknown value", "[NoDB]") bad_opt({"--log-progress", "foo"}, "Unknown value for --log-progress option: "); } - -TEST_CASE("Parsing with-forward-dependencies", "[NoDB]") -{ - auto const opt1 = opt({"--with-forward-dependencies", "true"}); - CHECK(opt1.with_forward_dependencies); - - auto const opt2 = opt({"--with-forward-dependencies", "false"}); - CHECK_FALSE(opt2.with_forward_dependencies); -} - -TEST_CASE("Parsing with-forward-dependencies fails for unknown value", "[NoDB]") -{ - bad_opt({"--with-forward-dependencies", "foo"}, - "Unknown value for" - " --with-forward-dependencies option: "); -} diff --git a/tests/test-output-gazetteer.cpp b/tests/test-output-gazetteer.cpp deleted file mode 100644 index c18ce95d9..000000000 --- a/tests/test-output-gazetteer.cpp +++ /dev/null @@ -1,792 +0,0 @@ -/** - * SPDX-License-Identifier: GPL-2.0-or-later - * - * This file is part of osm2pgsql (https://osm2pgsql.org/). - * - * Copyright (C) 2006-2024 by the osm2pgsql developer community. - * For a full list of authors see the git log. - */ - -#include - -#include -#include -#include - -#include "common-import.hpp" -#include "common-options.hpp" - -static testing::db::import_t db; - -// Use a random device with a fixed seed. We don't really care about -// the quality of random numbers here, we just need to generate valid -// OSM test data. The fixed seed ensures that the results are reproducible. -static std::mt19937_64 rng{47382}; // NOLINT(cert-msc32-c,cert-msc51-cpp) - -class node_opl_t -{ -public: - void add(osmid_t id, char const *tags) - { - std::uniform_real_distribution dist{-90, 89.99}; - - fmt::format_to(std::back_inserter(m_opl), "n{} T{} x{} y{}\n", id, tags, - 2 * dist(rng), dist(rng)); - } - - void del(osmid_t id) - { - fmt::format_to(std::back_inserter(m_opl), "n{} v2 dD\n", id); - } - - std::string get_and_clear_opl() - { - std::string ret = fmt::to_string(m_opl); - m_opl.clear(); - return ret; - } - - static char type() noexcept { return 'N'; } - -private: - fmt::memory_buffer m_opl; -}; - -class way_opl_t -{ -public: - void add(osmid_t id, char const *tags) - { - osmid_t const first_node = m_current_node_id; - osmid_t const last_node = make_nodes(); - - fmt::format_to(std::back_inserter(m_way_opl), "w{} T{} N", id, tags); - for (osmid_t i = first_node; i <= last_node; ++i) { - fmt::format_to(std::back_inserter(m_way_opl), "n{}{}", i, - i == last_node ? '\n' : ','); - } - } - - void del(osmid_t id) - { - fmt::format_to(std::back_inserter(m_way_opl), "w{} v2 dD\n", id); - } - - std::string get_and_clear_opl() - { - std::string final_opl = fmt::to_string(m_node_opl); - final_opl += fmt::to_string(m_way_opl); - - m_node_opl.clear(); - m_way_opl.clear(); - - return final_opl; - } - - static char type() noexcept { return 'W'; } - -private: - osmid_t make_nodes() - { - std::uniform_int_distribution intdist{2, 8}; - unsigned const num_nodes = intdist(rng); - - // compute the start point, all points afterwards are relative - std::uniform_real_distribution dist{-89.9, 89.9}; - double x = 2 * dist(rng); - double y = dist(rng); - - std::uniform_real_distribution diff_dist{-0.01, 0.01}; - for (unsigned i = 0; i < num_nodes; ++i) { - fmt::format_to(std::back_inserter(m_node_opl), "n{} x{} y{}\n", - m_current_node_id++, x, y); - double diffx = 0.0; - double diffy = 0.0; - do { - diffx = diff_dist(rng); - diffy = diff_dist(rng); - } while (diffx == 0.0 && diffy == 0.0); - x += diffx; - y += diffy; - } - - return m_current_node_id - 1; - } - - osmid_t m_current_node_id = 100; - fmt::memory_buffer m_node_opl; - fmt::memory_buffer m_way_opl; -}; - -class relation_opl_t -{ -public: - void add(osmid_t id, char const *tags) - { - osmid_t const first_node = m_current_node_id; - osmid_t const last_node = make_nodes(); - - // create a very simple multipolygon with one closed way - fmt::format_to(std::back_inserter(m_way_opl), "w{} N", id, tags); - for (osmid_t i = first_node; i <= last_node; ++i) { - fmt::format_to(std::back_inserter(m_way_opl), "n{},", i); - } - fmt::format_to(std::back_inserter(m_way_opl), "n{}\n", first_node); - - fmt::format_to(std::back_inserter(m_rel_opl), - "r{} Ttype=multipolygon,{} Mw{}@\n", id, tags, id); - } - - void del(osmid_t id) - { - fmt::format_to(std::back_inserter(m_rel_opl), "r{} v2 dD\n", id); - } - - std::string get_and_clear_opl() - { - std::string final_opl = fmt::to_string(m_node_opl); - final_opl += fmt::to_string(m_way_opl); - final_opl += fmt::to_string(m_rel_opl); - - m_node_opl.clear(); - m_way_opl.clear(); - m_rel_opl.clear(); - - return final_opl; - } - - static char type() noexcept { return 'R'; } - -private: - osmid_t make_nodes() - { - // compute a centre points and compute four corners from this - std::uniform_real_distribution dist{-89.9, 89.9}; - double const x = 2 * dist(rng); - double const y = dist(rng); - - std::uniform_real_distribution diff_dist{0.0000001, 0.01}; - - fmt::format_to(std::back_inserter(m_node_opl), "n{} x{} y{}\n", - m_current_node_id++, x - diff_dist(rng), - y - diff_dist(rng)); - fmt::format_to(std::back_inserter(m_node_opl), "n{} x{} y{}\n", - m_current_node_id++, x - diff_dist(rng), - y + diff_dist(rng)); - fmt::format_to(std::back_inserter(m_node_opl), "n{} x{} y{}\n", - m_current_node_id++, x + diff_dist(rng), - y + diff_dist(rng)); - fmt::format_to(std::back_inserter(m_node_opl), "n{} x{} y{}\n", - m_current_node_id++, x + diff_dist(rng), - y - diff_dist(rng)); - - return m_current_node_id - 1; - } - - osmid_t m_current_node_id = 100; - fmt::memory_buffer m_node_opl; - fmt::memory_buffer m_way_opl; - fmt::memory_buffer m_rel_opl; -}; - -using hstore_item = std::pair; -using hstore_list = std::vector; - -template -class gazetteer_fixture_t -{ -public: - void add(osmid_t id, char const *tags) { m_opl_factory.add(id, tags); } - - void del(osmid_t id) { m_opl_factory.del(id); } - - void import() - { - std::string const opl = m_opl_factory.get_and_clear_opl(); - REQUIRE_NOTHROW( - db.run_import(testing::opt_t().gazetteer().slim(), opl.c_str())); - } - - void update() - { - auto const opt = testing::opt_t().gazetteer().slim().append(); - std::string const opl = m_opl_factory.get_and_clear_opl(); - REQUIRE_NOTHROW(db.run_import(opt, opl.c_str())); - } - - int obj_count(testing::pg::conn_t const &conn, osmid_t id, char const *cls) - { - char const tchar = m_opl_factory.type(); - return conn.get_count("place", fmt::format("osm_type = '{}' AND" - " osm_id = {} AND" - " class = '{}'", - tchar, id, cls)); - } - - void obj_names(testing::pg::conn_t const &conn, osmid_t id, char const *cls, - hstore_list const &names) - { - hstore_compare(conn, id, cls, "name", names); - } - - void obj_address(testing::pg::conn_t const &conn, osmid_t id, - char const *cls, hstore_list const &names) - { - hstore_compare(conn, id, cls, "address", names); - } - - void obj_extratags(testing::pg::conn_t const &conn, osmid_t id, - char const *cls, hstore_list const &names) - { - hstore_compare(conn, id, cls, "extratags", names); - } - - std::string obj_field(testing::pg::conn_t const &conn, osmid_t id, - char const *cls, char const *column) - { - char const tchar = m_opl_factory.type(); - return conn.result_as_string(fmt::format( - "SELECT {} FROM place WHERE osm_type = '{}' AND osm_id = {}" - " AND class = '{}'", - column, tchar, id, cls)); - } - -private: - void hstore_compare(testing::pg::conn_t const &conn, osmid_t id, - char const *cls, char const *column, - hstore_list const &names) - { - char const tchar = m_opl_factory.type(); - auto const res = conn.exec("SELECT skeys({}), svals({}) FROM place" - " WHERE osm_type = '{}' AND " - " osm_id = {} AND class = '{}'", - column, column, tchar, id, cls); - - hstore_list actual; - for (int i = 0; i < res.num_tuples(); ++i) { - actual.emplace_back(res.get_value(i, 0), res.get_value(i, 1)); - } - - CHECK_THAT(actual, Catch::Matchers::UnorderedEquals(names)); - } - - T m_opl_factory; -}; - -namespace Catch { -template <> -struct StringMaker -{ - static std::string convert(hstore_item const &value) - { - return fmt::format("({}, {})", std::get<0>(value), std::get<1>(value)); - } -}; -} // namespace Catch - -using node_importer_t = gazetteer_fixture_t; -using way_importer_t = gazetteer_fixture_t; -using relation_importer_t = gazetteer_fixture_t; - -TEMPLATE_TEST_CASE("Main tags", "", node_importer_t, way_importer_t, - relation_importer_t) -{ - TestType t; - - SECTION("Import main tags as fallback") - { - t.add(100, "junction=yes,highway=bus_stop"); - t.add(101, "junction=yes,name=Bar"); - t.add(200, "building=yes,amenity=cafe"); - t.add(201, "building=yes,name=Intersting"); - t.add(202, "building=yes"); - - t.import(); - - auto conn = db.connect(); - - CHECK(0 == t.obj_count(conn, 100, "junction")); - CHECK(1 == t.obj_count(conn, 101, "junction")); - CHECK(0 == t.obj_count(conn, 200, "building")); - CHECK(1 == t.obj_count(conn, 201, "building")); - CHECK(0 == t.obj_count(conn, 202, "building")); - } - - SECTION("Main tag deleted") - { - t.add(1, "amenity=restaurant"); - t.add(2, "highway=bus_stop,railway=stop,name=X"); - t.add(3, "amenity=prison"); - - t.import(); - - auto conn = db.connect(); - - CHECK(1 == t.obj_count(conn, 1, "amenity")); - CHECK(1 == t.obj_count(conn, 2, "highway")); - CHECK(1 == t.obj_count(conn, 2, "railway")); - CHECK(1 == t.obj_count(conn, 3, "amenity")); - - t.add(1, "not_a=restaurant"); - t.add(2, "highway=bus_stop,name=X"); - t.del(3); - - t.update(); - - CHECK(0 == t.obj_count(conn, 1, "amenity")); - CHECK(2 == t.obj_count(conn, 2, "highway")); - CHECK(0 == t.obj_count(conn, 2, "railway")); - CHECK(0 == t.obj_count(conn, 3, "amenity")); - } - - SECTION("Main tag added") - { - t.add(1, "atiy=restaurant"); - t.add(2, "highway=bus_stop,name=X"); - - t.import(); - - auto conn = db.connect(); - - CHECK(0 == t.obj_count(conn, 1, "amenity")); - CHECK(1 == t.obj_count(conn, 2, "highway")); - CHECK(0 == t.obj_count(conn, 2, "railway")); - CHECK(0 == t.obj_count(conn, 3, "amenity")); - - t.add(1, "amenity=restaurant"); - t.add(2, "highway=bus_stop,railway=stop,name=X"); - t.add(3, "amenity=prison"); - - t.update(); - - CHECK(1 == t.obj_count(conn, 1, "amenity")); - CHECK(2 == t.obj_count(conn, 2, "highway")); - CHECK(1 == t.obj_count(conn, 2, "railway")); - CHECK(1 == t.obj_count(conn, 3, "amenity")); - } - - SECTION("Main tag modified") - { - t.add(10, "highway=footway,name=X"); - t.add(11, "amenity=atm"); - - t.import(); - - auto conn = db.connect(); - - CHECK(1 == t.obj_count(conn, 10, "highway")); - CHECK(1 == t.obj_count(conn, 11, "amenity")); - - t.add(10, "highway=path,name=X"); - t.add(11, "highway=primary"); - - t.update(); - - CHECK(2 == t.obj_count(conn, 10, "highway")); - CHECK(0 == t.obj_count(conn, 11, "amenity")); - CHECK(1 == t.obj_count(conn, 11, "highway")); - } - - SECTION("Main tags with name, name added") - { - t.add(45, "landuse=cemetry"); - t.add(46, "building=yes"); - - t.import(); - - auto conn = db.connect(); - - CHECK(0 == t.obj_count(conn, 45, "landuse")); - CHECK(0 == t.obj_count(conn, 46, "building")); - - t.add(45, "landuse=cemetry,name=TODO"); - t.add(46, "building=yes,addr:housenumber=1"); - - t.update(); - - CHECK(1 == t.obj_count(conn, 45, "landuse")); - CHECK(1 == t.obj_count(conn, 46, "building")); - } - - SECTION("Main tags with name, name removed") - { - t.add(45, "landuse=cemetry,name=TODO"); - t.add(46, "building=yes,addr:housenumber=1"); - - t.import(); - - auto conn = db.connect(); - - CHECK(1 == t.obj_count(conn, 45, "landuse")); - CHECK(1 == t.obj_count(conn, 46, "building")); - - t.add(45, "landuse=cemetry"); - t.add(46, "building=yes"); - - t.update(); - - CHECK(0 == t.obj_count(conn, 45, "landuse")); - CHECK(0 == t.obj_count(conn, 46, "building")); - } - - SECTION("Main tags with name, name modified") - { - t.add(45, "landuse=cemetry,name=TODO"); - t.add(46, "building=yes,addr:housenumber=1"); - - t.import(); - - auto conn = db.connect(); - - CHECK(1 == t.obj_count(conn, 45, "landuse")); - CHECK(1 == t.obj_count(conn, 46, "building")); - - t.add(45, "landuse=cemetry,name=DONE"); - t.add(46, "building=yes,addr:housenumber=10"); - - t.update(); - - CHECK(2 == t.obj_count(conn, 45, "landuse")); - CHECK(2 == t.obj_count(conn, 46, "building")); - } - - SECTION("Main tag added to address only node") - { - t.add(1, "addr:housenumber=345"); - - t.import(); - - auto conn = db.connect(); - - CHECK(1 == t.obj_count(conn, 1, "place")); - CHECK(0 == t.obj_count(conn, 1, "building")); - - t.add(1, "addr:housenumber=345,building=yes"); - - t.update(); - - CHECK(0 == t.obj_count(conn, 1, "place")); - CHECK(1 == t.obj_count(conn, 1, "building")); - } - - SECTION("Main tag removed from address only node") - { - t.add(1, "addr:housenumber=345,building=yes"); - - t.import(); - - auto conn = db.connect(); - - CHECK(0 == t.obj_count(conn, 1, "place")); - CHECK(1 == t.obj_count(conn, 1, "building")); - - t.add(1, "addr:housenumber=345"); - - t.update(); - - CHECK(1 == t.obj_count(conn, 1, "place")); - CHECK(0 == t.obj_count(conn, 1, "building")); - } - - SECTION("Main tags with name key, adding key name") - { - t.add(22, "bridge=yes"); - - t.import(); - - auto conn = db.connect(); - - CHECK(0 == t.obj_count(conn, 22, "bridge")); - - t.add(22, "bridge=yes,bridge:name=high"); - - t.update(); - - CHECK(1 == t.obj_count(conn, 22, "bridge")); - } - - SECTION("Main tags with name key, deleting key name") - { - t.add(22, "bridge=yes,bridge:name=high"); - - t.import(); - - auto conn = db.connect(); - - CHECK(1 == t.obj_count(conn, 22, "bridge")); - - t.add(22, "bridge=yes"); - - t.update(); - - CHECK(0 == t.obj_count(conn, 22, "bridge")); - } - - SECTION("Main tags with name key, changing key name") - { - t.add(22, "bridge=yes,bridge:name=high"); - - t.import(); - - auto conn = db.connect(); - - CHECK(1 == t.obj_count(conn, 22, "bridge")); - - t.add(22, "bridge=yes,bridge:name:en=high"); - - t.update(); - - CHECK(2 == t.obj_count(conn, 22, "bridge")); - } -} - -TEST_CASE("Operator tag") -{ - node_importer_t t; - - t.add(1001, "amenity=restaurant,operator=McDo"); - t.add(1002, "amenity=prison,operator=police"); - - t.import(); - - auto conn = db.connect(); - - t.obj_names(conn, 1001, "amenity", {{"operator", "McDo"}}); - t.obj_names(conn, 1002, "amenity", {}); -} - -TEST_CASE("Name and reg tags") -{ - node_importer_t t; - - t.add(2001, "highway=road,name=Foo,alt_name:de=Bar,ref=45"); - t.add(2002, "highway=road,name:prefix=Pre,name:suffix=Post,ref:de=55"); - t.add(2003, "highway=yes,name:%20%de=Foo,name=real1"); - t.add(2004, "highway=yes,name:%a%de=Foo,name=real2"); - t.add(2005, "highway=yes,name:%9%de=Foo,name:\\\\=real3"); - t.add(2006, "highway=yes,name:%9%de=Foo,name=rea\\l3"); - - t.import(); - - auto conn = db.connect(); - - t.obj_names(conn, 2001, "highway", - {{"name", "Foo"}, {"alt_name:de", "Bar"}, {"ref", "45"}}); - t.obj_names(conn, 2002, "highway", {}); - t.obj_extratags( - conn, 2002, "highway", - {{"name:prefix", "Pre"}, {"name:suffix", "Post"}, {"ref:de", "55"}}); - t.obj_names(conn, 2003, "highway", - {{"name: de", "Foo"}, {"name", "real1"}}); - t.obj_names(conn, 2004, "highway", - {{"name:\nde", "Foo"}, {"name", "real2"}}); - t.obj_names(conn, 2005, "highway", - {{"name:\tde", "Foo"}, {"name:\\\\", "real3"}}); - t.obj_names(conn, 2006, "highway", - {{"name:\tde", "Foo"}, {"name", "rea\\l3"}}); -} - -TEST_CASE("Name when using with_name flag") -{ - node_importer_t t; - - t.add(3001, "bridge=yes,bridge:name=GoldenGate"); - t.add(3002, "bridge=yes,bridge:name:en=Rainbow"); - - t.import(); - - auto conn = db.connect(); - - t.obj_names(conn, 3001, "bridge", {{"name", "GoldenGate"}}); - t.obj_names(conn, 3002, "bridge", {{"name:en", "Rainbow"}}); -} - -TEST_CASE("Address tags") -{ - node_importer_t t; - - t.add(4001, "addr:housenumber=34,addr:city=Esmarald,addr:county=Land"); - t.add(4002, "addr:streetnumber=10,is_in:city=Rootoo,is_in=Gold"); - - t.import(); - - auto conn = db.connect(); - - t.obj_address( - conn, 4001, "place", - {{"housenumber", "34"}, {"city", "Esmarald"}, {"county", "Land"}}); - t.obj_address( - conn, 4002, "place", - {{"streetnumber", "10"}, {"city", "Rootoo"}, {"is_in", "Gold"}}); -} - -TEST_CASE("Country codes") -{ - node_importer_t t; - - t.add(5001, "shop=yes,country_code=DE"); - t.add(5002, "shop=yes,country_code=toolong"); - t.add(5003, "shop=yes,country_code=x"); - t.add(5004, "shop=yes,addr:country=us"); - t.add(5005, "shop=yes,is_in:country=be"); - - t.import(); - - auto conn = db.connect(); - - t.obj_address(conn, 5001, "shop", {{"country", "DE"}}); - t.obj_address(conn, 5002, "shop", {}); - t.obj_address(conn, 5003, "shop", {}); - t.obj_address(conn, 5004, "shop", {{"country", "us"}}); - t.obj_address(conn, 5005, "shop", {}); -} - -TEST_CASE("Postcodes") -{ - node_importer_t t; - - t.add(6001, "shop=bank,addr:postcode=12345"); - t.add(6002, "shop=bank,tiger:zip_left=34343"); - t.add(6003, "shop=bank,is_in:postcode=9009"); - - t.import(); - - auto conn = db.connect(); - - t.obj_address(conn, 6001, "shop", {{"postcode", "12345"}}); - t.obj_address(conn, 6002, "shop", {{"postcode", "34343"}}); - t.obj_address(conn, 6003, "shop", {}); -} - -TEST_CASE("Main with extra") -{ - way_importer_t t; - - t.add(7001, "highway=primary,bridge=yes,name=1"); - - t.import(); - - auto conn = db.connect(); - - t.obj_extratags(conn, 7001, "highway", {{"bridge", "yes"}}); -} - -TEST_CASE("Global fallback and skipping") -{ - node_importer_t t; - - t.add(8001, "shop=shoes,note:de=Nein,xx=yy"); - t.add(8002, "shop=shoes,building=no,ele=234"); - t.add(8003, "shop=shoes,name:source=survey"); - - t.import(); - - auto conn = db.connect(); - - t.obj_extratags(conn, 8001, "shop", {{"xx", "yy"}}); - t.obj_extratags(conn, 8002, "shop", {{"ele", "234"}}); - t.obj_extratags(conn, 8003, "shop", {}); -} - -TEST_CASE("Admin levels") -{ - node_importer_t t; - - t.add(9001, "place=city"); - t.add(9002, "place=city,admin_level=16"); - t.add(9003, "place=city,admin_level=x"); - t.add(9004, "place=city,admin_level=1"); - t.add(9005, "place=city,admin_level=0"); - t.add(9006, "place=city,admin_level=2.5"); - - t.import(); - - auto conn = db.connect(); - - CHECK("15" == t.obj_field(conn, 9001, "place", "admin_level")); - CHECK("15" == t.obj_field(conn, 9002, "place", "admin_level")); - CHECK("15" == t.obj_field(conn, 9003, "place", "admin_level")); - CHECK("1" == t.obj_field(conn, 9004, "place", "admin_level")); - CHECK("15" == t.obj_field(conn, 9005, "place", "admin_level")); - CHECK("15" == t.obj_field(conn, 9006, "place", "admin_level")); -} - -TEST_CASE("Administrative boundaries with place tags") -{ - relation_importer_t t; - - t.add(10001, "boundary=administrative,place=city,name=A"); - t.add(10002, "boundary=natural,place=city,name=B"); - t.add(10003, "boundary=administrative,place=island,name=C"); - - t.import(); - - auto conn = db.connect(); - - CHECK(1 == t.obj_count(conn, 10001, "boundary")); - CHECK(0 == t.obj_count(conn, 10001, "place")); - t.obj_extratags(conn, 10001, "boundary", {{"place", "city"}}); - CHECK(1 == t.obj_count(conn, 10002, "boundary")); - CHECK(1 == t.obj_count(conn, 10002, "place")); - t.obj_extratags(conn, 10002, "boundary", {}); - CHECK(1 == t.obj_count(conn, 10003, "boundary")); - CHECK(1 == t.obj_count(conn, 10003, "place")); - t.obj_extratags(conn, 10003, "boundary", {}); -} - -TEST_CASE("Shorten tiger:county tags") -{ - node_importer_t t; - - t.add(11001, "place=village,tiger:county=Feebourgh%2c%%20%AL"); - t.add(11002, - "place=village,addr:state=Alabama,tiger:county=Feebourgh%2c%%20%AL"); - t.add(11003, "place=village,tiger:county=Feebourgh"); - - t.import(); - - auto conn = db.connect(); - - t.obj_address(conn, 11001, "place", {{"tiger:county", "Feebourgh county"}}); - t.obj_address(conn, 11002, "place", - {{"tiger:county", "Feebourgh county"}, {"state", "Alabama"}}); - t.obj_address(conn, 11003, "place", {{"tiger:county", "Feebourgh county"}}); -} - -TEST_CASE("Building fallbacks") -{ - node_importer_t t; - - t.add(12001, "tourism=hotel,building=yes"); - t.add(12002, "building=house"); - t.add(12003, "building=shed,addr:housenumber=1"); - t.add(12004, "building=yes,name=Das-Haus"); - t.add(12005, "building=yes,addr:postcode=12345"); - - t.import(); - - auto conn = db.connect(); - - CHECK("hotel" == t.obj_field(conn, 12001, "tourism", "type")); - CHECK(0 == t.obj_count(conn, 12001, "building")); - CHECK(0 == t.obj_count(conn, 12002, "building")); - CHECK("shed" == t.obj_field(conn, 12003, "building", "type")); - CHECK("yes" == t.obj_field(conn, 12004, "building", "type")); - CHECK("postcode" == t.obj_field(conn, 12005, "place", "type")); -} - -TEST_CASE("Address interpolations") -{ - way_importer_t t; - - t.add(13001, "addr:interpolation=odd"); - t.add(13002, "addr:interpolation=even,place=city"); - - t.import(); - - auto conn = db.connect(); - - CHECK("houses" == t.obj_field(conn, 13001, "place", "type")); - CHECK("houses" == t.obj_field(conn, 13002, "place", "type")); - t.obj_extratags(conn, 13002, "place", {{"place", "city"}}); -}