Tegral PrismaKT
Tegral PrismaKT is experimental and not ready for production use. Please follow this issue for more information.
PrismaKT is a tool that allows you to generate JetBrains Exposed boilerplate code that matches your Prisma schema.
It can:
- ✅ Generate tables (SQL DSL API) from a Prisma schema
- ✅ Generate entities (DAO API) from a Prisma schema
- ✅ Generate accurate columns for most
@db.Xyz
fields - ✅ Manually parse Schema files using Tegral Niwen
It currently does not/cannot:
- ❌* Generate relations
- ❌* Generate multi-column
@@id
fields. - ❌* Generate
JSON
fields - ❌* Automatically generate
Database.connect
calls - ❌* Have built-in integration with Tegral DI or Tegral Web
* These features are planned but are not currently available due to PrismaKT's experimental status. Follow this issue for details.
If you find more limitations (or other things you want to see), feel free to open an issue!
Setting up: with JBang
This is the easiest and fastest way of running Tegral PrismaKT, because it does not require changing many things in your Gradle configuration and does not require ping-ponging between Prisma and Gradle.
However, this is not the best way of using Tegral PrismaKT in a real appliaction, as using proper Gradle integrations will help make the development process less painful (i.e. re-running prisma generate when needing, ensuring models are generated before compiling, etc.).
Add the following to your build.gradle
file:
// Use the generated Kotlin files when compiling
sourceSets {
main {
kotlin {
// Change this to wherever you'll put the generated files
srcDir layout.buildDirectory.dir("prismaGeneratedSrc")
}
}
}
And the following to your schema.prisma
file:
generator prismakt {
provider = "jbang --quiet guru.zoroark.tegral:tegral-prismakt-generator:0.0.4-SNAPSHOT"
output = "../build/prismaGeneratedSrc" // or wherever you want
exposedTarget = "sql"
}
Setting up: with Gradle
You'll need a bit of experience with Gradle to successfully set this up. We're working on making things easier for you, but don't hesitate to open an issue if you need help!
This part will focus on creating a two-way integration between Gradle and Prisma:
In a nutshell, we'll use Gradle to manage PrismaKT, and give Prisma a command to call said PrismaKT.
Gradle setup
Assuming the following project structure:
my-project
+-- app
| +-- prisma/
| | +-- schema.prisma
| +-- src/...
| +-- build.gradle
+-- settings.gradle
In your app/build.gradle
file, add the following:
plugins {
// Plugin for integration of npx/npm/etc in Gradle
id "com.github.node-gradle.node" version "4.0.0"
}
configurations {
// A configuration that we'll use to depend on
generator {
// This is a configuration intended to be resolved (i.e. retrieve dependencies) and not consumed by others.
canBeConsumed false
canBeResolved true
// We want to get the full JAR, so we need to configure the attributes for this configuration to do so
attributes {
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.SHADOWED))
}
}
}
dependencies {
// Put your Tegral PrismaKT dependency here, with Tegral Catalog
generator tegralLibs.prismakt.generator
// or without Tegral Catalog (replace VERSION with the version you want)
generator "guru.zoroark.tegral:tegral-prismakt-generator:VERSION"
}
// Set up for letting Gradle call 'prisma generate' and take its results into account
sourceSets {
main {
kotlin {
srcDir layout.buildDirectory.dir("prismaGeneratedSrc")
}
}
}
// Ensure `prisma generate` is called before compiling any Kotlin code that may rely on the generated code
tasks.compileKotlin.dependsOn prismaGenerate
tasks.compileTestKotlin.dependsOn prismaGenerate
tasks.register('prismaGenerate', NpxTask) {
command = "prisma"
args = ["generate"]
inputs.file("prisma/schema.prisma")
outputs.dir(project.layout.buildDirectory.dir("prismakt-generator"))
dependsOn configurations.generator
// Created via providers.provider for lazy evaluation, otherwise this would
// retrieve information from configurations before their resolution
environment = providers.provider {
def command = "java -jar " + configurations.generator.find { it.name.endsWith(".jar") }
return ["PRISMAKT_CMD": command]
}
}
Prisma setup
In your prisma/schema.prisma
file, add (or replace the current generator with) the PrismaKT generator:
generator prismakt {
provider = env("PRISMAKT_CMD")
output = "../build/prismaGeneratedSrc"
exposedTarget = "sql"
}
If you want Tegral to generate DAO bindings, use exposedTarget = "dao"
, otherwise use exposedTarget = "sql"
Testing things out
You should now be able to run PrismaKT, either by running prisma generate
(when using JBang) or gradle prismaGenerate
(when using Gradle).
If everything goes well, you should see a prismaGeneratedSrc
folder appear in your build
folder, containing a prismakt.generated
package with your models.
Using the code
Exposed dependencies
Note that, to use the generated code, you will need the corresponding Exposed dependencies, i.e.:
- In all cases,
org.jetbrains.exposed:exposed-core
andorg.jetbrains.exposed:exposed-jdbc
- If you enabled DAO generation,
org.jetbrains.exposed:exposed-dao
- If you use
DateTime
fields,org.jetbrains.exposed:exposed-java-time
- The JDBC driver for your database (see here)
Generation example
The code generated should be available in the prismakt.generated
. Here's an example of such code:
package prismakt.generated
import kotlin.Int
import kotlin.String
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.dao.EntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IdTable
import org.jetbrains.exposed.sql.Column
public object DaoUserTable : IdTable<Int>(name = "\"DaoUser\"") {
public val email: Column<String> = text(name = "email")
public val name: Column<String?> = text(name = "name").nullable()
public val identifier: Column<EntityID<Int>> = integer(name =
"identifier").autoIncrement().entityId()
public override val id: Column<EntityID<Int>>
get() = identifier
}
public class DaoUserEntity(
id: EntityID<Int>,
) : Entity<Int>(id) {
public val identifier: Int
get() = this.id.value
public var email: String by DaoUserTable.email
public var name: String? by DaoUserTable.name
public companion object : EntityClass<Int, DaoUserEntity>(DaoUserTable)
}
Internals overview
Internally, the generator works as follows: