ValuePath.h header

#include <ew/core/ValuePath.h>

Namespace ew::core

Functions

const FieldDefinition * ew::core::taxonomy::fieldAtPath(const Taxonomy &taxonomy, const FieldDefinition &field, const QString &path)

The field path names, walking from field through taxonomy's blocks; null when the path names nothing.

The schema-side twin of valueAtPath, and what tells a consumer the TYPE at a path – so a rollup can refuse to sum a path that holds text before it sums anything.

QString ew::core::taxonomy::joinValuePath(const QStringList &steps)

The steps in path joined back into one – the inverse of splitValuePath.

QStringList ew::core::taxonomy::splitValuePath(const QString &path)

A dotted path to a value inside a property block – stats.strength, cost.materials.iron.

The reason a block is data rather than a naming convention. A rule, a rollup, a search column and an export all need to name one value inside a group, and they need to name it the SAME way or a rule written in one place silently matches nothing in another. The split and the walk both live here so there is exactly one answer to "what does `stats.strength` mean".

A path with one step is an ordinary field key, so every consumer can take a path and nothing has to special-case the un-nested case.

std::optional< ew::core::entity::FieldValue > ew::core::taxonomy::valueAtPath(const ew::core::entity::FieldValue &value, const QString &path)

The value path names inside value, or nothing when the path does not lead anywhere.

Answers nothing rather than an empty value for a path that does not EXIST, so a caller can tell "this stat is not filled in" from "this block has no such stat" – which is the difference between a blank on a form and a rule written against a typo.

QStringList ew::core::taxonomy::valuePathsFor(const Taxonomy &taxonomy, const FieldDefinition &field)

Every path a value of field offers, stats.strength and deeper, in declaration order.

Includes the field's own key first, so a caller listing "everything addressable here" gets the block itself as well as its members. Cycle-safe: a block already entered is not entered again, so a project holding a cycle written by an older build lists a finite set rather than hanging.

ew::core::entity::FieldValue ew::core::taxonomy::withValueAtPath(const ew::core::entity::FieldValue &value, const QString &path, ew::core::entity::FieldValue member)

value with the value at path replaced by member, creating the blocks along the way.

Creating them is the point: filling in stats.strength on an entity that has never had a stats value must work, and asking every caller to build the empty block first is how one of them comes to build it differently.