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
......@@ -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;
}
}
......
......@@ -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);
}
}
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