SQLDelight para Kotlin: guia completo com exemplos práticos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

SQLDelight para Kotlin: guia completo com exemplos práticos

1. O que é e para que serve

SQLDelight é uma biblioteca para Kotlin que gera código Kotlin type-safe (com segurança de tipos) a partir de consultas SQL. Desenvolvida pela Cash App (Square), ela suporta Kotlin Multiplatform (KMP), permitindo usar o mesmo código para trabalhar com bancos de dados em Android, iOS, JVM, JS e plataformas nativas.

A ideia principal do SQLDelight é que você escreve consultas SQL em arquivos .sq, e a biblioteca gera automaticamente classes, interfaces e funções Kotlin que correspondem exatamente às suas consultas. Isso elimina a necessidade de escrever código boilerplate para mapear resultados de consultas em objetos e previne injeções SQL em tempo de compilação.

Por que usar SQLDelight? Primeiro, ela oferece verificação completa de tipos em tempo de compilação: se você alterar a estrutura de uma tabela, o compilador apontará imediatamente todos os lugares que precisam ser atualizados. Segundo, ela suporta migrações, transações, consultas assíncronas e trabalho multiplataforma. Terceiro, integra-se com frameworks populares como Ktor, Koin, Dagger/Hilt e outros.

2. Instalação

O SQLDelight é instalado através do sistema de build Gradle. Para Kotlin Multiplatform, adicione o seguinte plugin no build.gradle.kts raiz:

// build.gradle.kts raiz
plugins {
    id("app.cash.sqldelight") version "2.0.2" apply false
}

// No módulo (ex: :shared)
plugins {
    id("app.cash.sqldelight")
}

sqldelight {
    databases {
        create("MyDatabase") {
            packageName.set("com.example.db")
        }
    }
}

dependencies {
    implementation("app.cash.sqldelight:coroutines-extensions:2.0.2")
    implementation("app.cash.sqldelight:runtime:2.0.2")
    // Para Android
    implementation("app.cash.sqldelight:android-driver:2.0.2")
    // Para iOS
    implementation("app.cash.sqldelight:native-driver:2.0.2")
    // Para JVM
    implementation("app.cash.sqldelight:sqlite-driver:2.0.2")
}

Após sincronizar o Gradle, crie o arquivo src/commonMain/sqldelight/com/example/db/MyDatabase.sq (o caminho deve coincidir com o packageName).

3. Início rápido — exemplo mínimo funcional

Crie o arquivo MyDatabase.sq:

-- MyDatabase.sq
CREATE TABLE Person (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    age INTEGER NOT NULL
);

selectAll:
SELECT * FROM Person;

insertPerson:
INSERT INTO Person(name, age) VALUES (?, ?);

Agora no código Kotlin:

import com.example.db.MyDatabase
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver

fun main() {
    val driver: SqlDriver = JdbcSqliteDriver("jdbc:sqlite:test.db")
    MyDatabase.Schema.create(driver)
    
    val database = MyDatabase(driver)
    val queries = database.myDatabaseQueries
    
    // Inserção
    queries.insertPerson("Alice", 30)
    queries.insertPerson("Bob", 25)
    
    // Consulta
    val people = queries.selectAll().executeAsList()
    people.forEach { person ->
        println("${person.name} tem ${person.age} anos")
    }
}

Este código criará a tabela, inserirá dois registros e os exibirá.

4. Principais métodos/funções/classes

4.1 executeAsList()

Assinatura: fun <T> executeAsList(): List<T>

O que faz: Executa uma consulta SELECT e retorna todas as linhas do resultado como uma lista de objetos do tipo gerado.

val allPeople: List<Person> = queries.selectAll().executeAsList()

4.2 executeAsOne()

Assinatura: fun <T> executeAsOne(): T

O que faz: Executa uma consulta SELECT que deve retornar exatamente uma linha. Lança exceção se não houver resultados ou se houver mais de um.

val person: Person = queries.selectById(1).executeAsOne()

4.3 executeAsOneOrNull()

Assinatura: fun <T> executeAsOneOrNull(): T?

O que faz: Similar ao executeAsOne(), mas retorna null se nenhum resultado for encontrado.

val person: Person? = queries.selectById(99).executeAsOneOrNull()

4.4 executeAsCount()

Assinatura: fun executeAsCount(): Long

O que faz: Executa uma consulta que retorna uma contagem (COUNT, SUM, etc.) e retorna o valor como Long.

val total: Long = queries.countPeople().executeAsCount()

4.5 execute()

Assinatura: fun execute(): Int

O que faz: Executa uma instrução de modificação (INSERT, UPDATE, DELETE) e retorna o número de linhas afetadas.

val rowsAffected: Int = queries.deletePerson(1).execute()

4.6 Transações

SQLDelight suporta transações com transaction { }:

database.transaction {
    queries.insertPerson("Charlie", 35)
    queries.insertPerson("Diana", 28)
    // Commit automático se nenhuma exceção for lançada
}

4.7 Consultas assíncronas com Coroutines

Com a extensão coroutines-extensions, você pode usar asFlow() para observar mudanças:

val peopleFlow: Flow<List<Person>> = queries.selectAll()
    .asFlow()
    .mapToList(Dispatchers.IO)

peopleFlow.collect { people ->
    println("Pessoas atualizadas: $people")
}

5. Migrações de banco de dados

SQLDelight gerencia migrações automaticamente. Crie arquivos .sqm na mesma pasta dos arquivos .sq:

-- 1.sqm
CREATE TABLE City (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    population INTEGER NOT NULL
);

A biblioteca aplica as migrações na ordem correta automaticamente.

6. Conclusão

SQLDelight é uma ferramenta poderosa para quem desenvolve com Kotlin, especialmente em projetos multiplataforma. Ela oferece segurança de tipos, reduz código boilerplate e melhora a produtividade. Comece com exemplos simples e explore recursos avançados como migrações, transações e consultas assíncronas conforme sua necessidade.

Recommendations