androidkotlingradlekotlin-multiplatformsqldelight

SQLDelight Issue in KMP


How to correctly configure two separate databases in a Kotlin Multiplatform project? I'm developing a Kotlin Multiplatform application targeting Desktop (JVM) and Android. I want to use two separate SQLite databases with SQLDelight:

CardDatabase: For the main application data (a card collection).

SettingsDatabase: For simple user settings (like language).

My goal is to keep the schemas, generated queries, and data models for these two databases completely separate to maintain a clean architecture.

The Problem I am struggling to configure the SQLDelight Gradle plugin to correctly handle these two separate databases. No matter how I configure the sqldelight block in my build.gradle.kts, I run into one of two issues:

Issue 1: Redeclaration Error

If I define both databases with their own package name, the build fails with a long list of Redeclaration errors. It seems as if SQLDelight is compiling the .sq files from both source directories for each database definition.

Example Error Log:

e: .../build/generated/sqldelight/code/SettingsDatabase/commonMain/com/example/myapp/db/CardDatabaseQueries.kt:14:14 Redeclaration: class CardDatabaseQueries : TransacterImpl

e: .../build/generated/sqldelight/code/SettingsDatabase/commonMain/com/example/myapp/db/CardEntity.kt:7:19 Redeclaration: data class CardEntity : Any ... (and so on for all entities and queries from CardDatabase.sq)

Issue 2: SqlDelight files must be placed in a package directory

When I try to use the srcDirs property to explicitly separate the source folders for each database, the build fails with this error, even though my files are in the correct package directories.

What I've Tried Separating the .sq files into their own subdirectories.

Assigning unique packageNames for each database in the sqldelight block.

Using srcDirs to explicitly tell each database definition where to look for its .sq files. This seems to be the correct approach according to Gradle principles, but it leads to the errors mentioned above.

Code to Reproduce the Issue Here is my current setup:

Key Versions (libs.versions.toml):

Folder Structure:

My .sq files are located in separate folders to keep them isolated:

composeApp/
└── src/
    └── commonMain/
        └── sqldelight/
            └── com/
                └── example/
                    └── myapp/
                        └── db/
                            ├── cards/
                            │   └── CardDatabase.sq
                            └── settings/
                                └── SettingsDatabase.sq

composeApp/build.gradle.kts (SQLDelight block):

This is my current attempt at configuring the plugin.

sqldelight {
    databases {
        create("CardDatabase") {
            packageName.set("com.example.myapp.db.cards")
            srcDirs.set(listOf("src/commonMain/sqldelight/com/example/myapp/db/cards"))
        }
        create("SettingsDatabase") {
            packageName.set("com.example.myapp.db.settings")
            srcDirs.set(listOf("src/commonMain/sqldelight/com/example/myapp/db/settings"))
        }
    }
}

CardDatabase.sq Content:

CREATE TABLE SetEntity (
    setId TEXT NOT NULL PRIMARY KEY
    -- ... other columns
);

CREATE TABLE PokemonCardEntity (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    setId TEXT NOT NULL,
    FOREIGN KEY(setId) REFERENCES SetEntity(setId)
    -- ... other columns
);

selectAllSets:
SELECT * FROM SetEntity;

SettingsDatabase.sq Content:

CREATE TABLE SettingsEntity (
    key TEXT NOT NULL PRIMARY KEY,
    value TEXT NOT NULL
);

getSetting:
SELECT value FROM SettingsEntity WHERE key = :key;

The Question What is the correct and modern way to configure the SQLDelight plugin in a Kotlin Multiplatform project to handle multiple, fully separated databases, each with its own source directory and generated package, to avoid the Redeclaration errors? Is there an issue with my usage of srcDirs or another property I should be using?

Thanks in advance for any help!


Solution

  • The separation into different folders is already correct, but must be done before the com.example.myapp. With the srcDirs you must then refer to this new root folder for the respective DB.

    As an example, this would look like this for you:

    └── src/
        └── commonMain/
            └── sqldelight/
                ├── cardDatabase/      <-- Source root for CardDatabase
                │   └── com/
                │       └── example/
                │           └── myapp/
                │               └── db/
                │                   └── cards/
                │                       └── CardDatabase.sq
                └── settingsDatabase/  <-- Source root for SettingsDatabase
                    └── com/
                        └── example/
                            └── myapp/
                                └── db/
                                    └── settings/
                                        └── SettingsDatabase.sq
    

    The corresponding build.gradle part looks like this:

    sqldelight {
        databases {
            create("CardDatabase") {
                // The package for the generated Kotlin API
                packageName.set("com.example.myapp.db.cards")
    
                // Point to the dedicated source root for this database.
                // SQLDelight will look for .sq files inside this folder.
                srcDirs.setFrom("src/commonMain/sqldelight/cardDatabase")
            }
            create("SettingsDatabase") {
                packageName.set("com.example.myapp.db.settings")
                srcDirs.setFrom("src/commonMain/sqldelight/settingsDatabase")
            }
        }
    }