Skip to content

Commit

Permalink
new update_value in category
Browse files Browse the repository at this point in the history
  • Loading branch information
mhekkel committed Jan 31, 2024
1 parent 2fed7a7 commit 9a3eced
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 26 deletions.
31 changes: 30 additions & 1 deletion include/cif++/category.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,32 @@ class category

// --------------------------------------------------------------------

using value_provider_type = std::function<std::string_view(std::string_view)>;

/// \brief Update a single item named @a item_name in the rows that match
/// \a cond to values provided by a callback function \a value_provider
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.

void update_value(condition &&cond, std::string_view item_name,
value_provider_type &&value_provider)
{
auto rs = find(std::move(cond));
std::vector<row_handle> rows;
std::copy(rs.begin(), rs.end(), std::back_inserter(rows));
update_value(rows, item_name, std::move(value_provider));
}

/// \brief Update a single item named @a item_name in the rows \a rows
/// to values provided by a callback function \a value_provider
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.

void update_value(const std::vector<row_handle> &rows, std::string_view item_name,
value_provider_type &&value_provider);

/// \brief Update a single item named @a item_name in the rows that match \a cond to value \a value
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
Expand All @@ -982,7 +1008,10 @@ class category
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.

void update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value);
void update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value)
{
update_value(rows, item_name, [value](std::string_view) { return value; });
}

// --------------------------------------------------------------------
// Naming used to be very inconsistent. For backward compatibility,
Expand Down
40 changes: 15 additions & 25 deletions src/category.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,7 +1339,8 @@ std::string category::get_unique_value(std::string_view item_name)
return result;
}

void category::update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value)
void category::update_value(const std::vector<row_handle> &rows, std::string_view item_name,
value_provider_type &&value_provider)
{
using namespace std::literals;

Expand All @@ -1352,40 +1353,29 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie

auto &col = m_items[colIx];

// this is expensive, but better throw early on
// check the value
if (col.m_validator)
{
std::error_code ec;
col.m_validator->validate_value(value, ec);
if (ec)
throw validation_exception(ec, m_name, item_name);
}

// first some sanity checks, what was the old value and is it the same for all rows?
std::string oldValue{ rows.front()[item_name].text() };
for (auto row : rows)
{
if (oldValue != row[item_name].text())
for (auto row : rows)
{
std::ostringstream os;
std::string value{ value_provider(row[item_name].text()) };

os << "Inconsistent old values in update_value, trying to set " << std::quoted(value)
<< " as value for item " << item_name << " in category " << m_name;

throw std::runtime_error(os.str());
std::error_code ec;
col.m_validator->validate_value(value, ec);
if (ec)
throw validation_exception(ec, m_name, item_name);
}
}

if (oldValue == value) // no need to do anything
return;

// update rows, but do not cascade
for (auto row : rows)
row.assign(colIx, value, false);

// see if we need to update any child categories that depend on this value
// update and see if we need to update any child categories that depend on this value
for (auto parent : rows)
{
std::string oldValue{ parent[item_name].text() };
std::string value{ value_provider(oldValue) };

parent.assign(colIx, value, false);

for (auto &&[childCat, linked] : m_child_links)
{
if (std::find(linked->m_parent_keys.begin(), linked->m_parent_keys.end(), item_name) == linked->m_parent_keys.end())
Expand Down

0 comments on commit 9a3eced

Please sign in to comment.