This commit is contained in:
tursom 2021-04-12 13:05:59 +08:00
parent cc32906fc9
commit 887f04bb06
48 changed files with 1055 additions and 396 deletions

View File

@ -7,5 +7,5 @@ import kotlin.reflect.KClass
annotation class Key(
val key: String = "",
val clazz: KClass<*> = Any::class,
val handler: String = ""
val handler: String = "",
)

View File

@ -5,5 +5,5 @@ import kotlin.reflect.KClass
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class NoPropertyClone(
vararg val classList: KClass<*>
vararg val classList: KClass<*>,
)

View File

@ -9,7 +9,7 @@ annotation class Relation(
val property: String = "",
val skip: Boolean = false,
val handler: String = "",
val handleClass: KClass<*> = Any::class
val handleClass: KClass<*> = Any::class,
)

View File

@ -3,5 +3,5 @@ package cn.tursom.core.clone
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation class Relations(
vararg val relations: Relation
vararg val relations: Relation,
)

View File

@ -5,6 +5,9 @@ plugins {
dependencies {
api(project(":"))
implementation(project(":ts-core"))
implementation(project(":ts-core:ts-clone"))
implementation(project(":ts-core:ts-log"))
api(group = "me.liuwj.ktorm", name = "ktorm-core", version = "3.1.0")
compileOnly(group = "com.baomidou", name = "mybatis-plus", version = "3.4.2")
compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.6")

View File

@ -1,6 +1,6 @@
package cn.tursom.database
import com.ddbes.kotlin.Utils
import cn.tursom.core.Utils
import com.google.gson.Gson
import me.liuwj.ktorm.schema.SqlType
import java.lang.reflect.Type
@ -12,7 +12,7 @@ import java.sql.Types
class JsonType<T : Any>(
val clazz: Type,
type: Int = Types.VARCHAR,
val gson: Gson = Utils.gson
val gson: Gson = Utils.gson,
) : SqlType<T>(type, "json") {
constructor(clazz: Class<T>, type: Int = Types.VARCHAR) : this(clazz as Type, type)

View File

@ -2,9 +2,8 @@
package cn.tursom.database
import com.ddbes.kotlin.Utils
import com.ddbes.kotlin.jdbc.simpTableField
import com.ddbes.kotlin.uncheckedCast
import cn.tursom.core.Utils
import cn.tursom.core.uncheckedCast
import com.google.gson.Gson
import me.liuwj.ktorm.dsl.Query
import me.liuwj.ktorm.dsl.QueryRowSet

View File

@ -0,0 +1,247 @@
/**
* SQL 访问增强工具实现从属性到数据库字段的自动映射
* @author 王景阔
*
* Files::name.tableField
* 可获得 Files name 属性对应的字段名
*/
@file:Suppress("unused")
package cn.tursom.database
import com.baomidou.mybatisplus.annotation.TableField
import com.baomidou.mybatisplus.annotation.TableName
import org.apache.ibatis.type.TypeHandler
import java.lang.reflect.Field
import java.lang.reflect.Modifier
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
import kotlin.reflect.full.companionObjectInstance
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.javaGetter
/**
* 数据库访问增强接口
* @author 王景阔
* 设计上使用代理模式实现字段名缓存
*/
interface TableField<T> {
var tableName: String
val fieldMap: Map<KProperty1<out T, *>, String>
val simpFieldMap: Map<KProperty1<out T, *>, String>
val fullFieldMap: Map<KProperty1<out T, *>, String>
val properties: Array<out KProperty1<out T, *>>
val allField: Array<out String>
val fullNameField: Array<out String>
val typeHandlerMap: Map<KProperty1<out T, *>, TypeHandler<Any>>
//operator fun get(field: KProperty<*>): String = fieldMap[field] ?: field.tableField
operator fun get(field: KProperty1<out T, *>): String = fieldMap[field] ?: field.simpTableField
}
val <T> Iterable<KProperty1<out T, *>>.filterNotExists
get() = filter {
it.javaField != null &&
it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null &&
!Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) &&
it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false
}
@get:JvmName("filterNotExistsPair")
val <T> Iterable<Pair<KProperty1<T, *>, *>>.filterNotExists
get() = filter { (it, _) ->
it.javaField != null &&
it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null &&
!Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) &&
it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false
}
@get:JvmName("filterNotExistsKProperty")
val Iterable<KProperty<*>>.filterNotExists
get() = filter {
it.javaField != null &&
it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null &&
!Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) &&
it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false
}
@get:JvmName("filterNotExistsKPropertyPair")
val Iterable<Pair<KProperty<*>, *>>.filterNotExists
get() = filter { (it, _) ->
it.javaField != null &&
it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null &&
!Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) &&
it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false
}
val String.sqlName: String
get() {
val sb = StringBuilder()
val iterator = iterator()
sb.append(iterator.nextChar().toLowerCase())
iterator.forEach {
if (it.isUpperCase()) {
sb.append('_')
sb.append(it.toLowerCase())
} else {
sb.append(it)
}
}
return sb.toString()
}
val KClass<*>.tableName: String get() = findAnnotation<TableName>()?.value ?: simpleName!!.sqlName
val Class<*>.tableName: String get() = getAnnotation(TableName::class.java)?.value ?: simpleName.sqlName
val KProperty<*>.tableFieldName: String? get() = javaField?.getAnnotation(TableField::class.java)?.value
val KProperty<*>.simpTableField: String get() = tableFieldName ?: name.sqlName
val KProperty<*>.selectionTableField: String
get() = tableFieldName?.let { if (it.isNotEmpty()) "$it as ${name.sqlName}" else null } ?: name.sqlName
inline val <reified T> KProperty1<out T, *>.tableField: String
get() {
val companion = T::class.companionObjectInstance
return if (companion is cn.tursom.database.TableField<*>) {
@Suppress("UNCHECKED_CAST")
companion as cn.tursom.database.TableField<T>
companion[this]
} else {
selectionTableField
}
}
inline val <reified T : Any> KProperty1<out T, *>.fullTableField: String
get() {
val companion = T::class.companionObjectInstance
return if (companion is cn.tursom.database.TableField<*>) {
@Suppress("UNCHECKED_CAST")
companion as cn.tursom.database.TableField<T>
companion.fullFieldMap[this] ?: "${companion.tableName}.${companion[this]}"
} else {
"${T::class.tableName}.$selectionTableField"
}
}
val KProperty<*>.fullTableField: String
get() {
val kotlin = (javaGetter?.declaringClass ?: javaField?.declaringClass)?.kotlin!!
return "${kotlin.tableName}.$selectionTableField"
}
val Field.tableField: String
get() {
val tableField = getAnnotation(TableField::class.java)
return tableField?.value?.let { if (it.isNotEmpty()) "$it as ${name.sqlName}" else null } ?: name.sqlName
}
val KProperty<*>.directTableField: String
get() = simpTableField
inline val <reified T> KProperty1<out T, *>.directTableField: String
get() {
val companion = T::class.companionObjectInstance
return if (companion is cn.tursom.database.TableField<*>) {
@Suppress("UNCHECKED_CAST")
companion as cn.tursom.database.TableField<T>
companion.simpFieldMap[this] ?: simpTableField
} else {
simpTableField
}
}
inline val <reified T> Array<out KProperty1<out T, *>>.directTableField: Array<out String> get() = asList().directTableField
inline val <reified T> Collection<KProperty1<out T, *>>.directTableField: Array<out String>
get() {
val companion = T::class.companionObjectInstance
val fieldList = arrayOfNulls<String>(size)
filterNotExists.forEach {
if (companion is cn.tursom.database.TableField<*>) {
@Suppress("UNCHECKED_CAST")
companion as cn.tursom.database.TableField<T>
companion.simpFieldMap[it] ?: it.simpTableField
} else {
it.simpTableField
}
}
@Suppress("UNCHECKED_CAST")
return fieldList as Array<out String>
}
val Field.directTableField: String
get() {
val tableField = getAnnotation(TableField::class.java)
return tableField?.value?.ifEmpty { null } ?: name.sqlName
}
inline val <reified T> Array<out KProperty1<T, *>>.tableField: Array<out String> get() = asList().tableField
inline val <reified T> Collection<KProperty1<T, *>>.tableField: Array<out String>
get() {
val companion = T::class.companionObjectInstance
return if (companion is cn.tursom.database.TableField<*>) {
@Suppress("UNCHECKED_CAST")
companion as cn.tursom.database.TableField<T>
filterNotExists.map { companion[it] }
} else {
filterNotExists.map { it.simpTableField }
}.toTypedArray()
}
inline val <reified T> Map<out KProperty1<T, *>, *>.tableField: Map<String, *>
get() {
val companion = T::class.companionObjectInstance
return if (companion is cn.tursom.database.TableField<*>) {
@Suppress("UNCHECKED_CAST")
companion as cn.tursom.database.TableField<T>
mapKeys { companion.simpFieldMap[it.key] ?: it.key.directTableField }
} else {
mapKeys { it.key.directTableField }
}
}
inline val <reified T> Array<out Pair<KProperty1<T, *>, *>>.tableField: Map<String, *> get() = asList().tableField
inline val <reified T> Collection<Pair<KProperty1<T, *>, *>>.tableField: Map<String, *>
get() {
val companion = T::class.companionObjectInstance
return if (companion is cn.tursom.database.TableField<*>) {
@Suppress("UNCHECKED_CAST")
companion as cn.tursom.database.TableField<T>
filterNotExists.associate { (companion.simpFieldMap[it.first] ?: it.first.directTableField) to it.second }
} else {
filterNotExists.associate { it.first.directTableField to it.second }
}
}
val Array<out Pair<KProperty<*>, *>>.fullTableField: Map<String, *> get() = asList().fullTableField
val Collection<Pair<KProperty<*>, *>>.fullTableField: Map<String, *>
get() {
val map = HashMap<String, Any?>(size)
filterNotExists.forEach { (property, value) ->
map[property.fullTableField] = value
}
return map
}
val Array<out KProperty<*>>.fullTableField: Array<out String> get() = asList().fullTableField
@get:JvmName("getKPropertyFullTableField")
val Collection<KProperty<*>>.fullTableField: Array<out String>
get() = filterNotExists.map { it.fullTableField }.toTypedArray()
inline val <reified T> Array<out KProperty1<T, *>>.fullTableField: Array<out String> get() = asList().fullTableField
inline val <reified T> Collection<KProperty1<T, *>>.fullTableField: Array<out String>
get() {
val tableName = T::class.tableName
val companion = T::class.companionObjectInstance
return if (companion is cn.tursom.database.TableField<*>) {
@Suppress("UNCHECKED_CAST")
companion as cn.tursom.database.TableField<T>
filterNotExists.map { "$tableName.${companion[it]}" }
} else {
filterNotExists.map { "$tableName.${it.simpTableField}" }
}.toTypedArray()
}

View File

@ -0,0 +1,69 @@
package cn.tursom.database
import cn.tursom.core.uncheckedCast
import cn.tursom.log.impl.Slf4jImpl
import org.apache.ibatis.type.TypeHandler
import java.lang.reflect.Modifier
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.jvmName
/**
* 自动注入表单名称映射
* @author 王景阔
* 实现使用 类名[属性对象] 的方式来获取数据库属性名
* 同时为 KProperty<*>.tableField 实现缓存加速
*/
open class TableFieldImpl<T>(clazz: KClass<*>? = null) : TableField<T> {
companion object : Slf4jImpl()
final override var tableName: String
@Transient
final override val fieldMap = HashMap<KProperty1<out T, *>, String>()
final override val simpFieldMap = HashMap<KProperty1<out T, *>, String>()
final override val fullFieldMap = HashMap<KProperty1<out T, *>, String>()
@Transient
final override val allField: Array<out String>
final override val fullNameField: Array<out String>
final override val properties: Array<KProperty1<T, *>>
override val typeHandlerMap = HashMap<KProperty1<out T, *>, TypeHandler<Any>>()
init {
if (clazz == null && this.javaClass == TableFieldImpl::class.java) {
throw NotImplementedError("需提供解析类")
}
@Suppress("UNCHECKED_CAST")
(clazz ?: this.javaClass.kotlin.run {
if (isCompanion) {
java.classLoader.loadClass(jvmName.dropLast(10)).kotlin
} else {
this
}
}).also {
tableName = it.tableName
}.memberProperties
.uncheckedCast<Collection<KProperty1<out T, *>>>()
.filter {
it.javaField != null &&
it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null &&
!Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) &&
it.javaField?.getAnnotation(com.baomidou.mybatisplus.annotation.TableField::class.java)?.exist != false
}
.forEach {
val simpTableField = it.simpTableField
trace("mapping {}::{}", tableName, simpTableField)
simpFieldMap[it] = simpTableField
fieldMap[it] = it.selectionTableField
fullFieldMap[it] = "$tableName.${it.name.sqlName}"
it.findAnnotation<com.baomidou.mybatisplus.annotation.TableField>()?.typeHandler
}
properties = fieldMap.keys.toTypedArray().uncheckedCast()
allField = fieldMap.values.toTypedArray()
fullNameField = allField.map { "$tableName.$it" }.toTypedArray()
}
}

View File

@ -20,6 +20,6 @@ interface TypeAdapter<T : Any> {
*/
fun register(
table: BaseTable<Any>,
field: KProperty1<Any, T>
field: KProperty1<Any, T>,
): Column<T>?
}

View File

@ -1,8 +1,8 @@
package cn.tursom.database
import com.ddbes.kotlin.classutil.getClassByPackage
import com.ddbes.kotlin.clone.InstantAllocator
import com.ddbes.kotlin.uncheckedCast
import cn.tursom.core.clone.InstantAllocator
import cn.tursom.core.getClassByPackage
import cn.tursom.core.uncheckedCast
import me.liuwj.ktorm.schema.BaseTable
import me.liuwj.ktorm.schema.Column
import java.util.concurrent.ConcurrentSkipListMap

View File

@ -0,0 +1,332 @@
/**
* QueryWrapper kotlin 化改造
* @author 王景阔
*/
@file:Suppress("unused")
package cn.tursom.database
import cn.tursom.core.uncheckedCast
import cn.tursom.database.annotations.Getter
import cn.tursom.log.impl.Slf4jImpl
import com.baomidou.mybatisplus.annotation.TableField
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper
import com.baomidou.mybatisplus.core.conditions.ISqlSegment
import com.baomidou.mybatisplus.core.conditions.Wrapper
import com.baomidou.mybatisplus.core.conditions.interfaces.Compare
import com.baomidou.mybatisplus.core.conditions.interfaces.Func
import com.baomidou.mybatisplus.core.conditions.interfaces.Join
import com.baomidou.mybatisplus.core.conditions.query.Query
import com.baomidou.mybatisplus.core.conditions.update.Update
import com.baomidou.mybatisplus.core.toolkit.Constants
import java.lang.reflect.Field
import java.lang.reflect.Modifier
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.javaGetter
val logger = Slf4jImpl.getLogger("com.ddbes.pan.kit.jdbc")
val select: Query<*, *, Any>.(Array<out Any>) -> Any = Query<*, *, Any>::select
@Suppress("UNCHECKED_CAST")
fun <T, Children : Wrapper<T>, Q> Query<Children, T, Q>.select(
columns: Array<out Q>,
): Children = (select as Query<Children, T, Q>.(Array<out Q>) -> Children)(columns)
/**
* QueryWrapper<T>().select(T::fieldName, value)
*/
inline fun <reified T, Children : Wrapper<T>> Query<Children, T, String>.select(
vararg columns: KProperty1<T, *>,
): Children = select(columns.tableField)
fun <T, Children : Wrapper<T>> Query<Children, T, String>.select(
vararg columns: KProperty<*>,
): Children = fullSelect(*columns)
fun <T, Children : Wrapper<T>> Query<Children, T, String>.fullSelect(
vararg columns: KProperty<*>,
): Children = select(columns.fullTableField)
/**
* QueryWrapper<T>().eq(T::fieldName, value)
*/
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.eq(
column: KProperty1<T, *>,
value: Any,
): Children = eq(column.directTableField, value)
fun <T, Children : Wrapper<T>> Compare<Children, String>.eq(
column: KProperty<*>,
value: Any,
): Children = eq(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.eq(
column: Pair<KProperty1<T, *>, Any?>,
): Children = eq(column.first.directTableField, column.second)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.eq(
vararg pair: Pair<KProperty1<T, *>, Any?>,
): Children = allEq(pair.tableField)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.eq(
pair: Collection<Pair<KProperty1<T, *>, Any>>,
): Children = allEq(pair.tableField)
fun <Children> Compare<Children, String>.eq(vararg pair: Pair<KProperty<*>, *>): Children = allEq(pair.fullTableField)
inline fun <reified T : Any, Children : Wrapper<T>> Compare<Children, String>.eq(entity: T): Children {
val eqs = LinkedList<Pair<KProperty1<T, *>, Any>>()
entity::class.memberProperties.uncheckedCast<Collection<KProperty1<T, *>>>().forEach {
it.isAccessible = true
eqs.add(it to (it(entity) ?: return@forEach))
}
return eq(eqs)
}
/**
* QueryWrapper<T>().allEq(mapOf(
* T::fieldName1 to value1,
* T::fieldName2 to value2,
* ...
* ))
*/
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.allEq(map: Map<out KProperty1<T, *>, *>): Children =
allEq(map.tableField)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.allEq(vararg pair: Pair<KProperty1<T, *>, *>): Children =
allEq(pair.tableField)
fun <Children> Compare<Children, String>.allEq(vararg pair: Pair<KProperty<*>, *>): Children =
allEq(pair.fullTableField)
fun <Children> Compare<Children, String>.allFullEq(vararg pair: Pair<KProperty<*>, *>): Children =
allEq(pair.fullTableField)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.ne(
column: KProperty1<T, *>,
value: Any?,
): Children = ne(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.gt(
column: KProperty1<T, *>,
value: Any?,
): Children = gt(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.ge(
column: KProperty1<T, *>,
value: Any?,
): Children = ge(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.lt(
column: KProperty1<T, *>,
value: Any?,
): Children = lt(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.le(
column: KProperty1<T, *>,
value: Any?,
): Children = le(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.between(
column: KProperty1<T, *>,
val1: Any?,
val2: Any?,
): Children = between(column.directTableField, val1, val2)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.notBetween(
column: KProperty1<T, *>,
val1: Any?,
val2: Any?,
): Children = notBetween(column.directTableField, val1, val2)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.like(
column: KProperty1<T, *>,
value: Any?,
): Children = like(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.notLike(
column: KProperty1<T, *>,
value: Any?,
): Children = notLike(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.likeLeft(
column: KProperty1<T, *>,
value: Any?,
): Children = likeLeft(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.likeRight(
column: KProperty1<T, *>,
value: Any?,
): Children = likeRight(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.having(
column: KProperty1<T, *>,
vararg value: Any?,
): Children = having(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.isNull(column: KProperty1<T, *>): Children =
isNull(column.directTableField)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.isNotNull(column: KProperty1<T, *>): Children =
isNotNull(column.directTableField)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.`in`(
column: KProperty1<T, *>,
value: Any?,
): Children = `in`(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.`in`(
column: KProperty1<T, *>,
value: Collection<Any?>,
): Children = `in`(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.`in`(
column: KProperty1<T, *>,
vararg value: Any,
): Children = `in`(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.notIn(
column: KProperty1<T, *>,
value: Collection<Any?>,
): Children = notIn(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.notIn(
column: KProperty1<T, *>,
vararg value: Any,
): Children = notIn(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.inSql(
column: KProperty1<T, *>,
value: String?,
): Children = inSql(column.directTableField, value)
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.notInSql(
column: KProperty1<T, *>,
value: String?,
): Children = notInSql(column.directTableField, value)
val groupBy: Func<*, String>.(Array<out String>) -> Any = Func<*, String>::groupBy
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.groupBy(column: KProperty1<T, *>): Children =
groupBy(column.directTableField)
@Suppress("UNCHECKED_CAST")
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.groupBy(vararg column: KProperty1<T, *>): Children =
groupBy(column.directTableField) as Children
val orderByAsc: Func<*, String>.(Array<out String>) -> Any = Func<*, String>::orderByAsc
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByAsc(column: KProperty1<T, *>): Children =
orderByAsc(column.directTableField)
@Suppress("UNCHECKED_CAST")
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByAsc(vararg column: KProperty1<T, *>): Children =
orderByAsc(column.directTableField) as Children
val orderByDesc: Func<*, String>.(Array<out String>) -> Any = Func<*, String>::orderByDesc
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByDesc(column: KProperty1<T, *>): Children =
orderByDesc(column.directTableField)
@Suppress("UNCHECKED_CAST")
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByDesc(vararg column: KProperty1<T, *>): Children =
orderByDesc(column.directTableField) as Children
/**
* QueryWrapper<T>()
* .xx()
* .xxx()
* ...
* .limit1()
*/
fun <Children> Join<Children>.limit1(): Children = last("LIMIT 1")
inline fun <reified T, Children : Wrapper<T>> Update<Children, String>.set(
column: KProperty1<T, *>,
value: Any?,
): Children {
if (column.javaField == null || Modifier.isTransient(column.javaField?.modifiers ?: Modifier.TRANSIENT) ||
column.javaField?.getAnnotation(TableField::class.java)?.exist == false
) {
return uncheckedCast()
}
val getter = column.findAnnotation<Getter>()
val v = if (getter == null || !(value != null && getter.getterType.isInstance(value))) {
value
} else {
val getterMethod = column.javaGetter!!.declaringClass.getDeclaredMethod(getter.getter, getter.getterType.java)
getterMethod.isAccessible = true
getterMethod.invoke(null, value)
}
return set(column.directTableField, v)
}
inline fun <reified T, Children : Wrapper<T>> Update<Children, String>.set(vararg values: Pair<KProperty1<T, *>, Any?>): Children {
var children: Children? = null
values.forEach { (column, value) ->
set(column, value).let {
if (children == null) children = it
}
}
return children ?: uncheckedCast()
}
inline fun <reified T : Any, Children : Wrapper<T>> Update<Children, String>.set(value: T): Children {
var children: Children? = null
value::class.memberProperties
.uncheckedCast<Collection<KProperty1<T, *>>>()
.filter {
it.javaField != null &&
it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == null &&
!Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) &&
it.javaField?.getAnnotation(TableField::class.java)?.exist != false
}
.forEach { property ->
property.isAccessible = true
set(property, property.get(value) ?: return@forEach).let {
if (children == null) children = it
}
}
return children ?: uncheckedCast()
}
object Regexp : ISqlSegment {
override fun getSqlSegment(): String = "REGEXP"
}
object WrapperEnhance : AbstractWrapper<Any, String, WrapperEnhance>() {
override fun instance(): WrapperEnhance = this
private val paramNameSeqField: Field =
AbstractWrapper::class.java.getDeclaredField("paramNameSeq").apply { isAccessible = true }
init {
initNeed()
}
fun <T, W : AbstractWrapper<T, String, W>> regex(wrapper: W, column: String, value: Any): W {
wrapper.expression.add(ISqlSegment { columnToString(column) }, Regexp, ISqlSegment {
val genParamName = Constants.WRAPPER_PARAM + (paramNameSeqField.get(wrapper) as AtomicInteger).incrementAndGet()
wrapper.paramNameValuePairs[genParamName] = value
String.format(Constants.WRAPPER_PARAM_FORMAT, Constants.WRAPPER, genParamName)
})
return wrapper
}
}
fun <T, W : AbstractWrapper<T, String, W>> W.regex(column: String, value: Any): W =
WrapperEnhance.regex(this, column, value)
inline fun <reified T, W : AbstractWrapper<T, String, W>> W.regex(
column: KProperty1<T, *>, value: Any,
): W = WrapperEnhance.regex(this, column.directTableField, value)
inline fun <reified T, W : AbstractWrapper<T, String, W>> W.regex(
column: KProperty1<T, *>, regex: Regex,
): W = WrapperEnhance.regex(this, column.directTableField, regex.toString())

View File

@ -0,0 +1,10 @@
package cn.tursom.database.annotations
import kotlin.reflect.KClass
/**
* 很抱歉我暂时做不到兼容 mybatis TypeHandler只能用这种方式凑合一下了
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class Getter(val getter: String, val getterType: KClass<*>)

View File

@ -1,6 +1,5 @@
package cn.tursom.database.annotations
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)

View File

@ -1,8 +1,8 @@
package cn.tursom.database.typeadapter
import cn.tursom.core.uncheckedCast
import cn.tursom.database.TypeAdapter
import com.ddbes.kotlin.jdbc.simpTableField
import com.ddbes.kotlin.uncheckedCast
import cn.tursom.database.simpTableField
import me.liuwj.ktorm.schema.BaseTable
import me.liuwj.ktorm.schema.Column
import me.liuwj.ktorm.schema.EnumSqlType