RLMMigration.mm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2014 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 "RLMMigration_Private.h"
  19. #import "RLMAccessor.h"
  20. #import "RLMObject_Private.h"
  21. #import "RLMObject_Private.hpp"
  22. #import "RLMObjectSchema_Private.hpp"
  23. #import "RLMObjectStore.h"
  24. #import "RLMProperty_Private.h"
  25. #import "RLMRealm_Dynamic.h"
  26. #import "RLMRealm_Private.hpp"
  27. #import "RLMResults_Private.hpp"
  28. #import "RLMSchema_Private.hpp"
  29. #import "RLMUtil.hpp"
  30. #import <realm/object-store/object_store.hpp>
  31. #import <realm/object-store/shared_realm.hpp>
  32. #import <realm/object-store/schema.hpp>
  33. #import <realm/table.hpp>
  34. using namespace realm;
  35. @implementation RLMMigration {
  36. realm::Schema *_schema;
  37. }
  38. - (instancetype)initWithRealm:(RLMRealm *)realm oldRealm:(RLMRealm *)oldRealm schema:(realm::Schema &)schema {
  39. self = [super init];
  40. if (self) {
  41. _realm = realm;
  42. _oldRealm = oldRealm;
  43. _schema = &schema;
  44. }
  45. return self;
  46. }
  47. - (RLMSchema *)oldSchema {
  48. return self.oldRealm.schema;
  49. }
  50. - (RLMSchema *)newSchema {
  51. return self.realm.schema;
  52. }
  53. - (void)enumerateObjects:(NSString *)className block:(__attribute__((noescape)) RLMObjectMigrationBlock)block {
  54. RLMResults *objects = [_realm.schema schemaForClassName:className] ? [_realm allObjects:className] : nil;
  55. RLMResults *oldObjects = [_oldRealm.schema schemaForClassName:className] ? [_oldRealm allObjects:className] : nil;
  56. // For whatever reason if this is a newly added table we enumerate the
  57. // objects in it, while in all other cases we enumerate only the existing
  58. // objects. It's unclear how this could be useful, but changing it would
  59. // also be a pointless breaking change and it's unlikely to be hurting anyone.
  60. if (objects && !oldObjects) {
  61. for (RLMObject *object in objects) {
  62. @autoreleasepool {
  63. block(nil, object);
  64. }
  65. }
  66. return;
  67. }
  68. // If a table will be deleted it can still be enumerated during the migration
  69. // so that data can be saved or transfered to other tables if necessary.
  70. if (!objects && oldObjects) {
  71. for (RLMObject *oldObject in oldObjects) {
  72. @autoreleasepool {
  73. block(oldObject, nil);
  74. }
  75. }
  76. return;
  77. }
  78. if (oldObjects.count == 0 || objects.count == 0) {
  79. return;
  80. }
  81. auto& info = _realm->_info[className];
  82. for (RLMObject *oldObject in oldObjects) {
  83. @autoreleasepool {
  84. Obj newObj;
  85. try {
  86. newObj = info.table()->get_object(oldObject->_row.get_key());
  87. }
  88. catch (KeyNotFound const&) {
  89. continue;
  90. }
  91. block(oldObject, (id)RLMCreateObjectAccessor(info, std::move(newObj)));
  92. }
  93. }
  94. }
  95. - (void)execute:(RLMMigrationBlock)block objectClass:(Class)dynamicObjectClass {
  96. if (!dynamicObjectClass) {
  97. dynamicObjectClass = RLMDynamicObject.class;
  98. }
  99. @autoreleasepool {
  100. // disable all primary keys for migration and use DynamicObject for all types
  101. for (RLMObjectSchema *objectSchema in _realm.schema.objectSchema) {
  102. objectSchema.accessorClass = dynamicObjectClass;
  103. objectSchema.primaryKeyProperty.isPrimary = NO;
  104. }
  105. for (RLMObjectSchema *objectSchema in _oldRealm.schema.objectSchema) {
  106. objectSchema.accessorClass = dynamicObjectClass;
  107. }
  108. block(self, _oldRealm->_realm->schema_version());
  109. _oldRealm = nil;
  110. _realm = nil;
  111. }
  112. }
  113. - (RLMObject *)createObject:(NSString *)className withValue:(id)value {
  114. return [_realm createObject:className withValue:value];
  115. }
  116. - (RLMObject *)createObject:(NSString *)className withObject:(id)object {
  117. return [self createObject:className withValue:object];
  118. }
  119. - (void)deleteObject:(RLMObject *)object {
  120. [_realm deleteObject:object];
  121. }
  122. - (BOOL)deleteDataForClassName:(NSString *)name {
  123. if (!name) {
  124. return false;
  125. }
  126. TableRef table = ObjectStore::table_for_object_type(_realm.group, name.UTF8String);
  127. if (!table) {
  128. return false;
  129. }
  130. if ([_realm.schema schemaForClassName:name]) {
  131. table->clear();
  132. }
  133. else {
  134. _realm.group.remove_table(table->get_key());
  135. }
  136. return true;
  137. }
  138. - (void)renamePropertyForClass:(NSString *)className oldName:(NSString *)oldName newName:(NSString *)newName {
  139. realm::ObjectStore::rename_property(_realm.group, *_schema, className.UTF8String,
  140. oldName.UTF8String, newName.UTF8String);
  141. }
  142. @end