SQLDelight Kotlin: guía completa con ejemplos prácticos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

SQLDelight para Kotlin: guía completa con ejemplos prácticos

1. ¿Qué es SQLDelight y por qué usarlo?

SQLDelight es una biblioteca para Kotlin que genera código Kotlin type-safe (tipado seguro) a partir de consultas SQL. Fue desarrollada por Cash App (Square) y es compatible con Kotlin Multiplatform (KMP), lo que permite usar el mismo código para trabajar con bases de datos en Android, iOS, JVM, JS y plataformas nativas.

La idea principal de SQLDelight es que escribes consultas SQL en archivos .sq y la biblioteca genera automáticamente clases, interfaces y funciones Kotlin que coinciden exactamente con tus consultas. Esto elimina la necesidad de escribir código repetitivo para mapear resultados de consultas a objetos y previene inyecciones SQL en tiempo de compilación.

¿Por qué usar SQLDelight? Primero, garantiza una verificación completa de tipos en compilación: si cambias la estructura de una tabla, el compilador te señalará inmediatamente todos los lugares donde debes actualizar las consultas. Segundo, soporta migraciones, transacciones, consultas asíncronas y trabajo multiplataforma. Tercero, se integra con frameworks populares como Ktor, Koin, Dagger/Hilt y otros.

2. Instalación

SQLDelight se instala a través del sistema de compilación Gradle. Para Kotlin Multiplatform, agrega el siguiente plugin en el archivo build.gradle.kts raíz:

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

// En el módulo (por ejemplo, :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")
}

Después de sincronizar Gradle, crea el archivo src/commonMain/sqldelight/com/example/db/MyDatabase.sq (la ruta debe coincidir con packageName).

3. Inicio rápido — ejemplo mínimo funcional

Crea el archivo 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 (?, ?);

Ahora en 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
    
    // Inserción
    queries.insertPerson("Ana", 30)
    queries.insertPerson("Carlos", 25)
    
    // Consulta
    val people = queries.selectAll().executeAsList()
    people.forEach { person ->
        println("${person.name} tiene ${person.age} años")
    }
}

Este código crea la tabla, inserta dos registros y los muestra.

4. Métodos/funciones/clases principales

4.1 executeAsList()

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

Qué hace: Ejecuta una consulta SELECT y devuelve todas las filas del resultado como una lista de objetos del tipo generado.

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

4.2 executeAsOne()

Firma: fun <T> executeAsOne(): T

Qué hace: Ejecuta una consulta SELECT que debe devolver exactamente una fila. Lanza una excepción si no hay filas o hay más de una.

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

4.3 executeAsOneOrNull()

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

Qué hace: Similar a executeAsOne(), pero devuelve null si no hay filas en lugar de lanzar una excepción.

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

4.4 executeAsCount()

Firma: fun executeAsCount(): Long

Qué hace: Ejecuta una consulta SELECT COUNT(*) y devuelve el número de filas como un valor Long.

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

4.5 execute()

Firma: fun execute(): Int

Qué hace: Ejecuta una consulta de modificación (INSERT, UPDATE, DELETE) y devuelve el número de filas afectadas.

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

4.6 asFlow() / .asFlow().mapToList()

Firma: fun <T> asFlow(): Flow<QueryResult<T>>

Qué hace: Convierte una consulta en un Flow de Kotlin, permitiendo observar cambios en los datos de forma reactiva. Ideal para arquitecturas modernas con StateFlow o LiveData.

val personasFlow: Flow<List<Person>> = queries.selectAll()
    .asFlow()
    .mapToList()

// En un ViewModel o corrutina
personasFlow.collect { lista ->
    println("Personas actualizadas: $lista")
}

5. Conclusión

SQLDelight es una herramienta poderosa para cualquier desarrollador Kotlin que trabaje con bases de datos. Su enfoque type-safe, soporte multiplataforma y generación automática de código la convierten en una opción ideal para proyectos modernos. Con esta guía tienes todo lo necesario para empezar: desde la instalación hasta los métodos más importantes con ejemplos prácticos.

¿Quieres profundizar más? Explora la documentación oficial de SQLDelight para descubrir características avanzadas como migraciones, transacciones y personalización de drivers.

Recommendations