Commit c3963bc4 by Maarten L. Hekkelman

Fixed linked update (regression)

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