Room support is currently in alpha!While we don’t expect any major changes and the library is tested on multiple platforms, it depends on raw tables, an unstable PowerSync feature.
PowerSync supports the Room database library for Kotlin (multiplatform).
https://mintcdn.com/powersync/T2mdeXADaWyXCq-s/logo/maven.svg?fit=max&auto=format&n=T2mdeXADaWyXCq-s&q=85&s=5d5148dc17eeb2df0dd8bf0e3235bfb0

Maven: com.powersync:integration-room

Features

When adopting the Room integration for PowerSync:
  • PowerSync will use the connection pool of the Room database for efficient queries.
  • Local writes from Room will update watched PowerSync queries, and they will trigger a CRUD upload.
  • Writes from PowerSync (including those made by the sync client) will immediately update your Room flows!

Installation

PowerSync acts as an addon to your existing Room database, which means that (unlike with most other PowerSync SDKs) you are still responsible for schema management. Room requires raw tables, as the views managed by PowerSync are incompatible with the schema verification when Room opens the database. To add PowerSync to your Room database,
  1. Add a dependency on com.powersync:core and com.powersync:integration-room.
  2. Add a dependency on androidx.sqlite:sqlite-bundled: Since PowerSync uses a SQLite extension (which are unsupported on the platform SQLite libraries on both Android and iOS), you need to bundle a SQLite with your app. On the RoomDatabase.Builder, call setDriver() with a PowerSync-enabled driver:
    val driver = BundledSQLiteDriver().also {
        it.loadPowerSyncExtension() // Extension method by PowerSync
    }
    
    Room.databaseBuilder(...).setDriver(driver).build()
    

Setup

Because PowerSync syncs into tables that you’ve created with Room, it needs to know which SQL statements to run for inserts, updates and deletes. Let’s say you had a table like the following:
@Entity
data class TodoItem(
    // Note that PowerSync uses textual ids (usually randomly-generated UUIDs)
    @PrimaryKey val id: String
    val title: String
    val authorId: String
)
To inform PowerSync about that table, include it as a RawTable in the schema:
val schema = Schema(
    RawTable(
        name = "todos",
        put =
            PendingStatement(
                "INSERT INTO todo_item (id, title, author_id) VALUES (?, ?, ?)",
                listOf(
                    PendingStatementParameter.Id,
                    PendingStatementParameter.Column("title"),
                    PendingStatementParameter.Column("author_id"),
                ),
            ),
        delete =
            PendingStatement(
                "DELETE FROM todo_item WHERE id = ?",
                listOf(PendingStatementParameter.Id),
            ),
    ),
)
Here:
  • The SQL statements must match the schema created by Room.
  • The RawTable.name and PendingStatementParameter.Column values must match the table and column names of the synced table from the PowerSync service, derived from your sync rules.
For more details, see raw tables. After these steps, you can open your Room database like you normally would. Then, you can use the following method to obtain a PowerSyncDatabase instance which is backed by Room:
val schema = Schema(...)
val pool = RoomConnectionPool(yourRoomDatabase, schema)
val powersync = PowerSyncDatabase.opened(
    pool = pool,
    scope = this,
    schema = schema,
    identifier = "databaseName", // Prefer to use the same path/name as your Room database
    logger = Logger,
)
The returned PowerSyncDatabase behaves just like a regular PowerSync database, meaning that you can call connect to establish a sync connection:
powersync.connect(
    YourBackendConnector(),
    options = SyncOptions(
        // Raw tables require the new client implementation.
        newClientImplementation = true
    )
)

Usage

To run queries, you can keep defining Room DAOs in the usual way:
@DAOs
interface TodoItemsDao {
    @Insert
    suspend fun create(item: TodoItem)

    @Query("SELECT * FROM todo_item")
    fun watchAll(): Flow<List<TodoItem>>
}

// ...

todoItemsDao.create(TodoItem(
    id = Uuid.random()toHexDashString(),
    title = "My first todo item",
    authorId = currentUserId
))

todoItemsDao.watchAll().collect { items ->
    println("This flow emits events for writes from Room and synced data from PowerSync")
}