RLMMigration.mm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 "object_store.hpp"
  31. #import "shared_realm.hpp"
  32. #import "schema.hpp"
  33. #import <realm/table.hpp>
  34. using namespace realm;
  35. // The source realm for a migration has to use a SharedGroup to be able to share
  36. // the file with the destination realm, but we don't want to let the user call
  37. // beginWriteTransaction on it as that would make no sense.
  38. @interface RLMMigrationRealm : RLMRealm
  39. @end
  40. @implementation RLMMigrationRealm
  41. - (BOOL)readonly {
  42. return YES;
  43. }
  44. - (void)beginWriteTransaction {
  45. @throw RLMException(@"Cannot modify the source Realm in a migration");
  46. }
  47. @end
  48. @implementation RLMMigration {
  49. realm::Schema *_schema;
  50. }
  51. - (instancetype)initWithRealm:(RLMRealm *)realm oldRealm:(RLMRealm *)oldRealm schema:(realm::Schema &)schema {
  52. self = [super init];
  53. if (self) {
  54. _realm = realm;
  55. _oldRealm = oldRealm;
  56. _schema = &schema;
  57. object_setClass(_oldRealm, RLMMigrationRealm.class);
  58. }
  59. return self;
  60. }
  61. - (RLMSchema *)oldSchema {
  62. return self.oldRealm.schema;
  63. }
  64. - (RLMSchema *)newSchema {
  65. return self.realm.schema;
  66. }
  67. - (void)enumerateObjects:(NSString *)className block:(__attribute__((noescape)) RLMObjectMigrationBlock)block {
  68. RLMResults *objects = [_realm.schema schemaForClassName:className] ? [_realm allObjects:className] : nil;
  69. RLMResults *oldObjects = [_oldRealm.schema schemaForClassName:className] ? [_oldRealm allObjects:className] : nil;
  70. // For whatever reason if this is a newly added table we enumerate the
  71. // objects in it, while in all other cases we enumerate only the existing
  72. // objects. It's unclear how this could be useful, but changing it would
  73. // also be a pointless breaking change and it's unlikely to be hurting anyone.
  74. if (objects && !oldObjects) {
  75. for (RLMObject *object in objects) {
  76. @autoreleasepool {
  77. block(nil, object);
  78. }
  79. }
  80. return;
  81. }
  82. if (oldObjects.count == 0 || objects.count == 0) {
  83. return;
  84. }
  85. auto& info = _realm->_info[className];
  86. for (RLMObject *oldObject in oldObjects) {
  87. @autoreleasepool {
  88. Obj newObj;
  89. try {
  90. newObj = info.table()->get_object(oldObject->_row.get_key());
  91. }
  92. catch (InvalidKey const&) {
  93. continue;
  94. }
  95. block(oldObject, (id)RLMCreateObjectAccessor(info, std::move(newObj)));
  96. }
  97. }
  98. }
  99. - (void)execute:(RLMMigrationBlock)block {
  100. @autoreleasepool {
  101. // disable all primary keys for migration and use DynamicObject for all types
  102. for (RLMObjectSchema *objectSchema in _realm.schema.objectSchema) {
  103. objectSchema.accessorClass = RLMDynamicObject.class;
  104. objectSchema.primaryKeyProperty.isPrimary = NO;
  105. }
  106. for (RLMObjectSchema *objectSchema in _oldRealm.schema.objectSchema) {
  107. objectSchema.accessorClass = RLMDynamicObject.class;
  108. }
  109. block(self, _oldRealm->_realm->schema_version());
  110. _oldRealm = nil;
  111. _realm = nil;
  112. }
  113. }
  114. - (RLMObject *)createObject:(NSString *)className withValue:(id)value {
  115. return [_realm createObject:className withValue:value];
  116. }
  117. - (RLMObject *)createObject:(NSString *)className withObject:(id)object {
  118. return [self createObject:className withValue:object];
  119. }
  120. - (void)deleteObject:(RLMObject *)object {
  121. [_realm deleteObject:object];
  122. }
  123. - (BOOL)deleteDataForClassName:(NSString *)name {
  124. if (!name) {
  125. return false;
  126. }
  127. TableRef table = ObjectStore::table_for_object_type(_realm.group, name.UTF8String);
  128. if (!table) {
  129. return false;
  130. }
  131. if ([_realm.schema schemaForClassName:name]) {
  132. table->clear();
  133. }
  134. else {
  135. _realm.group.remove_table(table->get_key());
  136. }
  137. return true;
  138. }
  139. - (void)renamePropertyForClass:(NSString *)className oldName:(NSString *)oldName newName:(NSString *)newName {
  140. realm::ObjectStore::rename_property(_realm.group, *_schema, className.UTF8String,
  141. oldName.UTF8String, newName.UTF8String);
  142. }
  143. @end