void 
OWLDatabase::update_relation(id_t id, const tags_t &attrs, const list<member> &members, const tags_t &tags) {
  // simple implementation as a delete-add. this isn't efficient, but it might not need to be.
  delete_relation(id);

  stringstream query;
  query << "insert into relations (id, version, changeset) values ("
        << id << ", "
        << required_attribute(attrs, "version") << ", "
        << required_attribute(attrs, "changeset") << ")";
  transaction.exec(query);

  // update relation members
  if (members.size() > 0) {
    stringstream query;
    query << "insert into relation_members (id, m_id, m_role, m_type, seq) values ";
    size_t i = 0;
    for (list<member>::const_iterator itr = members.begin(); itr != members.end(); ++itr) {
      if (i > 0) query << ", ";
      query << "(" << id << ", " << itr->id << ", E'" << transaction.esc(itr->role) << "', '" << itr->type << "', " << i << ")";
      ++i;
    }
    transaction.exec(query);
  }

  add_tags(transaction, "relation_tags", id, tags);
}
void 
OWLDatabase::update_way(id_t id, const tags_t &attrs, const vector<id_t> &way_nodes, const tags_t &tags,
                        optional<CompressedBitset> &bs) {
  // simple implementation as a delete-add. this isn't efficient, but it might not need to be.
  delete_way(id);

  {
    stringstream query;
    query << "insert into ways (id, version, changeset";
    if (bs) { query << ", tiles"; }
    query << ") values ("
          << id << ", "
          << required_attribute(attrs, "version") << ", "
          << required_attribute(attrs, "changeset");
    if (bs) {
      query << ", E'" << transaction.esc_raw(bs->str()) << "'::bytea";
    }
    query << ")";
    transaction.exec(query);
  }

  // update way nodes
  if (way_nodes.size() > 0) {
    stringstream query;
    query << "insert into way_nodes (id, node_id, seq) values ";
    for (size_t i = 0; i < way_nodes.size(); ++i) {
      if (i > 0) query << ", ";
      query << "(" << id << ", " << way_nodes[i] << ", " << i << ")";
    }
    transaction.exec(query);
  }

  add_tags(transaction, "way_tags", id, tags);
}
element::element(const tags_t &a, const tags_t &t) 
  : attrs(a), tags(t), 
    id(lexical_cast<id_t>(required_attribute(attrs, "id"))),
    changeset(lexical_cast<id_t>(required_attribute(attrs, "changeset"))),
    version(lexical_cast<id_t>(required_attribute(attrs, "version"))),
    uid(optional_id_attribute(attrs, "uid", 0)),
    visible(optional_bool_attribute(attrs, "visible", true)) {
}
bool 
OWLDatabase::node(id_t id, tags_t &attrs, tags_t &tags) {
  bool found = find_element(transaction, "nodes", "node_tags", id, attrs, tags);
  if (found) {
    const double lat = lexical_cast<double>(required_attribute(attrs, "lat")) / SCALE;
    const double lon = lexical_cast<double>(required_attribute(attrs, "lon")) / SCALE;
    attrs["lat"] = to_string_d(lat);
    attrs["lon"] = to_string_d(lon);
  }
  return found;
}
// setters
void
OWLDatabase::update_node(id_t id, const tags_t &attrs, const tags_t &tags) {
  // simple implementation as a delete-add. this isn't efficient, but it might not need to be.
  const int lat = nearbyint(lexical_cast<double>(required_attribute(attrs, "lat")) * SCALE);
  const int lon = nearbyint(lexical_cast<double>(required_attribute(attrs, "lon")) * SCALE);
  delete_node(id);

  stringstream query;
  query << "insert into nodes (id, version, changeset, lat, lon, tile) values ("
        << id << ", "
        << required_attribute(attrs, "version") << ", "
        << required_attribute(attrs, "changeset") << ", "
        << lat << ", " << lon << ", "
        << util::xy2tile(util::lon2x(lon), util::lat2y(lat)) << ")";
  transaction.exec(query);

  add_tags(transaction, "node_tags", id, tags);
}