Commit c3963bc4 by Maarten L. Hekkelman

Fixed linked update (regression)

parent 23bd51ac
...@@ -718,11 +718,13 @@ struct ConditionImpl ...@@ -718,11 +718,13 @@ struct ConditionImpl
virtual void prepare(const Category& c) {} virtual void prepare(const Category& c) {}
virtual bool test(const Category& c, const Row& r) const = 0; virtual bool test(const Category& c, const Row& r) const = 0;
virtual void str(std::ostream& os) const = 0;
}; };
struct AllConditionImpl : public ConditionImpl struct AllConditionImpl : public ConditionImpl
{ {
virtual bool test(const Category& c, const Row& r) const { return true; } virtual bool test(const Category& c, const Row& r) const { return true; }
virtual void str(std::ostream& os) const { os << "*"; }
}; };
struct orConditionImpl; struct orConditionImpl;
...@@ -789,11 +791,20 @@ class Condition ...@@ -789,11 +791,20 @@ class Condition
std::swap(mPrepared, rhs.mPrepared); std::swap(mPrepared, rhs.mPrepared);
} }
friend std::ostream& operator<<(std::ostream& os, const Condition& cond);
private: private:
detail::ConditionImpl* mImpl; detail::ConditionImpl* mImpl;
bool mPrepared = false; bool mPrepared = false;
}; };
inline std::ostream& operator<<(std::ostream& os, const Condition& cond)
{
if (cond.mImpl)
cond.mImpl->str(os);
return os;
}
namespace detail namespace detail
{ {
...@@ -808,7 +819,12 @@ struct KeyIsEmptyConditionImpl : public ConditionImpl ...@@ -808,7 +819,12 @@ struct KeyIsEmptyConditionImpl : public ConditionImpl
{ {
return r[mItemIx].empty(); return r[mItemIx].empty();
} }
virtual void str(std::ostream& os) const
{
os << mItemTag << " IS NULL";
}
std::string mItemTag; std::string mItemTag;
size_t mItemIx; size_t mItemIx;
}; };
...@@ -816,8 +832,8 @@ struct KeyIsEmptyConditionImpl : public ConditionImpl ...@@ -816,8 +832,8 @@ struct KeyIsEmptyConditionImpl : public ConditionImpl
struct KeyCompareConditionImpl : public ConditionImpl struct KeyCompareConditionImpl : public ConditionImpl
{ {
template<typename COMP> template<typename COMP>
KeyCompareConditionImpl(const std::string& ItemTag, COMP&& comp) KeyCompareConditionImpl(const std::string& ItemTag, COMP&& comp, const std::string& s)
: mItemTag(ItemTag), mComp(std::move(comp)) {} : mItemTag(ItemTag), mComp(std::move(comp)), mStr(s) {}
virtual void prepare(const Category& c); virtual void prepare(const Category& c);
...@@ -826,10 +842,16 @@ struct KeyCompareConditionImpl : public ConditionImpl ...@@ -826,10 +842,16 @@ struct KeyCompareConditionImpl : public ConditionImpl
return mComp(c, r, mCaseInsensitive); return mComp(c, r, mCaseInsensitive);
} }
virtual void str(std::ostream& os) const
{
os << mItemTag << (mCaseInsensitive ? "^ " : " ") << mStr;
}
std::string mItemTag; std::string mItemTag;
size_t mItemIx; size_t mItemIx;
bool mCaseInsensitive = false; bool mCaseInsensitive = false;
std::function<bool(const Category&, const Row&, bool)> mComp; std::function<bool(const Category&, const Row&, bool)> mComp;
std::string mStr;
}; };
struct KeyMatchesConditionImpl : public ConditionImpl struct KeyMatchesConditionImpl : public ConditionImpl
...@@ -843,6 +865,11 @@ struct KeyMatchesConditionImpl : public ConditionImpl ...@@ -843,6 +865,11 @@ struct KeyMatchesConditionImpl : public ConditionImpl
{ {
return std::regex_match(r[mItemIx].as<std::string>(), mRx); return std::regex_match(r[mItemIx].as<std::string>(), mRx);
} }
virtual void str(std::ostream& os) const
{
os << mItemTag << " =~ expression";
}
std::string mItemTag; std::string mItemTag;
size_t mItemIx; size_t mItemIx;
...@@ -858,6 +885,10 @@ struct anyIsConditionImpl : public ConditionImpl ...@@ -858,6 +885,10 @@ struct anyIsConditionImpl : public ConditionImpl
: mValue(value) {} : mValue(value) {}
virtual bool test(const Category& c, const Row& r) const; virtual bool test(const Category& c, const Row& r) const;
virtual void str(std::ostream& os) const
{
os << "<any> == " << mValue;
}
valueType mValue; valueType mValue;
}; };
...@@ -868,6 +899,10 @@ struct anyMatchesConditionImpl : public ConditionImpl ...@@ -868,6 +899,10 @@ struct anyMatchesConditionImpl : public ConditionImpl
: mRx(rx) {} : mRx(rx) {}
virtual bool test(const Category& c, const Row& r) const; virtual bool test(const Category& c, const Row& r) const;
virtual void str(std::ostream& os) const
{
os << "<any> =~ expression";
}
std::regex mRx; std::regex mRx;
}; };
...@@ -880,6 +915,11 @@ struct allConditionImpl : public ConditionImpl ...@@ -880,6 +915,11 @@ struct allConditionImpl : public ConditionImpl
{ {
return true; return true;
} }
virtual void str(std::ostream& os) const
{
os << "*";
}
}; };
struct andConditionImpl : public ConditionImpl struct andConditionImpl : public ConditionImpl
...@@ -908,6 +948,15 @@ struct andConditionImpl : public ConditionImpl ...@@ -908,6 +948,15 @@ struct andConditionImpl : public ConditionImpl
return mA->test(c, r) and mB->test(c, r); return mA->test(c, r) and mB->test(c, r);
} }
virtual void str(std::ostream& os) const
{
os << '(';
mA->str(os);
os << ") AND (";
mB->str(os);
os << ')';
}
ConditionImpl* mA; ConditionImpl* mA;
ConditionImpl* mB; ConditionImpl* mB;
}; };
...@@ -937,7 +986,16 @@ struct orConditionImpl : public ConditionImpl ...@@ -937,7 +986,16 @@ struct orConditionImpl : public ConditionImpl
{ {
return mA->test(c, r) or mB->test(c, r); return mA->test(c, r) or mB->test(c, r);
} }
virtual void str(std::ostream& os) const
{
os << '(';
mA->str(os);
os << ") OR (";
mB->str(os);
os << ')';
}
ConditionImpl* mA; ConditionImpl* mA;
ConditionImpl* mB; ConditionImpl* mB;
}; };
...@@ -964,7 +1022,14 @@ struct notConditionImpl : public ConditionImpl ...@@ -964,7 +1022,14 @@ struct notConditionImpl : public ConditionImpl
{ {
return not mA->test(c, r); return not mA->test(c, r);
} }
virtual void str(std::ostream& os) const
{
os << "NOT (";
mA->str(os);
os << ')';
}
ConditionImpl* mA; ConditionImpl* mA;
}; };
...@@ -1004,8 +1069,11 @@ struct Key ...@@ -1004,8 +1069,11 @@ struct Key
template<typename T> template<typename T>
Condition operator==(const Key& key, const T& v) Condition operator==(const Key& key, const T& v)
{ {
std::ostringstream s;
s << "== " << v;
return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase) return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase)
{ return r[tag].template compare<T>(v, icase) == 0; })); { return r[tag].template compare<T>(v, icase) == 0; }, s.str()));
} }
// inline Condition operator==(const Key& key, const detail::ItemReference& v) // inline Condition operator==(const Key& key, const detail::ItemReference& v)
...@@ -1037,29 +1105,41 @@ inline Condition operator!=(const Key& key, const char* v) ...@@ -1037,29 +1105,41 @@ inline Condition operator!=(const Key& key, const char* v)
template<typename T> template<typename T>
Condition operator>(const Key& key, const T& v) Condition operator>(const Key& key, const T& v)
{ {
std::ostringstream s;
s << ">" << v;
return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase) return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase)
{ return r[tag].template compare<T>(v, icase) > 0; })); { return r[tag].template compare<T>(v, icase) > 0; }, s.str()));
} }
template<typename T> template<typename T>
Condition operator>=(const Key& key, const T& v) Condition operator>=(const Key& key, const T& v)
{ {
std::ostringstream s;
s << ">=" << v;
return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase) return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase)
{ return r[tag].template compare<T>(v, icase) >= 0; })); { return r[tag].template compare<T>(v, icase) >= 0; }, s.str()));
} }
template<typename T> template<typename T>
Condition operator<(const Key& key, const T& v) Condition operator<(const Key& key, const T& v)
{ {
std::ostringstream s;
s << "<" << v;
return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase) return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase)
{ return r[tag].template compare<T>(v, icase) < 0; })); { return r[tag].template compare<T>(v, icase) < 0; }, s.str()));
} }
template<typename T> template<typename T>
Condition operator<=(const Key& key, const T& v) Condition operator<=(const Key& key, const T& v)
{ {
std::ostringstream s;
s << "<=" << v;
return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase) return Condition(new detail::KeyCompareConditionImpl(key.mItemTag, [tag = key.mItemTag, v](const Category& c, const Row& r, bool icase)
{ return r[tag].template compare<T>(v, icase) <= 0; })); { return r[tag].template compare<T>(v, icase) <= 0; }, s.str()));
} }
template<> template<>
......
...@@ -2519,7 +2519,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked) ...@@ -2519,7 +2519,7 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
std::string pk = linked->mParentKeys[ix]; std::string pk = linked->mParentKeys[ix];
std::string ck = linked->mChildKeys[ix]; std::string ck = linked->mChildKeys[ix];
// TODO add code to *NOT* test mandatory fiels for Empty // TODO add code to *NOT* test mandatory fields for Empty
if (pk == iv->mTag) if (pk == iv->mTag)
{ {
...@@ -2529,16 +2529,19 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked) ...@@ -2529,16 +2529,19 @@ void Row::assign(size_t column, const std::string& value, bool skipUpdateLinked)
else else
{ {
const char* value = (*this)[pk].c_str(); const char* value = (*this)[pk].c_str();
cond = std::move(cond) && ((Key(ck) == value) or Key(ck) == Empty()); if (*value == 0)
cond = std::move(cond) && Key(ck) == Empty();
else
cond = std::move(cond) && ((Key(ck) == value) or Key(ck) == Empty());
} }
} }
// if (cif::VERBOSE > 2) if (cif::VERBOSE >= 2)
// { {
// std::std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::std::endl std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::endl
// << cond << std::std::endl; << cond << std::endl;
// } }
auto rows = childCat->find(std::move(cond)); auto rows = childCat->find(std::move(cond));
for (auto& cr: rows) for (auto& cr: rows)
......
...@@ -894,86 +894,110 @@ void DictParser::linkItems() ...@@ -894,86 +894,110 @@ void DictParser::linkItems()
std::map<std::tuple<std::string,std::string>,size_t> linkIndex; std::map<std::tuple<std::string,std::string>,size_t> linkIndex;
std::map<std::tuple<std::string,std::string>,int> linkGroupIds; std::map<std::tuple<std::string,std::string>,int> linkGroupIds;
std::vector<std::tuple<std::vector<std::string>,std::vector<std::string>>> linkKeys; std::vector<std::tuple<std::vector<std::string>,std::vector<std::string>>> linkKeys;
for (auto gl: dict["pdbx_item_linked_group_list"]) auto addLink = [&](size_t ix, const std::string& pk, const std::string& ck)
{ {
std::string child, parent; auto&& [pkeys, ckeys] = linkKeys.at(ix);
int link_group_id;
cif::tie(child, parent, link_group_id) = gl.get("child_name", "parent_name", "link_group_id"); bool found = false;
for (size_t i = 0; i < pkeys.size(); ++i)
auto civ = mValidator.getValidatorForItem(child);
if (civ == nullptr)
error("in pdbx_item_linked_group_list, item '" + child + "' is not specified");
auto piv = mValidator.getValidatorForItem(parent);
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);
if (not linkIndex.count(key))
{ {
linkIndex[key] = linkKeys.size(); if (pkeys[i] == pk and ckeys[i] == ck)
linkKeys.push_back({}); {
found = true;
break;
}
}
linkGroupIds[key] = link_group_id; if (not found)
{
pkeys.push_back(pk);
ckeys.push_back(ck);
} }
};
size_t ix = linkIndex.at(key);
std::get<0>(linkKeys.at(ix)).push_back(piv->mTag);
std::get<1>(linkKeys.at(ix)).push_back(civ->mTag);
}
// for links recorded in categories but not in pdbx_item_linked_group_list auto& linkedGroupList = dict["pdbx_item_linked_group_list"];
for (auto li: mImpl->mLinkedItems)
{
std::string child, parent;
std::tie(child, parent) = li;
auto civ = mValidator.getValidatorForItem(child);
if (civ == nullptr)
error("in pdbx_item_linked_group_list, item '" + child + "' is not specified");
auto piv = mValidator.getValidatorForItem(parent);
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); if (linkedGroupList.empty())
if (not linkIndex.count(key)) {
// for links recorded in categories but not in pdbx_item_linked_group_list
for (auto li: mImpl->mLinkedItems)
{ {
linkIndex[key] = linkKeys.size(); std::string child, parent;
linkKeys.push_back({}); std::tie(child, parent) = li;
auto civ = mValidator.getValidatorForItem(child);
if (civ == nullptr)
error("in pdbx_item_linked_group_list, item '" + child + "' is not specified");
auto piv = mValidator.getValidatorForItem(parent);
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);
if (linkIndex.count(key))
{
linkIndex[key] = linkKeys.size();
linkKeys.push_back({});
}
size_t ix = linkIndex.at(key);
addLink(ix, piv->mTag, civ->mTag);
} }
size_t ix = linkIndex.at(key);
std::get<0>(linkKeys.at(ix)).push_back(piv->mTag);
std::get<1>(linkKeys.at(ix)).push_back(civ->mTag);
} }
else
auto& linkedGroup = dict["pdbx_item_linked_group"];
// now store the links in the validator
for (auto& kv: linkIndex)
{ {
ValidateLink link = {}; for (auto gl: linkedGroupList)
std::tie(link.mParentCategory, link.mChildCategory) = kv.first; {
std::string child, parent;
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)
error("in pdbx_item_linked_group_list, item '" + child + "' is not specified");
auto piv = mValidator.getValidatorForItem(parent);
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);
if (not linkIndex.count(key))
{
linkIndex[key] = linkKeys.size();
linkKeys.push_back({});
if (linkGroupIds.count(kv.first)) linkGroupIds[key] = link_group_id;
link.mLinkGroupID = linkGroupIds[kv.first]; }
std::tie(link.mParentKeys, link.mChildKeys) = linkKeys[kv.second]; size_t ix = linkIndex.at(key);
addLink(ix, piv->mTag, civ->mTag);
}
// look up the label auto& linkedGroup = dict["pdbx_item_linked_group"];
for (auto r: linkedGroup.find(cif::Key("category_id") == link.mChildCategory and cif::Key("link_group_id") == link.mLinkGroupID))
// now store the links in the validator
for (auto& kv: linkIndex)
{ {
link.mLinkGroupLabel = r["label"].as<std::string>(); ValidateLink link = {};
break; std::tie(link.mParentCategory, link.mChildCategory) = kv.first;
}
if (linkGroupIds.count(kv.first))
link.mLinkGroupID = linkGroupIds[kv.first];
std::tie(link.mParentKeys, link.mChildKeys) = linkKeys[kv.second];
// look up the label
for (auto r: linkedGroup.find(cif::Key("category_id") == link.mChildCategory and cif::Key("link_group_id") == link.mLinkGroupID))
{
link.mLinkGroupLabel = r["label"].as<std::string>();
break;
}
mValidator.addLinkValidator(std::move(link)); mValidator.addLinkValidator(std::move(link));
}
} }
// now make sure the itemType is specified for all itemValidators // now make sure the itemType is specified for all itemValidators
for (auto& cv: mValidator.mCategoryValidators) for (auto& cv: mValidator.mCategoryValidators)
......
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