Repository navigation
Expand file tree
/
Copy pathmutation_policy_plan.cpp
More file actions
130 lines (127 loc) · 5.29 KB
/
Copy pathmutation_policy_plan.cpp
File metadata and controls
130 lines (127 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <teaql/runtime/context.hpp>
#include <teaql/runtime/entity_runtime.hpp>
#include <teaql/runtime/dynamic_fields.hpp>
#include <charconv>
#include <mutex>
namespace teaql::detail {
namespace {
String next_execution_id(const UserContext& context) {
// A process-local scalar namespace, as in Rust. It owns no Context data.
// A mutex avoids requiring a 64-bit atomic runtime on 32-bit MIPS.
static std::mutex lock;
static std::uint64_t sequence = 1;
std::uint64_t value;
{
std::lock_guard guard(lock);
value = sequence++;
}
String result(context.trace_id(), context.memory_resource());
result += "-mutation-";
char buffer[32];
auto end = std::to_chars(buffer, buffer + sizeof(buffer), value).ptr;
result.append(buffer, end);
return result;
}
}
Result<MutationPlan, RuntimeError> graph_policy_plan(const UserContext& context,
const GraphMutationPlan& graph) {
auto r = context.memory_resource();
if (!graph.planned_root) {
return Result<MutationPlan, RuntimeError>::err(
r, RuntimeError::graph(r, "graph mutation plan has no planned root"));
}
MutationPlan plan(std::allocator_arg, Allocator(r));
const auto& root = *graph.planned_root;
plan.root_entity_type = root.entity;
plan.request_key = root.entity;
plan.request_key += ".saveGraph";
plan.audit_reason = clone_in(r, root.comment);
for (const auto& item : graph.items) {
if (item.kind == GraphMutationKind::Reference) {
continue;
}
auto kind = item.kind == GraphMutationKind::Create ? MutationOperationKind::Create
: item.kind == GraphMutationKind::Delete ? MutationOperationKind::Delete
: MutationOperationKind::Update;
const auto& values = item.values.fields;
auto id = values.find(std::string_view("id"));
Value missing_id(r, std::int64_t(0));
EntityKey key(std::allocator_arg,
Allocator(r),
item.entity,
id == values.end() ? missing_id : id->second);
plan.operations.emplace_back(kind, key);
auto& operation = plan.operations.back();
auto version = values.find(std::string_view("version"));
if (version != values.end()) {
operation.original_version = version->second.try_i64();
}
if (kind == MutationOperationKind::Create) {
operation.changed_values = clone_record(r, values);
} else if (kind == MutationOperationKind::Update) {
for (const auto& field : item.update_fields) {
auto found = values.find(field);
if (found != values.end()) {
operation.changed_values.insert_or_assign(String(field, r),
Value(r, found->second));
}
}
}
}
plan.execution_id = next_execution_id(context);
return Result<MutationPlan, RuntimeError>::ok(r, std::move(plan));
}
MutationPlan ledger_policy_plan(const UserContext& context,
const GraphNode& node,
const EntityRuntimeState& root) {
auto r = context.memory_resource();
auto changes = root.current_change_set();
auto deleted = root.deleted_keys();
auto fresh = root.new_keys();
EntityRuntimeState::Keys keys(r);
for (const auto& [key, values] : changes.changes()) {
keys.emplace(key);
}
if (const auto* dynamic = changes.dynamic_changes()) {
for (const auto& [key, values] : *dynamic) {
keys.emplace(key);
}
}
for (const auto& key : deleted) {
keys.emplace(key);
}
MutationPlan plan(std::allocator_arg, Allocator(r));
plan.request_key = node.entity;
plan.request_key += ".saveGraph";
plan.root_entity_type = node.entity;
auto comment = root.get_comment();
plan.audit_reason = clone_in(r, comment ? comment : node.comment);
for (const auto& key : keys) {
if (fresh.contains(key) && deleted.contains(key)) {
continue;
}
auto kind = deleted.contains(key) ? MutationOperationKind::Delete
: fresh.contains(key) ? MutationOperationKind::Create
: MutationOperationKind::Update;
plan.operations.emplace_back(kind, key);
auto& operation = plan.operations.back();
operation.original_version = root.get_original_version(key);
auto found = changes.changes().find(key);
if (found != changes.changes().end()) {
operation.changed_values = clone_record(r, found->second.fields);
}
if (const auto* dynamic = changes.dynamic_changes()) {
if (auto fields = dynamic->find(key); fields != dynamic->end()) {
for (const auto& [code, mutation] : fields->second) {
String field("#", r);
field += code;
operation.changed_values.insert_or_assign(
std::move(field), mutation_audit_value(r, mutation, nullptr));
}
}
}
}
plan.execution_id = next_execution_id(context);
return plan;
}
}