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

commonMain.io.realm.kotlin.internal.query.ObjectQuery.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:1.11.1' instead.

There is a newer version: 3.0.0
Show newest version
/*
 * Copyright 2021 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.query

import io.realm.kotlin.internal.InternalDeleteable
import io.realm.kotlin.internal.Mediator
import io.realm.kotlin.internal.Notifiable
import io.realm.kotlin.internal.Observable
import io.realm.kotlin.internal.RealmReference
import io.realm.kotlin.internal.RealmResultsImpl
import io.realm.kotlin.internal.RealmValueArgumentConverter.convertToQueryArgs
import io.realm.kotlin.internal.asInternalDeleteable
import io.realm.kotlin.internal.interop.ClassKey
import io.realm.kotlin.internal.interop.RealmInterop
import io.realm.kotlin.internal.interop.RealmQueryPointer
import io.realm.kotlin.internal.interop.RealmResultsPointer
import io.realm.kotlin.internal.interop.inputScope
import io.realm.kotlin.internal.schema.ClassMetadata
import io.realm.kotlin.notifications.ResultsChange
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.query.RealmScalarNullableQuery
import io.realm.kotlin.query.RealmScalarQuery
import io.realm.kotlin.query.RealmSingleQuery
import io.realm.kotlin.query.Sort
import io.realm.kotlin.types.BaseRealmObject
import kotlinx.coroutines.flow.Flow
import kotlin.reflect.KClass

@Suppress("SpreadOperator", "LongParameterList")
internal class ObjectQuery constructor(
    internal val realmReference: RealmReference,
    private val classKey: ClassKey,
    internal val clazz: KClass,
    private val mediator: Mediator,
    internal val queryPointer: RealmQueryPointer,
) : RealmQuery, InternalDeleteable, Observable, ResultsChange> {

    private val resultsPointer: RealmResultsPointer by lazy {
        RealmInterop.realm_query_find_all(queryPointer)
    }

    private val classMetadata: ClassMetadata? = realmReference.schemaMetadata[classKey]

    internal constructor(
        realmReference: RealmReference,
        key: ClassKey,
        clazz: KClass,
        mediator: Mediator,
        filter: String,
        args: Array
    ) : this(
        realmReference,
        key,
        clazz,
        mediator,
        parseQuery(realmReference, key, filter, args),
    )

    internal constructor(
        composedQueryPointer: RealmQueryPointer,
        objectQuery: ObjectQuery
    ) : this(
        objectQuery.realmReference,
        objectQuery.classKey,
        objectQuery.clazz,
        objectQuery.mediator,
        composedQueryPointer,
    )

    override fun find(): RealmResults =
        RealmResultsImpl(realmReference, resultsPointer, classKey, clazz, mediator)

    override fun query(filter: String, vararg arguments: Any?): RealmQuery =
        inputScope {
            val appendedQuery = RealmInterop.realm_query_append_query(
                queryPointer,
                filter,
                convertToQueryArgs(arguments)
            )
            ObjectQuery(appendedQuery, this@ObjectQuery)
        }

    // TODO OPTIMIZE Descriptors are added using 'append_query', which requires an actual predicate.
    //  This might result into query strings like "TRUEPREDICATE AND TRUEPREDICATE SORT(...)". We
    //  should look into how to avoid this, perhaps by exposing a different function that internally
    //  ignores unnecessary default predicates.
    override fun sort(property: String, sortOrder: Sort): RealmQuery =
        query("TRUEPREDICATE SORT($property ${sortOrder.name})")

    override fun sort(
        propertyAndSortOrder: Pair,
        vararg additionalPropertiesAndOrders: Pair
    ): RealmQuery {
        val (property, order) = propertyAndSortOrder
        val stringBuilder = StringBuilder().append("TRUEPREDICATE SORT($property $order")
        additionalPropertiesAndOrders.forEach { (extraProperty, extraOrder) ->
            stringBuilder.append(", $extraProperty $extraOrder")
        }
        stringBuilder.append(")")
        return query(stringBuilder.toString())
    }

    override fun distinct(property: String, vararg extraProperties: String): RealmQuery {
        val stringBuilder = StringBuilder().append("TRUEPREDICATE DISTINCT($property")
        extraProperties.forEach { extraProperty ->
            stringBuilder.append(", $extraProperty")
        }
        stringBuilder.append(")")
        return query(stringBuilder.toString())
    }

    override fun limit(limit: Int): RealmQuery = query("TRUEPREDICATE LIMIT($limit)")

    override fun first(): RealmSingleQuery =
        SingleQuery(realmReference, queryPointer, classKey, clazz, mediator)

    override fun  min(property: String, type: KClass): RealmScalarNullableQuery =
        MinMaxQuery(
            realmReference,
            queryPointer,
            mediator,
            classKey,
            clazz,
            classMetadata!!.getOrThrow(property),
            type,
            AggregatorQueryType.MIN
        )

    override fun  max(property: String, type: KClass): RealmScalarNullableQuery =
        MinMaxQuery(
            realmReference,
            queryPointer,
            mediator,
            classKey,
            clazz,
            classMetadata!!.getOrThrow(property),
            type,
            AggregatorQueryType.MAX
        )

    override fun  sum(property: String, type: KClass): RealmScalarQuery =
        SumQuery(
            realmReference,
            queryPointer,
            mediator,
            classKey,
            clazz,
            classMetadata!!.getOrThrow(property),
            type
        )

    override fun count(): RealmScalarQuery =
        CountQuery(realmReference, queryPointer, mediator, classKey, clazz)

    override fun notifiable(): Notifiable, ResultsChange> =
        QueryResultNotifiable(resultsPointer, classKey, clazz, mediator)

    override fun asFlow(keyPath: List?): Flow> {
        val keyPathInfo = keyPath?.let { Pair(classKey, it) }
        return realmReference.owner
            .registerObserver(this, keyPathInfo)
    }

    override fun delete() {
        // TODO C-API doesn't implement realm_query_delete_all so just fetch the result and delete
        //  that
        find().asInternalDeleteable().delete()
    }

    override fun description(): String {
        return RealmInterop.realm_query_get_description(queryPointer)
    }

    companion object {
        private fun parseQuery(
            realmReference: RealmReference,
            classKey: ClassKey,
            filter: String,
            args: Array
        ): RealmQueryPointer = inputScope {
            val queryArgs = convertToQueryArgs(args)

            try {
                RealmInterop.realm_query_parse(realmReference.dbPointer, classKey, filter, queryArgs)
            } catch (e: IndexOutOfBoundsException) {
                throw IllegalArgumentException(e.message, e.cause)
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy