Skip to content

Commit

Permalink
Merge pull request realm#2142 from realm/tg-migration-column-alignment
Browse files Browse the repository at this point in the history
Eliminate a redundant call to RLMRealmSetSchemaAndAlign when migrations occur
  • Loading branch information
tgoyne committed Jul 2, 2015
2 parents d4977aa + fd69a40 commit fe59598
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 4 deletions.
18 changes: 14 additions & 4 deletions Realm/RLMObjectStore.mm
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,14 @@ void RLMClearAccessorCache() {
}

static void RLMCopyColumnMapping(RLMObjectSchema *targetSchema, const ObjectSchema &tableSchema) {
REALM_ASSERT_DEBUG(targetSchema.properties.count == tableSchema.properties.size());

// copy updated column mapping
for (size_t i = 0; i < tableSchema.properties.size(); i++) {
((RLMProperty *)targetSchema.properties[i]).column = tableSchema.properties[i].table_column;
size_t i = 0;
for (RLMProperty *targetProp in targetSchema.properties) {
REALM_ASSERT_DEBUG(targetProp.name.UTF8String == tableSchema.properties[i].name);
targetProp.column = tableSchema.properties[i].table_column;
++i;
}

// re-order properties
Expand Down Expand Up @@ -149,7 +154,8 @@ void RLMUpdateRealmToSchemaVersion(RLMRealm *realm, NSUInteger newVersion, RLMSc
// write transaction
[realm beginWriteTransaction];

bool changed = ObjectStore::update_realm_with_schema(realm.group, newVersion, schema, [=](__unused Group *group, ObjectStore::Schema &schema) {
bool migrationCalled = false;
bool changed = ObjectStore::update_realm_with_schema(realm.group, newVersion, schema, [&](__unused Group *group, ObjectStore::Schema &schema) {
RLMRealmSetSchemaAndAlign(realm, targetSchema, schema);
if (migrationBlock) {
NSError *error = migrationBlock();
Expand All @@ -158,8 +164,12 @@ void RLMUpdateRealmToSchemaVersion(RLMRealm *realm, NSUInteger newVersion, RLMSc
@throw RLMException(error.description);
}
}
migrationCalled = true;
});
RLMRealmSetSchemaAndAlign(realm, targetSchema, schema);

if (!migrationCalled) {
RLMRealmSetSchemaAndAlign(realm, targetSchema, schema);
}

if (changed) {
[realm commitWriteTransaction];
Expand Down
55 changes: 55 additions & 0 deletions Realm/Tests/MigrationTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
#import "object_store.hpp"
#import <realm/table.hpp>

static void RLMAssertRealmSchemaMatchesTable(id self, RLMRealm *realm) {
for (RLMObjectSchema *objectSchema in realm.schema.objectSchema) {
Table *table = objectSchema.table;
for (RLMProperty *property in objectSchema.properties) {
XCTAssertEqual(property.column, table->get_column_index(RLMStringDataWithNSString(property.name)));
XCTAssertEqual(property.indexed, table->has_search_index(property.column));
}
}
}

@interface MigrationObject : RLMObject
@property int intCol;
@property NSString *stringCol;
Expand Down Expand Up @@ -143,6 +153,9 @@ - (void)testPerRealmMigration {
}];
RLMRealm *anotherRealm = [RLMRealm realmWithPath:RLMTestRealmPath()];

RLMAssertRealmSchemaMatchesTable(self, [RLMRealm defaultRealm]);
RLMAssertRealmSchemaMatchesTable(self, anotherRealm);

XCTAssertEqual(2U, [RLMRealm schemaVersionAtPath:anotherRealm.path encryptionKey:nil error:nil]);
XCTAssertTrue(migrationComplete);
}
Expand Down Expand Up @@ -175,6 +188,7 @@ - (void)testRemovingSubclass {
@autoreleasepool {
// verify migration
RLMRealm *realm = [self realmWithTestPath];
RLMAssertRealmSchemaMatchesTable(self, realm);
XCTAssertFalse(ObjectStore::table_for_object_type(realm.group, "DeletedClass"), @"The deleted class should not have a table.");
XCTAssertEqual(0U, [StringObject allObjectsInRealm:realm].count);
}
Expand Down Expand Up @@ -218,6 +232,7 @@ - (void)testAddingPropertyAtEnd {
// verify migration
@autoreleasepool {
RLMRealm *realm = [self realmWithTestPath];
RLMAssertRealmSchemaMatchesTable(self, realm);
MigrationObject *mig1 = [MigrationObject allObjectsInRealm:realm][1];
XCTAssertEqual(mig1.intCol, 2, @"Int column should have value 2");
XCTAssertEqualObjects(mig1.stringCol, @"2", @"String column should be populated");
Expand Down Expand Up @@ -250,6 +265,7 @@ - (void)testAddingPropertyAtBeginningPreservesData {

// verify migration
realm = [self realmWithTestPath];
RLMAssertRealmSchemaMatchesTable(self, realm);
ThreeFieldMigrationObject *mig = [ThreeFieldMigrationObject allObjectsInRealm:realm][0];
XCTAssertEqual(0, mig.col1);
XCTAssertEqual(1, mig.col2);
Expand Down Expand Up @@ -286,6 +302,7 @@ - (void)testRemoveProperty {

// verify migration
realm = [self realmWithTestPath];
RLMAssertRealmSchemaMatchesTable(self, realm);
MigrationObject *mig1 = [MigrationObject allObjectsInRealm:realm][1];
XCTAssertThrows(mig1[@"deletedCol"], @"Deleted column should no longer be accessible.");
}
Expand Down Expand Up @@ -322,10 +339,39 @@ - (void)testRemoveAndAddProperty {

// verify migration
realm = [self realmWithTestPath];
RLMAssertRealmSchemaMatchesTable(self, realm);
MigrationObject *mig1 = [MigrationObject allObjectsInRealm:realm][1];
XCTAssertThrows(mig1[@"oldIntCol"], @"Deleted column should no longer be accessible.");
}

- (void)testMigrationProperlySetsPropertyColumns {
RLMObjectSchema *objectSchema = [RLMObjectSchema schemaForObjectClass:MigrationObject.class];
objectSchema.properties = @[
[[RLMProperty alloc] initWithName:@"firstName" type:RLMPropertyTypeString objectClassName:nil indexed:false optional:NO],
[[RLMProperty alloc] initWithName:@"lastName" type:RLMPropertyTypeString objectClassName:nil indexed:false optional:NO],
[[RLMProperty alloc] initWithName:@"age" type:RLMPropertyTypeInt objectClassName:nil indexed:false optional:NO],
];

RLMRealm *realm = [self realmWithSingleObject:objectSchema];
[realm beginWriteTransaction];
[realm createObject:MigrationObject.className withValue:@[@"a", @"b", @1]];
[realm createObject:MigrationObject.className withValue:@[@"c", @"d", @2]];
[realm commitWriteTransaction];

[RLMRealm setSchemaVersion:1 forRealmAtPath:RLMTestRealmPath() withMigrationBlock:^(__unused RLMMigration *migration, uint64_t oldSchemaVersion) {
XCTAssertEqual(oldSchemaVersion, 0U, @"Initial schema version should be 0");
}];

// verify migration
objectSchema.properties = @[
[[RLMProperty alloc] initWithName:@"fullName" type:RLMPropertyTypeString objectClassName:nil indexed:false optional:NO],
[[RLMProperty alloc] initWithName:@"age" type:RLMPropertyTypeInt objectClassName:nil indexed:false optional:NO],
[[RLMProperty alloc] initWithName:@"pets" type:RLMPropertyTypeArray objectClassName:MigrationObject.className indexed:false optional:NO],
];
realm = [self realmWithSingleObject:objectSchema];
RLMAssertRealmSchemaMatchesTable(self, realm);
}

- (void)testChangePropertyType {
// make string an int
RLMObjectSchema *objectSchema = [RLMObjectSchema schemaForObjectClass:MigrationObject.class];
Expand Down Expand Up @@ -356,6 +402,7 @@ - (void)testChangePropertyType {

// verify migration
realm = [self realmWithTestPath];
RLMAssertRealmSchemaMatchesTable(self, realm);
MigrationObject *mig1 = [MigrationObject allObjectsInRealm:realm][1];
XCTAssertEqualObjects(mig1[@"stringCol"], @"2", @"stringCol should be string after migration.");
}
Expand Down Expand Up @@ -389,6 +436,7 @@ - (void)testPrimaryKeyMigration {
}];
}];
[RLMRealm migrateRealmAtPath:RLMTestRealmPath()];
RLMAssertRealmSchemaMatchesTable(self, [self realmWithTestPath]);
}

- (void)testRemovePrimaryKeyMigration {
Expand Down Expand Up @@ -417,6 +465,7 @@ - (void)testRemovePrimaryKeyMigration {
}];

XCTAssertNoThrow([self realmWithSingleObject:objectSchema]);
RLMAssertRealmSchemaMatchesTable(self, [self realmWithSingleObject:objectSchema]);
}

- (void)testStringPrimaryKeyMigration {
Expand All @@ -441,6 +490,7 @@ - (void)testStringPrimaryKeyMigration {
}];
}];
[RLMRealm migrateRealmAtPath:RLMTestRealmPath()];
RLMAssertRealmSchemaMatchesTable(self, [self realmWithTestPath]);
}

- (void)testStringPrimaryKeyNoIndexMigration {
Expand All @@ -466,6 +516,7 @@ - (void)testStringPrimaryKeyNoIndexMigration {
}];
}];
[RLMRealm migrateRealmAtPath:RLMTestRealmPath()];
RLMAssertRealmSchemaMatchesTable(self, [self realmWithTestPath]);
}

- (void)testIntPrimaryKeyNoIndexMigration {
Expand All @@ -490,6 +541,7 @@ - (void)testIntPrimaryKeyNoIndexMigration {

// check that column is now indexed
RLMRealm *realm = [self realmWithTestPath];
RLMAssertRealmSchemaMatchesTable(self, realm);
XCTAssertTrue(realm.schema[MigrationPrimaryKeyObject.className].table->has_search_index(0));

// verify that old data still exists
Expand Down Expand Up @@ -535,6 +587,7 @@ - (void)testDuplicatePrimaryKeyMigration {
XCTAssertEqual(true, duplicateDeleted);
}];
[RLMRealm migrateRealmAtPath:RLMTestRealmPath()];
RLMAssertRealmSchemaMatchesTable(self, [self realmWithTestPath]);

// make sure deletion occurred
XCTAssertEqual(1U, [[MigrationPrimaryKeyObject allObjectsInRealm:[RLMRealm realmWithPath:RLMTestRealmPath()]] count]);
Expand Down Expand Up @@ -681,6 +734,8 @@ - (void)testRearrangeProperties {
// test object from other realm still works
XCTAssertEqualObjects(obj.data, @"new data");

RLMAssertRealmSchemaMatchesTable(self, realm);

// verify schema for both objects
NSArray *properties = defaultObj.objectSchema.properties;
for (NSUInteger i = 0; i < properties.count; i++) {
Expand Down

0 comments on commit fe59598

Please sign in to comment.