Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
ashwini-desai committed Jun 12, 2020
2 parents 9af9a43 + f1601c2 commit 6808dc7
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 53 deletions.
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.61' apply false
id 'org.jetbrains.kotlin.jvm' version '1.3.72' apply false
}

subprojects {
Expand All @@ -16,7 +16,7 @@ subprojects {
testImplementation 'org.jetbrains.kotlin:kotlin-test'
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
testImplementation 'io.kotlintest:kotlintest-runner-junit5:3.4.2'
testCompile 'org.testcontainers:postgresql:1.12.5'
testCompile 'org.testcontainers:postgresql:1.14.3'
testCompile 'postgresql:postgresql:9.1-901-1.jdbc4'
}

Expand All @@ -34,10 +34,10 @@ project(":codegen") {
dependencies {
implementation project(":runtime")

implementation 'com.squareup:kotlinpoet:1.5.0'
implementation 'com.squareup:kotlinpoet:1.6.0'
implementation 'org.atteo:evo-inflector:1.2.2'
implementation 'org.apache.commons:commons-text:1.8'
implementation 'org.postgresql:postgresql:42.2.9'
implementation 'org.postgresql:postgresql:42.2.14'

testImplementation("io.kotlintest:kotlintest-runner-junit5:3.3.0")
}
Expand Down
45 changes: 19 additions & 26 deletions codegen/src/main/kotlin/norm/CodeGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,15 @@ class CodeGenerator(private val typeMapper: DbToKtDefaultTypeMapper = DbToKtDefa

fileBuilder.addType(
TypeSpec.classBuilder(ClassName(packageName, paramsClassName))
.addModifiers(KModifier.DATA)
.also { if (params.isNotEmpty()) it.addModifiers(KModifier.DATA) }
.primaryConstructor(
FunSpec.constructorBuilder()
.addParameters(params.distinctBy { it.name }.map {
ParameterSpec.builder(
it.name,
getTypeName(it)
).build()
ParameterSpec.builder(it.name, getTypeName(it)).build()
}).build()
)
.addProperties(params.distinctBy { it.name }.map {
PropertySpec.builder(it.name,
getTypeName(it)
)
PropertySpec.builder(it.name, getTypeName(it))
.initializer(it.name)
.build()
})
Expand Down Expand Up @@ -88,28 +83,24 @@ class CodeGenerator(private val typeMapper: DbToKtDefaultTypeMapper = DbToKtDefa
FunSpec.constructorBuilder()
.addParameters(cols.map {
ParameterSpec.builder(it.fieldName,
if(it.colType.startsWith("_")) ARRAY.parameterizedBy(typeMapper.getType(it.colType).asTypeName())
else typeMapper.getType(it.colType).asTypeName()
getTypeName(it)
).build()
}).build()
)
.addProperties(cols.map {
PropertySpec.builder(it.fieldName,
if(it.colType.startsWith("_")) ARRAY.parameterizedBy(typeMapper.getType(it.colType).asTypeName())
else typeMapper.getType(it.colType).asTypeName()
)
PropertySpec.builder(it.fieldName, getTypeName(it))
.initializer(it.fieldName)
.build()
})
.build()
)

val constructArgs = "\n" + cols.map {
if(it.colType.startsWith("_"))
"${it.fieldName} = rs.getArray(\"${it.colName}\").array as Array<${typeMapper.getType(it.colType).asClassName().simpleName}>"
val constructArgs = "\n" + cols.joinToString(",\n ") {
if (it.colType.startsWith("_"))
"${it.fieldName} = rs.getArray(\"${it.colName}\").array as ${getTypeName(it)}>"
else
"${it.fieldName} = rs.getObject(\"${it.colName}\") as ${typeMapper.getType(it.colType).asClassName().canonicalName}"
}.joinToString(",\n ")
"${it.fieldName} = rs.getObject(\"${it.colName}\") as ${getTypeName(it)}"
}

fileBuilder.addType(
TypeSpec.classBuilder(ClassName(packageName, rowMapperClassName))
Expand Down Expand Up @@ -164,16 +155,18 @@ class CodeGenerator(private val typeMapper: DbToKtDefaultTypeMapper = DbToKtDefa
return fileBuilder.build().toString()
}

private fun getTypeName(it: ParamModel): TypeName {
return if (it.dbType.startsWith("_"))
ARRAY.parameterizedBy(typeMapper.getType(it.dbType).asTypeName()).copy(nullable = it.isNullable)
else typeMapper.getType(it.dbType).asTypeName().copy(nullable = it.isNullable)
}
private fun getTypeName(it: ColumnModel) =
if (it.colType.startsWith("_")) ARRAY.parameterizedBy(typeMapper.getType(it.colType, false)).copy(nullable = it.isNullable)
else typeMapper.getType(it.colType, it.isNullable)

private fun getTypeName(it: ParamModel) =
if (it.dbType.startsWith("_")) ARRAY.parameterizedBy(typeMapper.getType(it.dbType, false)).copy(nullable = it.isNullable)
else typeMapper.getType(it.dbType, it.isNullable)

private fun addStatementsForParams(fb: FunSpec.Builder, params: List<ParamModel>) =
params.forEachIndexed { i, pm ->
when (pm.paramClassName) {
"java.sql.Array" -> fb.addStatement("ps.setArray(${i + 1}, ps.connection.createArrayOf(\"${pm.dbType.removePrefix("_")}\", params.${pm.name}))")
when {
pm.dbType.startsWith("_") -> fb.addStatement("ps.setArray(${i + 1}, ps.connection.createArrayOf(\"${pm.dbType.removePrefix("_")}\", params.${pm.name}))")
else -> fb.addStatement("ps.setObject(${i + 1}, params.${pm.name})")
}

Expand Down
12 changes: 5 additions & 7 deletions codegen/src/main/kotlin/norm/DbToKtDefaultTypeMapper.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package norm

import com.squareup.kotlinpoet.ARRAY
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.asTypeName
import org.postgresql.util.PGobject
import java.math.BigDecimal
import kotlin.reflect.KClass

typealias typeMapper = (String) -> KClass<*>

class DbToKtDefaultTypeMapper {
fun getType(colType: String): KClass<*> {
fun getType(colType: String, nullable: Boolean): TypeName {
return when (colType.toLowerCase()) {
"int4" -> Int::class
"int" -> Int::class
Expand All @@ -34,6 +32,6 @@ class DbToKtDefaultTypeMapper {
"_varchar" -> String::class
"_int4" -> Int::class
else -> String::class
}
}.asTypeName().copy(nullable = nullable)
}
}
6 changes: 2 additions & 4 deletions codegen/src/main/kotlin/norm/SqlAnalyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ data class ColumnModel(
data class ParamModel(
val name: String,
val dbType: String,
val isNullable: Boolean,
val paramClassName:String
val isNullable: Boolean
)

data class SqlModel(
Expand All @@ -46,8 +45,7 @@ class SqlAnalyzer(private val connection: Connection) {
ParamModel(
paramNames[it - 1].substring(1),
parameterMetaData.getParameterTypeName(it), // db type
parameterMetaData.isNullable(it) != ParameterMetaData.parameterNoNulls,
parameterMetaData.getParameterClassName(it)
parameterMetaData.isNullable(it) != ParameterMetaData.parameterNoNulls
)
}

Expand Down
42 changes: 33 additions & 9 deletions codegen/src/test/kotlin/norm/CodeGeneratorTest.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package norm

import io.kotlintest.matchers.string.shouldContain
import io.kotlintest.matchers.string.shouldNotContain
import io.kotlintest.shouldBe
import io.kotlintest.specs.StringSpec
import org.apache.commons.io.FileUtils
import org.junit.ClassRule
import org.postgresql.ds.PGSimpleDataSource

Expand All @@ -21,15 +24,9 @@ class CodeGeneratorTest : StringSpec() {

"Query class generator" {
dataSource.connection.use {
val generatedFileContent = codegen(it, "select * from employees where first_name = :name order by :field", "com.foo", "Foo")

generatedFileContent shouldContain "data class FooResult("
generatedFileContent shouldContain "data class FooParams("
generatedFileContent shouldContain "class FooParamSetter : ParamSetter<FooParams> {"
generatedFileContent shouldContain "class FooRowMapper : RowMapper<FooResult> {"
generatedFileContent shouldContain "class FooQuery : Query<FooParams, FooResult> {"

println(generatedFileContent)
val expectedFileContent = FileUtils.getFile( "src", "test", "resources", "generated/employee-query").readText().trimIndent()
val generatedFileContent = codegen(it, "select * from employees where first_name = :name order by :field", "com.foo", "Foo").trimIndent()
generatedFileContent shouldBe expectedFileContent
}
}

Expand Down Expand Up @@ -77,5 +74,32 @@ class CodeGeneratorTest : StringSpec() {

}

"should support jsonb type along with array"{

dataSource.connection.use {
val generatedFileContent = codegen(it, "insert into owners(colors,details) VALUES(:colors,:details)", "com.foo", "Foo")
generatedFileContent shouldContain "data class FooParams("
generatedFileContent shouldContain " val colors: Array<String>?"
generatedFileContent shouldContain " val details: PGobject?"

generatedFileContent shouldContain "class FooParamSetter : ParamSetter<FooParams> {"
generatedFileContent shouldContain " override fun map(ps: PreparedStatement, params: FooParams) {"
generatedFileContent shouldContain " ps.setArray(1, ps.connection.createArrayOf(\"varchar\", params.colors))"
generatedFileContent shouldContain " ps.setObject(2, params.details)"
generatedFileContent shouldContain " }"

println(generatedFileContent)
}
}

"should generate empty params class if inputs params are not present" {
dataSource.connection.use {
val generatedFileContent = codegen(it, "select * from employees", "com.foo", "Foo")
generatedFileContent shouldNotContain "data class FooParams"
generatedFileContent shouldContain "class FooParams"

println(generatedFileContent)
}
}
}
}
42 changes: 42 additions & 0 deletions codegen/src/test/resources/generated/employee-query
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.foo

import java.sql.PreparedStatement
import java.sql.ResultSet
import kotlin.Int
import kotlin.String
import norm.ParamSetter
import norm.Query
import norm.RowMapper

data class FooParams(
val name: String?,
val field: String?
)

class FooParamSetter : ParamSetter<FooParams> {
override fun map(ps: PreparedStatement, params: FooParams) {
ps.setObject(1, params.name)
ps.setObject(2, params.field)
}
}

data class FooResult(
val id: Int,
val firstName: String?,
val lastName: String?
)

class FooRowMapper : RowMapper<FooResult> {
override fun map(rs: ResultSet): FooResult = FooResult(
id = rs.getObject("id") as kotlin.Int,
firstName = rs.getObject("first_name") as kotlin.String?,
lastName = rs.getObject("last_name") as kotlin.String?)
}

class FooQuery : Query<FooParams, FooResult> {
override val sql: String = "select * from employees where first_name = ? order by ?"

override val mapper: RowMapper<FooResult> = FooRowMapper()

override val paramSetter: ParamSetter<FooParams> = FooParamSetter()
}
6 changes: 6 additions & 0 deletions codegen/src/test/resources/init_postgres.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@ CREATE TABLE departments (
CREATE TABLE combinations(
id serial PRIMARY KEY,
colors varchar[]);

CREATE TABLE owners(
id serial PRIMARY KEY,
colors varchar[],
details jsonb
)
6 changes: 3 additions & 3 deletions runtime/src/main/kotlin/norm/SqlExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ fun ResultSet.toTable(columnNames: List<String> = getColumnNames()): List<List<A

// TODO - handle prepareStatements Failure as well

fun PreparedStatement.withParams(params: List<Any> = listOf()): PreparedStatement =
fun PreparedStatement.withParams(params: List<Any?> = listOf()): PreparedStatement =
this.also { self ->
params.forEachIndexed { index, param -> self.setObject(index + 1, param) }
}

fun PreparedStatement.withBatches(batchedParams: List<List<Any>> = listOf()) =
fun PreparedStatement.withBatches(batchedParams: List<List<Any?>> = listOf()) =
this.also { ps ->
batchedParams.forEach { params ->
ps.withParams(params).addBatch()
Expand All @@ -52,7 +52,7 @@ fun Connection.executeCommand(sql: String, params: List<Any> = listOf()): Int =
.withParams(params)
.use { it.executeUpdate() } // auto-close ps

fun Connection.batchExecuteCommand(sql: String, batchedParams: List<List<Any>> = listOf()): List<Int> =
fun Connection.batchExecuteCommand(sql: String, batchedParams: List<List<Any?>> = listOf()): List<Int> =
this.prepareStatement(sql)
.withBatches(batchedParams)
.use { it.executeBatch() }
Expand Down

0 comments on commit 6808dc7

Please sign in to comment.