I have a KMM project and want to use SqlDelight
library, but when I build the project database schema not generated and table entities also.
actual class DatabaseDriverFactory(private val context: Context) {
actual fun createDriver(): SqlDriver {
//Unresolved reference: CoreDb
return AndroidSqliteDriver(CoreDb.Schema, context, "test.db")
}
}
I have defined sqldelight folder inside my shared module and also created folder for feature generated kotlin classes as it is configured in gradle.build.kts
and also have one *.sq
file inside sqldelight
folder
sqldelight {
database("CoreDb") {
packageName = "com.example.app.core.database"
sourceFolders = listOf("sqldelight")
dialect = "sqlite:3.24"
}
}
When I run generateSqlDelightInterface
task I just see those log
> Task :core:generateAndroidDebugCoreDbInterface NO-SOURCE
> Task :core:generateAndroidReleaseCoreDbInterface NO-SOURCE
> Task :core:generateIosMainCoreDbInterface NO-SOURCE
> Task :core:generateMetadataCommonMainCoreDbInterface NO-SOURCE
> Task :core:generateMetadataMainCoreDbInterface NO-SOURCE
> Task :core:generateSqlDelightInterface UP-TO-DATE
can't register checkAndroidModules
BUILD SUCCESSFUL in 311ms
1:40:36 PM: Task execution finished 'generateSqlDelightInterface'.
Here is my full build.gradle.kts
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
id("com.android.library")
id("kotlin-android-extensions")
id("koin")
id("com.squareup.sqldelight")
}
repositories {
gradlePluginPortal()
google()
jcenter()
mavenCentral()
maven {
url = uri("https://dl.bintray.com/kotlin/kotlin-eap")
}
maven {
url = uri("https://dl.bintray.com/ekito/koin")
}
}
kotlin {
android()
val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget =
if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true)
::iosArm64
else
::iosX64
iOSTarget("ios") {
binaries {
framework {
baseName = "core"
}
}
}
val coroutinesVersion = "1.3.9-native-mt"
val ktor_version = "1.4.2"
val serializationVersion = "1.0.0-RC"
val koin_version = "3.0.0-alpha-4"
val sqlDelight = "1.4.4"
sourceSets {
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-serialization:$ktor_version")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
implementation("com.squareup.sqldelight:runtime:$sqlDelight")
// SqlDelight extension
implementation("com.squareup.sqldelight:coroutines-extensions:$sqlDelight")
// Koin for Kotlin
implementation("org.koin:koin-core:$koin_version")
//shared preferences
implementation("com.russhwolf:multiplatform-settings:0.6.3")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting {
dependencies {
implementation("androidx.core:core-ktx:1.3.2")
implementation("io.ktor:ktor-client-android:$ktor_version")
implementation("com.squareup.sqldelight:android-driver:$sqlDelight")
}
}
val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.12")
}
}
val iosMain by getting {
dependencies {
implementation("io.ktor:ktor-client-ios:$ktor_version")
implementation("com.squareup.sqldelight:native-driver:$sqlDelight")
}
}
val iosTest by getting
}
}
android {
compileSdkVersion(29)
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdkVersion(23)
targetSdkVersion(29)
versionCode = 1
versionName = "1.0"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
}
val packForXcode by tasks.creating(Sync::class) {
group = "build"
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val sdkName = System.getenv("SDK_NAME") ?: "iphonesimulator"
val targetName = "ios" + if (sdkName.startsWith("iphoneos")) "Arm64" else "X64"
val framework =
kotlin.targets.getByName<KotlinNativeTarget>("ios").binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
val targetDir = File(buildDir, "xcode-frameworks")
from({ framework.outputDirectory })
into(targetDir)
}
tasks.getByName("build").dependsOn(packForXcode)
sqldelight {
database("CoreDb") {
packageName = "com.example.app.core.database"
sourceFolders = listOf("sqldelight")
dialect = "sqlite:3.24"
}
}
and for top level build.gradle
classpath "com.squareup.sqldelight:gradle-plugin:$sqlDelight"
Update
My project folder structure
root
app
src
...
core //(kmm shared module)
androidMain
com.example.app.core
database
commonMain
com.example.app.core
database
repository
...
sqldelight
iosMain
com.example.app.core
database
By doing code generation from SQL files, SQLDelight can generate code that works on any platform, because at the end of the day you are just executing SQL statements. You need to create a source folder for your SQL (*.sq) files at “src/main/sqldelight” folder, next to “java” or “kotlin” source folder.
You need to add the SQLDelight Gradle Plugin to your app or module because SQLDelight uses code generation from SQL files (*.sq), instead of code generation based on annotations (kapt). This gives us incremental builds, but requires us to add a plugin to our root build.gradle file.
Typically the first statement in the SQL file creates a table. From this SQLDelight will generate a Database Kotlin class with an associated Schema object that can be used to create your database and run your statements on it. Doing this also requires a driver, which SQLDelight provides implementations of:
Doing this also requires a driver, which SQLDelight provides implementations of: For use with the SqlJs driver, see here. SQL statements inside a .sq file can be labeled to have a typesafe function generated for them available at runtime.
It seems that you have your sqldelight
folder, where you put your *.sq
files, in the wrong place.
It should be put inside commonMain
directly and inside sqldelight
you must specify your package.
If your package is com.example.kmmtest003.database
your folder structure should be:
- commonMain
- sqldelight
- com
- example
- kmmtest003
- database
And here you must put your *.sq
files.
OTHER POSSIBLE REASONS
As IgorGanapolsky pointed out, this same issue could be caused also by an incompatible gradle plugin version.
This might help someone in the future...I had created a directory in KMM, and it was named sqldelight.com.package.database
I thought this was a proper package, but realized this was not being caught by SQLDelight, and thus my schema wasn't being generated.
I needed to create the structure as a proper directory structure (and then everything worked):
sqldelight
com
package
dataabase
Alternately, you can change the folder to kotlin if you want the SQL code to be in the same directory with your code:
sqldelight {
database("CoreDb") {
...
sourceFolders = listOf("kotlin")
...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With