Getting started with SQLDelight on Kotlin/JS¶
Warning
The synchronous sqljs-driver
(pre-2.0) has been replaced with the asynchronous web-worker-driver
.
This requires configuring the generateAsync
setting in your Gradle configuration.
First apply the gradle plugin in your project. Make sure to set generateAsync
to
true
when creating your database.
plugins {
id("app.cash.sqldelight") version "2.0.0-rc02"
}
repositories {
google()
mavenCentral()
}
sqldelight {
databases {
create("Database") {
packageName.set("com.example")
generateAsync.set(true)
}
}
}
plugins {
id "app.cash.sqldelight" version "2.0.0-rc02"
}
repositories {
google()
mavenCentral()
}
sqldelight {
databases {
Database { // This will be the name of the generated database class.
packageName = "com.example"
generateAsync = true
}
}
}
Put your SQL statements in a .sq
file under src/main/sqldelight
. Typically the first statement in the SQL file creates a table.
-- src/main/sqldelight/com/example/sqldelight/hockey/data/Player.sq
CREATE TABLE hockeyPlayer (
player_number INTEGER PRIMARY KEY NOT NULL,
full_name TEXT NOT NULL
);
CREATE INDEX hockeyPlayer_full_name ON hockeyPlayer(full_name);
INSERT INTO hockeyPlayer (player_number, full_name)
VALUES (15, 'Ryan Getzlaf');
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. Generating the Database
file happens during the 'generateSqlDelightInterface' gradle task. This task runs during the 'make project'/'make module' build task, or automatically if you have the SQLDelight IDE plugin.
Accessing the generated database also requires a driver, which SQLDelight provides implementations of:
kotlin {
sourceSets.jsMain.dependencies {
implementation("app.cash.sqldelight:web-worker-driver:2.0.0-rc02")
implementation(devNpm("copy-webpack-plugin", "9.1.0"))
}
}
kotlin {
sourceSets.jsMain.dependencies {
implementation "app.cash.sqldelight:web-worker-driver:2.0.0-rc02"
implementation devNpm("copy-webpack-plugin", "9.1.0")
}
}
The web worker driver allows SQLDelight to communicate with a SQL implementation that is running in a Web Worker. This allows all database operations to happen in a background process.
Info
The web worker driver is only compatible with browser targets.
Configuring a Web Worker¶
SQLDelight's web worker driver isn't tied to a specific implementation of a worker. Instead the driver communicates with the worker using a standardized set of messages. SQLDelight provides an implementation of a worker that uses SQL.js.
See the SQL.js Worker page for details on setting it up for your project, or the Custom Workers page for details on implementing your own.
Using a Web Worker¶
When creating an instance of a web worker driver, you must pass a reference to the web worker that
will be used to handle all SQL operations. The Worker
constructor accepts URL
object that references
the worker script.
Webpack has special support for referencing a worker script from an installed NPM package by passing
import.meta.url
as a second argument to the URL
constructor. Webpack will automatically bundle
the worker script from the referenced NPM package at build time. The example below shows a Worker
being created from SQLDelight's SQL.js Worker.
val driver = WebWorkerDriver(
Worker(
js("""new URL("@cashapp/sqldelight-sqljs-worker/sqljs.worker.js", import.meta.url)""")
)
)
Warning
In order for Webpack to correctly resolve this URL while bundling, you must construct the URL
object entirely within a js()
block as shown above with the import.meta.url
argument.
From here, you can use the driver like any other SQLDelight driver.
Using Queries¶
SQL statements inside a .sq
file can be labeled to have a typesafe function generated for them available at runtime.
selectAll:
SELECT *
FROM hockeyPlayer;
insert:
INSERT INTO hockeyPlayer(player_number, full_name)
VALUES (?, ?);
insertFullPlayerObject:
INSERT INTO hockeyPlayer(player_number, full_name)
VALUES ?;
Files with labeled statements in them will have a queries file generated from them that matches the .sq
file name - putting the above sql into Player.sq
generates PlayerQueries.kt
. To get a reference to PlayerQueries
you need to wrap the driver we made above:
// In reality the database and driver above should be created a single time
// and passed around using your favourite dependency injection/service
// locator/singleton pattern.
val database = Database(driver)
val playerQueries: PlayerQueries = database.playerQueries
println(playerQueries.selectAll().executeAsList())
// Prints [HockeyPlayer(15, "Ryan Getzlaf")]
playerQueries.insert(player_number = 10, full_name = "Corey Perry")
println(playerQueries.selectAll().executeAsList())
// Prints [HockeyPlayer(15, "Ryan Getzlaf"), HockeyPlayer(10, "Corey Perry")]
val player = HockeyPlayer(10, "Ronald McDonald")
playerQueries.insertFullPlayerObject(player)
And that's it! Check out the other pages on the sidebar for other functionality.