Commit 04b7828a by Maarten L. Hekkelman

validator work

parent 9c621eca
......@@ -32,6 +32,7 @@
#include <cif++/v2/iterator.hpp>
#include <cif++/v2/row.hpp>
#include <cif++/v2/validate.hpp>
namespace cif::v2
{
......@@ -127,17 +128,22 @@ class category
throw std::runtime_error("No Validator specified");
if (m_cat_validator == nullptr)
m_validator->reportError("undefined Category", true);
m_validator->report_error("undefined Category", true);
iset result;
for (auto &iv : m_cat_validator->mItemValidators)
result.insert(iv.mTag);
for (auto &iv : m_cat_validator->m_item_validators)
result.insert(iv.m_tag);
return result;
}
const Validator *get_validator() const { return m_validator; }
const ValidateCategory *get_cat_validator() const { return m_cat_validator; }
void set_validator(const validator *v, datablock &db);
void update_links(datablock &db);
const validator *get_validator() const { return m_validator; }
const category_validator *get_cat_validator() const { return m_cat_validator; }
bool is_valid() const;
// --------------------------------------------------------------------
......@@ -379,6 +385,10 @@ class category
// insert_impl(pos, std::move(row));
// }
iterator erase(iterator pos);
size_t erase(condition &&cond);
size_t erase(condition &&cond, std::function<void(row_handle)> &&visit);
iterator emplace(std::initializer_list<item> items)
{
return this->emplace(items.begin(), items.end());
......@@ -388,52 +398,52 @@ class category
iterator emplace(ItemIter b, ItemIter e)
{
// First, make sure all mandatory fields are supplied
// if (mCatValidator != nullptr and b != e)
// {
// for (auto &col : m_columns)
// {
// auto iv = mCatValidator->getValidatorForItem(col.mName);
// if (iv == nullptr)
// continue;
// bool seen = false;
// for (auto v = b; v != e; ++v)
// {
// if (iequals(v->name(), col.mName))
// {
// seen = true;
// break;
// }
// }
// if (not seen and iv->mMandatory)
// throw std::runtime_error("missing mandatory field " + col.mName + " for category " + mName);
// }
// if (mIndex != nullptr)
// {
// std::unique_ptr<ItemRow> nr(new ItemRow{nullptr, this, nullptr});
// Row r(nr.get());
// auto keys = keyFields();
// for (auto v = b; v != e; ++v)
// {
// if (keys.count(v->name()))
// r.assign(v->name(), v->value(), true);
// }
// auto test = mIndex->find(nr.get());
// if (test != nullptr)
// {
// if (VERBOSE > 1)
// std::cerr << "Not inserting new record in " << mName << " (duplicate Key)" << std::endl;
// result = test;
// isNew = false;
// }
// }
// }
if (m_cat_validator != nullptr and b != e)
{
for (const auto &[column, iv] : m_columns)
{
if (iv == nullptr)
continue;
bool seen = false;
for (auto v = b; v != e; ++v)
{
if (iequals(v->name(), column))
{
iv->operator()(v->value());
seen = true;
break;
}
}
if (not seen and iv->m_mandatory)
throw std::runtime_error("missing mandatory field " + column + " for category " + m_name);
}
// if (mIndex != nullptr)
// {
// std::unique_ptr<ItemRow> nr(new ItemRow{nullptr, this, nullptr});
// Row r(nr.get());
// auto keys = keyFields();
// for (auto v = b; v != e; ++v)
// {
// if (keys.count(v->name()))
// r.assign(v->name(), v->value(), true);
// }
// auto test = mIndex->find(nr.get());
// if (test != nullptr)
// {
// if (VERBOSE > 1)
// std::cerr << "Not inserting new record in " << mName << " (duplicate Key)" << std::endl;
// result = test;
// isNew = false;
// }
// }
}
row *r = this->create_row();
......@@ -486,12 +496,12 @@ class category
break;
}
// if (VERBOSE > 0 and result == m_columns.size() and mCatValidator != nullptr) // validate the name, if it is known at all (since it was not found)
// {
// auto iv = mCatValidator->getValidatorForItem(name);
// if (iv == nullptr)
// std::cerr << "Invalid name used '" << name << "' is not a known column in " + mName << std::endl;
// }
if (VERBOSE > 0 and result == m_columns.size() and m_cat_validator != nullptr) // validate the name, if it is known at all (since it was not found)
{
auto iv = m_cat_validator->get_validator_for_item(column_name);
if (iv == nullptr)
std::cerr << "Invalid name used '" << name << "' is not a known column in " + m_name << std::endl;
}
return result;
}
......@@ -504,14 +514,14 @@ class category
if (result == m_columns.size())
{
const ValidateItem *item_validator = nullptr;
const item_validator *item_validator = nullptr;
// if (mCatValidator != nullptr)
// {
// item_validator = mCatValidator->getValidatorForItem(column_name);
// if (item_validator == nullptr)
// m_validator->reportError("tag " + std::string(column_name) + " not allowed in category " + mName, false);
// }
if (m_cat_validator != nullptr)
{
item_validator = m_cat_validator->get_validator_for_item(column_name);
if (item_validator == nullptr)
m_validator->report_error("tag " + std::string(column_name) + " not allowed in category " + m_name, false);
}
m_columns.emplace_back(column_name, item_validator);
}
......@@ -523,6 +533,9 @@ class category
void update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate = true);
private:
bool is_orphan(row_handle r) const;
void erase_orphans(condition &&cond);
using allocator_type = std::allocator<void>;
constexpr allocator_type get_allocator() const
......@@ -645,15 +658,27 @@ class category
struct item_column
{
std::string m_name;
const ValidateItem *m_validator;
const item_validator *m_validator;
item_column(std::string_view name, const ValidateItem *validator)
item_column(std::string_view name, const item_validator *validator)
: m_name(name)
, m_validator(validator)
{
}
};
struct link
{
link(category *linked, const link_validator *v)
: linked(linked)
, v(v)
{
}
category *linked;
const link_validator *v;
};
// proxy methods for every insertion
iterator insert_impl(const_iterator pos, row *n);
......@@ -661,8 +686,10 @@ class category
std::string m_name;
std::vector<item_column> m_columns;
const Validator *m_validator = nullptr;
const ValidateCategory *m_cat_validator = nullptr;
const validator *m_validator = nullptr;
const category_validator *m_cat_validator = nullptr;
std::vector<link> m_parent_links, m_child_links;
bool m_cascade = true;
row *m_head = nullptr, *m_tail = nullptr;
};
......
......@@ -63,6 +63,31 @@ class datablock
const std::string &name() const { return m_name; }
void set_validator(const validator *v)
{
m_validator = v;
for (auto &cat : *this)
cat.set_validator(v, *this);
}
const validator *get_validator() const
{
return m_validator;
}
bool is_valid() const
{
if (m_validator == nullptr)
throw std::runtime_error("Validator not specified");
bool result = true;
for (auto &cat : *this)
result = cat.is_valid() and result;
return result;
}
// --------------------------------------------------------------------
bool empty() const { return m_categories.empty(); }
......@@ -102,6 +127,18 @@ class datablock
return i == m_categories.end() ? s_empty : *i;
}
category *get(std::string_view name)
{
auto i = std::find_if(m_categories.begin(), m_categories.end(), [name](const category &c)
{ return iequals(c.name(), name); });
return i == m_categories.end() ? nullptr : &*i;
}
const category *get(std::string_view name) const
{
return const_cast<datablock *>(this)->get(name);
}
std::tuple<iterator, bool> emplace(std::string_view name)
{
bool is_new = true;
......@@ -182,6 +219,7 @@ class datablock
private:
category_list m_categories;
std::string m_name;
const validator *m_validator = nullptr;
};
} // namespace cif::v2
\ No newline at end of file
......@@ -31,6 +31,6 @@
namespace cif::v2
{
Validator parse_dictionary(std::string_view name, std::istream &is);
validator parse_dictionary(std::string_view name, std::istream &is);
} // namespace cif::v2
......@@ -60,6 +60,57 @@ class file
file &operator=(const file &) = default;
file &operator=(file &&) = default;
void set_validator(const validator *v)
{
m_validator = v;
for (auto &db : *this)
db.set_validator(v);
}
const validator *get_validator() const
{
return m_validator;
}
bool is_valid() const
{
if (m_validator == nullptr)
std::runtime_error("No validator loaded explicitly, cannot continue");
bool result = true;
for (auto &d : *this)
result = d.is_valid() and result;
return result;
}
bool is_valid()
{
if (m_validator == nullptr)
{
if (VERBOSE > 0)
std::cerr << "No dictionary loaded explicitly, loading default" << std::endl;
load_dictionary();
}
bool result = true;
for (auto &d : *this)
result = d.is_valid() and result;
return result;
}
void load_dictionary()
{
load_dictionary("mmcif_ddl");
}
void load_dictionary(std::string_view name)
{
set_validator(&validator_factory::instance()[name]);
}
datablock &operator[](std::string_view name)
{
auto i = std::find_if(m_datablocks.begin(), m_datablocks.end(), [name](const datablock &c)
......@@ -112,27 +163,36 @@ class file
bool empty() const { return m_datablocks.empty(); }
size_t size() const { return m_datablocks.size(); }
iterator begin() { return m_datablocks.begin(); }
iterator end() { return m_datablocks.end(); }
const_iterator cbegin() { return m_datablocks.begin(); }
const_iterator cend() { return m_datablocks.end(); }
const_iterator begin() const { return m_datablocks.begin(); }
const_iterator end() const { return m_datablocks.end(); }
reference front() { return m_datablocks.front(); }
reference back() { return m_datablocks.back(); }
void load(std::istream &is)
{
// auto saved = mValidator;
// setValidator(nullptr);
auto saved = m_validator;
set_validator(nullptr);
parser p(is, *this);
p.parse_file();
// if (saved != nullptr)
// {
// setValidator(saved);
// (void)isValid();
// }
if (saved != nullptr)
{
set_validator(saved);
(void)is_valid();
}
}
private:
datablock_list m_datablocks;
std::unique_ptr<Validator> m_validator;
const validator* m_validator = nullptr;
};
}
\ No newline at end of file
......@@ -199,7 +199,7 @@ struct item_handle
item_handle &operator=(const T &value)
{
item v{"", value};
m_row_handle.assign(m_column, v.value(), false);
assign_value(v);
return *this;
}
......@@ -281,6 +281,8 @@ struct item_handle
uint16_t m_column;
row_handle &m_row_handle;
void assign_value(const item &value);
static constexpr const char *s_empty_result = "";
};
......@@ -432,6 +434,20 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, const ch
};
template <typename T>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::string_view>>>
{
// static std::string_view convert(const item_handle &ref)
// {
// return ref.text();
// }
static int compare(const item_handle &ref, const std::string_view &value, bool icase)
{
return icase ? cif::icompare(ref.text(), value) : ref.text().compare(value);
}
};
template <typename T>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::string>>>
{
static std::string convert(const item_handle &ref)
......
......@@ -135,6 +135,7 @@ class row_handle
{
public:
friend class item_handle;
friend class category;
row_handle() = default;
......@@ -262,6 +263,11 @@ class row_handle
uint16_t add_column(std::string_view name);
operator row*()
{
return m_row;
}
void assign(const item &i, bool updateLinked)
{
assign(i.name(), i.value(), updateLinked);
......
......@@ -27,6 +27,7 @@
#pragma once
#include <filesystem>
#include <mutex>
// duh.. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
// #include <regex>
......@@ -43,19 +44,19 @@ namespace io = boost::iostreams;
namespace cif::v2
{
struct ValidateCategory;
class ValidatorFactory;
struct category_validator;
class validator_factory;
// --------------------------------------------------------------------
class ValidationError : public std::exception
class validation_error : public std::exception
{
public:
ValidationError(const std::string &msg);
ValidationError(const std::string &cat, const std::string &item,
validation_error(const std::string &msg);
validation_error(const std::string &cat, const std::string &item,
const std::string &msg);
const char *what() const noexcept { return mMsg.c_str(); }
std::string mMsg;
const char *what() const noexcept { return m_msg.c_str(); }
std::string m_msg;
};
// --------------------------------------------------------------------
......@@ -67,126 +68,120 @@ enum class DDL_PrimitiveType
Numb
};
DDL_PrimitiveType mapToPrimitiveType(std::string_view s);
DDL_PrimitiveType map_to_primitive_type(std::string_view s);
struct ValidateType
struct type_validator
{
std::string mName;
DDL_PrimitiveType mPrimitiveType;
std::string m_name;
DDL_PrimitiveType m_primitive_type;
// std::regex mRx;
boost::regex mRx;
boost::regex m_rx;
bool operator<(const ValidateType &rhs) const
bool operator<(const type_validator &rhs) const
{
return icompare(mName, rhs.mName) < 0;
return icompare(m_name, rhs.m_name) < 0;
}
// compare values based on type
// int compare(const std::string& a, const std::string& b) const
// {
// return compare(a.c_str(), b.c_str());
// }
int compare(const char *a, const char *b) const;
};
struct ValidateItem
struct item_validator
{
std::string mTag;
bool mMandatory;
const ValidateType *mType;
cif::iset mEnums;
std::string mDefault;
bool mDefaultIsNull;
ValidateCategory *mCategory = nullptr;
std::string m_tag;
bool m_mandatory;
const type_validator *m_type;
cif::iset m_enums;
std::string m_default;
bool m_default_is_null;
category_validator *m_category = nullptr;
// ItemLinked is used for non-key links
struct ItemLinked
struct item_link
{
ValidateItem *mParent;
std::string mParentItem;
std::string mChildItem;
item_validator *m_parent;
std::string m_parent_item;
std::string m_child_item;
};
std::vector<ItemLinked> mLinked;
std::vector<item_link> mLinked;
bool operator<(const ValidateItem &rhs) const
bool operator<(const item_validator &rhs) const
{
return icompare(mTag, rhs.mTag) < 0;
return icompare(m_tag, rhs.m_tag) < 0;
}
bool operator==(const ValidateItem &rhs) const
bool operator==(const item_validator &rhs) const
{
return iequals(mTag, rhs.mTag);
return iequals(m_tag, rhs.m_tag);
}
void operator()(std::string value) const;
void operator()(std::string_view value) const;
};
struct ValidateCategory
struct category_validator
{
std::string mName;
std::vector<std::string> mKeys;
cif::iset mGroups;
cif::iset mMandatoryFields;
std::set<ValidateItem> mItemValidators;
std::string m_name;
std::vector<std::string> m_keys;
cif::iset m_groups;
cif::iset m_mandatory_fields;
std::set<item_validator> m_item_validators;
bool operator<(const ValidateCategory &rhs) const
bool operator<(const category_validator &rhs) const
{
return icompare(mName, rhs.mName) < 0;
return icompare(m_name, rhs.m_name) < 0;
}
void addItemValidator(ValidateItem &&v);
void addItemValidator(item_validator &&v);
const ValidateItem *getValidatorForItem(std::string_view tag) const;
const item_validator *get_validator_for_item(std::string_view tag) const;
const std::set<ValidateItem> &itemValidators() const
const std::set<item_validator> &item_validators() const
{
return mItemValidators;
return m_item_validators;
}
};
struct ValidateLink
struct link_validator
{
int mLinkGroupID;
std::string mParentCategory;
std::vector<std::string> mParentKeys;
std::string mChildCategory;
std::vector<std::string> mChildKeys;
std::string mLinkGroupLabel;
int m_link_group_id;
std::string m_parent_category;
std::vector<std::string> m_parent_keys;
std::string m_child_category;
std::vector<std::string> m_child_keys;
std::string m_link_group_label;
};
// --------------------------------------------------------------------
class Validator
class validator
{
public:
Validator(std::string_view name)
validator(std::string_view name)
: m_name(name)
{
}
~Validator() = default;
~validator() = default;
Validator(const Validator &rhs) = delete;
Validator &operator=(const Validator &rhs) = delete;
validator(const validator &rhs) = delete;
validator &operator=(const validator &rhs) = delete;
Validator(Validator &&rhs) = default;
Validator &operator=(Validator &&rhs) = default;
validator(validator &&rhs) = default;
validator &operator=(validator &&rhs) = default;
friend class dictionary_parser;
void addTypeValidator(ValidateType &&v);
const ValidateType *getValidatorForType(std::string_view typeCode) const;
void add_type_validator(type_validator &&v);
const type_validator *get_validator_for_type(std::string_view type_code) const;
void addCategoryValidator(ValidateCategory &&v);
const ValidateCategory *getValidatorForCategory(std::string_view category) const;
void add_category_validator(category_validator &&v);
const category_validator *get_validator_for_category(std::string_view category) const;
void addLinkValidator(ValidateLink &&v);
std::vector<const ValidateLink *> getLinksForParent(std::string_view category) const;
std::vector<const ValidateLink *> getLinksForChild(std::string_view category) const;
void add_link_validator(link_validator &&v);
std::vector<const link_validator *> get_links_for_parent(std::string_view category) const;
std::vector<const link_validator *> get_links_for_child(std::string_view category) const;
void reportError(const std::string &msg, bool fatal) const;
void report_error(const std::string &msg, bool fatal) const;
const std::string &name() const { return m_name; }
void set_name(const std::string &name) { m_name = name; }
......@@ -196,37 +191,37 @@ class Validator
private:
// name is fully qualified here:
ValidateItem *getValidatorForItem(std::string_view name) const;
item_validator *get_validator_for_item(std::string_view name) const;
std::string m_name;
std::string m_version;
bool m_strict = false;
std::set<ValidateType> mTypeValidators;
std::set<ValidateCategory> mCategoryValidators;
std::vector<ValidateLink> mLinkValidators;
std::set<type_validator> m_type_validators;
std::set<category_validator> m_category_validators;
std::vector<link_validator> m_link_validators;
};
// --------------------------------------------------------------------
class ValidatorFactory
class validator_factory
{
public:
static ValidatorFactory &instance()
static validator_factory &instance()
{
static ValidatorFactory s_instance;
static validator_factory s_instance;
return s_instance;
}
const Validator &operator[](std::string_view dictionary_name);
const validator &operator[](std::string_view dictionary_name);
private:
void construct_validator(std::string_view name, std::istream &is);
// --------------------------------------------------------------------
ValidatorFactory() = default;
validator_factory() = default;
std::mutex mMutex;
std::list<Validator> mValidators;
std::mutex m_mutex;
std::list<validator> m_validators;
};
} // namespace cif::v2
......@@ -25,10 +25,371 @@
*/
#include <cif++/v2/category.hpp>
#include <cif++/v2/datablock.hpp>
namespace cif::v2
{
template <typename V>
std::string join(const V &arr, std::string_view sep)
{
std::ostringstream s;
if (not arr.empty())
{
auto ai = arr.begin();
auto ni = std::next(ai);
for (;;)
{
s << *ai;
ai = ni;
ni = std::next(ai);
if (ni == arr.end())
break;
s << sep;
}
}
return s.str();
}
void category::set_validator(const validator *v, datablock &db)
{
m_validator = v;
// if (m_index != nullptr)
// {
// delete m_index;
// m_index = nullptr;
// }
if (m_validator != nullptr)
{
m_cat_validator = m_validator->get_validator_for_category(m_name);
// if (m_cat_validator != nullptr)
// {
// m_index = new CatIndex(this);
// m_index->reconstruct();
// //#if DEBUG
// // assert(m_index->size() == size());
// // m_index->validate();
// //#endif
// }
}
else
m_cat_validator = nullptr;
for (auto &&[column, cv] : m_columns)
cv = m_cat_validator ? m_cat_validator->get_validator_for_item(column) : nullptr;
update_links(db);
}
void category::update_links(datablock &db)
{
m_child_links.clear();
m_parent_links.clear();
if (m_validator != nullptr)
{
for (auto link : m_validator->get_links_for_parent(m_name))
{
auto childCat = db.get(link->m_child_category);
if (childCat == nullptr)
continue;
m_child_links.emplace_back(childCat, link);
}
for (auto link : m_validator->get_links_for_child(m_name))
{
auto parentCat = db.get(link->m_parent_category);
if (parentCat == nullptr)
continue;
m_parent_links.emplace_back(parentCat, link);
}
}
}
bool category::is_valid() const
{
bool result = true;
if (m_validator == nullptr)
throw std::runtime_error("no Validator specified");
if (empty())
{
if (VERBOSE > 2)
std::cerr << "Skipping validation of empty Category " << m_name << std::endl;
return true;
}
if (m_cat_validator == nullptr)
{
m_validator->report_error("undefined Category " + m_name, false);
return false;
}
auto mandatory = m_cat_validator->m_mandatory_fields;
for (auto &col : m_columns)
{
auto iv = m_cat_validator->get_validator_for_item(col.m_name);
if (iv == nullptr)
{
m_validator->report_error("Field " + col.m_name + " is not valid in Category " + m_name, false);
result = false;
}
// col.m_validator = iv;
if (col.m_validator != iv)
m_validator->report_error("Column validator is not specified correctly", true);
mandatory.erase(col.m_name);
}
if (not mandatory.empty())
{
m_validator->report_error("In Category " + m_name + " the following mandatory fields are missing: " + join(mandatory, ", "), false);
result = false;
}
//#if not defined(NDEBUG)
// // check index?
// if (m_index)
// {
// m_index->validate();
// for (auto r: *this)
// {
// if (m_index->find(r.mData) != r.mData)
// m_validator->report_error("Key not found in index for Category " + m_name);
// }
// }
//#endif
// validate all values
mandatory = m_cat_validator->m_mandatory_fields;
for (auto ri = m_head; ri != nullptr; ri = ri->m_next)
{
for (size_t cix = 0; cix < m_columns.size(); ++cix)
{
bool seen = false;
auto iv = m_columns[cix].m_validator;
if (iv == nullptr)
{
m_validator->report_error("invalid field " + m_columns[cix].m_name + " for Category " + m_name, false);
result = false;
continue;
}
for (auto vi = ri->m_head; vi != nullptr; vi = vi->m_next)
{
if (vi->m_column_ix == cix)
{
seen = true;
try
{
(*iv)(vi->text());
}
catch (const std::exception &e)
{
m_validator->report_error("Error validating " + m_columns[cix].m_name + ": " + e.what(), false);
continue;
}
}
}
if (seen or ri != m_head)
continue;
if (iv != nullptr and iv->m_mandatory)
{
m_validator->report_error("missing mandatory field " + m_columns[cix].m_name + " for Category " + m_name, false);
result = false;
}
}
}
return result;
}
category::iterator category::erase(iterator pos)
{
row_handle rh = *pos;
row *r = rh;
iterator result = ++pos;
iset keys;
if (m_cat_validator)
keys = iset(m_cat_validator->m_keys.begin(), m_cat_validator->m_keys.end());
if (m_head == nullptr)
throw std::runtime_error("erase");
// if (mIndex != nullptr)
// mIndex->erase(r.mData);
if (r == m_head)
{
m_head = m_head->m_next;
r->m_next = nullptr;
}
else
{
for (auto pi = m_head; pi != nullptr; pi = pi->m_next)
{
if (pi->m_next == r)
{
pi->m_next = r->m_next;
r->m_next = nullptr;
break;
}
}
}
// links are created based on the _pdbx_item_linked_group_list entries
// in mmcif_pdbx_v50.dic dictionary.
//
// For each link group in _pdbx_item_linked_group_list
// a std::set of keys from one category is mapped to another.
// If all values in a child are the same as the specified parent ones
// the child is removed as well, recursively of course.
if (m_validator != nullptr)
{
for (auto &&[childCat, link] : m_child_links)
{
condition cond;
for (size_t ix = 0; ix < link->m_parent_keys.size(); ++ix)
{
std::string_view value = rh[link->m_parent_keys[ix]].text();
cond = std::move(cond) and (key(link->m_child_keys[ix]) == value);
}
childCat->erase_orphans(std::move(cond));
}
}
delete_row(r);
// reset mTail, if needed
if (r == m_tail)
{
m_tail = m_head;
if (m_tail != nullptr)
while (m_tail->m_next != nullptr)
m_tail = m_tail->m_next;
}
return result;
}
size_t category::erase(condition &&cond)
{
size_t result = 0;
cond.prepare(*this);
auto ri = begin();
while (ri != end())
{
if (cond(*ri))
{
ri = erase(ri);
++result;
}
else
++ri;
}
return result;
}
size_t category::erase(condition &&cond, std::function<void(row_handle)> &&visit)
{
size_t result = 0;
cond.prepare(*this);
auto ri = begin();
while (ri != end())
{
if (cond(*ri))
{
visit(*ri);
ri = erase(ri);
++result;
}
else
++ri;
}
return result;
}
bool category::is_orphan(row_handle r) const
{
// be safe
if (m_cat_validator == nullptr)
return false;
bool isOrphan = true;
for (auto &&[parentCat, link] : m_parent_links)
{
condition cond;
for (size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
{
std::string_view value = r[link->m_child_keys[ix]].text();
cond = std::move(cond) and (key(link->m_parent_keys[ix]) == value);
}
// if (VERBOSE > 2)
// std::cerr << "Check condition '" << cond << "' in parent category " << link->mParentCategory << " for child cat " << mName << std::endl;
if (parentCat->exists(std::move(cond)))
{
if (VERBOSE > 2)
std::cerr << "Not removing because row has a parent in category " << link->m_parent_category << std::endl;
isOrphan = false;
break;
}
}
return isOrphan;
}
void category::erase_orphans(condition &&cond)
{
std::vector<row *> remove;
cond.prepare(*this);
for (auto r : *this)
{
if (cond(r) and is_orphan(r))
{
if (VERBOSE > 1)
std::cerr << "Removing orphaned record: " << std::endl
<< r << std::endl
<< std::endl;
remove.push_back(r);
}
}
for (auto r : remove)
erase(iterator(*this, r));
}
void category::update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate)
{
auto &col = m_columns[column];
......@@ -50,9 +411,9 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
std::string oldStrValue = oldValue ? oldValue : "";
// // check the value
// if (col.m_validator and validate)
// (*col.m_validator)(value);
// check the value
if (col.m_validator and validate)
col.m_validator->operator()(value);
// If the field is part of the Key for this Category, remove it from the index
// before updating
......@@ -60,11 +421,11 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
bool reinsert = false;
// if (updateLinked and // an update of an Item's value
// cat->mIndex != nullptr and cat->keyFieldsByIndex().count(column))
// cat->m_index != nullptr and cat->keyFieldsByIndex().count(column))
// {
// reinsert = cat->mIndex->find(mData);
// reinsert = cat->m_index->find(mData);
// if (reinsert)
// cat->mIndex->erase(mData);
// cat->m_index->erase(mData);
// }
// first remove old value with cix
......@@ -112,87 +473,89 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
// if (reinsert)
// cat->mIndex->insert(mData);
// // see if we need to update any child categories that depend on this value
// auto iv = col.m_validator;
// if (not skipUpdateLinked and iv != nullptr and mCascade)
// {
// for (auto &&[childCat, linked] : cat->mChildLinks)
// {
// if (find(linked->mParentKeys.begin(), linked->mParentKeys.end(), iv->mTag) == linked->mParentKeys.end())
// continue;
// Condition cond;
// std::string childTag;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// // TODO add code to *NOT* test mandatory fields for Empty
// if (pk == iv->mTag)
// {
// childTag = ck;
// cond = std::move(cond) && Key(ck) == oldStrValue;
// }
// else
// {
// const char *pk_value = (*this)[pk].c_str();
// if (*pk_value == 0)
// cond = std::move(cond) && Key(ck) == Empty();
// else
// cond = std::move(cond) && ((Key(ck) == pk_value) or Key(ck) == Empty());
// }
// }
// auto rows = childCat->find(std::move(cond));
// if (rows.empty())
// continue;
// // if (cif::VERBOSE > 2)
// // {
// // std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::endl
// // << cond << std::endl;
// // }
// // Now, suppose there are already rows in child that conform to the new value,
// // we then skip this renam
// Condition cond_n;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// // TODO add code to *NOT* test mandatory fields for Empty
// if (pk == iv->mTag)
// cond_n = std::move(cond_n) && Key(ck) == value;
// else
// {
// const char *pk_value = (*this)[pk].c_str();
// if (*pk_value == 0)
// cond_n = std::move(cond_n) && Key(ck) == Empty();
// else
// cond_n = std::move(cond_n) && ((Key(ck) == pk_value) or Key(ck) == Empty());
// }
// }
// auto rows_n = childCat->find(std::move(cond_n));
// if (not rows_n.empty())
// {
// if (cif::VERBOSE > 0)
// std::cerr << "Will not rename in child category since there are already rows that link to the parent" << std::endl;
// continue;
// }
// for (auto &cr : rows)
// cr.assign(childTag, value, false);
// }
// }
// see if we need to update any child categories that depend on this value
auto iv = col.m_validator;
if (updateLinked and iv != nullptr /*and m_cascade*/)
{
row_handle rh(*this, *row);
for (auto &&[childCat, linked] : m_child_links)
{
if (std::find(linked->m_parent_keys.begin(), linked->m_parent_keys.end(), iv->m_tag) == linked->m_parent_keys.end())
continue;
condition cond;
std::string childTag;
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
{
std::string pk = linked->m_parent_keys[ix];
std::string ck = linked->m_child_keys[ix];
// TODO add code to *NOT* test mandatory fields for Empty
if (pk == iv->m_tag)
{
childTag = ck;
cond = std::move(cond) and key(ck) == oldStrValue;
}
else
{
std::string_view pk_value = rh[pk].text();
if (pk_value.empty())
cond = std::move(cond) and key(ck) == null;
else
cond = std::move(cond) and ((key(ck) == pk_value) or key(ck) == null);
}
}
auto rows = childCat->find(std::move(cond));
if (rows.empty())
continue;
// if (cif::VERBOSE > 2)
// {
// std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::endl
// << cond << std::endl;
// }
// Now, suppose there are already rows in child that conform to the new value,
// we then skip this renam
condition cond_n;
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
{
std::string pk = linked->m_parent_keys[ix];
std::string ck = linked->m_child_keys[ix];
// TODO add code to *NOT* test mandatory fields for Empty
if (pk == iv->m_tag)
cond_n = std::move(cond_n) and key(ck) == value;
else
{
std::string_view pk_value = rh[pk].text();
if (pk_value.empty())
cond_n = std::move(cond_n) and key(ck) == null;
else
cond_n = std::move(cond_n) and ((key(ck) == pk_value) or key(ck) == null);
}
}
auto rows_n = childCat->find(std::move(cond_n));
if (not rows_n.empty())
{
if (cif::VERBOSE > 0)
std::cerr << "Will not rename in child category since there are already rows that link to the parent" << std::endl;
continue;
}
for (auto cr : rows)
cr.assign(childTag, value, false);
}
}
}
// proxy methods for every insertion
......
......@@ -47,11 +47,11 @@ bool is_column_type_uchar(const category &cat, std::string_view col)
auto cv = cat.get_cat_validator();
if (cv)
{
auto iv = cv->getValidatorForItem(col);
if (iv != nullptr and iv->mType != nullptr)
auto iv = cv->get_validator_for_item(col);
if (iv != nullptr and iv->m_type != nullptr)
{
auto type = iv->mType;
result = type->mPrimitiveType == DDL_PrimitiveType::UChar;
auto type = iv->m_type;
result = type->m_primitive_type == DDL_PrimitiveType::UChar;
}
}
......
......@@ -43,7 +43,7 @@ inline void replace_all(std::string &s, std::string_view pat, std::string_view r
class dictionary_parser : public parser
{
public:
dictionary_parser(Validator &validator, std::istream &is, file &f)
dictionary_parser(validator &validator, std::istream &is, file &f)
: parser(is, f)
, m_validator(validator)
{
......@@ -83,17 +83,17 @@ class dictionary_parser : public parser
// store all validators
for (auto &ic : mCategoryValidators)
m_validator.addCategoryValidator(std::move(ic));
m_validator.add_category_validator(std::move(ic));
mCategoryValidators.clear();
for (auto &iv : mItemValidators)
{
auto cv = m_validator.getValidatorForCategory(iv.first);
auto cv = m_validator.get_validator_for_category(iv.first);
if (cv == nullptr)
error("Undefined category '" + iv.first);
for (auto &v : iv.second)
const_cast<ValidateCategory *>(cv)->addItemValidator(std::move(v));
const_cast<category_validator *>(cv)->addItemValidator(std::move(v));
}
// check all item validators for having a typeValidator
......@@ -145,15 +145,15 @@ class dictionary_parser : public parser
std::vector<std::string> tags;
while (m_lookahead == CIFToken::Tag)
{
std::string catName, itemName;
std::tie(catName, itemName) = splitTagName(m_token_value);
std::string catName, item_name;
std::tie(catName, item_name) = splitTagName(m_token_value);
if (cat == dict.end())
std::tie(cat, std::ignore) = dict.emplace(catName);
else if (not iequals(cat->name(), catName))
error("inconsistent categories in loop_");
tags.push_back(itemName);
tags.push_back(item_name);
match(CIFToken::Tag);
}
......@@ -173,8 +173,8 @@ class dictionary_parser : public parser
}
else
{
std::string catName, itemName;
std::tie(catName, itemName) = splitTagName(m_token_value);
std::string catName, item_name;
std::tie(catName, item_name) = splitTagName(m_token_value);
if (cat == dict.end() or not iequals(cat->name(), catName))
std::tie(cat, std::ignore) = dict.emplace(catName);
......@@ -183,7 +183,7 @@ class dictionary_parser : public parser
if (cat->empty())
cat->emplace({});
cat->back()[itemName] = m_token_value;
cat->back()[item_name] = m_token_value;
match(CIFToken::Value);
}
......@@ -204,7 +204,7 @@ class dictionary_parser : public parser
for (auto g : dict["category_group"])
groups.insert(g["id"].as<std::string>());
mCategoryValidators.push_back(ValidateCategory{category, keys, groups});
mCategoryValidators.push_back(category_validator{category, keys, groups});
}
else
{
......@@ -212,9 +212,9 @@ class dictionary_parser : public parser
std::string typeCode;
cif::v2::tie(typeCode) = dict["item_type"].front().get("code");
const ValidateType *tv = nullptr;
const type_validator *tv = nullptr;
if (not(typeCode.empty() or typeCode == "?"))
tv = m_validator.getValidatorForType(typeCode);
tv = m_validator.get_validator_for_type(typeCode);
iset ess;
for (auto e : dict["item_enumeration"])
......@@ -240,10 +240,10 @@ class dictionary_parser : public parser
cif::v2::tie(tagName, category, mandatory) = i.get("name", "category_id", "mandatory_code");
std::string catName, itemName;
std::tie(catName, itemName) = splitTagName(tagName);
std::string catName, item_name;
std::tie(catName, item_name) = splitTagName(tagName);
if (catName.empty() or itemName.empty())
if (catName.empty() or item_name.empty())
error("Invalid tag name in _item.name " + tagName);
if (not iequals(category, catName) and not(category.empty() or category == "?"))
......@@ -253,13 +253,13 @@ class dictionary_parser : public parser
auto &ivs = mItemValidators[category];
auto vi = find(ivs.begin(), ivs.end(), ValidateItem{itemName});
auto vi = find(ivs.begin(), ivs.end(), item_validator{item_name});
if (vi == ivs.end())
ivs.push_back(ValidateItem{itemName, iequals(mandatory, "yes"), tv, ess, defaultValue, defaultIsNull});
ivs.push_back(item_validator{item_name, iequals(mandatory, "yes"), tv, ess, defaultValue, defaultIsNull});
else
{
// need to update the itemValidator?
if (vi->mMandatory != (iequals(mandatory, "yes")))
if (vi->m_mandatory != (iequals(mandatory, "yes")))
{
if (VERBOSE > 2)
{
......@@ -268,24 +268,24 @@ class dictionary_parser : public parser
if (iequals(tagName, saveFrameName))
std::cerr << "choosing " << mandatory << std::endl;
else
std::cerr << "choosing " << (vi->mMandatory ? "Y" : "N") << std::endl;
std::cerr << "choosing " << (vi->m_mandatory ? "Y" : "N") << std::endl;
}
if (iequals(tagName, saveFrameName))
vi->mMandatory = (iequals(mandatory, "yes"));
vi->m_mandatory = (iequals(mandatory, "yes"));
}
if (vi->mType != nullptr and tv != nullptr and vi->mType != tv)
if (vi->m_type != nullptr and tv != nullptr and vi->m_type != tv)
{
if (VERBOSE > 1)
std::cerr << "inconsistent type for " << tagName << " in dictionary" << std::endl;
}
// vi->mMandatory = (iequals(mandatory, "yes"));
if (vi->mType == nullptr)
vi->mType = tv;
if (vi->m_type == nullptr)
vi->m_type = tv;
vi->mEnums.insert(ess.begin(), ess.end());
vi->m_enums.insert(ess.begin(), ess.end());
// anything else yet?
// ...
......@@ -349,15 +349,15 @@ class dictionary_parser : public parser
int link_group_id;
cif::v2::tie(child, parent, link_group_id) = gl.get("child_name", "parent_name", "link_group_id");
auto civ = m_validator.getValidatorForItem(child);
auto civ = m_validator.get_validator_for_item(child);
if (civ == nullptr)
error("in pdbx_item_linked_group_list, item '" + child + "' is not specified");
auto piv = m_validator.getValidatorForItem(parent);
auto piv = m_validator.get_validator_for_item(parent);
if (piv == nullptr)
error("in pdbx_item_linked_group_list, item '" + parent + "' is not specified");
key_type key{piv->mCategory->mName, civ->mCategory->mName, link_group_id};
key_type key{piv->m_category->m_name, civ->m_category->m_name, link_group_id};
if (not linkIndex.count(key))
{
linkIndex[key] = linkKeys.size();
......@@ -365,7 +365,7 @@ class dictionary_parser : public parser
}
size_t ix = linkIndex.at(key);
addLink(ix, piv->mTag, civ->mTag);
addLink(ix, piv->m_tag, civ->m_tag);
}
// Only process inline linked items if the linked group list is absent
......@@ -377,15 +377,15 @@ class dictionary_parser : public parser
std::string child, parent;
std::tie(child, parent) = li;
auto civ = m_validator.getValidatorForItem(child);
auto civ = m_validator.get_validator_for_item(child);
if (civ == nullptr)
error("in pdbx_item_linked_group_list, item '" + child + "' is not specified");
auto piv = m_validator.getValidatorForItem(parent);
auto piv = m_validator.get_validator_for_item(parent);
if (piv == nullptr)
error("in pdbx_item_linked_group_list, item '" + parent + "' is not specified");
key_type key{piv->mCategory->mName, civ->mCategory->mName, 0};
key_type key{piv->m_category->m_name, civ->m_category->m_name, 0};
if (not linkIndex.count(key))
{
linkIndex[key] = linkKeys.size();
......@@ -393,7 +393,7 @@ class dictionary_parser : public parser
}
size_t ix = linkIndex.at(key);
addLink(ix, piv->mTag, civ->mTag);
addLink(ix, piv->m_tag, civ->m_tag);
}
}
......@@ -402,29 +402,29 @@ class dictionary_parser : public parser
// now store the links in the validator
for (auto &kv : linkIndex)
{
ValidateLink link = {};
std::tie(link.mParentCategory, link.mChildCategory, link.mLinkGroupID) = kv.first;
link_validator link = {};
std::tie(link.m_parent_category, link.m_child_category, link.m_link_group_id) = kv.first;
std::tie(link.mParentKeys, link.mChildKeys) = linkKeys[kv.second];
std::tie(link.m_parent_keys, link.m_child_keys) = linkKeys[kv.second];
// look up the label
for (auto r : linkedGroup.find("category_id"_key == link.mChildCategory and "link_group_id"_key == link.mLinkGroupID))
for (auto r : linkedGroup.find("category_id"_key == link.m_child_category and "link_group_id"_key == link.m_link_group_id))
{
link.mLinkGroupLabel = r["label"].as<std::string>();
link.m_link_group_label = r["label"].as<std::string>();
break;
}
m_validator.addLinkValidator(std::move(link));
m_validator.add_link_validator(std::move(link));
}
// now make sure the itemType is specified for all itemValidators
for (auto &cv : m_validator.mCategoryValidators)
for (auto &cv : m_validator.m_category_validators)
{
for (auto &iv : cv.mItemValidators)
for (auto &iv : cv.m_item_validators)
{
if (iv.mType == nullptr and cif::VERBOSE >= 0)
std::cerr << "Missing item_type for " << iv.mTag << std::endl;
if (iv.m_type == nullptr and cif::VERBOSE >= 0)
std::cerr << "Missing item_type for " << iv.m_tag << std::endl;
}
}
}
......@@ -449,10 +449,10 @@ class dictionary_parser : public parser
try
{
ValidateType v = {
code, mapToPrimitiveType(primitiveCode), boost::regex(construct, boost::regex::extended | boost::regex::optimize)};
type_validator v = {
code, map_to_primitive_type(primitiveCode), boost::regex(construct, boost::regex::extended | boost::regex::optimize)};
m_validator.addTypeValidator(std::move(v));
m_validator.add_type_validator(std::move(v));
}
catch (const std::exception &)
{
......@@ -473,19 +473,19 @@ class dictionary_parser : public parser
return result;
}
Validator &m_validator;
validator &m_validator;
bool m_collected_item_types = false;
std::vector<ValidateCategory> mCategoryValidators;
std::map<std::string, std::vector<ValidateItem>> mItemValidators;
std::vector<category_validator> mCategoryValidators;
std::map<std::string, std::vector<item_validator>> mItemValidators;
std::set<std::tuple<std::string, std::string>> mLinkedItems;
};
// --------------------------------------------------------------------
Validator parse_dictionary(std::string_view name, std::istream &is)
validator parse_dictionary(std::string_view name, std::istream &is)
{
Validator result(name);
validator result(name);
file f;
dictionary_parser p(result, is, f);
......
......@@ -31,13 +31,21 @@ namespace cif::v2
std::string_view item_handle::text() const
{
for (auto iv = m_row_handle.m_row->m_head; iv != nullptr; iv = iv->m_next)
if (m_row_handle.m_row != nullptr)
{
if (iv->m_column_ix == m_column)
return iv->text();
for (auto iv = m_row_handle.m_row->m_head; iv != nullptr; iv = iv->m_next)
{
if (iv->m_column_ix == m_column)
return iv->text();
}
}
return {};
}
void item_handle::assign_value(const item &v)
{
m_row_handle.assign(m_column, v.value(), false);
}
}
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
*
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
......@@ -28,8 +28,8 @@
#include <fstream>
#include <iostream>
#include <cif++/v2/validate.hpp>
#include <cif++/v2/dictionary_parser.hpp>
#include <cif++/v2/validate.hpp>
namespace cif
{
......@@ -41,19 +41,19 @@ namespace cif::v2
using cif::VERBOSE;
ValidationError::ValidationError(const std::string &msg)
: mMsg(msg)
validation_error::validation_error(const std::string &msg)
: m_msg(msg)
{
}
ValidationError::ValidationError(const std::string &cat, const std::string &item, const std::string &msg)
: mMsg("When validating _" + cat + '.' + item + ": " + msg)
validation_error::validation_error(const std::string &cat, const std::string &item, const std::string &msg)
: m_msg("When validating _" + cat + '.' + item + ": " + msg)
{
}
// --------------------------------------------------------------------
DDL_PrimitiveType mapToPrimitiveType(std::string_view s)
DDL_PrimitiveType map_to_primitive_type(std::string_view s)
{
DDL_PrimitiveType result;
if (iequals(s, "char"))
......@@ -63,13 +63,13 @@ DDL_PrimitiveType mapToPrimitiveType(std::string_view s)
else if (iequals(s, "numb"))
result = DDL_PrimitiveType::Numb;
else
throw ValidationError("Not a known primitive type");
throw validation_error("Not a known primitive type");
return result;
}
// --------------------------------------------------------------------
int ValidateType::compare(const char *a, const char *b) const
int type_validator::compare(const char *a, const char *b) const
{
int result = 0;
......@@ -81,7 +81,7 @@ int ValidateType::compare(const char *a, const char *b) const
{
try
{
switch (mPrimitiveType)
switch (m_primitive_type)
{
case DDL_PrimitiveType::Numb:
{
......@@ -123,7 +123,7 @@ int ValidateType::compare(const char *a, const char *b) const
char ca = *ai;
char cb = *bi;
if (mPrimitiveType == DDL_PrimitiveType::UChar)
if (m_primitive_type == DDL_PrimitiveType::UChar)
{
ca = tolower(ca);
cb = tolower(cb);
......@@ -161,10 +161,10 @@ int ValidateType::compare(const char *a, const char *b) const
// --------------------------------------------------------------------
//void ValidateItem::addLinked(ValidateItem* parent, const std::string& parentItem, const std::string& childItem)
// void ValidateItem::addLinked(ValidateItem* parent, const std::string& parentItem, const std::string& childItem)
//{
//// if (mParent != nullptr and VERBOSE)
//// cerr << "replacing parent in " << mCategory->mName << " from " << mParent->mCategory->mName << " to " << parent->mCategory->mName << endl;
//// cerr << "replacing parent in " << mCategory->m_name << " from " << mParent->mCategory->m_name << " to " << parent->mCategory->m_name << endl;
//// mParent = parent;
//
// if (mType == nullptr and parent != nullptr)
......@@ -181,40 +181,40 @@ int ValidateType::compare(const char *a, const char *b) const
// }
//}
void ValidateItem::operator()(std::string value) const
void item_validator::operator()(std::string_view value) const
{
if (not value.empty() and value != "?" and value != ".")
{
if (mType != nullptr and not regex_match(value, mType->mRx))
throw ValidationError(mCategory->mName, mTag, "Value '" + value + "' does not match type expression for type " + mType->mName);
if (m_type != nullptr and not regex_match(value.begin(), value.end(), m_type->m_rx))
throw validation_error(m_category->m_name, m_tag, "Value '" + std::string{value} + "' does not match type expression for type " + m_type->m_name);
if (not mEnums.empty())
if (not m_enums.empty())
{
if (mEnums.count(value) == 0)
throw ValidationError(mCategory->mName, mTag, "Value '" + value + "' is not in the list of allowed values");
if (m_enums.count(std::string{value}) == 0)
throw validation_error(m_category->m_name, m_tag, "Value '" + std::string{value} + "' is not in the list of allowed values");
}
}
}
// --------------------------------------------------------------------
void ValidateCategory::addItemValidator(ValidateItem &&v)
void category_validator::addItemValidator(item_validator &&v)
{
if (v.mMandatory)
mMandatoryFields.insert(v.mTag);
if (v.m_mandatory)
m_mandatory_fields.insert(v.m_tag);
v.mCategory = this;
v.m_category = this;
auto r = mItemValidators.insert(std::move(v));
auto r = m_item_validators.insert(std::move(v));
if (not r.second and VERBOSE >= 4)
std::cout << "Could not add validator for item " << v.mTag << " to category " << mName << std::endl;
std::cout << "Could not add validator for item " << v.m_tag << " to category " << m_name << std::endl;
}
const ValidateItem *ValidateCategory::getValidatorForItem(std::string_view tag) const
const item_validator *category_validator::get_validator_for_item(std::string_view tag) const
{
const ValidateItem *result = nullptr;
auto i = mItemValidators.find(ValidateItem{std::string(tag)});
if (i != mItemValidators.end())
const item_validator *result = nullptr;
auto i = m_item_validators.find(item_validator{std::string(tag)});
if (i != m_item_validators.end())
result = &*i;
else if (VERBOSE > 4)
std::cout << "No validator for tag " << tag << std::endl;
......@@ -223,53 +223,53 @@ const ValidateItem *ValidateCategory::getValidatorForItem(std::string_view tag)
// --------------------------------------------------------------------
void Validator::addTypeValidator(ValidateType &&v)
void validator::add_type_validator(type_validator &&v)
{
auto r = mTypeValidators.insert(std::move(v));
auto r = m_type_validators.insert(std::move(v));
if (not r.second and VERBOSE > 4)
std::cout << "Could not add validator for type " << v.mName << std::endl;
std::cout << "Could not add validator for type " << v.m_name << std::endl;
}
const ValidateType *Validator::getValidatorForType(std::string_view typeCode) const
const type_validator *validator::get_validator_for_type(std::string_view typeCode) const
{
const ValidateType *result = nullptr;
const type_validator *result = nullptr;
auto i = mTypeValidators.find(ValidateType{std::string(typeCode), DDL_PrimitiveType::Char, boost::regex()});
if (i != mTypeValidators.end())
auto i = m_type_validators.find(type_validator{std::string(typeCode), DDL_PrimitiveType::Char, boost::regex()});
if (i != m_type_validators.end())
result = &*i;
else if (VERBOSE > 4)
std::cout << "No validator for type " << typeCode << std::endl;
return result;
}
void Validator::addCategoryValidator(ValidateCategory &&v)
void validator::add_category_validator(category_validator &&v)
{
auto r = mCategoryValidators.insert(std::move(v));
auto r = m_category_validators.insert(std::move(v));
if (not r.second and VERBOSE > 4)
std::cout << "Could not add validator for category " << v.mName << std::endl;
std::cout << "Could not add validator for category " << v.m_name << std::endl;
}
const ValidateCategory *Validator::getValidatorForCategory(std::string_view category) const
const category_validator *validator::get_validator_for_category(std::string_view category) const
{
const ValidateCategory *result = nullptr;
auto i = mCategoryValidators.find(ValidateCategory{std::string(category)});
if (i != mCategoryValidators.end())
const category_validator *result = nullptr;
auto i = m_category_validators.find(category_validator{std::string(category)});
if (i != m_category_validators.end())
result = &*i;
else if (VERBOSE > 4)
std::cout << "No validator for category " << category << std::endl;
return result;
}
ValidateItem *Validator::getValidatorForItem(std::string_view tag) const
item_validator *validator::get_validator_for_item(std::string_view tag) const
{
ValidateItem *result = nullptr;
item_validator *result = nullptr;
std::string cat, item;
std::tie(cat, item) = splitTagName(tag);
auto *cv = getValidatorForCategory(cat);
auto *cv = get_validator_for_category(cat);
if (cv != nullptr)
result = const_cast<ValidateItem *>(cv->getValidatorForItem(item));
result = const_cast<item_validator *>(cv->get_validator_for_item(item));
if (result == nullptr and VERBOSE > 4)
std::cout << "No validator for item " << tag << std::endl;
......@@ -277,80 +277,80 @@ ValidateItem *Validator::getValidatorForItem(std::string_view tag) const
return result;
}
void Validator::addLinkValidator(ValidateLink &&v)
void validator::add_link_validator(link_validator &&v)
{
assert(v.mParentKeys.size() == v.mChildKeys.size());
if (v.mParentKeys.size() != v.mChildKeys.size())
assert(v.m_parent_keys.size() == v.m_child_keys.size());
if (v.m_parent_keys.size() != v.m_child_keys.size())
throw std::runtime_error("unequal number of keys for parent and child in link");
auto pcv = getValidatorForCategory(v.mParentCategory);
auto ccv = getValidatorForCategory(v.mChildCategory);
auto pcv = get_validator_for_category(v.m_parent_category);
auto ccv = get_validator_for_category(v.m_child_category);
if (pcv == nullptr)
throw std::runtime_error("unknown parent category " + v.mParentCategory);
throw std::runtime_error("unknown parent category " + v.m_parent_category);
if (ccv == nullptr)
throw std::runtime_error("unknown child category " + v.mChildCategory);
throw std::runtime_error("unknown child category " + v.m_child_category);
for (size_t i = 0; i < v.mParentKeys.size(); ++i)
for (size_t i = 0; i < v.m_parent_keys.size(); ++i)
{
auto piv = pcv->getValidatorForItem(v.mParentKeys[i]);
auto piv = pcv->get_validator_for_item(v.m_parent_keys[i]);
if (piv == nullptr)
throw std::runtime_error("unknown parent tag _" + v.mParentCategory + '.' + v.mParentKeys[i]);
throw std::runtime_error("unknown parent tag _" + v.m_parent_category + '.' + v.m_parent_keys[i]);
auto civ = ccv->getValidatorForItem(v.mChildKeys[i]);
auto civ = ccv->get_validator_for_item(v.m_child_keys[i]);
if (civ == nullptr)
throw std::runtime_error("unknown child tag _" + v.mChildCategory + '.' + v.mChildKeys[i]);
throw std::runtime_error("unknown child tag _" + v.m_child_category + '.' + v.m_child_keys[i]);
if (civ->mType == nullptr and piv->mType != nullptr)
const_cast<ValidateItem *>(civ)->mType = piv->mType;
if (civ->m_type == nullptr and piv->m_type != nullptr)
const_cast<item_validator *>(civ)->m_type = piv->m_type;
}
mLinkValidators.emplace_back(std::move(v));
m_link_validators.emplace_back(std::move(v));
}
std::vector<const ValidateLink *> Validator::getLinksForParent(std::string_view category) const
std::vector<const link_validator *> validator::get_links_for_parent(std::string_view category) const
{
std::vector<const ValidateLink *> result;
std::vector<const link_validator *> result;
for (auto &l : mLinkValidators)
for (auto &l : m_link_validators)
{
if (l.mParentCategory == category)
if (l.m_parent_category == category)
result.push_back(&l);
}
return result;
}
std::vector<const ValidateLink *> Validator::getLinksForChild(std::string_view category) const
std::vector<const link_validator *> validator::get_links_for_child(std::string_view category) const
{
std::vector<const ValidateLink *> result;
std::vector<const link_validator *> result;
for (auto &l : mLinkValidators)
for (auto &l : m_link_validators)
{
if (l.mChildCategory == category)
if (l.m_child_category == category)
result.push_back(&l);
}
return result;
}
void Validator::reportError(const std::string &msg, bool fatal) const
void validator::report_error(const std::string &msg, bool fatal) const
{
if (m_strict or fatal)
throw ValidationError(msg);
throw validation_error(msg);
else if (VERBOSE > 0)
std::cerr << msg << std::endl;
}
// --------------------------------------------------------------------
const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
const validator &validator_factory::operator[](std::string_view dictionary_name)
{
std::lock_guard lock(mMutex);
std::lock_guard lock(m_mutex);
for (auto &validator : mValidators)
for (auto &validator : m_validators)
{
if (iequals(validator.name(), dictionary_name))
return validator;
......@@ -384,12 +384,12 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
{
for (const char *dir : {
#if defined(CACHE_DIR)
CACHE_DIR,
CACHE_DIR,
#endif
#if defined(DATA_DIR)
DATA_DIR
DATA_DIR
#endif
})
})
{
auto p2 = std::filesystem::path(dir) / p;
if (std::filesystem::exists(p2, ec) and not ec)
......@@ -417,14 +417,14 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
throw std::runtime_error("Dictionary not found or defined (" + dictionary.string() + ")");
}
assert(iequals(mValidators.back().name(), dictionary_name));
assert(iequals(m_validators.back().name(), dictionary_name));
return mValidators.back();
return m_validators.back();
}
void ValidatorFactory::construct_validator(std::string_view name, std::istream &is)
void validator_factory::construct_validator(std::string_view name, std::istream &is)
{
mValidators.emplace_back(parse_dictionary(name, is));
parse_dictionary(name, is);
}
} // namespace cif
} // namespace cif::v2
......@@ -36,6 +36,7 @@
// #include <cif++/CifParser.hpp>
#include <cif++/v2/parser.hpp>
#include <cif++/v2/dictionary_parser.hpp>
namespace tt = boost::test_tools;
......@@ -307,7 +308,7 @@ _test.name
// test.clear();
// auto n = test.erase(cif::Key("id") == 1, [](const cif::Row &r)
// auto n = test.erase(cif::v2::key("id") == 1, [](const cif::Row &r)
// {
// BOOST_CHECK_EQUAL(r["id"].as<int>(), 1);
// BOOST_CHECK_EQUAL(r["name"].as<std::string>(), "aap"); });
......@@ -385,171 +386,172 @@ _test.value
BOOST_CHECK(test.find("value"_key == cif::v2::null).size() == 2);
}
// // --------------------------------------------------------------------
// BOOST_AUTO_TEST_CASE(d1)
// {
// 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
// _item_type_list.detail
// code char
// '[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
// ; code item types/single words ...
// ;
// text char
// '[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
// ; text item types / multi-line text ...
// ;
// int numb
// '[+-]?[0-9]+'
// ; int item types are the subset of numbers that are the negative
// or positive integers.
// ;
// 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_aliases.dictionary cif_core.dic
// _item_aliases.version 2.0.1
// _item_linked.child_name '_cat_2.parent_id'
// _item_linked.parent_name '_cat_1.id'
// _item_type.code code
// save_
// save__cat_1.name
// _item.name '_cat_1.name'
// _item.category_id cat_1
// _item.mandatory_code yes
// _item_aliases.dictionary cif_core.dic
// _item_aliases.version 2.0.1
// _item_type.code text
// 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_aliases.dictionary cif_core.dic
// _item_aliases.version 2.0.1
// _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_aliases.dictionary cif_core.dic
// _item_aliases.version 2.0.1
// _item_type.code code
// save_
// save__cat_2.desc
// _item.name '_cat_2.desc'
// _item.category_id cat_2
// _item.mandatory_code yes
// _item_aliases.dictionary cif_core.dic
// _item_aliases.version 2.0.1
// _item_type.code text
// save_
// )";
// --------------------------------------------------------------------
// 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);
BOOST_AUTO_TEST_CASE(d1)
{
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
_item_type_list.detail
code char
'[][_,.;:"&<>()/\{}'`~!@#$%A-Za-z0-9*|+-]*'
; code item types/single words ...
;
text char
'[][ \n\t()_,.;:"&<>/\{}'`~!@#$%?+=*A-Za-z0-9|^-]*'
; text item types / multi-line text ...
;
int numb
'[+-]?[0-9]+'
; int item types are the subset of numbers that are the negative
or positive integers.
;
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_aliases.dictionary cif_core.dic
_item_aliases.version 2.0.1
_item_linked.child_name '_cat_2.parent_id'
_item_linked.parent_name '_cat_1.id'
_item_type.code code
save_
save__cat_1.name
_item.name '_cat_1.name'
_item.category_id cat_1
_item.mandatory_code yes
_item_aliases.dictionary cif_core.dic
_item_aliases.version 2.0.1
_item_type.code text
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_aliases.dictionary cif_core.dic
_item_aliases.version 2.0.1
_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_aliases.dictionary cif_core.dic
_item_aliases.version 2.0.1
_item_type.code code
save_
save__cat_2.desc
_item.name '_cat_2.desc'
_item.category_id cat_2
_item.mandatory_code yes
_item_aliases.dictionary cif_core.dic
_item_aliases.version 2.0.1
_item_type.code text
save_
)";
// std::istream is_dict(&buffer);
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);
// cif::Validator validator("test", is_dict);
std::istream is_dict(&buffer);
// cif::File f;
// f.setValidator(&validator);
auto validator = cif::v2::parse_dictionary("test", is_dict);
// // --------------------------------------------------------------------
cif::v2::file f;
f.set_validator(&validator);
// const char data[] = R"(
// data_test
// loop_
// _cat_1.id
// _cat_1.name
// 1 Aap
// 2 Noot
// 3 Mies
// --------------------------------------------------------------------
// loop_
// _cat_2.id
// _cat_2.parent_id
// _cat_2.desc
// 1 1 'Een dier'
// 2 1 'Een andere aap'
// 3 2 'walnoot bijvoorbeeld'
// )";
const char data[] = R"(
data_test
loop_
_cat_1.id
_cat_1.name
1 Aap
2 Noot
3 Mies
// 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);
loop_
_cat_2.id
_cat_2.parent_id
_cat_2.desc
1 1 'Een dier'
2 1 'Een andere aap'
3 2 'walnoot bijvoorbeeld'
)";
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);
std::istream is_data(&data_buffer);
f.load(is_data);
// auto &cat1 = f.front()["cat_1"];
// auto &cat2 = f.front()["cat_2"];
auto &cat1 = f.front()["cat_1"];
auto &cat2 = f.front()["cat_2"];
// BOOST_CHECK(cat1.size() == 3);
// BOOST_CHECK(cat2.size() == 3);
BOOST_CHECK(cat1.size() == 3);
BOOST_CHECK(cat2.size() == 3);
// cat1.erase(cif::Key("id") == 1);
cat1.erase(cif::v2::key("id") == 1);
// BOOST_CHECK(cat1.size() == 2);
// BOOST_CHECK(cat2.size() == 1);
BOOST_CHECK(cat1.size() == 2);
BOOST_CHECK(cat2.size() == 1);
// // BOOST_CHECK_THROW(cat2.emplace({
// // { "id", 4 },
// // { "parent_id", 4 },
// // { "desc", "moet fout gaan" }
// // }), std::exception);
// BOOST_CHECK_THROW(cat2.emplace({
// { "id", 4 },
// { "parent_id", 4 },
// { "desc", "moet fout gaan" }
// }), std::exception);
// BOOST_CHECK_THROW(cat2.emplace({{"id", "vijf"}, // <- invalid value
// {"parent_id", 2},
// {"desc", "moet fout gaan"}}),
// std::exception);
// }
BOOST_CHECK_THROW(cat2.emplace({
{"id", "vijf"}, // <- invalid value
{"parent_id", 2},
{"desc", "moet fout gaan"}}),
std::exception);
}
// // --------------------------------------------------------------------
......@@ -621,7 +623,7 @@ _test.value
// std::istream is_dict(&buffer);
// cif::Validator validator("test", is_dict);
// cif::v2::validator validator("test", is_dict);
// cif::File f;
// f.setValidator(&validator);
......@@ -653,11 +655,11 @@ _test.value
// BOOST_CHECK(cat1.size() == 3);
// cat1.erase(cif::Key("id") == "AAP");
// cat1.erase(cif::v2::key("id") == "AAP");
// BOOST_CHECK(cat1.size() == 3);
// cat1.erase(cif::Key("id") == "noot");
// cat1.erase(cif::v2::key("id") == "noot");
// BOOST_CHECK(cat1.size() == 2);
// }
......@@ -769,7 +771,7 @@ _test.value
// std::istream is_dict(&buffer);
// cif::Validator validator("test", is_dict);
// cif::v2::validator validator("test", is_dict);
// cif::File f;
// f.setValidator(&validator);
......@@ -813,7 +815,7 @@ _test.value
// // check a rename in parent and child
// for (auto r : cat1.find(cif::Key("id") == 1))
// for (auto r : cat1.find(cif::v2::key("id") == 1))
// {
// r["id"] = 10;
// break;
......@@ -822,15 +824,15 @@ _test.value
// BOOST_CHECK(cat1.size() == 3);
// BOOST_CHECK(cat2.size() == 4);
// BOOST_CHECK(cat1.find(cif::Key("id") == 1).size() == 0);
// BOOST_CHECK(cat1.find(cif::Key("id") == 10).size() == 1);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 1).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 10).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 2);
// // check a rename in parent and child, this time only one child should be renamed
// for (auto r : cat1.find(cif::Key("id") == 2))
// for (auto r : cat1.find(cif::v2::key("id") == 2))
// {
// r["id"] = 20;
// break;
......@@ -839,25 +841,25 @@ _test.value
// BOOST_CHECK(cat1.size() == 3);
// BOOST_CHECK(cat2.size() == 4);
// BOOST_CHECK(cat1.find(cif::Key("id") == 2).size() == 0);
// BOOST_CHECK(cat1.find(cif::Key("id") == 20).size() == 1);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 2).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 20).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 2).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 20).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 2 and cif::Key("name2") == "noot").size() == 0);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 2 and cif::Key("name2") == "n2").size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 20 and cif::Key("name2") == "noot").size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 20 and cif::Key("name2") == "n2").size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2 and cif::v2::key("name2") == "noot").size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2 and cif::v2::key("name2") == "n2").size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20 and cif::v2::key("name2") == "noot").size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20 and cif::v2::key("name2") == "n2").size() == 0);
// // // --------------------------------------------------------------------
// // cat1.erase(cif::Key("id") == 10);
// // cat1.erase(cif::v2::key("id") == 10);
// // BOOST_CHECK(cat1.size() == 2);
// // BOOST_CHECK(cat2.size() == 2);
// // cat1.erase(cif::Key("id") == 20);
// // cat1.erase(cif::v2::key("id") == 20);
// // BOOST_CHECK(cat1.size() == 1);
// // BOOST_CHECK(cat2.size() == 1);
......@@ -972,7 +974,7 @@ _test.value
// std::istream is_dict(&buffer);
// cif::Validator validator("test", is_dict);
// cif::v2::validator validator("test", is_dict);
// cif::File f;
// f.setValidator(&validator);
......@@ -1026,7 +1028,7 @@ _test.value
// // check a rename in parent and child
// for (auto r : cat1.find(cif::Key("id") == 1))
// for (auto r : cat1.find(cif::v2::key("id") == 1))
// {
// r["id"] = 10;
// break;
......@@ -1035,13 +1037,13 @@ _test.value
// BOOST_CHECK(cat1.size() == 4);
// BOOST_CHECK(cat2.size() == 13);
// BOOST_CHECK(cat1.find(cif::Key("id") == 1).size() == 0);
// BOOST_CHECK(cat1.find(cif::Key("id") == 10).size() == 1);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 1).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 1).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 10).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 2);
// for (auto r : cat1.find(cif::Key("id") == 2))
// for (auto r : cat1.find(cif::v2::key("id") == 2))
// {
// r["id"] = 20;
// break;
......@@ -1050,13 +1052,13 @@ _test.value
// BOOST_CHECK(cat1.size() == 4);
// BOOST_CHECK(cat2.size() == 13);
// BOOST_CHECK(cat1.find(cif::Key("id") == 2).size() == 0);
// BOOST_CHECK(cat1.find(cif::Key("id") == 20).size() == 1);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 2).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 20).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 2).size() == 2);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 20).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 2);
// for (auto r : cat1.find(cif::Key("id") == 3))
// for (auto r : cat1.find(cif::v2::key("id") == 3))
// {
// r["id"] = 30;
// break;
......@@ -1065,13 +1067,13 @@ _test.value
// BOOST_CHECK(cat1.size() == 4);
// BOOST_CHECK(cat2.size() == 13);
// BOOST_CHECK(cat1.find(cif::Key("id") == 3).size() == 0);
// BOOST_CHECK(cat1.find(cif::Key("id") == 30).size() == 1);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 3).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 30).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 3).size() == 2);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 30).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 3).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 30).size() == 1);
// for (auto r : cat1.find(cif::Key("id") == 4))
// for (auto r : cat1.find(cif::v2::key("id") == 4))
// {
// r["id"] = 40;
// break;
......@@ -1080,11 +1082,11 @@ _test.value
// BOOST_CHECK(cat1.size() == 4);
// BOOST_CHECK(cat2.size() == 13);
// BOOST_CHECK(cat1.find(cif::Key("id") == 4).size() == 0);
// BOOST_CHECK(cat1.find(cif::Key("id") == 10).size() == 1);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 4).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::key("id") == 10).size() == 1);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 4).size() == 3);
// BOOST_CHECK(cat2.find(cif::Key("parent_id") == 40).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 4).size() == 3);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 40).size() == 0);
// }
// // --------------------------------------------------------------------
......@@ -1193,7 +1195,7 @@ _test.value
// std::istream is_dict(&buffer);
// cif::Validator validator("test", is_dict);
// cif::v2::validator validator("test", is_dict);
// cif::File f;
// f.setValidator(&validator);
......@@ -1241,7 +1243,7 @@ _test.value
// // --------------------------------------------------------------------
// // check iterate children
// auto PR2set = cat1.find(cif::Key("id") == 2);
// auto PR2set = cat1.find(cif::v2::key("id") == 2);
// BOOST_ASSERT(PR2set.size() == 1);
// auto PR2 = PR2set.front();
// BOOST_CHECK(PR2["id"].as<int>() == 2);
......@@ -1257,7 +1259,7 @@ _test.value
// // check a rename in parent and child
// for (auto r : cat1.find(cif::Key("id") == 1))
// for (auto r : cat1.find(cif::v2::key("id") == 1))
// {
// r["id"] = 10;
// break;
......@@ -1266,17 +1268,17 @@ _test.value
// 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(cat1.find(cif::v2::key("id") == 1).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::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);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 1).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 10).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 10).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 10).size() == 1);
// for (auto r : cat1.find(cif::Key("id") == 2))
// for (auto r : cat1.find(cif::v2::key("id") == 2))
// {
// r["id"] = 20;
// break;
......@@ -1285,17 +1287,17 @@ _test.value
// 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(cat1.find(cif::v2::key("id") == 2).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::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);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 2).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 2).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 2).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 20).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 20).size() == 2);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 20).size() == 2);
// for (auto r : cat1.find(cif::Key("id") == 3))
// for (auto r : cat1.find(cif::v2::key("id") == 3))
// {
// r["id"] = 30;
// break;
......@@ -1304,27 +1306,27 @@ _test.value
// 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(cat1.find(cif::v2::key("id") == 3).size() == 0);
// BOOST_CHECK(cat1.find(cif::v2::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);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 3).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 3).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 3).size() == 0);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id") == 30).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id2") == 30).size() == 1);
// BOOST_CHECK(cat2.find(cif::v2::key("parent_id3") == 30).size() == 1);
// // test delete
// cat1.erase(cif::Key("id") == 10);
// cat1.erase(cif::v2::key("id") == 10);
// BOOST_CHECK(cat1.size() == 2);
// BOOST_CHECK(cat2.size() == 4);
// cat1.erase(cif::Key("id") == 20);
// cat1.erase(cif::v2::key("id") == 20);
// BOOST_CHECK(cat1.size() == 1);
// BOOST_CHECK(cat2.size() == 1);
// cat1.erase(cif::Key("id") == 30);
// cat1.erase(cif::v2::key("id") == 30);
// BOOST_CHECK(cat1.size() == 0);
// BOOST_CHECK(cat2.size() == 0);
// }
......@@ -1349,21 +1351,21 @@ _test.value
// auto &db = f.front();
// for (auto r : db["test"].find(cif::Key("id") == 1))
// for (auto r : db["test"].find(cif::v2::key("id") == 1))
// {
// const auto &[id, name] = r.get<int, std::string>({"id", "name"});
// BOOST_CHECK(id == 1);
// BOOST_CHECK(name == "aap");
// }
// for (auto r : db["test"].find(cif::Key("id") == 4))
// for (auto r : db["test"].find(cif::v2::key("id") == 4))
// {
// const auto &[id, name] = r.get<int, std::string>({"id", "name"});
// BOOST_CHECK(id == 4);
// BOOST_CHECK(name.empty());
// }
// for (auto r : db["test"].find(cif::Key("id") == 5))
// for (auto r : db["test"].find(cif::v2::key("id") == 5))
// {
// const auto &[id, name] = r.get<int, std::string>({"id", "name"});
// BOOST_CHECK(id == 5);
......@@ -1456,7 +1458,7 @@ _test.value
// }
// }
// const auto &[id, name] = db["test"].find1<int, std::string>(cif::Key("id") == 1, "id", "name");
// const auto &[id, name] = db["test"].find1<int, std::string>(cif::v2::key("id") == 1, "id", "name");
// BOOST_CHECK(id == 1);
// BOOST_CHECK(name == "aap");
......@@ -1621,7 +1623,7 @@ _test.value
// } buffer(const_cast<char *>(dict), sizeof(dict) - 1);
// std::istream is_dict(&buffer);
// cif::Validator validator("test", is_dict);
// cif::v2::validator validator("test", is_dict);
// cif::File f;
// f.setValidator(&validator);
......
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