5#include <glaze/glaze.hpp>
19namespace morph::effects {
30inline void collectKey(
ResultJson const& value, std::string_view keyField, std::vector<glz::raw_json>& out) {
31 if (!value.is_object()) {
34 auto const& members = value.get_object();
35 auto const*
const key = members.find(keyField);
36 if (key == members.end()) {
39 if (
auto text = glz::write_json(key->second)) {
40 out.emplace_back(std::move(*text));
52 if (value.is_array()) {
53 for (
auto const& element : value.get_array()) {
56 }
else if (value.is_object()) {
57 auto const& members = value.get_object();
58 if (members.find(keyField) != members.end()) {
61 for (
auto const& [name, entry] : members) {
78 std::vector<glz::raw_json>& out) {
83 if (value.is_array()) {
84 for (
auto const& element : value.get_array()) {
89 if (!value.is_object()) {
92 auto const dot = path.find(
'.');
93 auto const segment = path.substr(0, dot);
94 auto const rest = dot == std::string_view::npos ? std::string_view{} : path.substr(dot + 1);
95 auto const& members = value.get_object();
96 if (
auto const*
const next = members.find(segment); next != members.end()) {
100 for (
auto const& [name, entry] : members) {
112 std::optional<std::vector<glz::raw_json>> keys) {
114 if (entry ==
changes.records.end()) {
125 for (
auto& key : *keys) {
126 auto const same = [&](glz::raw_json
const& have) {
return have.str == key.str; };
127 if (std::ranges::none_of(*entry->keys, same)) {
128 entry->keys->push_back(std::move(key));
138 auto const*
const root =
resolved.recordNamed(source);
139 if (root ==
nullptr) {
142 std::vector<std::type_index> reached{root->type};
144 for (std::size_t next = 0; next < reached.size(); ++next) {
146 auto const current = reached.at(next);
147 for (
auto const& candidate :
resolved.records) {
148 if (std::ranges::find(candidate.derivedFrom, current) == candidate.derivedFrom.end() ||
149 std::ranges::find(reached, candidate.type) != reached.end()) {
152 reached.push_back(candidate.type);
165 if (std::ranges::none_of(
changes.instances, same)) {
166 changes.instances.push_back(ranOn);
181 auto const*
const info =
resolved.recordNamed(record);
182 if (parsed ==
nullptr || info ==
nullptr || !info->keyField) {
186 std::vector<glz::raw_json> keys;
187 for (
auto const& held :
resolved.recordsOf(actionId)) {
188 if (held.record != record) {
191 for (
auto const& path : held.paths) {
208 auto const declared =
resolved.effectsOf(actionId);
213 std::optional<ResultJson> parsed;
214 bool parseTried =
false;
215 auto const parsedResult = [&]() ->
ResultJson const* {
219 if (!glz::read_json(tree, resultJson)) {
220 parsed = std::move(tree);
223 return parsed ? &*parsed :
nullptr;
225 for (
auto const& effect : *declared) {
226 switch (effect.kind) {
245 for (
auto& change :
changes.records) {
constexpr std::size_t kMaxChangeKeys
The most keys one RecordChange carries.
Changes deriveChangesFrom(Resolved const &resolved, std::string_view actionId, std::string_view resultJson, InstanceChange const &ranOn)
See morph::effects::deriveChanges, over given registries.
glz::generic_u64 ResultJson
The JSON tree a result is parsed into. It keeps integers exact, so a 64-bit key is copied as written.
Changes deriveChanges(std::string_view actionId, std::string_view resultJson, InstanceChange const &ranOn)
The changes a successful execute made, from the action's declared effects and its result.
void collectKeysAtLeaf(ResultJson const &value, std::string_view keyField, std::vector< glz::raw_json > &out)
Appends the keys of the records held at a value that the path has reached.
void collectKey(ResultJson const &value, std::string_view keyField, std::vector< glz::raw_json > &out)
Appends the key of one record value to out.
void addDerivedChanges(Resolved const &resolved, std::string const &source, Changes &changes)
Adds a whole-type change for every record derived, directly or through others, from source.
void addUpdatesChange(Resolved const &resolved, std::string_view actionId, std::string const &record, ResultJson const *parsed, Changes &changes)
Adds the change an updates<R> effect makes: the keys of the R rows found in the result.
void addInstanceChange(Changes &changes, InstanceChange const &ranOn)
Adds the change an execute's instance makes, unless it is already there.
void collectKeysAtPath(ResultJson const &value, std::string_view path, std::string_view keyField, std::vector< glz::raw_json > &out)
Walks the remaining path segments from value, then collects the keys found there.
void addRecordChange(Changes &changes, std::string const &record, std::optional< std::vector< glz::raw_json > > keys)
Adds a change for a record, merging with one already there.
Resolved const & resolved()
The process registries, matched and validated on the first call.
@ ChangesInstance
changesInstance
What one successful execute changed.
A change to the state of one model instance.
std::uint64_t instance
The instance id.
std::string primary
The directory key's text for a keyed shared instance; empty for a private one.
std::string modelType
The model's registered type name.
A change to the rows of one record type.
std::string record
The record's wire name.
Effect: the action may create, remove or change rows of record R, which its result need not carry.
The matched and validated registries: what every read is answered from.