All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.io.realm.RealmResults.kt Maven / Gradle / Ivy

Go to download

Library code for Realm Kotlin. This artifact is not supposed to be consumed directly, but through 'io.realm.kotlin:gradle-plugin:0.4.1' instead.

There is a newer version: 0.5.0
Show newest version
/*
 * 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 io.realm.internal.Mediator
import io.realm.internal.RealmObjectInternal
import io.realm.internal.RealmReference
import io.realm.internal.link
import io.realm.interop.Link
import io.realm.interop.NativePointer
import io.realm.interop.RealmInterop
import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass

// FIXME API-QUERY Final query design is tracked in https://github.com/realm/realm-kotlin/issues/84
//  - Lazy API makes it harded to debug
//  - Postponing execution to actually accessing the elements also prevents query parser errors to
//    be raised. Maybe we can get an option to prevalidate queries in the C-API?
/**
 * A _Realm Result_ holds the results of querying the Realm.
 *
 * @see Realm.objects
 * @see MutableRealm.objects
 */
class RealmResults : AbstractList, Queryable {

    private val mode: Mode
    private val realm: RealmReference
    private val clazz: KClass
    private val schema: Mediator
    internal val result: NativePointer

    private enum class Mode {
        // FIXME Needed to make working with @LinkingObjects easier.
        EMPTY, // RealmResults that is always empty.
        RESULTS // RealmResults wrapping a Realm Core Results.
    }
    // Wrap existing native Results class
    private constructor(realm: RealmReference, results: NativePointer, clazz: KClass, schema: Mediator) {
        this.mode = Mode.RESULTS
        this.realm = realm
        this.result = results
        this.clazz = clazz
        this.schema = schema
    }

    internal companion object {
        internal fun  fromQuery(realm: RealmReference, query: NativePointer, clazz: KClass, schema: Mediator): RealmResults {
            // realm_query_find_all doesn't fully evaluate until you interact with it.
            return RealmResults(realm, RealmInterop.realm_query_find_all(query), clazz, schema)
        }

        internal fun  fromResults(realm: RealmReference, results: NativePointer, clazz: KClass, schema: Mediator): RealmResults {
            return RealmResults(realm, results, clazz, schema)
        }
    }

    /**
     * The current version of the data in this Realm.
     */
    public fun version(): VersionId {
        return realm.owner.version
    }

    override val size: Int
        get() = RealmInterop.realm_results_count(result).toInt()

    override fun get(index: Int): T {
        val link: Link = RealmInterop.realm_results_get(result, index.toLong())
        val model = schema.createInstanceOf(clazz) as RealmObjectInternal
        model.link(realm, schema, clazz, link)
        @Suppress("UNCHECKED_CAST")
        return model as T
    }

    /**
     * Perform a query on the objects of this result using the Realm Query Language.
     *
     * See [these docs](https://docs.mongodb.com/realm-sdks/java/latest/io/realm/RealmQuery.html#rawPredicate-java.lang.String-java.lang.Object...-)
     * for a description of the equivalent realm-java API and
     * [these docs](https://docs.mongodb.com/realm-sdks/js/latest/tutorial-query-language.html)
     * for a more detailed description of the actual Realm Query Language.
     *
     * Ex.:
     *  `'color = "tan" AND name BEGINSWITH "B" SORT(name DESC) LIMIT(5)`
     *
     * @param query The query string to use for filtering and sort.
     * @param args The query parameters.
     * @return new result according to the query and query arguments.
     */
    @Suppress("SpreadOperator")
    override fun query(query: String, vararg args: Any): RealmResults {
        return fromQuery(
            realm,
            RealmInterop.realm_query_parse(result, clazz.simpleName!!, query, *args),
            clazz,
            schema,
        )
    }

    /**
     * FIXME Hidden until we can add proper support
     *
     * Observe changes to a Realm result.
     *
     * Follows the pattern of [Realm.addChangeListener]
     */
    internal fun addChangeListener(callback: Callback>): Cancellable {
        realm.checkClosed()
        return realm.owner.registerResultsChangeListener(this, callback)
    }

    /**
     * Observe changes to the RealmResult. If there is any change to objects represented by the query
     * backing the RealmResult, the flow will emit the updated RealmResult. The flow will continue
     * running indefinitely until canceled.
     *
     * The change calculations will on on the thread represented by [RealmConfiguration.notificationDispatcher].
     *
     * @return a flow representing changes to the RealmResults.
     */
    fun observe(): Flow> {
        realm.checkClosed()
        return realm.owner.registerResultsObserver(this)
    }

    /**
     * Delete all objects from this result from the realm.
     */
    fun delete() {
        // TODO OPTIMIZE Are there more efficient ways to do this? realm_query_delete_all is not
        //  available in C-API yet, but should probably await final query design
        //  https://github.com/realm/realm-kotlin/issues/84
        RealmInterop.realm_results_delete_all(result)
    }

    /**
     * Returns a frozen copy of this query result. If it is already frozen, the same instance
     * is returned.
     */
    internal fun freeze(realm: RealmReference): RealmResults {
        val frozenDbPointer = realm.dbPointer
        val frozenResults = RealmInterop.realm_results_freeze(result, frozenDbPointer)
        return fromResults(realm, frozenResults, clazz, schema)
    }

    /**
     * Thaw the frozen query result, turning it back into a live, thread-confined RealmResults.
     */
    internal fun thaw(realm: RealmReference): RealmResults {
        val liveDbPointer = realm.dbPointer
        val liveResultPtr = RealmInterop.realm_results_thaw(result, liveDbPointer)
        return fromResults(realm, liveResultPtr, clazz, schema)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy