Kotlin FRM 0.1.5

Kotlin FRM 0.1.5

API Changes


Postgres Schema Reflection

The gradle configuration has changed from databaseGeneratorConfig to PostgresGeneratorConfig

Maria DB Schema Reflection

Added ability to reflect Maria DB schema.

MariaDBGeneratorConfig {
    dataBases = listOf(db)
    dataBaseHost = dbHost
    dataBaseUser = dbUser
    dataBasePassword = dbPassword
    dataBasePort = dbPort
    namespace = "design.animus.kotlin.frm.sql.example.jvm.postgres.generated"
    outputDir = "$projectDir/generated"
    platforms = setOf(design.animus.kotlin.frm.sql.schema.common.JVM)
    excludeTables = setOf("flyway_schema_history")

MariaDB Executors


val FRMTestConfig = JaSyncMySQLConfig(
    System.getenv("myDataBaseHost") ?: "",
    System.getenv("myDataBaseUser") ?: "root",
    System.getenv("myDataBasePassword") ?: "mariadb",
executor = JaSyncMySQLExecutor()


val FRMTestConfig = VertxMySQLConfig(
executor = VertxMySQLExecutor(vertx)

Nested Query Support

Nested query allows you to use a query as a qualifier in conditional. Allowing for more dynamic queries to be made. The scope targets the data base type, and is extended off the table object.

        val delayedQuery = lazySelect(UserProfile)
                .filter {
                    UserProfile.id contains Users.nestedQuery {
                        select(Users.id) from Users where {
                            lower(Users.firstName) like "%ja%"
                .map(executor) { users ->
					// users record

A new extension method based off of the table is present

suspend fun <D : IDatabase, R : ADatabaseRecord, T : ITable<D, R>> T.nestedQuery(
        builder: ISQLBuilder<D, R, T> = CommonSQLBuilder(),
        block: suspend CommonSQLQuery<D, R, T>.() -> MutableQuery<D, R, T>
) = this.query(builder, block)

There are builder annotated wrappers at:

import design.animus.kotlin.frm.sql.query.postgres.builder
import design.animus.kotlin.frm.sql.query.mariadb.builder

This then takes a closure that builds a SQL query as expected.


// FRM
val delayedInsert = lazyInsert(Users)
                                listOf(Users.firstName to "Return", Users.lastName to "Johnson"),
                                listOf(Users.firstName to "Return", Users.lastName to "Nashorn")
// DSL
        val query = sqlQuery<ExampleIDatabase, UsersRecord, Users> {
            insert(Users) columns listOf(Users.firstName, Users.lastName) values listOf(
                listOf("John", "Doe"),
                listOf("Jane", "Doe")
            ) returning listOf(Users.id)
// FRM      
      val delayedUpdate = lazyUpdate(UserProfile)
                .changeOn { UserProfile.email equal "jdoe@google.com" }
                .mutateTo {
                    UserProfile.bio TO newBio
// DSL
        val query = Users.query {
            update(Users) set {
                Users.firstName TO "Bob"
                Users.lastName TO "Smith"
            } where {
                (Users.id equal 1)
            } returning (listOf(Users.id, Users.firstName, Users.lastName) as List<Fields<Any?, ExampleIDatabase, UsersRecord, Users >>)

A new method on both the DSL and FRM layer has been added for returning.


The DSL provides an infix function that takes a list of fields. Related to the table being mutated. This isn't as clean as a varargs. But those are not supported on infix functions.


The FRM layers provides a new returning method. This takes in a vararg of fields. So you can just do a comma separated list of fields you wish to change.

API Changes

Cleaning up FRM Methods

These are not front facing. But we have added additional types to clean up the path way for the FRM queries.

If you go to select something custom, i.e. custom fields or a join. It will no longer fit in the standard data class that we provide. With that in mind it makes no sense to provide a map that goes into the standard data class. A flow will probably help.

select * ((Users) -> map (UsersRecord)
select Users.id, Users.firstName ->  map (Map<String, Any?>)

We now know that you have changed the scope of the query. So we won't show the option to map straight into the data record. This is transparent to the end user.

Adding Common Queries

The generated table types now have common queries present generated during the reflection process.

  suspend fun <C : IExecutorConfig, RSLT> getAsync(
    inId: Int,
    executor: IAsyncExecutor<C, RSLT>,
    ctx: CoroutineContext = Dispatchers.Default
  ): AsyncDBResponse<Postgres, UsersRecord, Users, C, RSLT, UsersRecord> {
    val query = lazySelect(Users)
        .filter {
            (id equal inId)
    return query.defer(executor)

This can now be called by

val userOne: Users = Users.getAsycnc(1, jaSyncExecutor)

More methods will be added in the future.

On the Time Line

Time flies doesn't it. I anticipated this being done in early January. It was largely done then. I might do a follow up post shortly as to why the delay occurred. I'm trying to work on more timely releases going forward.