1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
#include "output.hpp"
#include "output-pgsql.hpp"
#include "output-gazetteer.hpp"
#include "output-null.hpp"
#include "output-multi.hpp"
#include "taginfo_impl.hpp"
#include <string.h>
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/functional/hash.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
namespace pt = boost::property_tree;
namespace {
template <typename T>
void override_if(T &t, const std::string &key, const pt::ptree &conf) {
boost::optional<T> opt = conf.get_optional<T>(key);
if (opt) {
t = *opt;
}
}
std::shared_ptr<output_t> parse_multi_single(const pt::ptree &conf,
const middle_query_t *mid,
const options_t &options) {
options_t new_opts = options;
std::string name = conf.get<std::string>("name");
std::string proc_type = conf.get<std::string>("type");
new_opts.tag_transform_script = conf.get_optional<std::string>("tagtransform");
new_opts.tag_transform_node_func = conf.get_optional<std::string>("tagtransform-node-function");
new_opts.tag_transform_way_func = conf.get_optional<std::string>("tagtransform-way-function");
new_opts.tag_transform_rel_func = conf.get_optional<std::string>("tagtransform-relation-function");
new_opts.tag_transform_rel_mem_func = conf.get_optional<std::string>("tagtransform-relation-member-function");
new_opts.tblsmain_index = conf.get_optional<std::string>("tablespace-index");
new_opts.tblsmain_data = conf.get_optional<std::string>("tablespace-data");
override_if<int>(new_opts.hstore_mode, "enable-hstore", conf);
override_if<bool>(new_opts.enable_hstore_index, "enable-hstore-index", conf);
override_if<bool>(new_opts.enable_multi, "enable-multi", conf);
override_if<bool>(new_opts.hstore_match_only, "hstore-match-only", conf);
hstores_t hstore_columns;
boost::optional<const pt::ptree &> hstores = conf.get_child_optional("hstores");
if (hstores) {
for (const pt::ptree::value_type &val: *hstores) {
hstore_columns.push_back(val.second.get_value<std::string>());
}
}
new_opts.hstore_columns = hstore_columns;
std::shared_ptr<geometry_processor> processor =
geometry_processor::create(proc_type, &new_opts);
// TODO: we're faking this up, but there has to be a better way?
OsmType osm_type = ((processor->interests() & geometry_processor::interest_node) > 0)
? OSMTYPE_NODE : OSMTYPE_WAY;
export_list columns;
const pt::ptree &tags = conf.get_child("tags");
for (const pt::ptree::value_type &val: tags) {
const pt::ptree &tag = val.second;
taginfo info;
info.name = tag.get<std::string>("name");
info.type = tag.get<std::string>("type");
std::string flags = tag.get_optional<std::string>("flags").get_value_or(std::string());
// TODO: we fake the line number here - any way to get the right one
// from the JSON parser?
info.flags = parse_tag_flags(flags.c_str(), -1);
// TODO: shouldn't need to specify a type here?
columns.add(osm_type, info);
}
return std::make_shared<output_multi_t>(name, processor, columns, mid, new_opts);
}
std::vector<std::shared_ptr<output_t> > parse_multi_config(const middle_query_t *mid, const options_t &options) {
std::vector<std::shared_ptr<output_t> > outputs;
if (!options.style.empty()) {
const std::string file_name(options.style);
try {
pt::ptree conf;
pt::read_json(file_name, conf);
for (const pt::ptree::value_type &val: conf) {
outputs.push_back(parse_multi_single(val.second, mid, options));
}
} catch (const std::exception &e) {
throw std::runtime_error((boost::format("Unable to parse multi config file `%1%': %2%")
% file_name % e.what()).str());
}
} else {
throw std::runtime_error("Style file is required for `multi' backend, but was not specified.");
}
return outputs;
}
} // anonymous namespace
std::vector<std::shared_ptr<output_t> > output_t::create_outputs(const middle_query_t *mid, const options_t &options) {
std::vector<std::shared_ptr<output_t> > outputs;
if (options.output_backend == "pgsql") {
outputs.push_back(std::make_shared<output_pgsql_t>(mid, options));
} else if (options.output_backend == "gazetteer") {
outputs.push_back(std::make_shared<output_gazetteer_t>(mid, options));
} else if (options.output_backend == "null") {
outputs.push_back(std::make_shared<output_null_t>(mid, options));
} else if (options.output_backend == "multi") {
outputs = parse_multi_config(mid, options);
} else {
throw std::runtime_error((boost::format("Output backend `%1%' not recognised. Should be one of [pgsql, gazetteer, null, multi].\n") % options.output_backend).str());
}
return outputs;
}
output_t::output_t(const middle_query_t *mid_, const options_t &options_)
: m_mid(mid_), m_options(options_)
{}
output_t::~output_t() = default;
size_t output_t::pending_count() const
{
return 0;
}
const options_t *output_t::get_options() const
{
return &m_options;
}
void output_t::merge_pending_relations(output_t*) {}
void output_t::merge_expire_trees(output_t*) {}
|