Skip to content

Commit 4ae0d45

Browse files
committed
Added JSON diffResult
1 parent 39a4eec commit 4ae0d45

16 files changed

+173
-56
lines changed

include/cgimap/api06/changeset_upload/osmchange_json_input_format.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,15 @@ class OSMChangeJSONParser {
106106
m_callback.start_document();
107107
_parser.parse(data);
108108
_parser.finish();
109+
110+
if (_parser.parser().isEmpty()) {
111+
throw payload_error("Empty JSON payload");
112+
}
113+
114+
if (element_count == 0) {
115+
throw payload_error("osmChange array is empty");
116+
}
117+
109118
m_callback.end_document();
110119
} catch (const std::exception& e) {
111120
throw http::bad_request(e.what()); // rethrow JSON parser error as HTTP 400 Bad request
@@ -122,6 +131,8 @@ class OSMChangeJSONParser {
122131
// OSM element callback
123132
bool process_element(ElementsParser &parser) {
124133

134+
element_count++;
135+
125136
// process action
126137
process_action(parser);
127138

@@ -306,6 +317,7 @@ class OSMChangeJSONParser {
306317
operation m_operation = operation::op_undefined;
307318
Parser_Callback& m_callback;
308319
bool m_if_unused = false;
320+
int element_count = 0;
309321
};
310322

311323
} // namespace api06

include/cgimap/json_formatter.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class json_formatter : public output_formatter {
2323
private:
2424
std::unique_ptr<json_writer> writer;
2525
bool is_in_elements_array{false};
26+
bool is_in_diffresult_array{false};
2627

2728
void write_tags(const tags_t &tags);
2829
void write_id(const element_info &elem);
@@ -38,6 +39,7 @@ class json_formatter : public output_formatter {
3839
void end_document() override;
3940
void write_bounds(const bbox &bounds) override;
4041
void start_element_type(element_type type) override;
42+
void start_diffresult() override;
4143
void end_element_type(element_type type) override;
4244
void start_action(action_type type) override;
4345
void end_action(action_type type) override;
@@ -60,6 +62,7 @@ class json_formatter : public output_formatter {
6062
const osm_nwr_signed_id_t old_id,
6163
const osm_nwr_id_t new_id,
6264
const osm_version_t new_version) override;
65+
6366
void write_diffresult_delete(const element_type elem,
6467
const osm_nwr_signed_id_t old_id) override;
6568

include/cgimap/osm_diffresult_responder.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class osm_diffresult_responder : public osm_responder {
2727

2828
~osm_diffresult_responder() override;
2929

30+
// lists the standard types that OSM format can respond in
31+
std::vector<mime::type> types_available() const override;
3032

3133
void write(output_formatter& f,
3234
const std::string &generator,

include/cgimap/output_formatter.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ T element_type_name(element_type elt) noexcept {
5656
return "";
5757
}
5858

59+
template <typename T = const char*>
60+
T action_type_name(action_type action) noexcept {
61+
62+
switch (action) {
63+
case action_type::create:
64+
return "create";
65+
break;
66+
case action_type::modify:
67+
return "modify";
68+
break;
69+
case action_type::del:
70+
return "delete";
71+
break;
72+
}
73+
return "";
74+
}
75+
5976
} // anonymous namespace
6077

6178
struct element_info {
@@ -214,6 +231,9 @@ struct output_formatter {
214231
// end a type of element. this is called once for nodes, ways or relations
215232
virtual void end_element_type(element_type type) = 0;
216233

234+
// marks the beginning of diffResult response processing
235+
virtual void start_diffresult() = 0;
236+
217237
// TODO: document me.
218238
virtual void start_action(action_type type) = 0;
219239
virtual void end_action(action_type type) = 0;

include/cgimap/text_formatter.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class text_formatter : public output_formatter {
3434
void write_bounds(const bbox &bounds) override;
3535
void start_element_type(element_type type) override;
3636
void end_element_type(element_type type) override;
37+
void start_diffresult() override;
3738
void start_action(action_type type) override;
3839
void end_action(action_type type) override;
3940
void error(const std::exception &e) override;

include/cgimap/xml_formatter.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class xml_formatter : public output_formatter {
3434
void end_document() override;
3535
void write_bounds(const bbox &bounds) override;
3636
void start_element_type(element_type type) override;
37+
void start_diffresult() override;
3738
void end_element_type(element_type type) override;
3839
void start_action(action_type type) override;
3940
void end_action(action_type type) override;

src/api06/changeset_upload_handler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ changeset_upload_responder::changeset_upload_responder(mime::type mt,
4747

4848
OSMChange_Handler handler(*node_updater, *way_updater, *relation_updater, changeset);
4949

50-
if (true) {
50+
// TODO: check HTTP Accept header
51+
if (mt != mime::type::application_json) {
5152
OSMChangeXMLParser(handler).process_message(payload);
5253
}
5354
else {

src/json_formatter.cpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ void json_formatter::end_document() {
5656

5757
writer->end_array(); // end of elements array
5858
is_in_elements_array = false;
59+
is_in_diffresult_array = false;
5960
writer->end_object();
6061
}
6162

@@ -69,11 +70,19 @@ void json_formatter::start_element_type(element_type type) {
6970
is_in_elements_array = true;
7071
}
7172

72-
void json_formatter::end_element_type(element_type type) {}
73+
void json_formatter::start_diffresult() {
74+
if (is_in_diffresult_array)
75+
return;
7376

74-
void json_formatter::start_action(action_type type) {
77+
writer->object_key("diffResult");
78+
writer->start_array();
79+
is_in_diffresult_array = true;
7580
}
7681

82+
void json_formatter::end_element_type(element_type type) {}
83+
84+
void json_formatter::start_action(action_type type) {}
85+
7786
void json_formatter::end_action(action_type type) {
7887
}
7988

@@ -229,28 +238,22 @@ void json_formatter::write_diffresult_create_modify(const element_type elem,
229238
const osm_version_t new_version)
230239
{
231240

232-
// writer->start_object();
233-
// writer->object_key("type");
234-
// writer->entry_string(element_type_name(elem));
235-
// writer->object_key("old_id");
236-
// writer->entry_int(old_id);
237-
// writer->object_key("new_id");
238-
// writer->entry_int(new_id);
239-
// writer->object_key("new_version");
240-
// writer->entry_int(new_version);
241-
// writer->end_object();
241+
writer->start_object();
242+
writer->property("type", element_type_name(elem));
243+
writer->property("old_id", old_id);
244+
writer->property("new_id", new_id);
245+
writer->property("new_version", new_version);
246+
writer->end_object();
242247
}
243248

244249

245250
void json_formatter::write_diffresult_delete(const element_type elem,
246251
const osm_nwr_signed_id_t old_id)
247252
{
248-
// writer->start_object();
249-
// writer->object_key("type");
250-
// writer->entry_string(element_type_name(elem));
251-
// writer->object_key("old_id");
252-
// writer->entry_int(old_id);
253-
// writer->end_object();
253+
writer->start_object();
254+
writer->property("type", element_type_name(elem));
255+
writer->property("old_id", old_id);
256+
writer->end_object();
254257
}
255258

256259
void json_formatter::flush() { writer->flush(); }

src/osm_diffresult_responder.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,20 @@ namespace {
3232

3333
throw std::runtime_error("Unhandled object_type in as_elem_type.");
3434
}
35-
3635
}
3736

3837
osm_diffresult_responder::osm_diffresult_responder(mime::type mt)
3938
: osm_responder(mt) {}
4039

4140
osm_diffresult_responder::~osm_diffresult_responder() = default;
4241

42+
std::vector<mime::type> osm_diffresult_responder::types_available() const {
43+
std::vector<mime::type> types;
44+
types.push_back(mime::type::application_xml);
45+
types.push_back(mime::type::application_json);
46+
return types;
47+
}
48+
4349
void osm_diffresult_responder::write(output_formatter& fmt,
4450
const std::string &generator,
4551
const std::chrono::system_clock::time_point &) {
@@ -48,6 +54,8 @@ void osm_diffresult_responder::write(output_formatter& fmt,
4854
try {
4955
fmt.start_document(generator, "diffResult");
5056

57+
fmt.start_diffresult();
58+
5159
// Iterate over all elements in the sequence defined in the osmChange
5260
// message
5361
for (const auto &item : m_diffresult) {

src/osmchange_responder.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ struct sorting_formatter : public output_formatter {
177177
throw std::runtime_error("Unexpected call to end_action.");
178178
}
179179

180+
void start_diffresult() override {
181+
// this shouldn't be called here
182+
throw std::runtime_error("Unexpected call to start_diffresult.");
183+
}
184+
180185
void write(output_formatter &fmt) {
181186
std::sort(m_elements.begin(), m_elements.end());
182187
for (const auto &e : m_elements) {

src/text_formatter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ void text_formatter::end_element_type(element_type) {
3939
// nothing needed here
4040
}
4141

42+
void text_formatter::start_diffresult() {
43+
// nothing needed here
44+
}
45+
4246
void text_formatter::start_action(action_type type) {
4347
// nothing needed here
4448
}

src/xml_formatter.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,12 @@ void xml_formatter::end_element_type(element_type) {
5252
// ditto - nothing needed here for XML.
5353
}
5454

55+
void xml_formatter::start_diffresult() {
56+
// not needed in case of xml
57+
}
58+
5559
void xml_formatter::start_action(action_type type) {
56-
switch (type) {
57-
case action_type::create:
58-
writer->start("create");
59-
break;
60-
case action_type::modify:
61-
writer->start("modify");
62-
break;
63-
case action_type::del:
64-
writer->start("delete");
65-
break;
66-
}
60+
writer->start(action_type_name(type));
6761
}
6862

6963
void xml_formatter::end_action(action_type type) {

test/test_apidb_backend_changeset_uploads.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@
1414
#include <iostream>
1515
#include <optional>
1616
#include <stdexcept>
17+
#include <sstream>
1718
#include <memory>
1819
#include <thread>
1920
#include <fmt/core.h>
2021
#include <libxml/tree.h>
2122
#include <libxml/parser.h>
2223
#include <libxml/xpath.h>
2324
#include <boost/program_options.hpp>
25+
#include <boost/algorithm/string.hpp>
26+
#include <boost/property_tree/ptree.hpp>
27+
#include <boost/property_tree/xml_parser.hpp>
28+
#include <boost/property_tree/json_parser.hpp>
2429

2530
#include <sys/time.h>
2631

@@ -46,6 +51,9 @@ using Catch::Matchers::StartsWith;
4651
using Catch::Matchers::EndsWith;
4752
using Catch::Matchers::Equals;
4853

54+
namespace al = boost::algorithm;
55+
namespace pt = boost::property_tree;
56+
4957
class global_settings_enable_upload_rate_limiter_test_class : public global_settings_default {
5058

5159
public:
@@ -2398,6 +2406,66 @@ TEST_CASE_METHOD( DatabaseTestsFixture, "test_osmchange_end_to_end", "[changeset
23982406
REQUIRE(req.response_status() == 200);
23992407
}
24002408

2409+
SECTION("JSON upload")
2410+
{
2411+
std::string payload = R"(
2412+
{
2413+
"version": "0.6",
2414+
"generator": "demo",
2415+
"osmChange": [
2416+
{
2417+
"type": "node",
2418+
"action": "create",
2419+
"id": -1,
2420+
"lat": 42,
2421+
"lon": 13,
2422+
"changeset": 1
2423+
},
2424+
{
2425+
"type": "node",
2426+
"action": "modify",
2427+
"id": -1,
2428+
"version": 1,
2429+
"lat": 42.7957187,
2430+
"lon": 13.5690032,
2431+
"changeset": 1,
2432+
"tags": {
2433+
"man_made": "mast",
2434+
"name": "Monte Piselli - San Giacomo"
2435+
}
2436+
}
2437+
]
2438+
}
2439+
)";
2440+
2441+
req.set_header("REQUEST_URI", "/api/0.6/changeset/1/upload.json");
2442+
req.set_payload(payload);
2443+
2444+
// execute the request
2445+
process_request(req, limiter, generator, route, *sel_factory, upd_factory.get());
2446+
2447+
CAPTURE(req.body().str());
2448+
2449+
REQUIRE(req.response_status() == 200);
2450+
2451+
SECTION("Validate diffResult in JSON format")
2452+
{
2453+
pt::ptree act_tree;
2454+
std::stringstream ss(req.body().str());
2455+
pt::read_json(ss, act_tree);
2456+
2457+
auto diffResult = act_tree.get_child("diffResult");
2458+
int version = 1;
2459+
for (auto & entry : diffResult) {
2460+
REQUIRE(entry.second.get<std::string>("type") == "node");
2461+
REQUIRE(entry.second.get<int64_t>("old_id") == -1);
2462+
REQUIRE(entry.second.get<int64_t>("new_id") > 0);
2463+
REQUIRE(entry.second.get<int64_t>("new_version") == version);
2464+
version++;
2465+
}
2466+
}
2467+
}
2468+
24012469
}
24022470

24032471
TEST_CASE_METHOD( DatabaseTestsFixture, "test_osmchange_rate_limiter", "[changeset][upload][db]" ) {

test/test_formatter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ void test_formatter::start_document(
152152
void test_formatter::end_document() {
153153
}
154154

155+
void test_formatter::start_diffresult() {
156+
}
157+
155158
void test_formatter::write_bounds(const bbox &bounds) {
156159
}
157160

test/test_formatter.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ struct test_formatter : public output_formatter {
8989
mime::type mime_type() const override;
9090
void start_document(const std::string &generator, const std::string &root_name) override;
9191
void end_document() override;
92+
void start_diffresult() override;
9293
void write_bounds(const bbox &bounds) override;
9394
void start_element_type(element_type type) override;
9495
void end_element_type(element_type type) override;

0 commit comments

Comments
 (0)