Realm Kotlin SDK

repository·main·Indexed 22 days ago

https://github.com/realm/realm-kotlin

A mobile database for phones, tablets, and wearables that supports Android and Kotlin Multiplatform. It provides an object-oriented data model to eliminate the need for an ORM, featuring support for Kotlin Coroutine Flows for data observation, a query language inspired by NSPredicate, and a shared implementation for data persistence logic across Android and iOS.

Tokens
5.8K
Snippets
22
Records
27
Agent score
78%

What's inside realm-kotlin

  1. Run Realm Kotlin benchmarks on Android

    main

    Android benchmarks utilize Jetpack Microbenchmarks. You can run them via Gradle or directly from your IDE as a normal Android Integration Test.

    Important Note on Emulators: While benchmarks can run on emulators, results are often unreliable due to high variance. For accurate results, use real devices. If you must use an emulator, use API level 29 or below to avoid scoped storage restrictions.

    To run via Gradle:

    ./gradlew androidApp:connectedCheck -e no-isolated-storage true
  2. Install Realm Kotlin SNAPSHOT releases

    main

    To test recent bugfixes or features not yet in an official release, you can use -SNAPSHOT versions from Maven Central. This requires configuring your buildscript and repositories to include the snapshot URL and setting a resolutionStrategy to prevent caching of changing modules.

    // Kotlin DSL Example
    
    // Global build.gradle
    buildscript {
        dependencies {
            classpath("io.realm.kotlin:gradle-plugin:<VERSION>-SNAPSHOT")
        }
    }
    
    repositories {
        google()
        mavenCentral()
        maven {
            url = uri("https://oss.sonatype.org/content/repositories/snapshots")
        }
    }
    
    // Module build.gradle
    plugins {
        id("io.realm.kotlin")
    }
    
    kotlin {
        sourceSets {
            val commonMain  by getting {
                dependencies {
                    implementation("io.realm.kotlin:library-base:<VERSION>-SNAPSHOT")
                }
            }
        }
    }
    
    // Don't cache SNAPSHOT (changing) dependencies.
    configurations.all {
        resolutionStrategy.cacheChangingModulesFor(0,TimeUnit.SECONDS)
    }
  3. Use Realm Kotlin in a Kotlin Multiplatform (KMM) shared module

    main

    You can use the Realm Kotlin SDK within the commonMain source set of a Kotlin Multiplatform project to provide a single, shared implementation of data persistence logic for both Android and iOS.

    In a typical KMM architecture, you implement your repositories (e.g., an ExpressionRepository) once in the shared module. This allows the shared business logic (e.g., a Calculator class) to trigger database operations that are then automatically available to all platform-specific targets.

    // Example conceptual structure in commonMain
    class ExpressionRepository(private val realm: Realm) {
        // Shared implementation for Android and iOS
        fun saveCalculation(expression: String) {
            realm.write { 
                // ... logic to persist data
            }
        }
    }
  4. Query data in Realm

    main

    Realm uses a query language inspired by Apple's NSPredicate. You can query for all objects of a type, or use string-based queries with arguments (using $0, $1, etc.) to filter results. Results can be converted to a Flow to observe changes asynchronously.

    // All persons
    import io.realm.kotlin.ext.query
    val all = realm.query<Person>().find()
    
    // Persons named 'Carlo'
    val personsByNameQuery: RealmQuery<Person> = realm.query<Person>("name = $0", "Carlo")
    val filteredByName: RealmResults<Person> = personsByNameQuery.find()
    
    // Person having a dog aged more than 7 with a name starting with 'Fi'
    val filteredByDog = realm.query<Person>("dog.age > $0 AND dog.name BEGINSWITH $1", 7, "Fi").find()
    
    // Observing changes with Coroutine Flows
    CoroutineScope(context).async {
        personsByNameQuery.asFlow().collect { result: ResultsChange<Person> ->
            println("Realm updated: Number of persons is ${result.list.size}")
        }
    }
  5. Retrieve Android benchmark data

    main

    Benchmark data for Android is typically stored on the device. You can pull the data to your local machine using adb pull to a specific directory:

    adb pull /sdcard/Android/media/io.realm.kotlin.benchmarks.android.test ./benchmark-data/android/
  6. Define Realm data models

    main

    To use Realm, define your data models as classes that implement the RealmObject interface. These classes represent the schema of your database. You can define relationships between objects (e.g., a Person having a Dog).

    class Person : RealmObject {
        var name: String = "Foo"
        var dog: Dog? = null
    }
    
    class Dog : RealmObject {
        var name: String = ""
        var age: Int = 0
    }
  7. Open a Realm database

    main

    To access the database, you must first define a RealmConfiguration specifying the schema (the set of RealmObject classes used) and then call Realm.open(configuration).

    // use the RealmConfiguration.Builder() for more options
    val configuration = RealmConfiguration.create(schema = setOf(Person::class, Dog::class)) 
    val realm = Realm.open(configuration)
  8. Run Realm Kotlin benchmarks on JVM

    main

    JVM benchmarks use the Java Microbenchmarking Harness (JMH). These must be run from the command line.

    Note on caching: If a benchmark file already exists, JMH will exit without re-running. To ensure a fresh run, execute ./gradlew clean before running the benchmark.

    To run all JVM benchmarks:

    ./gradlew jvmApp:clean jvmApp:jmh

    To run a specific subset of benchmarks using a regex pattern:

    ./gradlew jvmApp:clean jvmApp:jmh -Pjmh.include="BulkWrite*"

    Benchmark results are saved to: /jvmApp/build/reports/benchmarks.json

  9. Write data to Realm

    main

    All changes to the database must occur within a write transaction. You can use writeBlocking for synchronous writes or write for asynchronous writes using Kotlin coroutines. Inside the transaction block, use copyToRealm(object) to persist a plain Kotlin object into the Realm.

    // plain old kotlin object
    val person = Person().apply {
        name = "Carlo"
        dog = Dog().apply { name = "Fido"; age = 16 }
    }
    
    // Persist it in a transaction
    realm.writeBlocking { // this : MutableRealm
        val managedPerson = copyToRealm(person)
    }
    
    // Asynchronous updates with Kotlin coroutines
    CoroutineScope(context).async {
        realm.write { // this : MutableRealm
            val managedPerson = copyToRealm(person)
        }
    }
  10. Delete objects from Realm

    main

    Deletions must be performed within a write transaction. You can delete objects based on a query, from a query result, or by passing individual managed objects to the delete() method.

    // delete all Dogs
    realm.writeBlocking {
        // Selected by a query
        val query = this.query<Dog>()
        delete(query)
    
        // From a query result
        val results = query.find()
        delete(results)
    
        // From individual objects
        results.forEach { delete(it) }
    }
  11. Update existing Realm objects

    main

    To update an object, first find it using a query. Within a write transaction, use findLatest(object) to get the live, managed version of the object before applying changes.

    // Find the first Person without a dog
    realm.query<Person>("dog == NULL LIMIT(1)")
        .first()
        .find()
        ?.also { personWithoutDog ->
            // Add a dog in a transaction
            realm.writeBlocking {
                findLatest(personWithoutDog)?.dog = Dog().apply { name = "Laika"; age = 3 }
            }
        }