RLMClassInfo.mm 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 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. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import "RLMClassInfo.hpp"
  19. #import "RLMRealm_Private.hpp"
  20. #import "RLMObjectSchema_Private.hpp"
  21. #import "RLMSchema.h"
  22. #import "RLMProperty_Private.h"
  23. #import "RLMQueryUtil.hpp"
  24. #import "RLMUtil.hpp"
  25. #import <realm/object-store/object_schema.hpp>
  26. #import <realm/object-store/object_store.hpp>
  27. #import <realm/object-store/schema.hpp>
  28. #import <realm/object-store/shared_realm.hpp>
  29. #import <realm/table.hpp>
  30. using namespace realm;
  31. RLMClassInfo::RLMClassInfo(__unsafe_unretained RLMRealm *const realm,
  32. __unsafe_unretained RLMObjectSchema *const rlmObjectSchema,
  33. const realm::ObjectSchema *objectSchema)
  34. : realm(realm), rlmObjectSchema(rlmObjectSchema), objectSchema(objectSchema) { }
  35. RLMClassInfo::RLMClassInfo(RLMRealm *realm, RLMObjectSchema *rlmObjectSchema,
  36. std::unique_ptr<realm::ObjectSchema> schema)
  37. : realm(realm)
  38. , rlmObjectSchema(rlmObjectSchema)
  39. , objectSchema(&*schema)
  40. , dynamicObjectSchema(std::move(schema))
  41. , dynamicRLMObjectSchema(rlmObjectSchema)
  42. { }
  43. realm::TableRef RLMClassInfo::table() const {
  44. if (auto key = objectSchema->table_key) {
  45. return realm.group.get_table(objectSchema->table_key);
  46. }
  47. return nullptr;
  48. }
  49. RLMProperty *RLMClassInfo::propertyForTableColumn(ColKey col) const noexcept {
  50. auto const& props = objectSchema->persisted_properties;
  51. for (size_t i = 0; i < props.size(); ++i) {
  52. if (props[i].column_key == col) {
  53. return rlmObjectSchema.properties[i];
  54. }
  55. }
  56. return nil;
  57. }
  58. RLMProperty *RLMClassInfo::propertyForPrimaryKey() const noexcept {
  59. return rlmObjectSchema.primaryKeyProperty;
  60. }
  61. realm::ColKey RLMClassInfo::tableColumn(NSString *propertyName) const {
  62. return tableColumn(RLMValidatedProperty(rlmObjectSchema, propertyName));
  63. }
  64. realm::ColKey RLMClassInfo::tableColumn(RLMProperty *property) const {
  65. return objectSchema->persisted_properties[property.index].column_key;
  66. }
  67. realm::ColKey RLMClassInfo::computedTableColumn(RLMProperty *property) const {
  68. // Retrieve the table key and class info for the origin property
  69. // that corresponds to the target property.
  70. RLMClassInfo& originInfo = realm->_info[property.objectClassName];
  71. TableKey originTableKey = originInfo.objectSchema->table_key;
  72. TableRef originTable = realm.group.get_table(originTableKey);
  73. // Get the column key for origin's forward link that links to the property on the target.
  74. ColKey forwardLinkKey = originInfo.tableColumn(property.linkOriginPropertyName);
  75. // The column key opposite of the origin's forward link is the target's backlink property.
  76. return originTable->get_opposite_column(forwardLinkKey);
  77. }
  78. RLMClassInfo &RLMClassInfo::linkTargetType(size_t propertyIndex) {
  79. return realm->_info[rlmObjectSchema.properties[propertyIndex].objectClassName];
  80. }
  81. RLMClassInfo &RLMClassInfo::linkTargetType(realm::Property const& property) {
  82. REALM_ASSERT(property.type == PropertyType::Object);
  83. return linkTargetType(&property - &objectSchema->persisted_properties[0]);
  84. }
  85. RLMClassInfo &RLMClassInfo::resolve(__unsafe_unretained RLMRealm *const realm) {
  86. return realm->_info[rlmObjectSchema.className];
  87. }
  88. bool RLMClassInfo::isSwiftClass() const noexcept {
  89. return rlmObjectSchema.isSwiftClass;
  90. }
  91. bool RLMClassInfo::isDynamic() const noexcept {
  92. return !!dynamicObjectSchema;
  93. }
  94. static KeyPath keyPathFromString(RLMRealm *realm,
  95. RLMSchema *schema,
  96. const RLMClassInfo *info,
  97. RLMObjectSchema *rlmObjectSchema,
  98. NSString *keyPath) {
  99. KeyPath keyPairs;
  100. for (NSString *component in [keyPath componentsSeparatedByString:@"."]) {
  101. RLMProperty *property = rlmObjectSchema[component];
  102. if (!property) {
  103. throw RLMException(@"Invalid property name: property '%@' not found in object of type '%@'",
  104. component, rlmObjectSchema.className);
  105. }
  106. TableKey tk = info->objectSchema->table_key;
  107. ColKey ck;
  108. if (property.type == RLMPropertyTypeObject) {
  109. ck = info->tableColumn(property.name);
  110. info = &realm->_info[property.objectClassName];
  111. rlmObjectSchema = schema[property.objectClassName];
  112. } else if (property.type == RLMPropertyTypeLinkingObjects) {
  113. ck = info->computedTableColumn(property);
  114. info = &realm->_info[property.objectClassName];
  115. rlmObjectSchema = schema[property.objectClassName];
  116. } else {
  117. ck = info->tableColumn(property.name);
  118. }
  119. keyPairs.emplace_back(tk, ck);
  120. }
  121. return keyPairs;
  122. }
  123. std::optional<realm::KeyPathArray> RLMClassInfo::keyPathArrayFromStringArray(NSArray<NSString *> *keyPaths) const {
  124. std::optional<KeyPathArray> keyPathArray;
  125. if (keyPaths.count) {
  126. keyPathArray.emplace();
  127. for (NSString *keyPath in keyPaths) {
  128. keyPathArray->push_back(keyPathFromString(realm, realm.schema, this,
  129. rlmObjectSchema, keyPath));
  130. }
  131. }
  132. return keyPathArray;
  133. }
  134. RLMSchemaInfo::impl::iterator RLMSchemaInfo::begin() noexcept { return m_objects.begin(); }
  135. RLMSchemaInfo::impl::iterator RLMSchemaInfo::end() noexcept { return m_objects.end(); }
  136. RLMSchemaInfo::impl::const_iterator RLMSchemaInfo::begin() const noexcept { return m_objects.begin(); }
  137. RLMSchemaInfo::impl::const_iterator RLMSchemaInfo::end() const noexcept { return m_objects.end(); }
  138. RLMClassInfo& RLMSchemaInfo::operator[](NSString *name) {
  139. auto it = m_objects.find(name);
  140. if (it == m_objects.end()) {
  141. @throw RLMException(@"Object type '%@' is not managed by the Realm. "
  142. @"If using a custom `objectClasses` / `objectTypes` array in your configuration, "
  143. @"add `%@` to the list of `objectClasses` / `objectTypes`.",
  144. name, name);
  145. }
  146. return *&it->second;
  147. }
  148. RLMClassInfo* RLMSchemaInfo::operator[](realm::TableKey key) {
  149. for (auto& [name, info] : m_objects) {
  150. if (info.objectSchema->table_key == key)
  151. return &info;
  152. }
  153. return nullptr;
  154. }
  155. RLMSchemaInfo::RLMSchemaInfo(RLMRealm *realm) {
  156. RLMSchema *rlmSchema = realm.schema;
  157. realm::Schema const& schema = realm->_realm->schema();
  158. // rlmSchema can be larger due to multiple classes backed by one table
  159. REALM_ASSERT(rlmSchema.objectSchema.count >= schema.size());
  160. m_objects.reserve(schema.size());
  161. for (RLMObjectSchema *rlmObjectSchema in rlmSchema.objectSchema) {
  162. auto it = schema.find(rlmObjectSchema.objectStoreName);
  163. if (it == schema.end()) {
  164. continue;
  165. }
  166. m_objects.emplace(std::piecewise_construct,
  167. std::forward_as_tuple(rlmObjectSchema.className),
  168. std::forward_as_tuple(realm, rlmObjectSchema,
  169. &*it));
  170. }
  171. }
  172. RLMSchemaInfo RLMSchemaInfo::clone(realm::Schema const& source_schema,
  173. __unsafe_unretained RLMRealm *const target_realm) {
  174. RLMSchemaInfo info;
  175. info.m_objects.reserve(m_objects.size());
  176. auto& schema = target_realm->_realm->schema();
  177. REALM_ASSERT_DEBUG(schema == source_schema);
  178. for (auto& [name, class_info] : m_objects) {
  179. if (class_info.isDynamic()) {
  180. continue;
  181. }
  182. size_t idx = class_info.objectSchema - &*source_schema.begin();
  183. info.m_objects.emplace(std::piecewise_construct,
  184. std::forward_as_tuple(name),
  185. std::forward_as_tuple(target_realm, class_info.rlmObjectSchema,
  186. &*schema.begin() + idx));
  187. }
  188. return info;
  189. }
  190. void RLMSchemaInfo::appendDynamicObjectSchema(std::unique_ptr<realm::ObjectSchema> schema,
  191. RLMObjectSchema *objectSchema,
  192. __unsafe_unretained RLMRealm *const target_realm) {
  193. m_objects.emplace(std::piecewise_construct,
  194. std::forward_as_tuple(objectSchema.className),
  195. std::forward_as_tuple(target_realm, objectSchema,
  196. std::move(schema)));
  197. }