Commit e450fee0 by Maarten L. Hekkelman

Fixed processing links

parent d7c162c7
......@@ -13,3 +13,5 @@ libcif++.la
config.status
config.log
libtool
rsrc/lib-version.txt
version-info*.txt
......@@ -347,9 +347,16 @@ namespace detail
static int compare(const ItemReference& ref, double value, bool icase)
{
int result = 0;
const char* s = ref.c_str();
if (s == nullptr or *s == 0)
result = 1;
else
{
try
{
double v = std::stod(ref.c_str());
auto v = std::strtod(s, nullptr);
if (v < value)
result = -1;
else if (v > value)
......@@ -361,6 +368,7 @@ namespace detail
std::cerr << "conversion error in compare for '" << ref.c_str() << '\'' << std::endl;
result = 1;
}
}
return result;
}
......@@ -380,9 +388,16 @@ namespace detail
static int compare(const ItemReference& ref, unsigned long value, bool icase)
{
int result = 0;
const char* s = ref.c_str();
if (s == nullptr or *s == 0)
result = 1;
else
{
try
{
auto v = std::stoul(ref.c_str());
auto v = std::strtoul(s, nullptr, 10);
if (v < value)
result = -1;
else if (v > value)
......@@ -394,6 +409,7 @@ namespace detail
std::cerr << "conversion error in compare for '" << ref.c_str() << '\'' << std::endl;
result = 1;
}
}
return result;
}
......@@ -413,9 +429,16 @@ namespace detail
static int compare(const ItemReference& ref, long value, bool icase)
{
int result = 0;
const char* s = ref.c_str();
if (s == nullptr or *s == 0)
result = 1;
else
{
try
{
auto v = std::stol(ref.c_str());
auto v = std::strtol(s, nullptr, 10);
if (v < value)
result = -1;
else if (v > value)
......@@ -427,6 +450,7 @@ namespace detail
std::cerr << "conversion error in compare for '" << ref.c_str() << '\'' << std::endl;
result = 1;
}
}
return result;
}
......
......@@ -2524,7 +2524,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
if (pk == iv->mTag)
{
childTag = ck;
cond = std::move(cond) && ((Key(ck) == oldStrValue) or Key(ck) == Empty());
cond = std::move(cond) && Key(ck) == oldStrValue;
}
else
{
......@@ -2534,7 +2534,6 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
else
cond = std::move(cond) && ((Key(ck) == value) or Key(ck) == Empty());
}
}
if (cif::VERBOSE >= 2)
......
......@@ -891,8 +891,13 @@ void DictParser::linkItems()
auto& dict = *mDataBlock;
std::map<std::tuple<std::string,std::string>,size_t> linkIndex;
std::map<std::tuple<std::string,std::string>,int> linkGroupIds;
// links are identified by a parent category, a child category and a group ID
using key_type = std::tuple<std::string,std::string,int>;
std::map<key_type,size_t> linkIndex;
// Each link group consists of a set of keys
std::vector<std::tuple<std::vector<std::string>,std::vector<std::string>>> linkKeys;
auto addLink = [&](size_t ix, const std::string& pk, const std::string& ck)
......@@ -918,13 +923,11 @@ void DictParser::linkItems()
auto& linkedGroupList = dict["pdbx_item_linked_group_list"];
if (linkedGroupList.empty())
{
// for links recorded in categories but not in pdbx_item_linked_group_list
for (auto li: mImpl->mLinkedItems)
for (auto gl: linkedGroupList)
{
std::string child, parent;
std::tie(child, parent) = li;
int link_group_id;
cif::tie(child, parent, link_group_id) = gl.get("child_name", "parent_name", "link_group_id");
auto civ = mValidator.getValidatorForItem(child);
if (civ == nullptr)
......@@ -934,7 +937,7 @@ void DictParser::linkItems()
if (piv == nullptr)
error("in pdbx_item_linked_group_list, item '" + parent + "' is not specified");
auto key = std::make_tuple(piv->mCategory->mName, civ->mCategory->mName);
key_type key{ piv->mCategory->mName, civ->mCategory->mName, link_group_id };
if (not linkIndex.count(key))
{
linkIndex[key] = linkKeys.size();
......@@ -944,14 +947,15 @@ void DictParser::linkItems()
size_t ix = linkIndex.at(key);
addLink(ix, piv->mTag, civ->mTag);
}
}
else
// Only process inline linked items if the linked group list is absent
if (linkedGroupList.empty())
{
for (auto gl: linkedGroupList)
// for links recorded in categories but not in pdbx_item_linked_group_list
for (auto li: mImpl->mLinkedItems)
{
std::string child, parent;
int link_group_id;
cif::tie(child, parent, link_group_id) = gl.get("child_name", "parent_name", "link_group_id");
std::tie(child, parent) = li;
auto civ = mValidator.getValidatorForItem(child);
if (civ == nullptr)
......@@ -961,13 +965,11 @@ void DictParser::linkItems()
if (piv == nullptr)
error("in pdbx_item_linked_group_list, item '" + parent + "' is not specified");
auto key = std::make_tuple(piv->mCategory->mName, civ->mCategory->mName);
key_type key{ piv->mCategory->mName, civ->mCategory->mName, 0 };
if (not linkIndex.count(key))
{
linkIndex[key] = linkKeys.size();
linkKeys.push_back({});
linkGroupIds[key] = link_group_id;
}
size_t ix = linkIndex.at(key);
......@@ -981,10 +983,7 @@ void DictParser::linkItems()
for (auto& kv: linkIndex)
{
ValidateLink link = {};
std::tie(link.mParentCategory, link.mChildCategory) = kv.first;
if (linkGroupIds.count(kv.first))
link.mLinkGroupID = linkGroupIds[kv.first];
std::tie(link.mParentCategory, link.mChildCategory, link.mLinkGroupID) = kv.first;
std::tie(link.mParentKeys, link.mChildKeys) = linkKeys[kv.second];
......
......@@ -611,7 +611,6 @@ _cat_2.desc
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(d4)
......@@ -838,3 +837,226 @@ _cat_2.parent_id3
f.write(std::cout, {});
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(d5)
{
const char dict[] = R"(
data_test_dict.dic
_datablock.id test_dict.dic
_datablock.description
;
A test dictionary
;
_dictionary.title test_dict.dic
_dictionary.datablock_id test_dict.dic
_dictionary.version 1.0
loop_
_item_type_list.code
_item_type_list.primitive_code
_item_type_list.construct
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
int numb
'[+-]?[0-9]+'
save_cat_1
_category.description 'A simple test category'
_category.id cat_1
_category.mandatory_code no
_category_key.name '_cat_1.id'
save_
save__cat_1.id
_item.name '_cat_1.id'
_item.category_id cat_1
_item.mandatory_code yes
_item_type.code int
save_
save_cat_2
_category.description 'A second simple test category'
_category.id cat_2
_category.mandatory_code no
_category_key.name '_cat_2.id'
save_
save__cat_2.id
_item.name '_cat_2.id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id
_item.name '_cat_2.parent_id'
_item.category_id cat_2
_item.mandatory_code yes
_item_type.code int
save_
save__cat_2.parent_id2
_item.name '_cat_2.parent_id2'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
save__cat_2.parent_id3
_item.name '_cat_2.parent_id3'
_item.category_id cat_2
_item.mandatory_code no
_item_type.code code
save_
loop_
_pdbx_item_linked_group_list.child_category_id
_pdbx_item_linked_group_list.link_group_id
_pdbx_item_linked_group_list.child_name
_pdbx_item_linked_group_list.parent_name
_pdbx_item_linked_group_list.parent_category_id
cat_2 1 '_cat_2.parent_id' '_cat_1.id' cat_1
cat_2 2 '_cat_2.parent_id2' '_cat_1.id' cat_1
cat_2 3 '_cat_2.parent_id3' '_cat_1.id' cat_1
loop_
_pdbx_item_linked_group.category_id
_pdbx_item_linked_group.link_group_id
_pdbx_item_linked_group.label
cat_2 1 cat_2:cat_1:1
cat_2 2 cat_2:cat_1:2
cat_2 3 cat_2:cat_1:3
)";
struct membuf : public std::streambuf
{
membuf(char* text, size_t length)
{
this->setg(text, text, text + length);
}
} buffer(const_cast<char*>(dict), sizeof(dict) - 1);
std::istream is_dict(&buffer);
cif::File f;
f.loadDictionary(is_dict);
// --------------------------------------------------------------------
const char data[] = R"(
data_test
loop_
_cat_1.id
1
2
3
loop_
_cat_2.id
_cat_2.parent_id
_cat_2.parent_id2
_cat_2.parent_id3
1 1 ? ?
2 ? 1 ?
3 ? ? 1
4 2 2 ?
5 2 ? 2
6 ? 2 2
7 3 3 3
)";
struct data_membuf : public std::streambuf
{
data_membuf(char* text, size_t length)
{
this->setg(text, text, text + length);
}
} data_buffer(const_cast<char*>(data), sizeof(data) - 1);
std::istream is_data(&data_buffer);
f.load(is_data);
auto& cat1 = f.firstDatablock()["cat_1"];
auto& cat2 = f.firstDatablock()["cat_2"];
// check a rename in parent and child
for (auto r: cat1.find(cif::Key("id") == 1))
{
r["id"] = 10;
break;
}
f.write(std::cout, {});
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 7);
BOOST_CHECK(cat1.find(cif::Key("id") == 1).size() == 0);
BOOST_CHECK(cat1.find(cif::Key("id") == 10).size() == 1);
BOOST_CHECK(cat2.find(cif::Key("parent_id") == 1).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id2") == 1).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id3") == 1).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id") == 10).size() == 1);
BOOST_CHECK(cat2.find(cif::Key("parent_id2") == 10).size() == 1);
BOOST_CHECK(cat2.find(cif::Key("parent_id3") == 10).size() == 1);
for (auto r: cat1.find(cif::Key("id") == 2))
{
r["id"] = 20;
break;
}
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 7);
BOOST_CHECK(cat1.find(cif::Key("id") == 2).size() == 0);
BOOST_CHECK(cat1.find(cif::Key("id") == 20).size() == 1);
BOOST_CHECK(cat2.find(cif::Key("parent_id") == 2).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id2") == 2).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id3") == 2).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id") == 20).size() == 2);
BOOST_CHECK(cat2.find(cif::Key("parent_id2") == 20).size() == 2);
BOOST_CHECK(cat2.find(cif::Key("parent_id3") == 20).size() == 2);
for (auto r: cat1.find(cif::Key("id") == 3))
{
r["id"] = 30;
break;
}
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 7);
BOOST_CHECK(cat1.find(cif::Key("id") == 3).size() == 0);
BOOST_CHECK(cat1.find(cif::Key("id") == 30).size() == 1);
BOOST_CHECK(cat2.find(cif::Key("parent_id") == 3).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id2") == 3).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id3") == 3).size() == 0);
BOOST_CHECK(cat2.find(cif::Key("parent_id") == 30).size() == 1);
BOOST_CHECK(cat2.find(cif::Key("parent_id2") == 30).size() == 1);
BOOST_CHECK(cat2.find(cif::Key("parent_id3") == 30).size() == 1);
// test delete
cat1.erase(cif::Key("id") == 10);
BOOST_CHECK(cat1.size() == 2);
BOOST_CHECK(cat2.size() == 4);
cat1.erase(cif::Key("id") == 20);
BOOST_CHECK(cat1.size() == 1);
BOOST_CHECK(cat2.size() == 1);
cat1.erase(cif::Key("id") == 30);
BOOST_CHECK(cat1.size() == 0);
BOOST_CHECK(cat2.size() == 0);
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment