commonMain.io.realm.kotlin.internal.RealmObjectReference.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of library-base-jvm Show documentation
Show all versions of library-base-jvm Show documentation
Library code for Realm Kotlin. This artifact is not supposed to be consumed directly, but through 'io.realm.kotlin:gradle-plugin:1.11.1' instead.
/*
* Copyright 2022 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.kotlin.internal
import io.realm.kotlin.internal.interop.Callback
import io.realm.kotlin.internal.interop.PropertyKey
import io.realm.kotlin.internal.interop.RealmChangesPointer
import io.realm.kotlin.internal.interop.RealmInterop
import io.realm.kotlin.internal.interop.RealmKeyPathArrayPointer
import io.realm.kotlin.internal.interop.RealmNotificationTokenPointer
import io.realm.kotlin.internal.interop.RealmObjectInterop
import io.realm.kotlin.internal.interop.RealmObjectPointer
import io.realm.kotlin.internal.schema.ClassMetadata
import io.realm.kotlin.internal.schema.PropertyMetadata
import io.realm.kotlin.notifications.ObjectChange
import io.realm.kotlin.notifications.internal.DeletedObjectImpl
import io.realm.kotlin.notifications.internal.InitialObjectImpl
import io.realm.kotlin.notifications.internal.UpdatedObjectImpl
import io.realm.kotlin.types.BaseRealmObject
import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass
/**
* A RealmObjectReference that links a specific Kotlin RealmObjectInternal instance with an underlying C++
* Realm Object.
*
* It contains a pointer to the object and it is the main entry point to the Realm object features.
*/
// TODO Public due to being a transitive dependency of RealmObjectInternal
public class RealmObjectReference(
public val className: String,
public val type: KClass,
public val owner: RealmReference,
public val mediator: Mediator,
public override val objectPointer: RealmObjectPointer,
) :
RealmStateHolder,
RealmObjectInterop,
InternalDeleteable,
CoreNotifiable, ObjectChange> {
public val metadata: ClassMetadata = owner.schemaMetadata[className]!!
// Any methods added to this interface, needs to be fake overridden on the user classes by
// the compiler plugin, see "RealmObjectInternal overrides" in RealmModelLowering.lower
public fun propertyInfoOrThrow(
propertyName: String
): PropertyMetadata = this.metadata.getOrThrow(propertyName)
override fun realmState(): RealmState {
return owner
}
private fun newObjectReference(
owner: RealmReference,
pointer: RealmObjectPointer,
clazz: KClass = type
): RealmObjectReference = RealmObjectReference(
type = clazz,
owner = owner,
mediator = mediator,
className = className,
objectPointer = pointer
)
@Suppress("unchecked_cast")
override fun freeze(
frozenRealm: RealmReference
): RealmObjectReference? {
return RealmInterop.realm_object_resolve_in(
objectPointer,
frozenRealm.dbPointer
)?.let { pointer: RealmObjectPointer ->
newObjectReference(frozenRealm, pointer)
} as RealmObjectReference?
}
override fun thaw(liveRealm: RealmReference): RealmObjectReference? {
return thaw(liveRealm, type)
}
@Suppress("unchecked_cast")
public fun thaw(
liveRealm: RealmReference,
clazz: KClass
): RealmObjectReference? {
val dbPointer = liveRealm.dbPointer
return RealmInterop.realm_object_resolve_in(objectPointer, dbPointer)
?.let { pointer: RealmObjectPointer ->
newObjectReference(liveRealm, pointer, clazz)
} as RealmObjectReference?
}
override fun registerForNotification(
keyPaths: RealmKeyPathArrayPointer?,
callback: Callback
): RealmNotificationTokenPointer {
// We should never get here unless it is a managed object as unmanaged doesn't support observing
return RealmInterop.realm_object_add_notification_callback(
this.objectPointer,
keyPaths,
callback
)
}
override fun changeFlow(scope: ProducerScope>): ChangeFlow, ObjectChange> =
ObjectChangeFlow(scope)
internal fun getChangedFieldNames(
change: RealmChangesPointer
): Array {
return RealmInterop.realm_object_changes_get_modified_properties(
change
).map { propertyKey: PropertyKey ->
metadata[propertyKey]?.name ?: ""
}.toTypedArray()
}
override fun asFlow(keyPaths: List?): Flow> {
val keyPathInfo = keyPaths?.let {
Pair(metadata.classKey, it)
}
return this.owner.owner.registerObserver(this, keyPathInfo)
}
override fun delete() {
if (isFrozen()) {
throw IllegalArgumentException(
"Frozen objects cannot be deleted. They must be converted to live objects first " +
"by using `MutableRealm/DynamicMutableRealm.findLatest(frozenObject)`."
)
}
if (!isValid()) {
throw IllegalArgumentException(INVALID_OBJECT_MSG)
}
objectPointer.let { RealmInterop.realm_object_delete(it) }
}
override fun isValid(): Boolean =
objectPointer.let { ptr ->
!ptr.isReleased() && RealmInterop.realm_object_is_valid(ptr)
}
internal fun checkValid() {
if (!this.isValid()) {
throw IllegalStateException(INVALID_OBJECT_MSG)
}
}
public companion object {
public const val INVALID_OBJECT_MSG: String = "Cannot perform this operation on an invalid/deleted object"
}
}
internal fun RealmObjectReference.checkNotificationsAvailable() {
if (RealmInterop.realm_is_closed(owner.dbPointer)) {
throw IllegalStateException("Changes cannot be observed when the Realm has been closed.")
}
if (!isValid()) {
throw IllegalStateException("Changes cannot be observed on objects that have been deleted from the Realm.")
}
}
internal class ObjectChangeFlow(scope: ProducerScope>) :
ChangeFlow, ObjectChange>(scope) {
override fun initial(frozenRef: RealmObjectReference): ObjectChange {
val obj: E = frozenRef.toRealmObject()
return InitialObjectImpl(obj)
}
override fun update(
frozenRef: RealmObjectReference,
change: RealmChangesPointer
): ObjectChange {
val obj: E = frozenRef.toRealmObject()
val changedFieldNames = frozenRef.getChangedFieldNames(change)
return UpdatedObjectImpl(obj, changedFieldNames)
}
override fun delete(): ObjectChange = DeletedObjectImpl()
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy