Skip to content

Commit

Permalink
Merge pull request #111 from zerebubuth/changesets
Browse files Browse the repository at this point in the history
Add support for changesets
  • Loading branch information
zerebubuth authored Sep 19, 2016
2 parents 84c2fd6 + 0697e91 commit bc93003
Show file tree
Hide file tree
Showing 50 changed files with 1,746 additions and 437 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ test/test_apidb_backend
test/test_parse_id_list
test/test_http
test/test_oauth
test/test_parse_time
test/*.trs
include/cgimap/config.hpp.in
include/cgimap/config.hpp
Expand Down
3 changes: 2 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ endif

TESTS = test/map.testcore test/node.testcore test/anon.testcore test/way.testcore test/relation.testcore
TESTS += test/empty.testcore test/way_full.testcore test/relation_full.testcore
TESTS += test/test_parse_id_list test/test_oauth test/test_http
TESTS += test/test_parse_id_list test/test_oauth test/test_http test/test_parse_time
TESTS += test/changesets.testcore
if ENABLE_EXPERIMENTAL
TESTS += test/node_ways.testcore
endif
Expand Down
36 changes: 36 additions & 0 deletions include/cgimap/api06/changeset_handler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef API06_CHANGESET_HANDLER_HPP
#define API06_CHANGESET_HANDLER_HPP

#include "cgimap/handler.hpp"
#include "cgimap/osm_current_responder.hpp"
#include "cgimap/request.hpp"
#include <string>

namespace api06 {

class changeset_responder : public osm_current_responder {
public:
changeset_responder(mime::type, osm_changeset_id_t, bool, factory_ptr &);
~changeset_responder();

private:
osm_changeset_id_t id;
bool include_discussion;
};

class changeset_handler : public handler {
public:
changeset_handler(request &req, osm_changeset_id_t id);
~changeset_handler();

std::string log_name() const;
responder_ptr_t responder(factory_ptr &x) const;

private:
osm_changeset_id_t id;
bool include_discussion;
};

} // namespace api06

#endif /* API06_CHANGESET_HANDLER_HPP */
52 changes: 52 additions & 0 deletions include/cgimap/backend/apidb/pqxx_string_traits.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#ifndef BACKEND_APIDB_PQXX_STRING_TRAITS_HPP
#define BACKEND_APIDB_PQXX_STRING_TRAITS_HPP

#include "cgimap/types.hpp"
#include "cgimap/infix_ostream_iterator.hpp"
#include <vector>
#include <set>
#include <sstream>
#include <algorithm>
#include <pqxx/pqxx>

namespace pqxx {

/*
* PQXX_ARRAY_STRING_TRAITS provides an instantiation of the string_traits
* template from PQXX which is used to stringify arguments when sending them
* to Postgres. Cgimap uses several different containers across different
* integer types, all of which stringify to arrays in the same way.
*
* Note that it would be nicer to hide this in a .cpp, but it seems that the
* implementation has to be available when used in the prepared statement
* code.
*/
#define PQXX_ARRAY_STRING_TRAITS(type) \
template <> struct string_traits<type> { \
static const char *name() { return #type; } \
static bool has_null() { return false; } \
static bool is_null(const type &) { return false; } \
static std::stringstream null() { \
internal::throw_null_conversion(name()); \
throw 0; /* need this to satisfy compiler escape detection */ \
} \
static void from_string(const char[], type &) {} \
static std::string to_string(const type &ids) { \
std::stringstream ostr; \
ostr << "{"; \
std::copy(ids.begin(), ids.end(), \
infix_ostream_iterator<type::value_type>(ostr, ",")); \
ostr << "}"; \
return ostr.str(); \
} \
}

PQXX_ARRAY_STRING_TRAITS(std::vector<osm_nwr_id_t>);
PQXX_ARRAY_STRING_TRAITS(std::set<osm_nwr_id_t>);
PQXX_ARRAY_STRING_TRAITS(std::vector<tile_id_t>);
PQXX_ARRAY_STRING_TRAITS(std::vector<osm_changeset_id_t>);
PQXX_ARRAY_STRING_TRAITS(std::set<osm_changeset_id_t>);

} // namespace pqxx

#endif /* BACKEND_APIDB_PQXX_STRING_TRAITS_HPP */
10 changes: 10 additions & 0 deletions include/cgimap/backend/apidb/readonly_pgsql_selection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class readonly_pgsql_selection : public data_selection {
void write_nodes(output_formatter &formatter);
void write_ways(output_formatter &formatter);
void write_relations(output_formatter &formatter);
void write_changesets(output_formatter &formatter, const boost::posix_time::ptime &now);

visibility_t check_node_visibility(osm_nwr_id_t id);
visibility_t check_way_visibility(osm_nwr_id_t id);
Expand All @@ -42,6 +43,10 @@ class readonly_pgsql_selection : public data_selection {
void select_relations_from_relations();
void select_relations_members_of_relations();

bool supports_changesets();
int select_changesets(const std::vector<osm_changeset_id_t> &);
void select_changeset_discussions();

/**
* a factory for the creation of read-only selections, so it
* can set up prepared statements.
Expand All @@ -67,7 +72,12 @@ class readonly_pgsql_selection : public data_selection {
// unlike writeable_pgsql_selection.
pqxx::work w;

// true if we want to include changeset discussions along with
// the changesets themselves. defaults to false.
bool include_changeset_discussions;

// the set of selected nodes, ways and relations
std::set<osm_changeset_id_t> sel_changesets;
std::set<osm_nwr_id_t> sel_nodes, sel_ways, sel_relations;
cache<osm_changeset_id_t, changeset> &cc;
};
Expand Down
9 changes: 9 additions & 0 deletions include/cgimap/backend/apidb/writeable_pgsql_selection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class writeable_pgsql_selection : public data_selection {
void write_nodes(output_formatter &formatter);
void write_ways(output_formatter &formatter);
void write_relations(output_formatter &formatter);
void write_changesets(output_formatter &formatter, const boost::posix_time::ptime &now);

visibility_t check_node_visibility(osm_nwr_id_t id);
visibility_t check_way_visibility(osm_nwr_id_t id);
Expand All @@ -39,6 +40,10 @@ class writeable_pgsql_selection : public data_selection {
void select_relations_from_relations();
void select_relations_members_of_relations();

bool supports_changesets();
int select_changesets(const std::vector<osm_changeset_id_t> &);
void select_changeset_discussions();

/**
* abstracts the creation of transactions for the writeable
* data selection.
Expand Down Expand Up @@ -68,6 +73,10 @@ class writeable_pgsql_selection : public data_selection {
// true if a query hasn't been run yet, i.e: it's possible to
// assume that all the temporary tables are empty.
bool m_tables_empty;

// true if we want to include changeset discussions along with
// the changesets themselves. defaults to false.
bool include_changeset_discussions;
};

#endif /* WRITEABLE_PGSQL_SELECTION_HPP */
2 changes: 2 additions & 0 deletions include/cgimap/bbox.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ struct bbox {

bbox();

bool operator==(const bbox &) const;

/**
* Attempt to parse a bounding box from a comma-separated string
* of coordinates. Returns true if parsing was succesful and the
Expand Down
17 changes: 17 additions & 0 deletions include/cgimap/data_selection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

/**
* represents a selected set of data which can be written out to
Expand All @@ -29,6 +30,10 @@ class data_selection {
/// write the relations to an output formatter
virtual void write_relations(output_formatter &formatter) = 0;

/// does this data selection support changesets?
virtual void write_changesets(output_formatter &formatter,
const boost::posix_time::ptime &now);

/******************* information functions *******************/

// check if the node is visible, deleted or has never existed
Expand Down Expand Up @@ -82,6 +87,18 @@ class data_selection {
/// select relations which are members of selected relations
virtual void select_relations_members_of_relations() = 0;

/// does this data selection support changesets?
virtual bool supports_changesets();

/// select specified changesets, returning the number of
/// changesets selected.
virtual int select_changesets(const std::vector<osm_changeset_id_t> &);

/// select the changeset discussions as well. this effectively
/// just sets a flag - by default, discussions are not included,
/// if this is called then discussions will be included.
virtual void select_changeset_discussions();

/**
* factory for the creation of data selections. this abstracts away
* the creation process of transactions, and allows some up-front
Expand Down
9 changes: 8 additions & 1 deletion include/cgimap/fcgi_request.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@
#include <boost/scoped_ptr.hpp>

struct fcgi_request : public request {
explicit fcgi_request(int socket);
fcgi_request(int socket, const boost::posix_time::ptime &now);
virtual ~fcgi_request();
const char *get_param(const char *key);

// getting and setting the current time
boost::posix_time::ptime get_current_time() const;
// need to be able to set the time, since the fcgi_request is
// actually wrapping the whole socket and so persists over
// several calls.
void set_current_time(const boost::posix_time::ptime &now);

int accept_r();
static int open_socket(const std::string &, int);
void dispose();
Expand Down
4 changes: 3 additions & 1 deletion include/cgimap/handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <string>
#include <memory>
#include <boost/shared_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

/**
* object which is able to respond to an already-setup request.
Expand All @@ -19,7 +20,8 @@ class responder {
responder(mime::type);
virtual ~responder();
virtual void write(boost::shared_ptr<output_formatter> f,
const std::string &generator) = 0;
const std::string &generator,
const boost::posix_time::ptime &now) = 0;

mime::type resource_type() const;

Expand Down
6 changes: 6 additions & 0 deletions include/cgimap/json_formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ class json_formatter : public output_formatter {
void write_relation(const element_info &elem, const members_t &members,
const tags_t &tags);

void write_changeset(const changeset_info &elem,
const tags_t &tags,
bool include_comments,
const comments_t &comments,
const boost::posix_time::ptime &now);

void flush();
void error(const std::string &);
};
Expand Down
3 changes: 2 additions & 1 deletion include/cgimap/osm_current_responder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class osm_current_responder : public osm_responder {
// writes whatever is in the tmp_nodes/ways/relations tables to the given
// formatter.
void write(boost::shared_ptr<output_formatter> f,
const std::string &generator);
const std::string &generator,
const boost::posix_time::ptime &now);

protected:
// current selection of elements to be written out
Expand Down
60 changes: 60 additions & 0 deletions include/cgimap/output_formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
#include "cgimap/types.hpp"
#include "cgimap/mime_types.hpp"
#include <list>
#include <vector>
#include <stdexcept>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>

/**
* What type of element the formatter is starting to write.
*/
enum element_type {
element_type_changeset,
element_type_node,
element_type_way,
element_type_relation
Expand All @@ -37,6 +40,55 @@ struct element_info {
bool visible;
};

struct changeset_info {
changeset_info();
changeset_info(const changeset_info &);
changeset_info(osm_changeset_id_t id_,
const std::string &created_at_,
const std::string &closed_at_,
const boost::optional<osm_user_id_t> &uid_,
const boost::optional<std::string> &display_name_,
const boost::optional<bbox> &bounding_box_,
size_t num_changes_,
size_t comments_count_);

// returns true if the changeset is "open" at a particular
// point in time.
//
// note that the definition of "open" is fraught with
// difficulty, and it's not wise to rely on it too much.
bool is_open_at(const boost::posix_time::ptime &) const;

// standard meaning of ID
osm_changeset_id_t id;
// changesets are created at a certain time and may be either
// closed explicitly with a closing time, or close implicitly
// an hour after the last update to the changeset. closed_at
// should have an ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ
std::string created_at, closed_at;
// anonymous objects don't have UIDs or display names
boost::optional<osm_user_id_t> uid;
boost::optional<std::string> display_name;
// changesets with edits will have a bounding box containing
// the extent of all the changes.
boost::optional<bbox> bounding_box;
// the number of changes (new element versions) associated
// with this changeset.
size_t num_changes;
// if the changeset has a discussion attached, then this will
// be the number of comments.
size_t comments_count;
};

struct changeset_comment_info {
osm_user_id_t author_id;
std::string body;
std::string created_at;
std::string author_display_name;

bool operator==(const changeset_comment_info &) const;
};

struct member_info {
element_type type;
osm_nwr_id_t ref;
Expand All @@ -46,6 +98,7 @@ struct member_info {
typedef std::list<osm_nwr_id_t> nodes_t;
typedef std::list<member_info> members_t;
typedef std::list<std::pair<std::string, std::string> > tags_t;
typedef std::vector<changeset_comment_info> comments_t;

/**
* Base type for different output formats. Hopefully this is general
Expand Down Expand Up @@ -96,6 +149,13 @@ struct output_formatter {
virtual void write_relation(const element_info &elem,
const members_t &members, const tags_t &tags) = 0;

// output a single changeset.
virtual void write_changeset(const changeset_info &elem,
const tags_t &tags,
bool include_comments,
const comments_t &comments,
const boost::posix_time::ptime &now) = 0;

// flush the current state
virtual void flush() = 0;

Expand Down
4 changes: 4 additions & 0 deletions include/cgimap/request.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>

// forward declaration of output_buffer, which is only needed here by
// reference.
Expand All @@ -29,6 +30,9 @@ struct request {
// the key could not be found. this function can be called at any time.
virtual const char *get_param(const char *key) = 0;

// get the current time of the request.
virtual boost::posix_time::ptime get_current_time() const = 0;

/********************** RESPONSE HEADER FUNCTIONS **************************/

// set the status for the response. by default, the status is 500 and the user
Expand Down
3 changes: 3 additions & 0 deletions include/cgimap/router.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ struct match_string : public ops<match_string> {
match_string(const std::string &s);
match_string(const char *s);

// copy just copies the held string
inline match_string(const match_string &m) : str(m.str) {}

match_type match(part_iterator &begin, const part_iterator &end) const;

private:
Expand Down
Loading

0 comments on commit bc93003

Please sign in to comment.