diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e0628556b..875b1f3ceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Breaking Changes * Removed all references and API's releated to permissions. These are now managed through MongoDB Realm. Read more [here](XXX). * Removed Query Based Sync API's and Subscriptions. These API's are not initially supported by MongoDB Realm. They will be re-introduced in a future release. `SyncConfiguration.partionKey()` has been added as a replacement. Read more [here](XXX). +* Removed `RealmConfiguration.migration(RealmMigration)`. Specify migrations using `RealmConfigruation.schemeVersion(long, RealmMigration)` instead. ### Enhancements * None. diff --git a/realm/realm-library/src/androidTest/java/io/realm/RealmConfigurationTests.java b/realm/realm-library/src/androidTest/java/io/realm/RealmConfigurationTests.java index ba0fca9266..c6293198cd 100644 --- a/realm/realm-library/src/androidTest/java/io/realm/RealmConfigurationTests.java +++ b/realm/realm-library/src/androidTest/java/io/realm/RealmConfigurationTests.java @@ -280,7 +280,7 @@ public void schemaDoesNotContainAllDefinedObjectShouldThrow() { @Test public void migration_nullThrows() { try { - configFactory.createConfigurationBuilder().migration(null).build(); + configFactory.createConfigurationBuilder().schemaVersion(1, null).build(); fail(); } catch (IllegalArgumentException ignored) { } @@ -332,8 +332,7 @@ public void standardSetup() { .directory(configFactory.getRoot()) .name("foo.realm") .encryptionKey(TestHelper.getRandomKey()) - .schemaVersion(42) - .migration(new RealmMigration() { + .schemaVersion(42, new RealmMigration() { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { // no-op @@ -1028,8 +1027,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { @Test public void detectMissingEqualsInCustomMigration() { - RealmConfiguration config1 = configFactory.createConfigurationBuilder().migration(new MigrationWithNoEquals()).build(); - RealmConfiguration config2 = configFactory.createConfigurationBuilder().migration(new MigrationWithNoEquals()).build(); + RealmConfiguration config1 = configFactory.createConfigurationBuilder().schemaVersion(1,new MigrationWithNoEquals()).build(); + RealmConfiguration config2 = configFactory.createConfigurationBuilder().schemaVersion(1,new MigrationWithNoEquals()).build(); Realm realm = Realm.getInstance(config1); try { diff --git a/realm/realm-library/src/androidTest/java/io/realm/RealmMigrationTests.java b/realm/realm-library/src/androidTest/java/io/realm/RealmMigrationTests.java index 4e83ab71ec..065476ea7e 100644 --- a/realm/realm-library/src/androidTest/java/io/realm/RealmMigrationTests.java +++ b/realm/realm-library/src/androidTest/java/io/realm/RealmMigrationTests.java @@ -159,9 +159,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { RealmConfiguration v2Config = configFactory.createConfigurationBuilder() .name(MIGRATED_REALM) + .schemaVersion(2, migration) .schema(StringOnly.class, FieldOrder.class) - .schemaVersion(2) - .migration(migration) .build(); oldRealm = Realm.getInstance(v2Config); @@ -202,9 +201,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(StringOnly.class, AnnotationTypes.class) - .migration(migration) .build(); try { realm = Realm.getInstance(realmConfig); @@ -239,9 +237,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { // Creates v1 of the Realm. RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(Thread.class, AnnotationTypes.class) - .migration(migration) .build(); try { realm = Realm.getInstance(realmConfig); @@ -276,9 +273,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { // Creates v1 of the Realm. RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(Thread.class, StringOnly.class) - .migration(migration) .build(); try { realm = Realm.getInstance(realmConfig); @@ -314,9 +310,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { // Creates v1 of the Realm. RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(Thread.class, PrimaryKeyAsString.class) - .migration(migration) .build(); try { realm = Realm.getInstance(realmConfig); @@ -375,9 +370,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationClassRenamed.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); @@ -411,9 +405,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationClassRenamed.class) - .migration(migration) .build(); // Trigger migration Realm realm = Realm.getInstance(realmConfig); @@ -442,9 +435,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationClassRenamed.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); @@ -479,9 +471,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationClassRenamed.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); realm.close(); @@ -520,8 +511,7 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) - .migration(migration) + .schemaVersion(1, migration) .build(); // Creating Realm instance fails. @@ -553,9 +543,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationPosteriorIndexOnly.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); Table table = realm.getSchema().getTable(MigrationPosteriorIndexOnly.class); @@ -578,9 +567,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationPriorIndexOnly.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); Table table = realm.getSchema().getTable(MigrationPriorIndexOnly.class); @@ -602,9 +590,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationFieldRenamed.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); @@ -663,9 +650,8 @@ public void apply(DynamicRealmObject obj) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationFieldTypeToInt.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); @@ -707,9 +693,8 @@ public void apply(DynamicRealmObject obj) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(MigrationFieldTypeToInteger.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); @@ -744,8 +729,7 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { RealmConfiguration configuration = configFactory.createConfigurationBuilder() .schema(PrimaryKeyAsString.class) - .schemaVersion(1) - .migration(migration) + .schemaVersion(1, migration) .build(); // Create the schema and set the int field as primary key @@ -789,8 +773,7 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { RealmConfiguration configuration = configFactory.createConfigurationBuilder() .schema(PrimaryKeyAsInteger.class) - .schemaVersion(1) - .migration(migration) + .schemaVersion(1, migration) .build(); // Create the schema and set the String field as primary key @@ -844,9 +827,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { // Creates v1 of the Realm. RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(StringOnly.class, AnnotationTypes.class) - .migration(migration) .build(); realm = Realm.getInstance(realmConfig); @@ -877,9 +859,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(StringOnly.class, AnnotationTypes.class) - .migration(migration) .build(); realm = Realm.getInstance(realmConfig); @@ -944,9 +925,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { try { RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(0) + .schemaVersion(0, realmMigration) .schema(StringOnly.class) - .migration(realmMigration) .build(); Realm realm = Realm.getInstance(realmConfig); realm.close(); @@ -975,9 +955,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .schema(StringOnly.class) - .migration(migration) .build(); Realm realm = Realm.getInstance(realmConfig); assertTrue(migrationCalled.get()); @@ -1069,10 +1048,9 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { @SuppressWarnings("unchecked") RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .name(field) .schema(NullTypes.class) - .migration(migration) .build(); Realm.deleteRealm(realmConfig); // Prepares the version 0 db. @@ -1136,10 +1114,9 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { @SuppressWarnings("unchecked") RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(1) + .schemaVersion(1, migration) .name(field) .schema(NullTypes.class) - .migration(migration) .build(); Realm.deleteRealm(realmConfig); // Prepares the version 0 db. @@ -1177,9 +1154,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(SCHEMA_VERSION) + .schemaVersion(SCHEMA_VERSION, migration) .schema(clazz) - .migration(migration) .build(); Realm.deleteRealm(realmConfig); configFactory.copyRealmFromAssets(context, "default-notnullable-primarykey.realm", Realm.DEFAULT_REALM_NAME); @@ -1205,14 +1181,13 @@ public void notSettingNullableToPrimaryKeyThrows() throws IOException { for (final Class clazz : classes) { try { RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() - .schemaVersion(0) - .schema(clazz) - .migration(new RealmMigration() { + .schemaVersion(0, new RealmMigration() { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { // Intentionally lefts empty to preserve not-nullablility of PrimaryKey on old schema. } }) + .schema(clazz) .build(); Realm realm = Realm.getInstance(realmConfig); realm.close(); @@ -1269,7 +1244,7 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { @Test public void migrateRealm_config_nonExistingRealmFile() throws FileNotFoundException { - RealmConfiguration config = configFactory.createConfigurationBuilder().migration(new RealmMigration() { + RealmConfiguration config = configFactory.createConfigurationBuilder().schemaVersion(1, new RealmMigration() { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { @@ -1307,8 +1282,7 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { RealmConfiguration config = configFactory.createConfigurationBuilder() .schema(schemaClass) - .schemaVersion(2) - .migration(migration) + .schemaVersion(2, migration) .assetFile("rename-and-add.realm") .build(); Realm realm = Realm.getInstance(config); @@ -1336,8 +1310,7 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { RealmConfiguration config = configFactory.createConfigurationBuilder() .schema(schemaClass) - .schemaVersion(2) - .migration(migration) + .schemaVersion(2, migration) .assetFile("rename-and-add-indexed.realm") .build(); realm = Realm.getInstance(config); @@ -1406,8 +1379,7 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }; RealmConfiguration config = configFactory.createConfigurationBuilder() - .migration(migration) - .schemaVersion(1) + .schemaVersion(1, migration) .schema(StringOnly.class) .build(); createEmptyRealmVersion0(config); diff --git a/realm/realm-library/src/androidTest/java/io/realm/RealmObjectTests.java b/realm/realm-library/src/androidTest/java/io/realm/RealmObjectTests.java index 16b1180e1a..277119eb6a 100644 --- a/realm/realm-library/src/androidTest/java/io/realm/RealmObjectTests.java +++ b/realm/realm-library/src/androidTest/java/io/realm/RealmObjectTests.java @@ -1354,33 +1354,34 @@ private RealmConfiguration prepareColumnSwappedRealm() throws FileNotFoundExcept final RealmConfiguration columnSwappedRealmConfigForV0 = configFactory.createConfigurationBuilder() .name("columnSwapped.realm") - .migration(new RealmMigration() { - @Override - public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { - final Table table = realm.getSchema().getTable(StringAndInt.class); - final long strColKey = table.getColumnKey("str"); - final long numberColKey = table.getColumnKey("number"); - - for (String columnName :table.getColumnNames()) { - table.removeColumn(table.getColumnKey(columnName)); - } - final long newStrIndex; - // Swaps column indices. - if (strColKey < numberColKey) { - table.addColumn(RealmFieldType.INTEGER, "number"); - newStrIndex = table.addColumn(RealmFieldType.STRING, "str"); - } else { - newStrIndex = table.addColumn(RealmFieldType.STRING, "str"); - table.addColumn(RealmFieldType.INTEGER, "number"); - } - table.convertColumnToNullable(newStrIndex); - } - }) + // FIXME Does not really have any effect as migrations are not execute when version is not bumped. Remove? +// .schemaVersion(0, new RealmMigration() { +// @Override +// public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { +// final Table table = realm.getSchema().getTable(StringAndInt.class); +// final long strColKey = table.getColumnKey("str"); +// final long numberColKey = table.getColumnKey("number"); +// +// for (String columnName :table.getColumnNames()) { +// table.removeColumn(table.getColumnKey(columnName)); +// } +// final long newStrIndex; +// // Swaps column indices. +// if (strColKey < numberColKey) { +// table.addColumn(RealmFieldType.INTEGER, "number"); +// newStrIndex = table.addColumn(RealmFieldType.STRING, "str"); +// } else { +// newStrIndex = table.addColumn(RealmFieldType.STRING, "str"); +// table.addColumn(RealmFieldType.INTEGER, "number"); +// } +// table.convertColumnToNullable(newStrIndex); +// } +// }) .build(); final RealmConfiguration columnSwappedRealmConfigForV1 = configFactory.createConfigurationBuilder() .name("columnSwapped.realm") - .migration(new RealmMigration() { + .schemaVersion(1L, new RealmMigration() { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { // Does nothing. @@ -1391,7 +1392,8 @@ public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { Realm.deleteRealm(columnSwappedRealmConfigForV0); Realm.getInstance(columnSwappedRealmConfigForV0).close(); - Realm.migrateRealm(columnSwappedRealmConfigForV0); + // FIXME Does not really have any effect as migrations are not execute when version is not bumped. Remove? +// Realm.migrateRealm(columnSwappedRealmConfigForV0); return columnSwappedRealmConfigForV1; } diff --git a/realm/realm-library/src/androidTest/java/io/realm/RealmTests.java b/realm/realm-library/src/androidTest/java/io/realm/RealmTests.java index af3e3508cf..66bdeb4ddd 100644 --- a/realm/realm-library/src/androidTest/java/io/realm/RealmTests.java +++ b/realm/realm-library/src/androidTest/java/io/realm/RealmTests.java @@ -4573,13 +4573,12 @@ public void getInstance_migrationExceptionThrows_migrationBlockDefiend_realmInst RealmConfiguration config = configFactory.createConfigurationBuilder() .name("readonly.realm") .schema(StringOnlyReadOnly.class, AllJavaTypes.class) - .schemaVersion(2) - .assetFile("readonly.realm") - .migration(new RealmMigration() { + .schemaVersion(2, new RealmMigration() { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { } }) + .assetFile("readonly.realm") .build(); try { diff --git a/realm/realm-library/src/androidTest/kotlin/io/realm/RealmMigrationTestsKotlin.kt b/realm/realm-library/src/androidTest/kotlin/io/realm/RealmMigrationTestsKotlin.kt new file mode 100644 index 0000000000..0b1edcacc6 --- /dev/null +++ b/realm/realm-library/src/androidTest/kotlin/io/realm/RealmMigrationTestsKotlin.kt @@ -0,0 +1,127 @@ +/* + * Copyright 2020 Realm Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.realm + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.realm.entities.StringAndInt +import io.realm.entities.StringOnly +import io.realm.exceptions.RealmMigrationNeededException +import io.realm.rule.TestRealmConfigurationFactory +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertFalse +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.lang.IllegalArgumentException +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue + +@RunWith(AndroidJUnit4::class) +// TODO Migrate Java test cases from RealmMigrationTests and remove Kotlin suffix when done. +class RealmMigrationTestsKotlin { + + @get:Rule + val configFactory = TestRealmConfigurationFactory() + + private open class NoOpMigration : RealmMigration { + var triggered: Boolean = false + var oldVersion: Long = 0 + var newVersion: Long = 0 + override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { + this.triggered = true + this.oldVersion = oldVersion + this.newVersion = newVersion + } + } + + @Test + fun migrationNotTriggeredForInitialCreation() { + val migration = NoOpMigration() + val configV5: RealmConfiguration = configFactory.createConfigurationBuilder() + .schemaVersion(5, migration) + .build() + Realm.getInstance(configV5).close() + assertFalse(migration.triggered) + } + + @Test + fun explicitMigrationWithoutMigrationThrows() { + val configV0: RealmConfiguration = configFactory.createConfigurationBuilder() + .build() + Realm.getInstance(configV0).close() + assertFailsWith { + Realm.migrateRealm(configV0) + } + } + + @Test + fun migrationNotTriggeredIfVersionIsNotUpdated() { + val configV0: RealmConfiguration = configFactory.createConfigurationBuilder() + .schema(StringAndInt::class.java) + .build() + Realm.getInstance(configV0).close() + + val migration = NoOpMigration() + val configV0Updated: RealmConfiguration = configFactory.createConfigurationBuilder() + .schemaVersion(0, migration) + .schema(StringAndInt::class.java, StringOnly::class.java) + .build() + // Neither through implicit migration + assertFailsWith { + Realm.getInstance(configV0Updated).close() + } + // nor through explicit migration + assertFailsWith { + Realm.migrateRealm(configV0Updated, migration) + } + assertFalse(migration.triggered) + } + + // Test that + // - updating version number without migration and schema change will silently accept new + // scheme version + @Test + fun silentVersionUpdate() { + val realmConfigV0: RealmConfiguration = configFactory.createConfigurationBuilder().build() + Realm.getInstance(realmConfigV0).close() + val newVersion = 2L + val realmConfigV1: RealmConfiguration = configFactory.createConfigurationBuilder() + .schemaVersion(newVersion) + .build() + Realm.getInstance(realmConfigV1).use { + assertEquals(newVersion, it.version) + } + } + + // Test that + // - migration is invoked when updating version, even though scheme has not been updated + @Test + fun migrationOnSchemaVersionOnlyUpdate() { + val realmConfigV0: RealmConfiguration = configFactory.createConfigurationBuilder().build() + Realm.getInstance(realmConfigV0).close() + val newVersion = 2L + val migration = NoOpMigration() + val realmConfigV1: RealmConfiguration = configFactory.createConfigurationBuilder() + .schemaVersion(newVersion, migration) + .build() + Realm.getInstance(realmConfigV1).use { + assertEquals(newVersion, it.version) + } + assertTrue(migration.triggered) + } + +} diff --git a/realm/realm-library/src/main/java/io/realm/RealmConfiguration.java b/realm/realm-library/src/main/java/io/realm/RealmConfiguration.java index f0466edf59..88083bc74b 100644 --- a/realm/realm-library/src/main/java/io/realm/RealmConfiguration.java +++ b/realm/realm-library/src/main/java/io/realm/RealmConfiguration.java @@ -468,6 +468,8 @@ boolean isSyncConfiguration() { * RealmConfiguration.Builder used to construct instances of a RealmConfiguration in a fluent manner. */ public static class Builder { + private static long DEFAULT_SCHEMA_VERSION = 0; + // IMPORTANT: When adding any new methods to this class also add them to SyncConfiguration. private File directory; private String fileName; @@ -510,7 +512,7 @@ private void initializeBuilder(Context context) { this.directory = context.getFilesDir(); this.fileName = Realm.DEFAULT_REALM_NAME; this.key = null; - this.schemaVersion = 0; + this.schemaVersion = DEFAULT_SCHEMA_VERSION; this.migration = null; this.deleteRealmIfMigrationNeeded = false; this.durability = OsRealmConfig.Durability.FULL; @@ -578,13 +580,19 @@ public Builder encryptionKey(byte[] key) { } /** - * Sets the schema version of the Realm. This must be equal to or higher than the schema version of the existing - * Realm file, if any. If the schema version is higher than the already existing Realm, a migration is needed. + * Sets the schema version for version only updates. + *

+ * The version must be equal to or higher than the schema version of the existing Realm file, if any. + * If the schema version is lower than for an existing Realm file, an {@link IllegalArgumentException} + * will be thrown when {@linkplain Realm#getInstance(RealmConfiguration) opening it}. *

- * If no migration code is provided, Realm will throw a - * {@link io.realm.exceptions.RealmMigrationNeededException}. + * If the schema is actually changed use {@link #schemaVersion(long, RealmMigration)} to + * handle migration appropriately or a {@link io.realm.exceptions.RealmMigrationNeededException} + * will be thrown when {@linkplain Realm#getInstance(RealmConfiguration) opening it} + *

+ * @throws IllegalArgumentException If {@code schemaVersion} is negative. * - * @see #migration(RealmMigration) + * @see #schemaVersion(long, RealmMigration) */ public Builder schemaVersion(long schemaVersion) { if (schemaVersion < 0) { @@ -595,14 +603,27 @@ public Builder schemaVersion(long schemaVersion) { } /** - * Sets the {@link io.realm.RealmMigration} to be run if a migration is needed. If this migration fails to - * upgrade the on-disc schema to the runtime schema, a {@link io.realm.exceptions.RealmMigrationNeededException} - * will be thrown. + * Update the schema version of the Realm and apply the provided migration. + *

+ * The schema version must be equal to or higher than the schema version of the existing + * Realm file, if any, and the supplied {@link RealmMigration} must handled any schema changes. + * For version only updates the supplied + * {@link RealmMigration#migrate(DynamicRealm, long, long)} can be a no operation. + *

+ * If the schema has changed without increasing the version or failing to resolve schema + * migration through the supplied {@link RealmMigration}, Realm will throw a + * {@link io.realm.exceptions.RealmMigrationNeededException} when + * {@linkplain Realm#getInstance(RealmConfiguration) opened}. + *

+ * If the schema version is lower than for an existing Realm file an {@link IllegalArgumentException} + * will be thrown when trying to {@linkplain Realm#getInstance(RealmConfiguration) opening it}. + * + * @throws IllegalArgumentException If {@code schemaVersion} is negative or {@code migration} is null. */ - public Builder migration(RealmMigration migration) { - //noinspection ConstantConditions + public Builder schemaVersion(long schemaVersion, RealmMigration migration) { + schemaVersion(schemaVersion); if (migration == null) { - throw new IllegalArgumentException("A non-null migration must be provided"); + throw new IllegalArgumentException("Migration cannot be null"); } this.migration = migration; return this;