Realm C++ SDK main@ea665a54a297dd13d7a3789dd5f5ea7317032c84

observation.hpp

1
2//
3// Copyright 2022 Realm Inc.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
18
19#ifndef CPPREALM_OBSERVATION_HPP
20#define CPPREALM_OBSERVATION_HPP
21
22#include <cpprealm/internal/bridge/list.hpp>
23#include <cpprealm/internal/bridge/obj.hpp>
24#include <cpprealm/internal/bridge/object.hpp>
25#include <cpprealm/internal/bridge/realm.hpp>
26#include <cpprealm/macros.hpp>
27
28#include <cpprealm/internal/bridge/table.hpp>
29#include <cpprealm/internal/bridge/thread_safe_reference.hpp>
30
31#include <iostream>
32#include <variant>
33
34namespace realm {
35
36 template<typename T>
38 using underlying = T;
40 const T *object;
42 bool is_deleted = false;
50 std::exception_ptr error;
54 std::vector<PropertyChange<T>> property_changes;
55 };
56
57 template<typename T>
59 ObjectChangeCallbackWrapper(std::function<void(object_change < T > )> &&b,
60 const T *obj,
61 std::shared_ptr<internal::bridge::object> internal_object)
62 : block(std::move(b)), object(*obj), m_object(internal_object) {
63 static_cast<void>(obj);
64 }
65 std::function<void(object_change < T > )> block;
66 const T object;
67 std::shared_ptr<internal::bridge::object> m_object;
68
69 std::optional<std::vector<std::string>> property_names = std::nullopt;
70 std::optional<std::vector<typename decltype(T::schema)::variant_t>> old_values = std::nullopt;
71 bool deleted = false;
72
73 void populateProperties(internal::bridge::collection_change_set const &c) {
74 if (property_names) {
75 return;
76 }
77 if (!c.deletions().empty()) {
78 deleted = true;
79 return;
80 }
81 if (c.columns().empty()) {
82 return;
83 }
84
85 // FIXME: It's possible for the column key of a persisted property
86 // FIXME: to equal the column key of a computed property.
87 auto properties = std::vector<std::string>();
88 auto table = m_object->get_obj().get_table();
89
90 for (auto i = 0; i < std::tuple_size<decltype(T::schema.properties)>{}; i++) {
91 if (c.columns().count(table.get_column_key(T::schema.names[i]).value())) {
92 properties.push_back(T::schema.names[i]);
93 }
94 }
95
96 if (!properties.empty()) {
97 property_names = properties;
98 }
99 }
100
101 std::optional<std::vector<typename decltype(T::schema)::variant_t>>
102 readValues(internal::bridge::collection_change_set const &c) {
103 if (c.empty()) {
104 return std::nullopt;
105 }
106 populateProperties(c);
107 if (!property_names) {
108 return std::nullopt;
109 }
110
111 std::vector<typename decltype(T::schema)::variant_t> values;
112 for (auto &name: *property_names) {
113 auto value = T::schema.property_value_for_name(name, object, true);
114 values.push_back(value);
115 }
116 return values;
117 }
118
119 void before(internal::bridge::collection_change_set const &c) override {
120 old_values = readValues(c);
121 }
122
123 void after(internal::bridge::collection_change_set const &c) override {
124 auto new_values = readValues(c);
125 if (deleted) {
126 forward_change(nullptr, {}, {}, {}, nullptr);
127 } else if (new_values) {
128 forward_change(&object,
129 *property_names,
130 old_values ? *old_values : std::vector<typename decltype(T::schema)::variant_t>{},
131 *new_values,
132 nullptr);
133 }
134 property_names = std::nullopt;
135 old_values = std::nullopt;
136 }
137
138 void error(std::exception_ptr err) {
139 forward_change(nullptr, {}, {}, {}, err);
140 }
141
142 void forward_change(const T *ptr,
143 std::vector<std::string> property_names,
144 std::vector<typename decltype(T::schema)::variant_t> old_values,
145 std::vector<typename decltype(T::schema)::variant_t> new_values,
146 const std::exception_ptr &error) {
147 if (!ptr) {
148 if (error) {
149 auto oc = object_change<T>();
150 oc.error = error;
151 block(std::forward<realm::object_change<T>>(std::move(oc)));
152 } else {
153 auto oc = object_change<T>();
154 oc.is_deleted = true;
155 block(std::forward<realm::object_change<T>>(std::move(oc)));
156 }
157 } else {
158 std::vector<PropertyChange<T>> property_changes;
159 for (size_t i = 0; i < property_names.size(); i++) {
160 PropertyChange<T> property;
161 property.name = property_names[i];
162 if (!old_values.empty()) {
163 property.old_value = old_values[i];
164 }
165 if (!new_values.empty()) {
166 property.new_value = new_values[i];
167 }
168 property_changes.push_back(std::move(property));
169 }
170 auto oc = object_change<T>();
171 oc.object = ptr;
172 oc.property_changes = property_changes;
173 block(std::forward<realm::object_change<T>>(std::move(oc)));
174 }
175 }
176 };
177
179 std::vector<uint64_t> deletions;
180 std::vector<uint64_t> insertions;
181 std::vector<uint64_t> modifications;
182
183 // This flag indicates whether the underlying object which is the source of this
184 // collection was deleted. This applies to lists, dictionaries and sets.
185 // This enables notifiers to report a change on empty collections that have been deleted.
186 bool collection_root_was_deleted = false;
187
188 [[nodiscard]] bool empty() const noexcept {
189 return deletions.empty() && insertions.empty() && modifications.empty() &&
190 !collection_root_was_deleted;
191 }
192 };
193
195 std::function<void(collection_change)> handler;
196 bool ignoreChangesInInitialNotification;
197
198 collection_callback_wrapper(std::function<void(collection_change)> handler,
199 bool ignoreChangesInInitialNotification)
200 : handler(handler)
201 , ignoreChangesInInitialNotification(ignoreChangesInInitialNotification)
202 {}
203
204
205 void before(const realm::internal::bridge::collection_change_set &c) final {}
206 void after(internal::bridge::collection_change_set const& changes) final {
207 if (ignoreChangesInInitialNotification) {
208 ignoreChangesInInitialNotification = false;
209 handler({{},{},{}});
210 }
211 else if (changes.empty()) {
212 handler({{},{},{}});
213
214 }
215 else if (!changes.collection_root_was_deleted() || !changes.deletions().empty()) {
216 handler({to_vector(changes.deletions()),
217 to_vector(changes.insertions()),
218 to_vector(changes.modifications()),
219 });
220 }
221 }
222
223 private:
224 std::vector<uint64_t> to_vector(const internal::bridge::index_set& index_set) {
225 auto vector = std::vector<uint64_t>();
226 for (auto index : index_set.as_indexes()) {
227 vector.push_back(index);
228 }
229 return vector;
230 };
231 };
232}
233
234
235template <typename T>
236inline std::ostream& operator<< (std::ostream& stream, const realm::object_change<T>& object)
237{
238 stream << "{\n";
239 stream << "\tis_deleted: " << object.is_deleted << "\n";
240 stream << "\tchange_to: " << object.property.name << "\n";
241 if (object.property.old_value) {
242 stream << "\told_value: ";
243 std::visit([&stream](auto&& arg) {
244 using M = std::decay_t<decltype(arg)>;
245 stream << static_cast<M>(arg);
246 }, *object.property.old_value);
247 }
248 if (object.property.new_value) {
249 stream << "\tnew_value: ";
250 std::visit([&stream](auto&& arg) {
251 using M = std::decay_t<decltype(arg)>;
252 stream << static_cast<M>(arg);
253 }, *object.property.new_value);
254 }
255 stream << "\n}";
256 return stream;
257}
258
259#endif //CPPREALM_OBSERVATION_HPP
Definition: observation.hpp:58
Definition: notifications.hpp:80
std::string name
Definition: notifications.hpp:84
Definition: observation.hpp:194
Definition: observation.hpp:178
Definition: object.hpp:63
Definition: observation.hpp:37
bool is_deleted
The object has been deleted from the Realm.
Definition: observation.hpp:42
std::vector< PropertyChange< T > > property_changes
Definition: observation.hpp:54
const T * object
The object being observed.
Definition: observation.hpp:40
std::exception_ptr error
Definition: observation.hpp:50
Definition: flex_sync.hpp:37