Realm C++ SDK Version v2.2.0

schema.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_SCHEMA_HPP
20#define CPPREALM_SCHEMA_HPP
21
22#include <cpprealm/link.hpp>
23#include <cpprealm/internal/bridge/lnklst.hpp>
24#include <cpprealm/internal/bridge/object_schema.hpp>
25#include <cpprealm/internal/bridge/realm.hpp>
26#include <cpprealm/internal/bridge/table.hpp>
27#include <cpprealm/internal/type_info.hpp>
28#include <variant>
29
30#include <type_traits>
31#include <iostream>
32
33namespace realm {
34 enum class ObjectType {
35 None,
36 TopLevel,
37 Embedded,
38 Asymmetric
39 };
40 namespace internal {
41 template <typename T>
43 template <typename Result, typename Class>
44 struct ptr_type_extractor_base<Result Class::*>
45 {
46 using class_type = Class;
47 using member_type = Result;
48 };
49
50 template <auto T>
52 };
53
54 template<typename... Ts>
55 constexpr auto make_subpack_tuple(Ts&&... xs)
56 {
57 return std::tuple<Ts...>(std::forward<Ts>(xs)...);
58 }
59
60 template <typename T>
62 using Result = T;
63 };
64 }
65
66
67 // MARK: schema
68 namespace schemagen {
69 template <auto Ptr, bool IsPrimaryKey = false>
70 struct property {
72 using VariantResult =
73 std::conditional_t<std::is_pointer_v<Result>, managed<Result>, Result>;
74
76 static constexpr auto ptr = Ptr;
77 static constexpr bool is_primary_key = IsPrimaryKey || internal::type_info::is_primary_key<Result>::value;
78 internal::bridge::property::type type;
79 const char* name = "";
80
82 {
83 }
84 explicit constexpr property(const char* actual_name)
86 {
87 name = actual_name;
88 }
89
90 operator internal::bridge::property() const {
91 internal::bridge::property property(name, type, is_primary_key);
93 if constexpr (std::is_pointer_v<typename Result::value_type>) {
94 property.set_object_link(managed<std::remove_pointer_t<typename Result::value_type>, void>::schema.name);
95 }
97 if constexpr (std::is_pointer_v<typename Result::value_type>) {
98 property.set_object_link(managed<std::remove_pointer_t<typename Result::value_type>, void>::schema.name);
99 }
103 property.set_object_link(managed<std::remove_pointer_t<typename Result::mapped_type::value_type>, void>::schema.name);
104 property.set_type(type | internal::bridge::property::type::Nullable);
105 }
106 } else if constexpr (std::is_pointer_v<typename Result::mapped_type>) {
107 property.set_object_link(managed<std::remove_pointer_t<typename Result::mapped_type>, void>::schema.name);
108 property.set_type(type | internal::bridge::property::type::Nullable);
109 }
110 } else if constexpr (std::is_pointer_v<Result>) {
111 property.set_object_link(managed<typename std::remove_pointer_t<Result>, void>::schema.name);
112 property.set_type(type | internal::bridge::property::type::Nullable);
115 }
116
117 return property;
118 }
119 };
120
121 template <typename T, typename ... Types>
123 using type = T;
124 };
125
126 template <template<typename...> typename Variant, typename... VariantTypes, typename NextType, typename... RemainingTypes>
127 struct unique_variant<Variant<VariantTypes...> , NextType, RemainingTypes...>
128 : std::conditional<
129 std::disjunction< std::is_same<NextType, VariantTypes> ... >::value
130 , unique_variant<Variant<VariantTypes...>, RemainingTypes...>
131 , unique_variant<Variant<VariantTypes..., NextType>, RemainingTypes...>
132 >::type
133 {};
134
135 template <typename Class, typename ...Properties>
136 struct schema {
137 const char *name;
138 const char *names[sizeof...(Properties)] = {};
139 const char *primary_key_name = "";
140
141 static constexpr std::tuple<Properties...> properties{};
142 using variant_t = typename unique_variant<std::variant<>, std::monostate, typename Properties::VariantResult...>::type;
143
144 template<size_t N>
145 constexpr auto do_apply_name(const std::tuple<Properties...> &tup) {
146 if constexpr (N + 1 == sizeof...(Properties)) {
147 names[N] = std::get<N>(tup).name;
148 if (std::get<N>(tup).is_primary_key) {
149 primary_key_name = std::get<N>(tup).name;
150 }
151 return;
152 } else {
153 names[N] = std::get<N>(tup).name;
154 if (std::get<N>(tup).is_primary_key) {
155 primary_key_name = std::get<N>(tup).name;
156 }
157 return do_apply_name<N + 1>(tup);
158 }
159 }
160
161 constexpr auto apply_name(const std::tuple<Properties...> &tup) {
162 return do_apply_name<0>(tup);
163 }
164
165 std::tuple<Properties...> ps;
166
167 explicit constexpr schema(const char *name_, Properties &&... props)
168 : name(name_)
169 , ps(props...) {
170 auto tup = std::make_tuple(props...);
171 apply_name(tup);
172 }
173 explicit constexpr schema(const char *name_, std::tuple<Properties...>&& props)
174 : name(name_)
175 , ps(props) {
176 apply_name(props);
177 }
178 explicit constexpr schema(const char *name_, ObjectType object_type, std::tuple<Properties...>&& props)
179 : name(name_)
180 , ps(props), m_object_type(object_type) {
181 apply_name(props);
182 }
183 template<size_t N, typename P>
184 static constexpr auto primary_key(P &) {
185 if constexpr (P::is_primary_key) {
186 return P();
187 } else {
188 if constexpr (N + 1 == sizeof...(Properties)) {
189 return;
190 } else {
191 return primary_key<N + 1>(std::get<N + 1>(properties));
192 }
193 }
194 }
195
196 static constexpr auto primary_key() {
197 return primary_key<0>(std::get<0>(properties));
198 }
199
200 using PrimaryKeyProperty = decltype(primary_key());
201 static constexpr bool HasPrimaryKeyProperty = !std::is_void_v<PrimaryKeyProperty>;
202
203 bool is_embedded() const {
204 return m_object_type == ObjectType::Embedded;
205 }
206
207 [[nodiscard]] internal::bridge::object_schema to_core_schema() const {
209 schema.set_name(name);
210
211 auto add_property = [&](const internal::bridge::property &p) {
212 if (!p.name().empty()) {
213 schema.add_property(p);
214 }
215 };
216 std::apply([&](const auto&... p) {
217 (add_property(p), ...);
218 }, ps);
219
220 if constexpr (HasPrimaryKeyProperty) {
221 schema.set_primary_key(primary_key_name);
222 }
223 if (m_object_type == ObjectType::Embedded) {
224 schema.set_object_type(internal::bridge::object_schema::object_type::Embedded);
225 }
226 if (m_object_type == ObjectType::Asymmetric) {
227 schema.set_object_type(internal::bridge::object_schema::object_type::TopLevelAsymmetric);
228 }
229 return schema;
230 }
231
232 template<size_t N, typename P>
233 constexpr auto set(Class &object, P &property) const {
234 if constexpr (N + 1 == sizeof...(Properties)) {
235 property.set(object, names[N]);
236 return;
237 } else {
238 property.set(object, names[N]);
239 return set<N + 1>(object, std::get<N + 1>(properties));
240 }
241 }
242
243 template<size_t N, typename P>
244 constexpr variant_t
245 property_value_for_name(std::string_view property_name, const managed<Class, void> &cls, P &property, bool excluding_collections = true) const {
246 bool is_array = realm::internal::bridge::property_has_flag(property.type, realm::internal::bridge::property::type::Array);
247 bool is_dictionary = realm::internal::bridge::property_has_flag(property.type, realm::internal::bridge::property::type::Dictionary);
248 bool is_set = realm::internal::bridge::property_has_flag(property.type, realm::internal::bridge::property::type::Set);
249 bool is_collection = is_array || is_dictionary || is_set;
250 if (excluding_collections && is_collection) {
251 return variant_t{std::monostate()};
252 }
253
254 if constexpr (N + 1 == sizeof...(Properties)) {
255 if (property_name == std::string_view(names[N])) {
256 auto ptr = managed<Class, void>::template unmanaged_to_managed_pointer(property.ptr);
257 if constexpr (std::is_pointer_v<typename P::Result>) {
258 return (cls.*ptr);
259 } else {
260 return (cls.*ptr).detach();
261 }
262 }
263 return variant_t{};
264 } else {
265 if (property_name == std::string_view(names[N])) {
266 auto ptr = managed<Class, void>::template unmanaged_to_managed_pointer(property.ptr);
267 if constexpr (std::is_pointer_v<typename P::Result>) {
268 return (cls.*ptr);
269 } else {
270 return (cls.*ptr).detach();
271 }
272 }
273 return property_value_for_name<N + 1>(property_name, cls, std::get<N + 1>(properties), excluding_collections);
274 }
275 }
276 constexpr auto property_value_for_name(std::string_view property_name, const managed<Class, void> &cls, bool excluding_collections = true) const {
277 return property_value_for_name<0>(property_name, cls, std::get<0>(properties), excluding_collections);
278 }
279
280 template<size_t N, typename T, typename P>
281 constexpr const char*
282 name_for_property(T ptr, P &property) const {
283 if constexpr (N + 1 == sizeof...(Properties)) {
284 if constexpr (std::is_same_v<decltype(ptr), std::remove_const_t<decltype(property.ptr)>>) {
285 if (ptr == property.ptr) {
286 return property.name;
287 }
288 }
289 return "";
290 } else {
291 if constexpr (std::is_same_v<decltype(ptr), std::remove_const_t<decltype(property.ptr)>>) {
292 if (ptr == property.ptr) {
293 return property.name;
294 }
295 }
296 return name_for_property<N + 1>(ptr, std::get<N + 1>(ps));
297 }
298 }
299 template <auto ptr>
300 constexpr const char* name_for_property() const {
301 return name_for_property<0>(ptr, std::get<0>(ps));
302 }
303 template <typename T>
304 constexpr const char* name_for_property(T ptr) const {
305 return name_for_property<0>(ptr, std::get<0>(ps));
306 }
307 private:
308 ObjectType m_object_type = ObjectType::None;
309 };
310 }
311 template <auto Ptr, bool IsPrimaryKey = false>
312 static constexpr auto property(const char* name)
313 {
315 }
316
317 template <typename ...T>
318 static constexpr auto schema(const char * name,
319 T&&... props) {
320 auto tup = internal::make_subpack_tuple(props...);
321 auto i = std::get<0>(tup);
322 using Cls = typename decltype(i)::Class;
323 return schemagen::schema<Cls, T...>(name, std::move(props)...);
324 }
325
326 template <typename ...T>
327 static constexpr auto schema(const char * name,
328 std::tuple<T...>&& props) {
329 auto i = std::get<0>(props);
330 using Cls = typename decltype(i)::Class;
331 return schemagen::schema<Cls, T...>(name, std::move(props));
332 }
333
334 template <typename ...T>
335 static constexpr auto schema(const char * name,
336 ObjectType object_type,
337 std::tuple<T...>&& props) {
338 auto i = std::get<0>(props);
339 using Cls = typename decltype(i)::Class;
340 return schemagen::schema<Cls, T...>(name, object_type, std::move(props));
341 }
342}
343
344#endif /* CPPREALM_SCHEMA_HPP */
Definition: object_schema.hpp:33
Definition: property.hpp:33
Definition: schema.hpp:51
Definition: type_info.hpp:70
Definition: type_info.hpp:45
Definition: type_info.hpp:297
Definition: type_info.hpp:62
Definition: type_info.hpp:54
Definition: obj.hpp:62
Definition: managed_primary_key.hpp:30
Definition: schema.hpp:70
Definition: schema.hpp:136
Definition: schema.hpp:122