主要修改点:
- 给所有生成的代码加上了文档注释
- 使用 facebook ktfmt 格式化代码,kotlinpoet 默认生成的代码有时候格式并不符合通用规范,有点丑
- 重构
add
& update
函数,增加 isDynamic
参数,支持插入/更新全量字段或仅非空字段
- 删除
addAll
& updateAll
函数,后续在另外的代码仓库中提供,同时删除了其对应的 ext 和 example 模块
- 删除
checkIfSequenceModified
函数,改为在 add
& update
函数中内联生成其函数体,在 api 包里面添加任何 public 成员都要慎重,尽量坚持最小化原则
- 修改 copyright 年份
- 其他代码格式的微调
修改后,interface 实体类生成的代码如下:
package org.ktorm.ksp.example
import java.time.LocalDate
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.Suppress
import kotlin.UInt
import org.ktorm.database.Database
import org.ktorm.entity.Entity
import org.ktorm.entity.EntitySequence
import org.ktorm.entity.sequenceOf
import org.ktorm.ksp.api.Undefined
import org.ktorm.schema.Column
import org.ktorm.schema.Table
import org.ktorm.schema.date
import org.ktorm.schema.int
import org.ktorm.schema.long
import org.ktorm.schema.varchar
public open class Employees(alias: String?) : Table<Employee>("employee", alias) {
public val id: Column<Int> = int("id").primaryKey().bindTo { it.id }
public val name: Column<String> = varchar("name").bindTo { it.name }
public val job: Column<String> = varchar("job").bindTo { it.job }
public val managerId: Column<Int> = int("manager_id").bindTo { it.managerId }
public val hireDate: Column<LocalDate> = date("hire_date").bindTo { it.hireDate }
public val salary: Column<Long> = long("salary").bindTo { it.salary }
public val age: Column<UInt> = registerColumn("age", UIntSqlType).bindTo { it.age }
public val gender: Column<Gender> =
registerColumn("gender", IntEnumSqlTypeFactory.createSqlType(Employee::gender)).bindTo { it.gender }
public val department: Column<Int> = int("department_id").references(Departments) { it.department }
public override fun aliased(alias: String): Employees = Employees(alias)
public companion object : Employees(alias = null)
}
public val Database.employees: EntitySequence<Employee, Employees>
get() = this.sequenceOf(Employees)
@Suppress("FunctionName")
public fun Employee(
id: Int? = Undefined.of(),
name: String? = Undefined.of(),
job: String? = Undefined.of(),
managerId: Int? = Undefined.of(),
hireDate: LocalDate? = Undefined.of(),
salary: Long? = Undefined.of(),
age: UInt? = Undefined.of(),
gender: Gender? = Undefined.of(),
department: Department? = Undefined.of()
): Employee {
val entity = Entity.create<Employee>()
if (id !== Undefined.of<Int>()) {
entity.id = id ?: error("`id` should not be null.")
}
if (name !== Undefined.of<String>()) {
entity.name = name ?: error("`name` should not be null.")
}
if (job !== Undefined.of<String>()) {
entity.job = job ?: error("`job` should not be null.")
}
if (managerId !== Undefined.of<Int>()) {
entity.managerId = managerId
}
if (hireDate !== Undefined.of<LocalDate>()) {
entity.hireDate = hireDate ?: error("`hireDate` should not be null.")
}
if (salary !== Undefined.of<Long>()) {
entity.salary = salary ?: error("`salary` should not be null.")
}
if ((age as Any?) !== (Undefined.of<UInt>() as Any?)) {
entity.age = age ?: error("`age` should not be null.")
}
if (gender !== Undefined.of<Gender>()) {
entity.gender = gender
}
if (department !== Undefined.of<Department>()) {
entity.department = department ?: error("`department` should not be null.")
}
return entity
}
public fun Employee.copy(
id: Int? = Undefined.of(),
name: String? = Undefined.of(),
job: String? = Undefined.of(),
managerId: Int? = Undefined.of(),
hireDate: LocalDate? = Undefined.of(),
salary: Long? = Undefined.of(),
age: UInt? = Undefined.of(),
gender: Gender? = Undefined.of(),
department: Department? = Undefined.of()
): Employee {
val entity = this.copy()
if (id !== Undefined.of<Int>()) {
entity.id = id ?: error("`id` should not be null.")
}
if (name !== Undefined.of<String>()) {
entity.name = name ?: error("`name` should not be null.")
}
if (job !== Undefined.of<String>()) {
entity.job = job ?: error("`job` should not be null.")
}
if (managerId !== Undefined.of<Int>()) {
entity.managerId = managerId
}
if (hireDate !== Undefined.of<LocalDate>()) {
entity.hireDate = hireDate ?: error("`hireDate` should not be null.")
}
if (salary !== Undefined.of<Long>()) {
entity.salary = salary ?: error("`salary` should not be null.")
}
if ((age as Any?) !== (Undefined.of<UInt>() as Any?)) {
entity.age = age ?: error("`age` should not be null.")
}
if (gender !== Undefined.of<Gender>()) {
entity.gender = gender
}
if (department !== Undefined.of<Department>()) {
entity.department = department ?: error("`department` should not be null.")
}
return entity
}
public operator fun Employee.component1(): Int = this.id
public operator fun Employee.component2(): String = this.name
public operator fun Employee.component3(): String = this.job
public operator fun Employee.component4(): Int? = this.managerId
public operator fun Employee.component5(): LocalDate = this.hireDate
public operator fun Employee.component6(): Long = this.salary
public operator fun Employee.component7(): UInt = this.age
public operator fun Employee.component8(): Gender? = this.gender
public operator fun Employee.component9(): Department = this.department
data class 实体类生成的代码如下:
package org.ktorm.ksp.example
import kotlin.Boolean
import kotlin.Int
import kotlin.String
import kotlin.Suppress
import org.ktorm.database.Database
import org.ktorm.dsl.QueryRowSet
import org.ktorm.dsl.eq
import org.ktorm.entity.EntitySequence
import org.ktorm.entity.sequenceOf
import org.ktorm.expression.ArgumentExpression
import org.ktorm.expression.ColumnAssignmentExpression
import org.ktorm.expression.ColumnExpression
import org.ktorm.expression.InsertExpression
import org.ktorm.expression.UpdateExpression
import org.ktorm.schema.BaseTable
import org.ktorm.schema.Column
import org.ktorm.schema.SqlType
import org.ktorm.schema.int
import org.ktorm.schema.varchar
public open class Students(alias: String?) : BaseTable<Student>("student", alias) {
public val id: Column<Int> = int("id").primaryKey()
public val name: Column<String> = varchar("name")
public val age: Column<Int> = int("age")
public override fun aliased(alias: String): Students = Students(alias)
public override fun doCreateEntity(row: QueryRowSet, withReferences: Boolean): Student {
return Student(id = row[id], name = row[name], age = row[age]!!)
}
public companion object : Students(alias = null)
}
public val Database.students: EntitySequence<Student, Students>
get() = this.sequenceOf(Students)
@Suppress("UNCHECKED_CAST")
public fun EntitySequence<Student, Students>.add(entity: Student, isDynamic: Boolean = false): Int {
val isModified =
expression.where != null ||
expression.groupBy.isNotEmpty() ||
expression.having != null ||
expression.isDistinct ||
expression.orderBy.isNotEmpty() ||
expression.offset != null ||
expression.limit != null
if (isModified) {
val msg =
"Entity manipulation functions are not supported by this sequence object. " +
"Please call on the origin sequence returned from database.sequenceOf(table)"
throw UnsupportedOperationException(msg)
}
val assignments = LinkedHashMap<Column<*>, Any?>()
if (isDynamic) {
entity.id?.let { assignments[sourceTable.id] = it }
entity.name?.let { assignments[sourceTable.name] = it }
entity.age.let { assignments[sourceTable.age] = it }
} else {
entity.id?.let { assignments[sourceTable.id] = it }
entity.name.let { assignments[sourceTable.name] = it }
entity.age.let { assignments[sourceTable.age] = it }
}
if (assignments.isEmpty()) {
return 0
}
val expression =
InsertExpression(
table = sourceTable.asExpression(),
assignments =
assignments.map { (col, argument) ->
ColumnAssignmentExpression(
column = col.asExpression() as ColumnExpression<Any>,
expression = ArgumentExpression(argument, col.sqlType as SqlType<Any>)
)
}
)
if (entity.id != null) {
return database.executeUpdate(expression)
} else {
val (effects, rowSet) = database.executeUpdateAndRetrieveKeys(expression)
if (rowSet.next()) {
val generatedKey = sourceTable.id.sqlType.getResult(rowSet, 1)
if (generatedKey != null) {
if (database.logger.isDebugEnabled()) {
database.logger.debug("Generated Key: $generatedKey")
}
entity.id = generatedKey
}
}
return effects
}
}
@Suppress("UNCHECKED_CAST")
public fun EntitySequence<Student, Students>.update(entity: Student, isDynamic: Boolean = false): Int {
val isModified =
expression.where != null ||
expression.groupBy.isNotEmpty() ||
expression.having != null ||
expression.isDistinct ||
expression.orderBy.isNotEmpty() ||
expression.offset != null ||
expression.limit != null
if (isModified) {
val msg =
"Entity manipulation functions are not supported by this sequence object. " +
"Please call on the origin sequence returned from database.sequenceOf(table)"
throw UnsupportedOperationException(msg)
}
val assignments = LinkedHashMap<Column<*>, Any?>()
if (isDynamic) {
entity.name?.let { assignments[sourceTable.name] = it }
entity.age.let { assignments[sourceTable.age] = it }
} else {
entity.name.let { assignments[sourceTable.name] = it }
entity.age.let { assignments[sourceTable.age] = it }
}
if (assignments.isEmpty()) {
return 0
}
val conditions = sourceTable.id eq entity.id!!
val expression =
UpdateExpression(
table = sourceTable.asExpression(),
assignments =
assignments.map { (col, argument) ->
ColumnAssignmentExpression(
column = col.asExpression() as ColumnExpression<Any>,
expression = ArgumentExpression(argument, col.sqlType as SqlType<Any>)
)
},
where = conditions
)
return database.executeUpdate(expression)
}