hey guys! what is the best practice of using SQLDe...
# squarelibraries
e
hey guys! what is the best practice of using SQLDelight in a multi-module projects, especially KMM project? If I have several modules working with the database it looks logical to place DB logic and base classes in some shared core module. But the specific SQL files probably should be in thier specific feature-modules. And here I come into set of questions. Should I enable the gradle plugin in every module which uses DB (and has it’s own entities which it works with) and also in the core module? If the schema files will be present in different modules how will the db be created initially?
a
you can specify schema dependencies on other modules in your project https://cashapp.github.io/sqldelight/2.0.1/multiplatform_sqlite/gradle/#dependency
let me find a sample fixture that demonstrates how its used
some module will be the root of the dependency tree, thats the module where you should actually create the instance of it
the type thats generated will inherit from all the submodules with schemas, so you can use the single db instance in any of those modules and it will work
e
@alec So should I put this code only in one root module?
Copy code
sqldelight {
    databases {
        create("Database") {
a
e
I assume it should be most high-level app module, because only it “knows” about all modules-dependencies
a
its just that the highest level app module is the last one to declare schema dependencies and can create the db
e
so the
create("Database")
will be only in one place, but other parts of this setup as a plugin should be present en each module using db, right?
a
you would still need
create("Database")
in multiple modules the sub module would have
Copy code
sqldelight {
  create("Database") {
    packageName = "com.submodule"
  }
}
and the parent module would have
Copy code
sqldelight {
  create("Database") {
    packageName = "com.parentmodule"
    dependency project(":submodule")
  }
}
its important that all modules have the same database name ("Database" in this case), but have different package names
e
this is very helpful, thank you! 🙂
@alec One more question. Should I also have Android dependencies in each module and the DriverFactory and
fun createDatabase(driverFactory): Database
or this goes only into main app module?
a
only into the main app module
e
And in the feature-modules, should I inject the database instance from the app module to work with it? Not fully understand how it will work in the feature-module if the plugin will general only specific part of the database interface inside the module.
a
there will be two interfaces generated:
Copy code
interface com.submodule.Database

interface com.parentmodule.Database : com.submodule.Database
so in the submodule you reference
com.submodule.Database
. You can still create a single instance of
com.parentmodule.Database
as normal, but pass it to submodules where it can be used as a
com.submodule.Database
since it inherits
e
wow, thank you so much!
a
Hey @electrolobzik Were you able to make it work? If possible can you share a sample? Thanks in advance
e
@Ashu Tyagi yes, I am using it in the big app. Can’t share the code, but feel free to ask questions, if you need more details.
a
Okay. So I have a
core-database
module. I have created a file called TestDatabase in sqldelight/com/demo/app/core_database/TestDatabase.sq Please note that TestDatabase.sq is an empty file. build.gradle of
core-database
has the following configuration
Copy code
sqldelight {
    databases {
        create("TestDatabase") {
            packageName.set("com.core_database")
        }
    }
}
And then there are two feature modules • feature-A • feature-B Each feature module defines it's own Table.sq files, Let's call them
EntityA.sq
&
EntityB.sq
. build.gradle on feature module looks liks this:
Copy code
sqldelight {
    databases {
        create("TestDatabase") {
            packageName.set("com.featureA")
            dependency(project(":shared:core-database"))
        }
    }
}
Now, How do I create the instance of
com.featureA.TestDatabase
? I have tried by doing
com.featureA.TestDatabase(driver = getSqliteDriver())
The sqlite driver is getting created inside
core_database
module. But I'm getting the following error:
no such table : EntityA
My hunch is, since we define
com.core_database.TestDatabase.Schema
while creating AndroidSqliteDriver, It doesn't have reference to
core.featureA.TestDatabase.Schema
. Any idea how can I solve this? Sorry for the long post. Thanks in advance. @electrolobzik
e
You should create only one instance of the main database (which should have dependencies on the feature database, not opposite). This main database you can pass to the feature module via DI and use there as a it would be constructed there.
The main database should be in the app module or in any other module, which depends on all your features.
if core, featureA and featureB modules all have their own database queries, you should create the main database, which will depend on all of these 3.
In other words if you specify dependency on module X in SQLDelight of module Y you will get both X and Y methods in the Database object of the module Y.
a
Understood. It's working now. Thanks a lot 🙌
👍 1
e
I’m glad to help.
c
Follow-up on this. In my project I have an umbrella module that itself doesn't have any .sq files. However it is the one that depends on multiple other modules each of which have sqldelight configured as described further above in this thread. My problem is since my umbrella module does not have any .sq files, there is no
com.umbrellamodule.Database
created. I could work around it by creating a
.sq
file with some dummy tables or queries, but my question is is there a better way? I would like to have a single interface created this way because I would like to inject a singleton into all submodules and this single interface would implement all the
com.submoduleX.Database
interfaces.
Okay I just realized that it is sufficient to have an empty .sq file in the umbrella module. That is sufficient to generate the
com.umbrellamodule.Database
interface that implements all dependent interfaces.
643 Views