Skip to content

Commit

Permalink
Rework dynamic API to use generic 'get'
Browse files Browse the repository at this point in the history
  • Loading branch information
rorbech committed Jul 4, 2024
1 parent 18b4def commit 3048570
Show file tree
Hide file tree
Showing 12 changed files with 1,068 additions and 1,587 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ import io.realm.kotlin.MutableRealm
import io.realm.kotlin.Realm
import io.realm.kotlin.internal.dynamic.DynamicUnmanagedRealmObject
import io.realm.kotlin.schema.RealmStorageType
import io.realm.kotlin.types.RealmDictionary
import io.realm.kotlin.types.RealmList
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.RealmSet

/**
* A **dynamic mutable realm object** gives access and possibility to update the data of the realm
Expand All @@ -33,16 +30,6 @@ import io.realm.kotlin.types.RealmSet
*/
public interface DynamicMutableRealmObject : DynamicRealmObject {

override fun getObject(propertyName: String): DynamicMutableRealmObject?

override fun getObjectList(propertyName: String): RealmList<DynamicMutableRealmObject>

override fun getObjectSet(propertyName: String): RealmSet<DynamicMutableRealmObject>

override fun getObjectDictionary(
propertyName: String
): RealmDictionary<DynamicMutableRealmObject?>

/**
* Sets the value for the given field.
*
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import org.mongodb.kbson.Decimal128
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KProperty1
import kotlin.reflect.KType

/**
* This object holds helper methods for the compiler plugin generated methods, providing the
Expand Down Expand Up @@ -888,16 +889,137 @@ internal object RealmObjectHelper {
}
}

internal fun <R> dynamicGetFromKType(
obj: RealmObjectReference<out BaseRealmObject>,
propertyName: String,
type: KType,
issueDynamicMutableObject: Boolean = false
): R {
obj.checkValid()
val collectionType = when {
type.classifier == RealmList::class -> CollectionType.RLM_COLLECTION_TYPE_LIST
type.classifier == RealmSet::class -> CollectionType.RLM_COLLECTION_TYPE_SET
type.classifier == RealmDictionary::class -> CollectionType.RLM_COLLECTION_TYPE_DICTIONARY
else -> CollectionType.RLM_COLLECTION_TYPE_NONE
}
val elementType: KType = if (collectionType != CollectionType.RLM_COLLECTION_TYPE_NONE) {
type.arguments[0].type!!
} else type

val propertyMetadata = checkPropertyType(
obj,
propertyName,
collectionType,
elementType.classifier as KClass<*>,
// type.classifier as KClass<R & Any>,
elementType.isMarkedNullable
)
val operatorType = when {
propertyMetadata.type == PropertyType.RLM_PROPERTY_TYPE_MIXED ->
CollectionOperatorType.REALM_ANY

propertyMetadata.type != PropertyType.RLM_PROPERTY_TYPE_OBJECT ->
CollectionOperatorType.PRIMITIVE

!obj.owner.schemaMetadata[propertyMetadata.linkTarget]!!.isEmbeddedRealmObject ->
CollectionOperatorType.REALM_OBJECT

else -> CollectionOperatorType.EMBEDDED_OBJECT
}
// FIXME get<RealmAny> to return collections in mixed
return when (collectionType) {
CollectionType.RLM_COLLECTION_TYPE_NONE -> {
return getterScope {
val transport = realm_get_value(obj.objectPointer, propertyMetadata.key)

// Consider moving this dynamic conversion to Converters.kt
val value = when (type.classifier) {
DynamicRealmObject::class,
DynamicMutableRealmObject::class -> realmValueToRealmObject(
transport,
type.classifier as KClass<out BaseRealmObject>,
obj.mediator,
obj.owner
)
RealmAny::class -> realmValueToRealmAny(
realmValue = transport,
parent = obj,
mediator = obj.mediator,
owner = obj.owner,
issueDynamicObject = true,
issueDynamicMutableObject = issueDynamicMutableObject,
getListFunction = {
RealmInterop.realm_get_list(
obj.objectPointer,
propertyMetadata.key
)
},
getDictionaryFunction = {
RealmInterop.realm_get_dictionary(
obj.objectPointer,
propertyMetadata.key
)
}
)

else -> with(primitiveTypeConverters.getValue(type.classifier as KClass<R & Any>)) {
realmValueToPublic(transport)
}
}
value?.let {
@Suppress("UNCHECKED_CAST")
if ((type.classifier as KClass<R & Any>).isInstance(value)) {
value as R
} else {
throw ClassCastException("Retrieving value of type '${(type.classifier as KClass<R & Any>).simpleName}' but was of type '${value::class.simpleName}'")
}
} as R
}
}
CollectionType.RLM_COLLECTION_TYPE_LIST -> {
getListByKey(
obj,
propertyMetadata,
elementType.classifier as KClass<R & Any>,
operatorType,
true,
issueDynamicMutableObject
) as R
}
CollectionType.RLM_COLLECTION_TYPE_SET -> {
getSetByKey(
obj,
propertyMetadata,
elementType.classifier as KClass<R & Any>,
operatorType,
true,
issueDynamicMutableObject
) as R
}
CollectionType.RLM_COLLECTION_TYPE_DICTIONARY -> {
getDictionaryByKey(
obj,
propertyMetadata,
elementType.classifier as KClass<R & Any>,
operatorType,
true,
issueDynamicMutableObject
) as R
}
else -> sdkError("Unknown collection type $collectionType")
}
}

/**
* Get values for non-collection properties by name.
*
* This will verify that the requested type (`clazz`) and nullability matches the property
* properties in the schema.
*/
internal fun <R : Any> dynamicGet(
internal fun <R> dynamicGet(
obj: RealmObjectReference<out BaseRealmObject>,
propertyName: String,
clazz: KClass<R>,
clazz: KClass<R & Any>,
nullable: Boolean,
issueDynamicMutableObject: Boolean = false
): R? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,125 +18,19 @@ package io.realm.kotlin.internal.dynamic

import io.realm.kotlin.dynamic.DynamicMutableRealmObject
import io.realm.kotlin.internal.RealmObjectHelper
import io.realm.kotlin.types.RealmDictionary
import io.realm.kotlin.types.RealmList
import io.realm.kotlin.types.RealmSet
import kotlin.reflect.KClass
import kotlin.reflect.KType

internal class DynamicMutableRealmObjectImpl : DynamicMutableRealmObject, DynamicRealmObjectImpl() {

override fun <T : Any> getValue(propertyName: String, clazz: KClass<T>): T {
// dynamicGetSingle checks nullability of property, so null pointer check raises appropriate NPE
return RealmObjectHelper.dynamicGet(
this.`io_realm_kotlin_objectReference`!!,
propertyName,
clazz,
nullable = false,
issueDynamicMutableObject = true
)!!
}

override fun <T : Any> getNullableValue(propertyName: String, clazz: KClass<T>): T? {
return RealmObjectHelper.dynamicGet(
`io_realm_kotlin_objectReference`!!,
propertyName,
clazz,
nullable = true,
issueDynamicMutableObject = true
override fun <T> get(propertyName: String, type: KType): T {
return RealmObjectHelper.dynamicGetFromKType(
obj = this.`io_realm_kotlin_objectReference`!!,
propertyName = propertyName,
type = type,
issueDynamicMutableObject = true,
)
}

override fun getObject(propertyName: String): DynamicMutableRealmObject? {
return getNullableValue(propertyName, DynamicMutableRealmObject::class)
}

override fun <T : Any> getValueList(propertyName: String, clazz: KClass<T>): RealmList<T> {
return RealmObjectHelper.dynamicGetList(
`io_realm_kotlin_objectReference`!!,
propertyName,
clazz,
nullable = false,
issueDynamicMutableObject = true
).let {
@Suppress("unchecked_cast")
it as RealmList<T>
}
}

override fun <T : Any> getNullableValueList(propertyName: String, clazz: KClass<T>): RealmList<T?> {
return RealmObjectHelper.dynamicGetList(
`io_realm_kotlin_objectReference`!!,
propertyName,
clazz,
nullable = true,
issueDynamicMutableObject = true
)
}

override fun getObjectList(propertyName: String): RealmList<DynamicMutableRealmObject> {
return getValueList(propertyName, DynamicMutableRealmObject::class)
}

override fun <T : Any> getValueSet(propertyName: String, clazz: KClass<T>): RealmSet<T> {
return RealmObjectHelper.dynamicGetSet(
`io_realm_kotlin_objectReference`!!,
propertyName,
clazz,
nullable = false,
issueDynamicMutableObject = true
).let {
@Suppress("unchecked_cast")
it as RealmSet<T>
}
}

override fun <T : Any> getNullableValueSet(propertyName: String, clazz: KClass<T>): RealmSet<T?> {
return RealmObjectHelper.dynamicGetSet(
`io_realm_kotlin_objectReference`!!,
propertyName,
clazz,
nullable = true,
issueDynamicMutableObject = true
)
}

override fun getObjectSet(propertyName: String): RealmSet<DynamicMutableRealmObject> {
return getValueSet(propertyName, DynamicMutableRealmObject::class)
}

override fun <T : Any> getValueDictionary(
propertyName: String,
clazz: KClass<T>,
): RealmDictionary<T> {
return RealmObjectHelper.dynamicGetDictionary(
`io_realm_kotlin_objectReference`!!,
propertyName,
clazz,
nullable = false,
issueDynamicMutableObject = true
).let {
@Suppress("unchecked_cast")
it as RealmDictionary<T>
}
}

override fun <T : Any> getNullableValueDictionary(
propertyName: String,
clazz: KClass<T>
): RealmDictionary<T?> {
return RealmObjectHelper.dynamicGetDictionary(
`io_realm_kotlin_objectReference`!!,
propertyName,
clazz,
nullable = true,
issueDynamicMutableObject = true
)
}

override fun getObjectDictionary(propertyName: String): RealmDictionary<DynamicMutableRealmObject?> {
return getNullableValueDictionary(propertyName, DynamicMutableRealmObject::class)
}

override fun <T> set(propertyName: String, value: T): DynamicMutableRealmObject {
// `io_realm_kotlin_objectReference` is not null, as DynamicMutableRealmObject are always managed
val reference = this.io_realm_kotlin_objectReference!!
Expand Down
Loading

0 comments on commit 3048570

Please sign in to comment.