Skip to content

Commit 64f1096

Browse files
authored
Add option for automatic resolution of embedded object constraints during migration (#1473)
1 parent 273fd31 commit 64f1096

File tree

13 files changed

+274
-2
lines changed

13 files changed

+274
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
### Enhancements
77
* Support for performing geospatial queries using the new classes: `GeoPoint`, `GeoCircle`, `GeoBox`, and `GeoPolygon`. See `GeoPoint` documentation on how to persist locations. (Issue [#1403](https://github.com/realm/realm-kotlin/pull/1403))
8+
* Support for automatic resolution of embedded object constraints during migration through `RealmConfiguration.Builder.migration(migration: AutomaticSchemaMigration, resolveEmbeddedObjectConstraints: Boolean)`. (Issue [#1464](https://github.com/realm/realm-kotlin/issues/1464)
89
* [Sync] Add support for customizing authorization headers and adding additional custom headers to all Atlas App service requests with `AppConfiguration.Builder.authorizationHeaderName()` and `AppConfiguration.Builder.addCustomRequestHeader(...)`. (Issue [#1453](https://github.com/realm/realm-kotlin/pull/1453))
910

1011
### Fixed

packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ expect object RealmInterop {
186186
fun realm_config_get_encryption_key(config: RealmConfigurationPointer): ByteArray?
187187
fun realm_config_set_should_compact_on_launch_function(config: RealmConfigurationPointer, callback: CompactOnLaunchCallback)
188188
fun realm_config_set_migration_function(config: RealmConfigurationPointer, callback: MigrationCallback)
189+
fun realm_config_set_automatic_backlink_handling(config: RealmConfigurationPointer, enabled: Boolean)
189190
fun realm_config_set_data_initialization_function(config: RealmConfigurationPointer, callback: DataInitializationCallback)
190191
fun realm_config_set_in_memory(config: RealmConfigurationPointer, inMemory: Boolean)
191192
fun realm_schema_validate(schema: RealmSchemaPointer, mode: SchemaValidationMode): Boolean

packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ actual object RealmInterop {
172172
realmc.realm_config_set_migration_function(config.cptr(), callback)
173173
}
174174

175+
actual fun realm_config_set_automatic_backlink_handling(config: RealmConfigurationPointer, enabled: Boolean) {
176+
realmc.realm_config_set_automatic_backlink_handling(config.cptr(), enabled)
177+
}
178+
175179
actual fun realm_config_set_data_initialization_function(config: RealmConfigurationPointer, callback: DataInitializationCallback) {
176180
realmc.realm_config_set_data_initialization_function(config.cptr(), callback)
177181
}

packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,15 @@ actual object RealmInterop {
433433
)
434434
}
435435

436+
actual fun realm_config_set_automatic_backlink_handling(
437+
config: RealmConfigurationPointer,
438+
enabled: Boolean
439+
) {
440+
realm_wrapper.realm_config_set_automatic_backlink_handling(
441+
config.cptr(),
442+
enabled,
443+
)
444+
}
436445
actual fun realm_config_set_migration_function(
437446
config: RealmConfigurationPointer,
438447
callback: MigrationCallback

packages/library-base/src/commonMain/kotlin/io/realm/kotlin/RealmConfiguration.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import io.realm.kotlin.internal.platform.appFilesDirectory
2222
import io.realm.kotlin.internal.util.CoroutineDispatcherFactory
2323
import io.realm.kotlin.log.RealmLog
2424
import io.realm.kotlin.log.RealmLogger
25+
import io.realm.kotlin.migration.AutomaticSchemaMigration
2526
import io.realm.kotlin.migration.RealmMigration
2627
import io.realm.kotlin.types.TypedRealmObject
2728
import kotlin.reflect.KClass
@@ -55,6 +56,7 @@ public interface RealmConfiguration : Configuration {
5556
private var directory: String = appFilesDirectory()
5657
private var deleteRealmIfMigrationNeeded: Boolean = false
5758
private var migration: RealmMigration? = null
59+
private var automaticEmbeddedObjectConstraintsResolution = false
5860

5961
/**
6062
* Sets the path to the directory that contains the realm file. If the directory does not
@@ -109,6 +111,29 @@ public interface RealmConfiguration : Configuration {
109111
public fun migration(migration: RealmMigration): Builder =
110112
apply { this.migration = migration }
111113

114+
/**
115+
* Sets the migration to handle schema updates with automatic migration of data.
116+
*
117+
* @param migration the [AutomaticSchemaMigration] instance to handle schema and data
118+
* migration in the event of a schema update.
119+
* @param resolveEmbeddedObjectConstraints a flag to indicate whether realm should resolve
120+
* embedded object constraints after migration. If this is `true` then all embedded objects
121+
* without a parent will be deleted and every embedded object with multiple references to it
122+
* will be duplicated so that every referencing object will hold its own copy of the
123+
* embedded object.
124+
*
125+
* @see RealmMigration
126+
* @see AutomaticSchemaMigration
127+
*/
128+
public fun migration(
129+
migration: AutomaticSchemaMigration,
130+
resolveEmbeddedObjectConstraints: Boolean = false
131+
): Builder =
132+
apply {
133+
this.migration = migration
134+
this.automaticEmbeddedObjectConstraintsResolution = resolveEmbeddedObjectConstraints
135+
}
136+
112137
override fun name(name: String): Builder = apply {
113138
checkName(name)
114139
this.name = name
@@ -163,6 +188,7 @@ public interface RealmConfiguration : Configuration {
163188
deleteRealmIfMigrationNeeded,
164189
compactOnLaunchCallback,
165190
migration,
191+
automaticEmbeddedObjectConstraintsResolution,
166192
initialDataCallback,
167193
inMemory,
168194
initialRealmFileConfiguration,

packages/library-base/src/commonMain/kotlin/io/realm/kotlin/internal/ConfigurationImpl.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import kotlin.reflect.KClass
4747

4848
// TODO Public due to being accessed from `library-sync`
4949
@Suppress("LongParameterList")
50-
public open class ConfigurationImpl constructor(
50+
public open class ConfigurationImpl(
5151
directory: String,
5252
name: String,
5353
schema: Set<KClass<out BaseRealmObject>>,
@@ -60,6 +60,7 @@ public open class ConfigurationImpl constructor(
6060
private val userEncryptionKey: ByteArray?,
6161
compactOnLaunchCallback: CompactOnLaunchCallback?,
6262
private val userMigration: RealmMigration?,
63+
automaticBacklinkHandling: Boolean,
6364
initialDataCallback: InitialDataCallback?,
6465
override val isFlexibleSyncConfiguration: Boolean,
6566
inMemory: Boolean,
@@ -218,6 +219,7 @@ public open class ConfigurationImpl constructor(
218219
migrationCallback?.let {
219220
RealmInterop.realm_config_set_migration_function(nativeConfig, it)
220221
}
222+
RealmInterop.realm_config_set_automatic_backlink_handling(nativeConfig, automaticBacklinkHandling)
221223

222224
userEncryptionKey?.let { key: ByteArray ->
223225
RealmInterop.realm_config_set_encryption_key(nativeConfig, key)

packages/library-base/src/commonMain/kotlin/io/realm/kotlin/internal/RealmConfigurationImpl.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import kotlin.reflect.KClass
3030
public const val REALM_FILE_EXTENSION: String = ".realm"
3131

3232
@Suppress("LongParameterList")
33-
internal class RealmConfigurationImpl constructor(
33+
internal class RealmConfigurationImpl(
3434
directory: String,
3535
name: String,
3636
schema: Set<KClass<out BaseRealmObject>>,
@@ -43,6 +43,7 @@ internal class RealmConfigurationImpl constructor(
4343
override val deleteRealmIfMigrationNeeded: Boolean,
4444
compactOnLaunchCallback: CompactOnLaunchCallback?,
4545
migration: RealmMigration?,
46+
automaticBacklinkHandling: Boolean,
4647
initialDataCallback: InitialDataCallback?,
4748
inMemory: Boolean,
4849
override val initialRealmFileConfiguration: InitialRealmFileConfiguration?,
@@ -63,6 +64,7 @@ internal class RealmConfigurationImpl constructor(
6364
encryptionKey,
6465
compactOnLaunchCallback,
6566
migration,
67+
automaticBacklinkHandling,
6668
initialDataCallback,
6769
false,
6870
inMemory,

packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/sync/SyncConfiguration.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ public interface SyncConfiguration : Configuration {
568568
encryptionKey,
569569
compactOnLaunchCallback,
570570
null, // migration is not relevant for sync,
571+
false, // automatic backlink handling is not relevant for sync
571572
initialDataCallback,
572573
partitionValue == null,
573574
inMemory,
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2023 Realm Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.realm.kotlin.entities.migration.embedded.after
18+
19+
import io.realm.kotlin.types.EmbeddedRealmObject
20+
21+
class EmbeddedMigrationChild : EmbeddedRealmObject {
22+
var id: String = "child"
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2023 Realm Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.realm.kotlin.entities.migration.embedded.after
18+
19+
import io.realm.kotlin.types.RealmObject
20+
21+
class EmbeddedMigrationParent : RealmObject {
22+
var id: String = "parent"
23+
var child: EmbeddedMigrationChild? = null
24+
}

0 commit comments

Comments
 (0)