Entity.h header

#include <ew/core/entity/Entity.h>

Namespace ew::core::entity

Entity class

class ew::core::entity::Entity

A codex entity: a named content object that belongs to a taxonomy category and carries values for the fields that apply to it. This is the bridge between the content graph and the taxonomy.

Values are stored by field key and are typed (see FieldValue): a Number holds a number, a Boolean holds a boolean, a Reference holds an id. They used to be strings whatever the field declared, so every consumer re-parsed – and every consumer could parse differently.

The entity does not police the type, because it does not hold the schema. The fields that apply come from TWO places – the category chain (see taxonomy::Taxonomy::effectiveFields) and its own ownFields, which belong to this entity alone – so the category id no longer selects the whole schema by itself and the entity has to be asked. Coercion and rejection therefore happen at the boundary holding both (see coerceToFieldType and ew::app::entity::coerceForField).

Members

ew::core::entity::Entity::Entity(ew::core::foundation::ContentId id, ew::core::foundation::CategoryId categoryId, QString name)

Creates an entity with identity id, in category categoryId (a null id means uncategorized), and display name name.

ew::core::foundation::CategoryId ew::core::entity::Entity::categoryId() const

The entity's PRIMARY category; a null id means uncategorized.

Primary rather than only: an entity may carry further memberships – see additionalCategoryIds below. This one decides where it sits in the codex tree and what it is called in one word, because a thing shown in two places at once is a thing a reader cannot find twice as easily – they simply lose track of which copy they edited.

void ew::core::entity::Entity::setCategoryId(ew::core::foundation::CategoryId categoryId)

Sets the entity's primary category (a null id means uncategorized).

const std::vector< ew::core::foundation::CategoryId > & ew::core::entity::Entity::additionalCategoryIds() const

The entity's further category memberships, in the order they apply, primary excluded.

The axis a single category could not express. A sword that is both an Item and a Cursed Object had to be modelled by duplicating fields across categories, by inventing a combined category for every pairing, or by keeping the second role as loose text. Each membership contributes its own properties, and the order decides which declaration wins a shared key – primary first, then these, first-wins, with the collision reported rather than silent.

void ew::core::entity::Entity::setAdditionalCategoryIds(const std::vector< ew::core::foundation::CategoryId > &categoryIds)

Sets the further memberships. The primary is not one of them and is ignored if present.

std::vector< ew::core::foundation::CategoryId > ew::core::entity::Entity::categoryIds() const

Every membership in the order they apply: the primary first, then the additional ones.

The list consumers should walk. Asking for the primary alone is right only where the answer is about PLACEMENT – where the entity sits in the tree – and asking that when the question was "is this an Item" is how the cursed sword escapes the rule written for Items.

int ew::core::entity::Entity::sortIndex() const

Where this entity sits among its siblings when the writer has arranged them by hand; 0 means they have not. See Category::sortIndex for the rule, which is shared: the codex tree holds categories and entities in one list and orders them together.

void ew::core::entity::Entity::setSortIndex(int sortIndex)

Sets this entity's place among its siblings; 0 returns it to the default order.

const QString & ew::core::entity::Entity::name() const

The entity's display name (used for lists, links, and previews).

void ew::core::entity::Entity::setName(QString name)

Sets the entity's display name.

void ew::core::entity::Entity::setValue(QString key, FieldValue value)

Sets the value for field key, replacing any existing value.

std::optional< FieldValue > ew::core::entity::Entity::value(QStringView key) const

Returns the value stored for field key, or std::nullopt if none is set.

std::optional< QString > ew::core::entity::Entity::valueText(QStringView key) const

The value for field key written for a person to read, or std::nullopt if none is set.

For the many surfaces that want a string and do not care what kind of value produced it – a table cell, a search index, a tooltip. It goes through FieldValue::toDisplayString, so a number rendered in a table and the same number in a hover preview cannot come out differently.

bool ew::core::entity::Entity::hasValue(QStringView key) const

Returns true if a value is stored for field key.

bool ew::core::entity::Entity::clearValue(QStringView key)

Removes the value for field key. Returns true if a value was removed.

const std::map< QString, FieldValue > & ew::core::entity::Entity::values() const

All stored field values, keyed by field key in deterministic (sorted) order.

std::optional< qint64 > ew::core::entity::Entity::birthInstant() const

The instant (minutes since the story epoch) this entity came into being, if known. A canon fact the timeline continuity engine uses for lifespan and age checks: an event with this entity as a participant must not occur before it.

void ew::core::entity::Entity::setBirthInstant(std::optional< qint64 > birthInstant)

Sets the entity's birth instant (std::nullopt when unknown).

std::optional< qint64 > ew::core::entity::Entity::deathInstant() const

The instant this entity ceased to be, if known. An event with this entity as a participant must not occur after it.

void ew::core::entity::Entity::setDeathInstant(std::optional< qint64 > deathInstant)

Sets the entity's death instant (std::nullopt when unknown).

const std::vector< TimedFieldValue > & ew::core::entity::Entity::timedValues() const

The entity's state-over-time: the timed changes to its field values across the story timeline (see TimedFieldValue), in no particular order. Empty when the entity has no timed values (its fields are constant).

void ew::core::entity::Entity::setTimedValues(std::vector< TimedFieldValue > timedValues)

Sets the entity's state-over-time (its timed field-value changes).

std::optional< FieldValue > ew::core::entity::Entity::valueAt(QStringView key, qint64 instant) const

The effective value of field key at story instant: the value of the latest timed change for key at or before instant, or – when no timed change applies that early – the base value (Entity::value). std::nullopt when the field has neither a timed change in effect by instant nor a base value.

std::optional< QString > ew::core::entity::Entity::valueTextAt(QStringView key, qint64 instant) const

valueAt written for a person to read; std::nullopt when there is no value in effect.

const std::vector< taxonomy::FieldDefinition > & ew::core::entity::Entity::ownFields() const

The field definitions this entity holds ITSELF, beyond the ones its category chain gives it.

A property about one thing and nothing else: the noble houses of one kingdom, when the kingdom beside it has no such thing. No SIBLING entity ever sees them – that is the whole point, since before these existed the only place to put a property was the entity's CATEGORY, so adding one for a single entity gave it to every entity in that category and everything below it.

A category nested UNDER this entity may take one, if it asks: a kingdom's noble houses may be exactly what its cities want. That is the receiving category's decision like any other, not something the model rules on.

They are also what makes the migration safe. An entity holds VALUES keyed by field key, and a value whose definition is nowhere in scope is invisible – so demoting a property off a category with nowhere here to put its definition would silently orphan the data.

void ew::core::entity::Entity::setOwnFields(std::vector< taxonomy::FieldDefinition > ownFields)

Sets the field definitions this entity holds itself.

const std::set< QString > & ew::core::entity::Entity::aliases() const

Alternative names/nicknames this entity is also known by (e.g. "Strider", "Elessar" for Aragorn). Used for link resolution – the prose auto-linker treats each alias like the primary name – and for spell-check (so coined names are not flagged). Deduplicated and ordered for deterministic serialization; empty when the entity has none.

void ew::core::entity::Entity::setAliases(std::set< QString > aliases)

Sets the entity's alternative names/nicknames.

void ew::core::entity::Entity::setGallery(std::vector< ew::core::foundation::ContentId > gallery)

Sets the entity's gallery (Media ids in display order; the first is the thumbnail).

TimedFieldValue struct

struct ew::core::entity::TimedFieldValue

A change to one of an entity's field values at a point in story time: from instant onward, the field key takes the value value. This is how an entity's attributes evolve over the timeline – a character's location, rank, or status; a faction's ruler – distinct from the base field value (Entity::value), which is the initial value in effect before any timed change. The instant is minutes since the project's story epoch, matching timeline events and lifespans.

Members

QString ew::core::entity::TimedFieldValue::key

The field key whose value changes (the same key space as Entity::value).

qint64 ew::core::entity::TimedFieldValue::instant = 0

When the change takes effect, in minutes since the project's story epoch.

FieldValue ew::core::entity::TimedFieldValue::value

The field's value from instant onward. Typed like the base value it overrides – a timed change to a Number field carries a number, not the text of one.

bool operator==(const TimedFieldValue &, const TimedFieldValue &)=default

Two timed values compare equal when key, instant, and value all match.