Consolidated solution for RDB merge ('apply'). Potentially one bug fixed (tag mapping)

This commit is contained in:
Matthias Koefferlein 2024-08-17 22:03:00 +02:00
parent 2eef9c38d6
commit 0f833da652
3 changed files with 196 additions and 161 deletions

View File

@ -482,11 +482,11 @@ Values::compare (const Values &other, const std::set<id_type> &common_tags) cons
Values::const_iterator a = begin (), b = other.begin (); Values::const_iterator a = begin (), b = other.begin ();
while (a != end () && b != other.end ()) { while (a != end () && b != other.end ()) {
id_type t12 = 0; id_type t1 = 0;
while (a != end () && a->tag_id () != 0) { while (a != end () && a->tag_id () != 0) {
auto j = common_tags.find (a->tag_id ()); auto j = common_tags.find (a->tag_id ());
if (j != common_tags.end ()) { if (j != common_tags.end ()) {
t12 = a->tag_id (); t1 = a->tag_id ();
break; break;
} }
++a; ++a;
@ -506,8 +506,8 @@ Values::compare (const Values &other, const std::set<id_type> &common_tags) cons
return b != other.end (); return b != other.end ();
} }
if (t12 != t2) { if (t1 != t2) {
return t12 < t2; return t1 < t2;
} }
if (a->get () && b->get ()) { if (a->get () && b->get ()) {
@ -952,6 +952,24 @@ Tags::clear ()
m_tags.clear (); m_tags.clear ();
} }
void
Tags::remove_tag (id_type id)
{
auto j = m_tags_per_id.find (id);
if (j != m_tags_per_id.end ()) {
m_tags.erase (m_tags.begin () + j->second);
for (auto i = m_tags_per_id.begin (); i != m_tags_per_id.end (); ++i) {
if (i->second > j->second) {
i->second -= 1;
}
}
m_tags_per_id.erase (id);
}
}
const Tag & const Tag &
Tags::tag (const std::string &name, bool user_tag) const Tags::tag (const std::string &name, bool user_tag) const
{ {
@ -1915,8 +1933,6 @@ Database::apply (const rdb::Database &other)
{ {
std::map<id_type, id_type> cell2cell; std::map<id_type, id_type> cell2cell;
std::map<id_type, id_type> cat2cat; std::map<id_type, id_type> cat2cat;
std::map<id_type, id_type> tag2tag;
std::map<id_type, id_type> rev_tag2tag;
for (auto c = other.cells ().begin (); c != other.cells ().end (); ++c) { for (auto c = other.cells ().begin (); c != other.cells ().end (); ++c) {
// TODO: do we have a consistent scheme of naming variants? What requirements // TODO: do we have a consistent scheme of naming variants? What requirements

View File

@ -679,12 +679,9 @@ public:
/** /**
* @brief Compare two value sets (less operator) * @brief Compare two value sets (less operator)
* *
* This compare function will use the tag mapping provided by tag map ("this" tag id to "other" tag id). * This compare function will use the tags provide in "common_tags". Tags outside this set are ignored.
* Values with tags not listed in the tag map will not be compared.
* Untagged values (tag_id 0) will be compared always. * Untagged values (tag_id 0) will be compared always.
* *
* "rev_tag_map" needs to be the reverse of "tag_map".
*
* The order of the values matters. * The order of the values matters.
*/ */
bool compare (const Values &other, const std::set<id_type> &common_tags) const; bool compare (const Values &other, const std::set<id_type> &common_tags) const;
@ -1979,9 +1976,20 @@ public:
/** /**
* @brief Clear the collection of tags * @brief Clear the collection of tags
*
* NOTE: this will not remove the tags from items or values, so the use cases for this method
* are limited.
*/ */
void clear (); void clear ();
/**
* @brief Removes the tag with the given ID
*
* NOTE: this will not remove the tags from items or values, so the use cases for this method
* are limited.
*/
void remove_tag (id_type id);
/** /**
* @brief Gets the name and user flag for a tag ID * @brief Gets the name and user flag for a tag ID
* *

View File

@ -816,7 +816,18 @@ TEST(13_ApplyIgnoreUnknownTag)
i2->values ().clear (); i2->values ().clear ();
i2->add_value (std::string ("xyz"), vtag22); i2->add_value (std::string ("xyz"), vtag22);
// values with incompatible tags are ignored -> tag2 is applied // values with incompatible tags are ignored, but vtag1 is a common tag.
// So far, nothing is applied as the we match abc[vtag1] vs. xyz[vtag2] which is both different value and tag-
db1.apply (db2);
EXPECT_EQ (i1->tag_str (), "");
// NOTE: don't do this at home
const_cast<rdb::Tags &> (db2.tags ()).remove_tag (vtag21);
// vtag1 is no longer a common tag -> we match abc[vtag1] vs. xyz[vtag2] where vtag1 is not known on the
// other side and vtag2 is not known on the self side.
// Hence, the values are ignored and the tag is applied.
db1.apply (db2); db1.apply (db2);
EXPECT_EQ (i1->tag_str (), "tag2"); EXPECT_EQ (i1->tag_str (), "tag2");