diff --git a/src/rdb/rdb/rdb.cc b/src/rdb/rdb/rdb.cc index 2d77e5c46..807d0c668 100644 --- a/src/rdb/rdb/rdb.cc +++ b/src/rdb/rdb/rdb.cc @@ -60,16 +60,18 @@ namespace rdb // type index specializations template <> RDB_PUBLIC int type_index_of () { return 0; } -template <> RDB_PUBLIC int type_index_of () { return 1; } -template <> RDB_PUBLIC int type_index_of () { return 2; } -template <> RDB_PUBLIC int type_index_of () { return 3; } -template <> RDB_PUBLIC int type_index_of () { return 4; } -template <> RDB_PUBLIC int type_index_of () { return 5; } -template <> RDB_PUBLIC int type_index_of () { return 6; } -template <> RDB_PUBLIC int type_index_of () { return 7; } +template <> RDB_PUBLIC int type_index_of () { return 1; } +template <> RDB_PUBLIC int type_index_of () { return 2; } +template <> RDB_PUBLIC int type_index_of () { return 3; } +template <> RDB_PUBLIC int type_index_of () { return 4; } +template <> RDB_PUBLIC int type_index_of () { return 5; } +template <> RDB_PUBLIC int type_index_of () { return 6; } +template <> RDB_PUBLIC int type_index_of () { return 7; } +template <> RDB_PUBLIC int type_index_of () { return 8; } // Explicit instantiations to make VC++ happy in debug mode template class RDB_PUBLIC Value; +template class RDB_PUBLIC Value; template class RDB_PUBLIC Value; template class RDB_PUBLIC Value; template class RDB_PUBLIC Value; @@ -85,6 +87,11 @@ template <> RDB_PUBLIC std::string Value::to_string () const return "float: " + tl::to_string (m_value); } +template <> RDB_PUBLIC std::string Value::to_string () const +{ + return "int: " + tl::to_string (m_value); +} + template <> RDB_PUBLIC std::string Value::to_string () const { return "text: " + tl::to_word_or_quoted_string (m_value); @@ -127,6 +134,11 @@ template <> RDB_PUBLIC std::string Value::to_display_string () const return tl::to_string (m_value); } +template <> RDB_PUBLIC std::string Value::to_display_string () const +{ + return tl::to_string (m_value); +} + template <> RDB_PUBLIC std::string Value::to_display_string () const { return m_value; @@ -169,6 +181,11 @@ template <> RDB_PUBLIC bool Value::is_shape () const return false; } +template <> RDB_PUBLIC bool Value::is_shape () const +{ + return false; +} + template <> RDB_PUBLIC bool Value::is_shape () const { return false; @@ -420,7 +437,7 @@ Values::compare (const Values &other, const std::map &tag_map, } id_type t2 = 0; - while (b != end () && b->tag_id () != 0) { + while (b != other.end () && b->tag_id () != 0) { auto j = rev_tag_map.find (b->tag_id ()); if (j != rev_tag_map.end ()) { t2 = j->first; @@ -438,18 +455,21 @@ Values::compare (const Values &other, const std::map &tag_map, } if (a->get () && b->get ()) { - if (a->get ()->compare (b->get ())) { + if (rdb::ValueBase::compare (a->get (), b->get ())) { return true; - } else if (b->get ()->compare (a->get ())) { + } else if (rdb::ValueBase::compare (b->get (), a->get ())) { return false; } } else if ((a->get () != 0) != (b->get () != 0)) { return (a->get () != 0) < (b->get () != 0); } + ++a; + ++b; + } - return false; + return b != other.end (); } std::string diff --git a/src/rdb/rdb/rdb.h b/src/rdb/rdb/rdb.h index 936ab28e6..3541e6768 100644 --- a/src/rdb/rdb/rdb.h +++ b/src/rdb/rdb/rdb.h @@ -752,6 +752,14 @@ public: m_values.swap (other.m_values); } + /** + * @brief Clears the values + */ + void clear () + { + m_values.clear (); + } + /** * @brief Convert the values collection to a string */ diff --git a/src/rdb/unit_tests/rdbTests.cc b/src/rdb/unit_tests/rdbTests.cc index 55e78c1f9..5665aa522 100644 --- a/src/rdb/unit_tests/rdbTests.cc +++ b/src/rdb/unit_tests/rdbTests.cc @@ -598,3 +598,226 @@ TEST(7) #endif } + + +TEST(8_ApplyBasicEmptyValue) +{ + rdb::Database db1; + rdb::Category *cat1 = db1.create_category ("cat_name"); + rdb::Cell *c1 = db1.create_cell ("cell"); + rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ()); + + rdb::Database db2; + db2.create_category ("dummy_cat"); + rdb::Category *cat2 = db2.create_category ("cat_name"); + db2.create_cell ("dummy_cell"); + rdb::Cell *c2 = db2.create_cell ("cell"); + rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ()); + + rdb::id_type tag2 = db2.tags ().tag ("tag2").id (); + i2->add_tag (tag2); + + EXPECT_EQ (i2->tag_str (), "tag2"); + EXPECT_EQ (i1->tag_str (), ""); + + // empty value apply + db1.apply (db2); + + EXPECT_EQ (i1->tag_str (), "tag2"); +} + +TEST(9_ApplyBasicSomeValue) +{ + rdb::Database db1; + rdb::Category *cat1 = db1.create_category ("cat_name"); + rdb::Cell *c1 = db1.create_cell ("cell"); + rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ()); + i1->add_value (std::string ("abc")); + + rdb::Database db2; + db2.create_category ("dummy_cat"); + rdb::Category *cat2 = db2.create_category ("cat_name"); + db2.create_cell ("dummy_cell"); + rdb::Cell *c2 = db2.create_cell ("cell"); + rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ()); + + db2.tags ().tag ("dummy_tag"); + rdb::id_type tag2 = db2.tags ().tag ("tag2").id (); + i2->add_tag (tag2); + + EXPECT_EQ (i2->tag_str (), "tag2"); + EXPECT_EQ (i1->tag_str (), ""); + + // empty value apply + db1.apply (db2); + + // not applied (different value) + EXPECT_EQ (i1->tag_str (), ""); + + // incorrect value + i2->add_value (17); + + db1.apply (db2); + + // still not applied + EXPECT_EQ (i1->tag_str (), ""); + + // correct value + i2->values ().clear (); + i2->add_value (std::string ("abc")); + + db1.apply (db2); + + // now, the tag is applied + EXPECT_EQ (i1->tag_str (), "tag2"); + + // too many values + i1->remove_tags (); + i2->add_value (17); + + db1.apply (db2); + + // not applied + EXPECT_EQ (i1->tag_str (), ""); +} + +TEST(10_ApplyTaggedValue) +{ + rdb::Database db1; + rdb::Category *cat1 = db1.create_category ("cat_name"); + rdb::Cell *c1 = db1.create_cell ("cell"); + rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ()); + rdb::id_type vtag11 = db1.tags ().tag ("vtag1").id (); + rdb::id_type vtag12 = db1.tags ().tag ("vtag2").id (); + i1->add_value (std::string ("abc")); + + rdb::Database db2; + db2.create_category ("dummy_cat"); + rdb::Category *cat2 = db2.create_category ("cat_name"); + db2.create_cell ("dummy_cell"); + rdb::Cell *c2 = db2.create_cell ("cell"); + rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ()); + db2.tags ().tag ("dummy_tag"); + + rdb::id_type tag2 = db2.tags ().tag ("tag2").id (); + rdb::id_type vtag21 = db2.tags ().tag ("vtag1").id (); + i2->add_tag (tag2); + i2->add_value (std::string ("abc"), vtag21); + + // empty tag vs. vtag1 + db1.apply (db2); + + // not applied (empty tag vs. tagged) + EXPECT_EQ (i1->tag_str (), ""); + + // vtag2 vs. vtag1 + i1->values ().clear (); + i1->add_value (std::string ("abc"), vtag12); + + db1.apply (db2); + + // not applied (different tags) + EXPECT_EQ (i1->tag_str (), ""); + + // vtag1 vs. vtag1 + i1->values ().clear (); + i1->add_value (std::string ("abc"), vtag11); + + db1.apply (db2); + + // this time it is applied (same tag) + EXPECT_EQ (i1->tag_str (), "tag2"); +} + +TEST(11_ApplyWrongCat) +{ + rdb::Database db1; + rdb::Category *cat1 = db1.create_category ("cat_name"); + rdb::Cell *c1 = db1.create_cell ("cell"); + rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ()); + + rdb::Database db2; + db2.create_category ("dummy_cat"); + rdb::Category *cat2 = db2.create_category ("xcat_name"); + db2.create_cell ("dummy_cell"); + rdb::Cell *c2 = db2.create_cell ("cell"); + rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ()); + + rdb::id_type tag2 = db2.tags ().tag ("tag2").id (); + i2->add_tag (tag2); + + EXPECT_EQ (i2->tag_str (), "tag2"); + EXPECT_EQ (i1->tag_str (), ""); + + // empty value apply + db1.apply (db2); + + EXPECT_EQ (i1->tag_str (), ""); +} + +TEST(12_ApplyWrongCell) +{ + rdb::Database db1; + rdb::Category *cat1 = db1.create_category ("cat_name"); + rdb::Cell *c1 = db1.create_cell ("cell"); + rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ()); + + rdb::Database db2; + db2.create_category ("dummy_cat"); + rdb::Category *cat2 = db2.create_category ("cat_name"); + db2.create_cell ("dummy_cell"); + rdb::Cell *c2 = db2.create_cell ("xcell"); + rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ()); + + rdb::id_type tag2 = db2.tags ().tag ("tag2").id (); + i2->add_tag (tag2); + + EXPECT_EQ (i2->tag_str (), "tag2"); + EXPECT_EQ (i1->tag_str (), ""); + + // empty value apply + db1.apply (db2); + + EXPECT_EQ (i1->tag_str (), ""); +} + +TEST(13_ApplyIgnoreUnknownTag) +{ + rdb::Database db1; + rdb::Category *cat1 = db1.create_category ("cat_name"); + rdb::Cell *c1 = db1.create_cell ("cell"); + rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ()); + rdb::id_type vtag11 = db1.tags ().tag ("vtag1").id (); + i1->add_value (std::string ("abc"), vtag11); + + rdb::Database db2; + db2.create_category ("dummy_cat"); + rdb::Category *cat2 = db2.create_category ("cat_name"); + db2.create_cell ("dummy_cell"); + rdb::Cell *c2 = db2.create_cell ("cell"); + rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ()); + db2.tags ().tag ("dummy_tag"); + + rdb::id_type tag2 = db2.tags ().tag ("tag2").id (); + rdb::id_type vtag21 = db2.tags ().tag ("vtag1").id (); + rdb::id_type vtag22 = db2.tags ().tag ("vtag2").id (); + i2->add_tag (tag2); + + // same tags, different values + i2->add_value (std::string ("xyz"), vtag21); + + db1.apply (db2); + + // not applied + EXPECT_EQ (i1->tag_str (), ""); + + // different tags without mapping + i2->values ().clear (); + i2->add_value (std::string ("xyz"), vtag22); + + // values with incompatible tags are ignored -> tag2 is applied + db1.apply (db2); + + EXPECT_EQ (i1->tag_str (), "tag2"); +} +