mirror of
https://github.com/tursom/TursomServer.git
synced 2025-03-13 11:20:10 +08:00
update ts-database
This commit is contained in:
parent
8bddb93f4b
commit
49a6df2e55
@ -1,7 +1,7 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.5.21"
|
||||
kotlin("jvm") version "1.5.31"
|
||||
`maven-publish`
|
||||
id("ts-gradle")
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ include("ts-web")
|
||||
include("ts-web:ts-web-netty")
|
||||
include("ts-web:ts-web-coroutine")
|
||||
include("ts-database")
|
||||
include("ts-database:ts-ktorm")
|
||||
include("ts-database:ts-mybatisplus")
|
||||
include("ts-database:ts-mongodb")
|
||||
include("ts-database:ts-mongodb:ts-mongodb-spring")
|
||||
include("ts-database:ts-redis")
|
||||
|
@ -629,3 +629,17 @@ inline operator fun <reified T> Array<out T>.plus(other: Array<out T>): Array<T>
|
||||
System.arraycopy(other, 0, array, size, other.size)
|
||||
return array.uncheckedCast()
|
||||
}
|
||||
|
||||
val <T : Any> KClass<T>.allMemberPropertiesSequence: Sequence<KProperty1<T, *>>
|
||||
get() = sequence {
|
||||
yieldAll(memberProperties)
|
||||
var superClass = superclasses.firstOrNull {
|
||||
!it.java.isInterface
|
||||
}
|
||||
while (superClass != null) {
|
||||
yieldAll(superClass.memberProperties.uncheckedCast<Collection<KProperty1<T, *>>>())
|
||||
superClass = superClass.superclasses.firstOrNull {
|
||||
!it.java.isInterface
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package cn.tursom.core.reference
|
||||
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* 通过垃圾回收机制实现的自动关闭
|
||||
* 记得保存StrongReference对象防止Closeable意外关闭
|
||||
*/
|
||||
class AutoCloseFreeReference(
|
||||
private val closeable: Closeable,
|
||||
r: StrongReference<Closeable>,
|
||||
) : FreeReference<StrongReference<Closeable>>(r) {
|
||||
override fun release() {
|
||||
closeable.close()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Closeable> T.registerAutoClose(): StrongReference<T> {
|
||||
val r = StrongReference(this)
|
||||
AutoCloseFreeReference(this, r)
|
||||
return r
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package cn.tursom.core.reference
|
||||
|
||||
open class StrongReference<out T>(
|
||||
val r: T,
|
||||
)
|
@ -34,7 +34,7 @@ object Parser {
|
||||
clazz.isInstance(yaml) -> yaml.cast()
|
||||
clazz.isInheritanceFrom(Enum::class.java) -> try {
|
||||
val valueOf = clazz.getDeclaredMethod("valueOf", String::class.java)
|
||||
valueOf.invoke(null, yaml.toString().toUpperCase()).cast<T?>()
|
||||
valueOf.invoke(null, yaml.toString().uppercase(Locale.getDefault())).cast<T?>()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import cn.tursom.core.isStatic
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import java.util.*
|
||||
|
||||
inline fun <reified T : Annotation> Class<*>.getAnnotation(): T? = getAnnotation(T::class.java)
|
||||
inline fun <reified T : Annotation> Field.getAnnotation(): T? = getAnnotation(T::class.java)
|
||||
@ -40,7 +41,7 @@ fun <T : Enum<out T>> Class<out T>.valueOf(value: String): T? {
|
||||
valueOf.invoke(null, value) as T
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
valueOf?.invoke(null, value.toUpperCase()) as? T?
|
||||
valueOf?.invoke(null, value.uppercase(Locale.getDefault())) as? T?
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package cn.tursom.core.coroutine
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
object GlobalScope : CoroutineScope {
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
}
|
22
ts-database/ts-ktorm/build.gradle.kts
Normal file
22
ts-database/ts-ktorm/build.gradle.kts
Normal file
@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
id("ts-gradle")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
api(kotlin("reflect"))
|
||||
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-clone"))
|
||||
implementation(project(":ts-core:ts-log"))
|
||||
api(group = "org.ktorm", name = "ktorm-core", version = "3.4.1")
|
||||
compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.7")
|
||||
|
||||
testApi(group = "junit", name = "junit", version = "4.13.2")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import cn.tursom.core.clone.Property
|
||||
import cn.tursom.core.clone.inject
|
||||
import cn.tursom.core.clone.instance
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import com.baomidou.mybatisplus.annotation.TableField
|
||||
import cn.tursom.database.ktorm.annotations.KtormTableField
|
||||
import org.ktorm.dsl.QueryRowSet
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
@ -14,6 +14,7 @@ import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty0
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
open class AutoTable<T : Any>(
|
||||
@ -24,16 +25,18 @@ open class AutoTable<T : Any>(
|
||||
schema: String? = null,
|
||||
val unsafe: Boolean = true,
|
||||
) : BaseTable<T>(tableName, alias, catalog, schema, entityClass) {
|
||||
private val fieldMap: Map<String, KProperty<*>>
|
||||
private val fieldColumns: MutableMap<KProperty<*>, Column<*>> = HashMap()
|
||||
private val fieldMap: Map<String, KProperty1<T, *>>
|
||||
private val fieldColumns: MutableMap<KProperty1<T, *>, Column<*>> = HashMap()
|
||||
private val fieldNameColumnMap: MutableMap<String, Column<*>> = HashMap()
|
||||
|
||||
val fieldColumnsMap: Map<KProperty1<T, *>, Column<*>> by ::fieldColumns
|
||||
|
||||
init {
|
||||
fieldMap = entityClass.memberProperties.associateBy { it.simpTableField }
|
||||
entityClass.memberProperties.forEach {
|
||||
val field = it.javaField ?: return@forEach
|
||||
val tableField: TableField? = field.getAnnotation(TableField::class.java)
|
||||
if (tableField?.exist == false) return@forEach
|
||||
it.isAccessible = true
|
||||
if (field.getAnnotation(KtormTableField::class.java)?.exist == false) return@forEach
|
||||
//TypeAdapterFactory.register(this, it)
|
||||
val column = TypeAdapterFactory.register(this, it) ?: return@forEach
|
||||
fieldColumns[it] = column
|
||||
@ -50,7 +53,8 @@ open class AutoTable<T : Any>(
|
||||
return instance
|
||||
}
|
||||
|
||||
operator fun <R : Any> get(property: KProperty1<in T, R?>): Column<R> = fieldColumns[property].uncheckedCast()
|
||||
operator fun <R : Any> get(property: KProperty1<in T, R?>): Column<R> =
|
||||
fieldColumns[property.uncheckedCast()].uncheckedCast()
|
||||
//operator fun <R : Any> get(property: KProperty1<T, R?>): Column<R> = this[property.simpTableField].cast()
|
||||
|
||||
fun <V : Any> field(): FieldProxy<T, V> = fieldProxyInstance.uncheckedCast()
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import cn.tursom.core.Utils
|
||||
import com.google.gson.Gson
|
@ -0,0 +1,63 @@
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import org.ktorm.database.Database
|
||||
import org.ktorm.dsl.*
|
||||
import org.ktorm.schema.Column
|
||||
import org.ktorm.schema.ColumnDeclaring
|
||||
|
||||
inline fun <reified T : Any> Database.update(
|
||||
noinline block: UpdateStatementBuilder.(AutoTable<T>) -> Unit
|
||||
): Int {
|
||||
return update(AutoTable[T::class], block)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Database.batchUpdate(
|
||||
noinline block: BatchUpdateStatementBuilder<AutoTable<T>>.() -> Unit
|
||||
): IntArray {
|
||||
return batchUpdate(AutoTable[T::class], block)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Database.insert(
|
||||
noinline block: AssignmentsBuilder.(AutoTable<T>) -> Unit
|
||||
): Int {
|
||||
return insert(AutoTable[T::class], block)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Database.insert(
|
||||
value: T
|
||||
): Int {
|
||||
val table = AutoTable[T::class]
|
||||
return insert(table) {
|
||||
table.fieldColumnsMap.forEach { (property, column) ->
|
||||
val columnValue = property.get(value) ?: return@forEach
|
||||
set(column.uncheckedCast(), columnValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Database.insertAndGenerateKey(
|
||||
noinline block: AssignmentsBuilder.(AutoTable<T>) -> Unit
|
||||
): Any {
|
||||
return insertAndGenerateKey(AutoTable[T::class], block)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Database.batchInsert(
|
||||
noinline block: BatchInsertStatementBuilder<AutoTable<T>>.() -> Unit
|
||||
): IntArray {
|
||||
return batchInsert(AutoTable[T::class], block)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Query.insertTo(vararg columns: Column<*>): Int {
|
||||
return insertTo(AutoTable[T::class], columns = columns)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Database.delete(
|
||||
noinline predicate: (AutoTable<T>) -> ColumnDeclaring<Boolean>
|
||||
): Int {
|
||||
return delete(AutoTable[T::class], predicate)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Database.deleteAll(): Int {
|
||||
return deleteAll(AutoTable[T::class])
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import org.ktorm.dsl.*
|
||||
import org.ktorm.expression.*
|
@ -1,6 +1,6 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import cn.tursom.core.Utils
|
||||
import cn.tursom.core.uncheckedCast
|
@ -8,11 +8,10 @@
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import org.apache.ibatis.type.TypeHandler
|
||||
import cn.tursom.database.ktorm.annotations.KtormTableField
|
||||
import cn.tursom.database.ktorm.annotations.KtormTableName
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.KClass
|
||||
@ -36,46 +35,44 @@ interface TableField<T> {
|
||||
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
|
||||
val <T> Iterable<KProperty1<out T, *>>.filterNotExists: List<KProperty1<out T, *>>
|
||||
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
|
||||
it.javaField?.getAnnotation(KtormTableField::class.java)?.exist != false
|
||||
}
|
||||
|
||||
@get:JvmName("filterNotExistsPair")
|
||||
val <T> Iterable<Pair<KProperty1<T, *>, *>>.filterNotExists: List<Pair<KProperty1<T, *>, *>>
|
||||
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(KtormTableField::class.java)?.exist != false
|
||||
}
|
||||
|
||||
@get:JvmName("filterNotExistsKProperty")
|
||||
val Iterable<KProperty<*>>.filterNotExists: List<KProperty<*>>
|
||||
get() = filter {
|
||||
it.javaField != null &&
|
||||
(it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java)) == null &&
|
||||
!Modifier.isTransient(it.javaField?.modifiers ?: Modifier.TRANSIENT) &&
|
||||
it.javaField?.getAnnotation(KtormTableField::class.java)?.exist != false
|
||||
}
|
||||
|
||||
@get:JvmName("filterNotExistsKPropertyPair")
|
||||
val Iterable<Pair<KProperty<*>, *>>.filterNotExists
|
||||
val Iterable<Pair<KProperty<*>, *>>.filterNotExists: List<Pair<KProperty<*>, *>>
|
||||
get() = filter { (it, _) ->
|
||||
it.javaField != null &&
|
||||
it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == 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
|
||||
it.javaField?.getAnnotation(KtormTableField::class.java)?.exist != false
|
||||
}
|
||||
|
||||
val String.sqlName: String
|
||||
@ -94,9 +91,9 @@ val String.sqlName: String
|
||||
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 KClass<*>.tableName: String get() = findAnnotation<KtormTableName>()?.name ?: simpleName!!.sqlName
|
||||
val Class<*>.tableName: String get() = getAnnotation(KtormTableName::class.java)?.name ?: simpleName.sqlName
|
||||
val KProperty<*>.tableFieldName: String? get() = javaField?.getAnnotation(KtormTableField::class.java)?.name
|
||||
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
|
||||
@ -104,9 +101,9 @@ val KProperty<*>.selectionTableField: String
|
||||
inline val <reified T> KProperty1<out T, *>.tableField: String
|
||||
get() {
|
||||
val companion = T::class.companionObjectInstance
|
||||
return if (companion is cn.tursom.database.TableField<*>) {
|
||||
return if (companion is TableField<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
companion as cn.tursom.database.TableField<T>
|
||||
companion as TableField<T>
|
||||
companion[this]
|
||||
} else {
|
||||
selectionTableField
|
||||
@ -116,9 +113,9 @@ inline val <reified T> KProperty1<out T, *>.tableField: String
|
||||
inline val <reified T : Any> KProperty1<out T, *>.fullTableField: String
|
||||
get() {
|
||||
val companion = T::class.companionObjectInstance
|
||||
return if (companion is cn.tursom.database.TableField<*>) {
|
||||
return if (companion is TableField<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
companion as cn.tursom.database.TableField<T>
|
||||
companion as TableField<T>
|
||||
companion.fullFieldMap[this] ?: "${companion.tableName}.${companion[this]}"
|
||||
} else {
|
||||
"${T::class.tableName}.$selectionTableField"
|
||||
@ -133,8 +130,8 @@ val KProperty<*>.fullTableField: String
|
||||
|
||||
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 tableField = getAnnotation(KtormTableField::class.java)
|
||||
return tableField?.name?.let { if (it.isNotEmpty()) "$it as ${name.sqlName}" else null } ?: name.sqlName
|
||||
}
|
||||
|
||||
val KProperty<*>.directTableField: String
|
||||
@ -143,9 +140,9 @@ val KProperty<*>.directTableField: String
|
||||
inline val <reified T> KProperty1<out T, *>.directTableField: String
|
||||
get() {
|
||||
val companion = T::class.companionObjectInstance
|
||||
return if (companion is cn.tursom.database.TableField<*>) {
|
||||
return if (companion is TableField<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
companion as cn.tursom.database.TableField<T>
|
||||
companion as TableField<T>
|
||||
companion.simpFieldMap[this] ?: simpTableField
|
||||
} else {
|
||||
simpTableField
|
||||
@ -158,9 +155,9 @@ inline val <reified T> Collection<KProperty1<out T, *>>.directTableField: Array<
|
||||
val companion = T::class.companionObjectInstance
|
||||
val fieldList = arrayOfNulls<String>(size)
|
||||
filterNotExists.forEach {
|
||||
if (companion is cn.tursom.database.TableField<*>) {
|
||||
if (companion is TableField<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
companion as cn.tursom.database.TableField<T>
|
||||
companion as TableField<T>
|
||||
companion.simpFieldMap[it] ?: it.simpTableField
|
||||
} else {
|
||||
it.simpTableField
|
||||
@ -172,17 +169,17 @@ inline val <reified T> Collection<KProperty1<out T, *>>.directTableField: Array<
|
||||
|
||||
val Field.directTableField: String
|
||||
get() {
|
||||
val tableField = getAnnotation(TableField::class.java)
|
||||
return tableField?.value?.ifEmpty { null } ?: name.sqlName
|
||||
val tableField = getAnnotation(KtormTableField::class.java)
|
||||
return tableField?.name?.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<*>) {
|
||||
return if (companion is TableField<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
companion as cn.tursom.database.TableField<T>
|
||||
companion as TableField<T>
|
||||
filterNotExists.map { companion[it] }
|
||||
} else {
|
||||
filterNotExists.map { it.simpTableField }
|
||||
@ -192,9 +189,9 @@ inline val <reified T> Collection<KProperty1<T, *>>.tableField: Array<out Strin
|
||||
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<*>) {
|
||||
return if (companion is TableField<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
companion as cn.tursom.database.TableField<T>
|
||||
companion as TableField<T>
|
||||
mapKeys { companion.simpFieldMap[it.key] ?: it.key.directTableField }
|
||||
} else {
|
||||
mapKeys { it.key.directTableField }
|
||||
@ -205,9 +202,9 @@ inline val <reified T> Array<out Pair<KProperty1<T, *>, *>>.tableField: Map<Stri
|
||||
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<*>) {
|
||||
return if (companion is TableField<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
companion as cn.tursom.database.TableField<T>
|
||||
companion as TableField<T>
|
||||
filterNotExists.associate { (companion.simpFieldMap[it.first] ?: it.first.directTableField) to it.second }
|
||||
} else {
|
||||
filterNotExists.associate { it.first.directTableField to it.second }
|
||||
@ -237,9 +234,9 @@ inline val <reified T> Collection<KProperty1<T, *>>.fullTableField: Array<out S
|
||||
get() {
|
||||
val tableName = T::class.tableName
|
||||
val companion = T::class.companionObjectInstance
|
||||
return if (companion is cn.tursom.database.TableField<*>) {
|
||||
return if (companion is TableField<*>) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
companion as cn.tursom.database.TableField<T>
|
||||
companion as TableField<T>
|
||||
filterNotExists.map { "$tableName.${companion[it]}" }
|
||||
} else {
|
||||
filterNotExists.map { "$tableName.${it.simpTableField}" }
|
@ -1,8 +1,8 @@
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import cn.tursom.database.ktorm.annotations.KtormTableField
|
||||
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
|
||||
@ -31,7 +31,6 @@ open class TableFieldImpl<T>(clazz: KClass<*>? = null) : TableField<T> {
|
||||
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) {
|
||||
@ -50,9 +49,9 @@ open class TableFieldImpl<T>(clazz: KClass<*>? = null) : TableField<T> {
|
||||
.uncheckedCast<Collection<KProperty1<out T, *>>>()
|
||||
.filter {
|
||||
it.javaField != null &&
|
||||
it.findAnnotation() ?: it.javaField?.getAnnotation(Transient::class.java) == 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
|
||||
it.javaField?.getAnnotation(KtormTableField::class.java)?.exist != false
|
||||
}
|
||||
.forEach {
|
||||
val simpTableField = it.simpTableField
|
||||
@ -60,7 +59,6 @@ open class TableFieldImpl<T>(clazz: KClass<*>? = null) : TableField<T> {
|
||||
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()
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.ktorm
|
||||
|
||||
import cn.tursom.core.getClassByPackage
|
||||
import cn.tursom.core.reflect.InstantAllocator
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.database.annotations
|
||||
package cn.tursom.database.ktorm.annotations
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
@ -1,4 +1,4 @@
|
||||
package cn.tursom.database.annotations
|
||||
package cn.tursom.database.ktorm.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
@ -0,0 +1,9 @@
|
||||
package cn.tursom.database.ktorm.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FIELD, AnnotationTarget.ANNOTATION_CLASS)
|
||||
annotation class KtormTableField(
|
||||
val name: String = "",
|
||||
val exist: Boolean = true,
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
package cn.tursom.database.ktorm.annotations
|
||||
|
||||
@MustBeDocumented
|
||||
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FIELD, AnnotationTarget.ANNOTATION_CLASS)
|
||||
annotation class KtormTableName(
|
||||
val name: String = "",
|
||||
)
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.boolean
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.boolean
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import kotlin.reflect.KProperty1
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.bytes
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.bytes
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import kotlin.reflect.KProperty1
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.jdbcDate
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.jdbcDate
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.sql.Date
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.double
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.double
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import kotlin.reflect.KProperty1
|
@ -1,8 +1,8 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.simpTableField
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.simpTableField
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import org.ktorm.schema.EnumSqlType
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.float
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.float
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import kotlin.reflect.KProperty1
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.timestamp
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.timestamp
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.time.Instant
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.int
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.int
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import kotlin.reflect.KProperty1
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.decimal
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.decimal
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.math.BigDecimal
|
@ -1,8 +1,8 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.annotations.Json
|
||||
import cn.tursom.database.json
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.annotations.Json
|
||||
import cn.tursom.database.ktorm.json
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import kotlin.reflect.KProperty1
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.date
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.date
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.time.LocalDate
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.datetime
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.datetime
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.time.LocalDateTime
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.time
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.time
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.time.LocalTime
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.long
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.long
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import kotlin.reflect.KProperty1
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.monthDay
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.monthDay
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.time.MonthDay
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.varchar
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.varchar
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import kotlin.reflect.KProperty1
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.jdbcTime
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.jdbcTime
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.sql.Time
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.jdbcTimestamp
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.jdbcTimestamp
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.sql.Timestamp
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.uuid
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.uuid
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.util.*
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.year
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.year
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.time.Year
|
@ -1,7 +1,7 @@
|
||||
package cn.tursom.database.typeadapter
|
||||
package cn.tursom.database.ktorm.typeadapter
|
||||
|
||||
import cn.tursom.database.TypeAdapter
|
||||
import cn.tursom.database.yearMonth
|
||||
import cn.tursom.database.ktorm.TypeAdapter
|
||||
import cn.tursom.database.ktorm.yearMonth
|
||||
import org.ktorm.schema.BaseTable
|
||||
import org.ktorm.schema.Column
|
||||
import java.time.YearMonth
|
22
ts-database/ts-mybatisplus/build.gradle.kts
Normal file
22
ts-database/ts-mybatisplus/build.gradle.kts
Normal file
@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
id("ts-gradle")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
api(kotlin("reflect"))
|
||||
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-clone"))
|
||||
implementation(project(":ts-core:ts-log"))
|
||||
implementation(group = "com.baomidou", name = "mybatis-plus", version = "3.4.3.2")
|
||||
compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.7")
|
||||
|
||||
testApi(group = "junit", name = "junit", version = "4.13.2")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,134 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.interfaces.Compare
|
||||
import java.util.*
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
@Suppress("unused")
|
||||
@MybatisPlusEnhanceDslMaker
|
||||
interface CompareEnhance<T, out W : AbstractWrapper<T, String, out W>, Children : Wrapper<T>> :
|
||||
EnhanceEntityClassEnhance<T>,
|
||||
RegexAbstractWrapperEnhance<T, W, Children> {
|
||||
val compare: Compare<Children, String> get() = uncheckedCast()
|
||||
|
||||
/**
|
||||
* QueryWrapper<T>().eq(T::fieldName, value)
|
||||
*/
|
||||
infix fun KProperty1<T, *>.eq(
|
||||
value: Any,
|
||||
): Children = compare.eq(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty<*>.eq(
|
||||
value: Any,
|
||||
): Children = compare.eq(getFieldData()!!.name, value)
|
||||
|
||||
fun eq(
|
||||
column: Pair<KProperty1<T, *>, Any?>,
|
||||
): Children = compare.eq(column.first.getFieldData()!!.name, column.second)
|
||||
|
||||
fun eq(
|
||||
vararg pair: Pair<KProperty1<T, *>, Any?>,
|
||||
): Children = compare.eq(pair.asSequence())
|
||||
|
||||
fun eq(
|
||||
pair: Collection<Pair<KProperty1<T, *>, Any>>,
|
||||
): Children = compare.eq(pair.asSequence())
|
||||
|
||||
fun eq(
|
||||
pair: Sequence<Pair<KProperty<*>, *>>,
|
||||
): Children = compare.allEq(
|
||||
pair.mapNotNull { (property, value) ->
|
||||
val fieldData = property.getFieldData() ?: return@mapNotNull null
|
||||
fieldData.name to value
|
||||
}.associate {
|
||||
it
|
||||
}
|
||||
)
|
||||
|
||||
fun <Children> Compare<Children, String>.eq(vararg pair: Pair<KProperty<*>, *>): Children = eq(pair.asSequence())
|
||||
|
||||
fun eq(entity: T): Children {
|
||||
val eqs = LinkedList<Pair<KProperty1<T, *>, Any>>()
|
||||
entity!!.javaClass.kotlin.memberProperties.uncheckedCast<Collection<KProperty1<T, *>>>().forEach {
|
||||
it.isAccessible = true
|
||||
eqs.add(it to (it(entity) ?: return@forEach))
|
||||
}
|
||||
return eq(eqs)
|
||||
}
|
||||
|
||||
fun eqMapEntry(
|
||||
pair: Sequence<Map.Entry<KProperty<*>, *>>,
|
||||
): Children = compare.allEq(
|
||||
pair.mapNotNull { (property, value) ->
|
||||
val fieldData = property.getFieldData() ?: return@mapNotNull null
|
||||
fieldData.name to value
|
||||
}.associate {
|
||||
it
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* QueryWrapper<T>().allEq(mapOf(
|
||||
* T::fieldName1 to value1,
|
||||
* T::fieldName2 to value2,
|
||||
* ...
|
||||
* ))
|
||||
*/
|
||||
fun allEq(map: Map<out KProperty1<T, *>, *>): Children = compare.eq(map.asSequence())
|
||||
|
||||
fun allEq(vararg pair: Pair<KProperty<*>, *>): Children = compare.eq(pair.asSequence())
|
||||
|
||||
fun allFullEq(vararg pair: Pair<KProperty<*>, *>): Children = compare.eq(pair.asSequence())
|
||||
|
||||
infix fun KProperty1<T, *>.ne(
|
||||
value: Any?,
|
||||
): Children = compare.ne(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.gt(
|
||||
value: Any?,
|
||||
): Children = compare.gt(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.ge(
|
||||
value: Any?,
|
||||
): Children = compare.ge(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.lt(
|
||||
value: Any?,
|
||||
): Children = compare.lt(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.le(
|
||||
value: Any?,
|
||||
): Children = compare.le(getFieldData()!!.name, value)
|
||||
|
||||
fun KProperty1<T, *>.between(
|
||||
val1: Any?,
|
||||
val2: Any?,
|
||||
): Children = compare.between(getFieldData()!!.name, val1, val2)
|
||||
|
||||
fun KProperty1<T, *>.notBetween(
|
||||
val1: Any?,
|
||||
val2: Any?,
|
||||
): Children = compare.notBetween(getFieldData()!!.name, val1, val2)
|
||||
|
||||
infix fun KProperty1<T, *>.like(
|
||||
value: Any?,
|
||||
): Children = compare.like(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.notLike(
|
||||
value: Any?,
|
||||
): Children = compare.notLike(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.likeLeft(
|
||||
value: Any?,
|
||||
): Children = compare.likeLeft(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.likeRight(
|
||||
value: Any?,
|
||||
): Children = compare.likeRight(getFieldData()!!.name, value)
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
|
||||
|
||||
class DdbesQueryWrapper<T>(
|
||||
override var enhanceEntityClass: Class<T>
|
||||
) : QueryWrapper<T>(),
|
||||
QueryEnhance<T, DdbesQueryWrapper<T>>,
|
||||
DdbesWrapperEnhance<T, QueryWrapper<T>, DdbesQueryWrapper<T>> {
|
||||
init {
|
||||
this.entityClass = enhanceEntityClass
|
||||
}
|
||||
|
||||
companion object {
|
||||
inline operator fun <reified T> invoke() = DdbesQueryWrapper(T::class.java)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper
|
||||
|
||||
class DdbesUpdateWrapper<T>(
|
||||
override val enhanceEntityClass: Class<T>,
|
||||
) : UpdateWrapper<T>(),
|
||||
UpdateEnhance<T, DdbesUpdateWrapper<T>>,
|
||||
DdbesWrapperEnhance<T, UpdateWrapper<T>, DdbesUpdateWrapper<T>> {
|
||||
companion object {
|
||||
inline operator fun <reified T> invoke() = DdbesUpdateWrapper(T::class.java)
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper
|
||||
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.interfaces.Nested
|
||||
|
||||
@MybatisPlusEnhanceDslMaker
|
||||
interface DdbesWrapperEnhance<T, W : AbstractWrapper<T, String, out W>, EnhanceWrapper : Wrapper<T>> :
|
||||
CompareEnhance<T, W, EnhanceWrapper>,
|
||||
JoinEnhance<EnhanceWrapper>,
|
||||
FuncEnhance<T, EnhanceWrapper>,
|
||||
Compare<W, String>,
|
||||
Nested<W, W>,
|
||||
Join<W>,
|
||||
Func<W, String>
|
@ -0,0 +1,6 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
@MybatisPlusEnhanceDslMaker
|
||||
interface EnhanceEntityClassEnhance<T> {
|
||||
val enhanceEntityClass: Class<T>
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper
|
||||
|
||||
inline fun <C : CompareEnhance<T, W, Children>, T, W : AbstractWrapper<T, String, W>, Children : Wrapper<T>> C.compare(
|
||||
compare: CompareEnhance<T, W, Children>.() -> Unit
|
||||
): C {
|
||||
compare()
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <C : FuncEnhance<T, Children>, T, Children : Wrapper<T>> C.func(
|
||||
func: FuncEnhance<T, Children>.() -> Unit
|
||||
): C {
|
||||
func()
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <C : JoinEnhance<Children>, Children> C.join(
|
||||
join: JoinEnhance<Children>.() -> Unit
|
||||
): C {
|
||||
join()
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <C : QueryEnhance<T, Children>, T, Children : Wrapper<T>> C.query(
|
||||
query: QueryEnhance<T, Children>.() -> Unit
|
||||
): C {
|
||||
query()
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <C : UpdateEnhance<T, Children>, T, Children : Wrapper<T>> C.update(
|
||||
update: UpdateEnhance<T, Children>.() -> Unit
|
||||
): C {
|
||||
update()
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <C : DdbesWrapperEnhance<T, W, EnhanceWrapper>,
|
||||
T, W : AbstractWrapper<T, String, out W>, EnhanceWrapper : Wrapper<T>>
|
||||
C.query(
|
||||
query: DdbesWrapperEnhance<T, W, EnhanceWrapper>.() -> Unit
|
||||
): C {
|
||||
query()
|
||||
return this
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class EnhanceField(
|
||||
val field: String,
|
||||
)
|
@ -0,0 +1,67 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.interfaces.Func
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
@Suppress("unused")
|
||||
@MybatisPlusEnhanceDslMaker
|
||||
interface FuncEnhance<T, out Children : Wrapper<T>> {
|
||||
val func: Func<out Children, String> get() = uncheckedCast()
|
||||
|
||||
fun KProperty1<T, *>.having(
|
||||
vararg value: Any?,
|
||||
): Children = func.having(getFieldData()!!.name, value)
|
||||
|
||||
fun KProperty1<T, *>.isNull(column: KProperty1<T, *>): Children = func.isNull(column.getFieldData()!!.name)
|
||||
|
||||
fun KProperty1<T, *>.isNotNull(column: KProperty1<T, *>): Children = func.isNotNull(column.getFieldData()!!.name)
|
||||
|
||||
infix fun KProperty1<T, *>.`in`(
|
||||
value: Any?,
|
||||
): Children = func.`in`(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.`in`(
|
||||
value: Collection<Any?>,
|
||||
): Children = func.`in`(getFieldData()!!.name, value)
|
||||
|
||||
fun KProperty1<T, *>.`in`(
|
||||
vararg value: Any,
|
||||
): Children = func.`in`(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.notIn(
|
||||
value: Collection<Any?>,
|
||||
): Children = func.notIn(getFieldData()!!.name, value)
|
||||
|
||||
fun KProperty1<T, *>.notIn(
|
||||
vararg value: Any,
|
||||
): Children = func.notIn(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.inSql(
|
||||
value: String?,
|
||||
): Children = func.inSql(getFieldData()!!.name, value)
|
||||
|
||||
infix fun KProperty1<T, *>.notInSql(
|
||||
value: String?,
|
||||
): Children = func.notInSql(getFieldData()!!.name, value)
|
||||
|
||||
|
||||
fun groupBy(column: KProperty1<T, *>): Children = func.groupBy(column.getFieldData()!!.name)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun groupBy(vararg columns: KProperty1<T, *>): Children =
|
||||
func.groupBy(columns.map { column -> column.getFieldData()!!.name })
|
||||
|
||||
fun orderByAsc(column: KProperty1<T, *>): Children = func.orderByAsc(column.getFieldData()!!.name)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun orderByAsc(vararg columns: KProperty1<T, *>): Children =
|
||||
func.orderByAsc(columns.map { column -> column.getFieldData()!!.name })
|
||||
|
||||
fun orderByDesc(column: KProperty1<T, *>): Children = func.orderByDesc(column.getFieldData()!!.name).uncheckedCast()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun orderByDesc(vararg columns: KProperty1<T, *>): Children =
|
||||
func.orderByDesc(columns.map { column -> column.getFieldData()!!.name }).uncheckedCast()
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage
|
||||
import com.baomidou.mybatisplus.extension.service.IService
|
||||
|
||||
|
||||
inline fun <reified T> IService<T>.update(
|
||||
wrapperBuilder: DdbesUpdateWrapper<T>.() -> Unit
|
||||
): Boolean {
|
||||
val wrapper = DdbesUpdateWrapper<T>()
|
||||
wrapper.wrapperBuilder()
|
||||
return update(wrapper)
|
||||
}
|
||||
|
||||
inline fun <reified T> IService<T>.update(
|
||||
queryBuilder: DdbesWrapperEnhance<T, UpdateWrapper<T>, DdbesUpdateWrapper<T>>.() -> Unit,
|
||||
updateBuilder: UpdateEnhance<T, DdbesUpdateWrapper<T>>.() -> Unit
|
||||
): Boolean {
|
||||
val wrapper = DdbesUpdateWrapper<T>()
|
||||
wrapper.queryBuilder()
|
||||
wrapper.updateBuilder()
|
||||
return update(wrapper)
|
||||
}
|
||||
|
||||
inline fun <reified T> IService<T>.remove(
|
||||
wrapperBuilder: DdbesQueryWrapper<T>.() -> Unit
|
||||
): Boolean {
|
||||
val wrapper = DdbesQueryWrapper<T>()
|
||||
wrapper.wrapperBuilder()
|
||||
return remove(wrapper)
|
||||
}
|
||||
|
||||
inline fun <reified T> IService<T>.getOne(
|
||||
throwEx: Boolean = true,
|
||||
wrapperBuilder: DdbesQueryWrapper<T>.() -> Unit
|
||||
): T {
|
||||
val wrapper = DdbesQueryWrapper<T>()
|
||||
wrapper.wrapperBuilder()
|
||||
return getOne(wrapper, throwEx)
|
||||
}
|
||||
|
||||
inline fun <reified T> IService<T>.count(
|
||||
wrapperBuilder: DdbesQueryWrapper<T>.() -> Unit
|
||||
): Long {
|
||||
val wrapper = DdbesQueryWrapper<T>()
|
||||
wrapper.wrapperBuilder()
|
||||
return count(wrapper)
|
||||
}
|
||||
|
||||
inline fun <reified T> IService<T>.list(
|
||||
wrapperBuilder: DdbesQueryWrapper<T>.() -> Unit
|
||||
): List<T> {
|
||||
val wrapper = DdbesQueryWrapper<T>()
|
||||
wrapper.wrapperBuilder()
|
||||
return list(wrapper)
|
||||
}
|
||||
|
||||
inline fun <reified T, E : IPage<T>> IService<T>.page(
|
||||
page: E,
|
||||
wrapperBuilder: DdbesQueryWrapper<T>.() -> Unit
|
||||
): E {
|
||||
val wrapper = DdbesQueryWrapper<T>()
|
||||
wrapper.wrapperBuilder()
|
||||
return page(page, wrapper)
|
||||
}
|
||||
|
||||
inline fun <reified T, E : IPage<Map<String, Any>>> IService<T>.pageMaps(
|
||||
page: E,
|
||||
wrapperBuilder: DdbesQueryWrapper<T>.() -> Unit
|
||||
): E {
|
||||
val wrapper = DdbesQueryWrapper<T>()
|
||||
wrapper.wrapperBuilder()
|
||||
return pageMaps(page, wrapper)
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import com.baomidou.mybatisplus.core.conditions.interfaces.Join
|
||||
|
||||
@MybatisPlusEnhanceDslMaker
|
||||
interface JoinEnhance<out Children> {
|
||||
val join: Join<out Children> get() = uncheckedCast()
|
||||
|
||||
/**
|
||||
* QueryWrapper<T>()
|
||||
* .xx()
|
||||
* .xxx()
|
||||
* ...
|
||||
* .limit1()
|
||||
*/
|
||||
fun limit1(): Children = join.last("LIMIT 1").uncheckedCast()
|
||||
|
||||
fun limit(count: Int): Children = join.last("LIMIT $count").uncheckedCast()
|
||||
fun limit(start: Int, count: Int): Children = join.last("LIMIT $start, $count").uncheckedCast()
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
@DslMarker
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class MybatisPlusEnhanceDslMaker
|
@ -0,0 +1,46 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.query.Query
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
@Suppress("unused")
|
||||
@MybatisPlusEnhanceDslMaker
|
||||
interface QueryEnhance<T, out Children : Wrapper<T>> : EnhanceEntityClassEnhance<T> {
|
||||
val query: Query<out Children, T, out Any> get() = uncheckedCast()
|
||||
|
||||
fun select(
|
||||
columns: Collection<String>,
|
||||
): Children = query.select(enhanceEntityClass) {
|
||||
it.column in columns
|
||||
}
|
||||
|
||||
fun select(
|
||||
columns: Sequence<String>,
|
||||
): Children = select(columns.toSet())
|
||||
|
||||
/**
|
||||
* QueryWrapper<T>().select(T::fieldName, value)
|
||||
*/
|
||||
fun select(
|
||||
vararg columns: KProperty1<T, *>,
|
||||
): Children = select(columns = columns as Array<out KProperty<*>>)
|
||||
|
||||
fun select(
|
||||
vararg columns: KProperty<*>,
|
||||
): Children = select(columns.mapNotNull {
|
||||
it.getFieldData()?.field?.name
|
||||
}.toSet())
|
||||
|
||||
fun fullSelect(
|
||||
vararg columns: KProperty<*>,
|
||||
): Children = selectMethod(uncheckedCast(), columns.mapNotNull {
|
||||
it.getFieldData()?.selectionName
|
||||
}.toTypedArray()).uncheckedCast()
|
||||
|
||||
fun joinSelect(
|
||||
vararg columns: KProperty<*>,
|
||||
): Children = fullSelect(columns = columns)
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
@MybatisPlusEnhanceDslMaker
|
||||
interface RegexAbstractWrapperEnhance<T, out W : AbstractWrapper<T, String, out W>, Children> {
|
||||
val wrapper: W get() = uncheckedCast()
|
||||
|
||||
infix fun String.regex(
|
||||
value: Any
|
||||
): Children = WrapperEnhance.regex(wrapper, this, value).uncheckedCast()
|
||||
|
||||
infix fun KProperty1<T, *>.regex(
|
||||
value: Any,
|
||||
): Children = WrapperEnhance.regex(wrapper, getFieldData()!!.name, value).uncheckedCast()
|
||||
|
||||
infix fun KProperty1<T, *>.regex(
|
||||
regex: Regex,
|
||||
): Children = WrapperEnhance.regex(wrapper, getFieldData()!!.name, regex.toString()).uncheckedCast()
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* SQL 访问增强工具,实现从属性到数据库字段的自动映射
|
||||
* @author 王景阔
|
||||
* 例:
|
||||
* Files::name.tableField
|
||||
* 可获得 Files 的 name 属性对应的字段名。
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import cn.tursom.core.*
|
||||
import cn.tursom.core.reference.StrongReference
|
||||
import cn.tursom.core.reflect.getAnnotation
|
||||
import com.baomidou.mybatisplus.annotation.TableField
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper
|
||||
import java.lang.reflect.Field
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
data class FieldData(
|
||||
val field: Field,
|
||||
val name: String,
|
||||
val selectionName: String,
|
||||
val tableField: TableField?,
|
||||
val column: String,
|
||||
val exist: Boolean = !field.transient && !field.static && tableField?.exist ?: true,
|
||||
)
|
||||
|
||||
val String.sqlName: String
|
||||
get() {
|
||||
val sb = StringBuilder()
|
||||
val iterator = iterator()
|
||||
sb.append(iterator.nextChar().lowercaseChar())
|
||||
iterator.forEach {
|
||||
if (it.isUpperCase()) {
|
||||
sb.append('_')
|
||||
sb.append(it.lowercaseChar())
|
||||
} else {
|
||||
sb.append(it)
|
||||
}
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
val Class<*>.tableName
|
||||
get() = getAnnotation<TableName>()?.value ?: simpleName.sqlName
|
||||
|
||||
internal val allSelectionFieldMap = ConcurrentHashMap<Class<*>, Array<out String>>()
|
||||
internal val fieldDataMap = ConcurrentHashMap<Field, FieldData>()
|
||||
internal val kPropertyFieldDataMap = ConcurrentHashMap<KProperty<*>, StrongReference<FieldData?>>()
|
||||
|
||||
val Iterable<Field>.filterNotExists
|
||||
get() = asSequence().filter {
|
||||
it.getFieldData().exist
|
||||
}
|
||||
|
||||
@get:JvmName("filterNotExistsField")
|
||||
val Sequence<Field>.filterNotExists
|
||||
get() = filter {
|
||||
it.getFieldData().exist
|
||||
}
|
||||
|
||||
@get:JvmName("filterNotExistsKProperty")
|
||||
val <T : KProperty<*>> Sequence<T>.filterNotExists
|
||||
get() = filter {
|
||||
it.getFieldData()?.exist ?: false
|
||||
}
|
||||
|
||||
fun Field.getFieldData(): FieldData = fieldDataMap.getOrPut(this) {
|
||||
val tableField = getAnnotation<TableField>()
|
||||
try {
|
||||
val tableInfo = TableInfoHelper.getTableInfo(declaringClass)
|
||||
tableInfo?.fieldList?.firstOrNull {
|
||||
it.field == this
|
||||
}?.let { tableFieldInfo ->
|
||||
FieldData(
|
||||
field = tableFieldInfo.field,
|
||||
name = "${tableInfo.tableName}.${tableFieldInfo.column}",
|
||||
selectionName = "${tableInfo.tableName}.${tableFieldInfo.column} as ${name.sqlName}",
|
||||
tableField = getAnnotation(),
|
||||
column = tableFieldInfo.column,
|
||||
)
|
||||
} ?: run {
|
||||
if (tableInfo != null) {
|
||||
FieldData(
|
||||
field = this,
|
||||
name = "${tableInfo.tableName}.${name.sqlName}",
|
||||
selectionName = "${tableInfo.tableName}.${name.sqlName}",
|
||||
tableField = tableField,
|
||||
column = tableField?.value ?: name.sqlName,
|
||||
)
|
||||
} else null
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
null
|
||||
} ?: run {
|
||||
val tableName = declaringClass.tableName
|
||||
FieldData(
|
||||
field = this,
|
||||
name = "$tableName.${tableField?.value ?: name.sqlName}",
|
||||
selectionName = if (tableField == null) {
|
||||
"$tableName.${name.sqlName}"
|
||||
} else {
|
||||
"$tableName.${tableField.value} as ${name.sqlName}"
|
||||
},
|
||||
tableField = tableField,
|
||||
column = tableField?.value ?: name.sqlName,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun KProperty<*>.getFieldData(): FieldData? {
|
||||
return kPropertyFieldDataMap.getOrPut(this) {
|
||||
StrongReference(javaField?.getFieldData() ?: run {
|
||||
val owner = owner ?: return@run null
|
||||
val enhanceField = findAnnotation<EnhanceField>() ?: return@run null
|
||||
if (enhanceField.field.isBlank()) {
|
||||
return@run null
|
||||
}
|
||||
owner.kotlin.allMemberPropertiesSequence.firstOrNull {
|
||||
it.name == enhanceField.field
|
||||
}?.getFieldData()
|
||||
})
|
||||
}?.r
|
||||
}
|
||||
|
||||
fun getAllSelectionFieldArray(clazz: Class<*>): Array<out String> = allSelectionFieldMap.getOrPut(clazz) {
|
||||
clazz.allFieldsSequence.filterNotExists.map {
|
||||
it.getFieldData().column
|
||||
}.toList().toTypedArray()
|
||||
}
|
||||
|
||||
fun getAllSelectionField(clazz: Class<*>): List<String> = allSelectionFieldMap.getOrPut(clazz) {
|
||||
clazz.allFieldsSequence.filterNotExists.map {
|
||||
it.getFieldData().column
|
||||
}.toList().toTypedArray()
|
||||
}.asList()
|
||||
|
||||
fun getSelectionField(vararg columns: KProperty<*>): Sequence<String> = getSelectionField(columns.asSequence())
|
||||
fun getSelectionField(columns: Iterable<KProperty<*>>): Sequence<String> = getSelectionField(columns.asSequence())
|
||||
|
||||
fun getSelectionField(columns: Sequence<KProperty<*>>): Sequence<String> = columns.map {
|
||||
it.getFieldData()
|
||||
}.filterNotNull().map {
|
||||
it.column
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import cn.tursom.core.allFieldsSequence
|
||||
import cn.tursom.core.uncheckedCast
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper
|
||||
import com.baomidou.mybatisplus.core.conditions.update.Update
|
||||
import java.sql.SQLException
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
@MybatisPlusEnhanceDslMaker
|
||||
interface UpdateEnhance<T, out Children : Wrapper<T>> {
|
||||
val update: Update<out Children, String> get() = uncheckedCast()
|
||||
|
||||
infix fun KProperty1<T, *>.set(
|
||||
value: Any?,
|
||||
): Children {
|
||||
if (getFieldData()?.exist == false) {
|
||||
logger.warn(
|
||||
"cannot get field data for {}, javaField: {}, kPropertyFieldDataMap: {}",
|
||||
this, javaField, kPropertyFieldDataMap[this]
|
||||
)
|
||||
throw SQLException("using non exist field $name")
|
||||
}
|
||||
return update.set(getFieldData()!!.name, value).uncheckedCast()
|
||||
}
|
||||
|
||||
fun set(vararg values: Pair<KProperty1<T, *>, Any?>): Children {
|
||||
values.forEach { (column, value) ->
|
||||
column set value
|
||||
}
|
||||
return uncheckedCast()
|
||||
}
|
||||
|
||||
fun set(value: T?): Children {
|
||||
value ?: return uncheckedCast()
|
||||
value.javaClass.allFieldsSequence.filterNotExists.forEach { field ->
|
||||
field.isAccessible = true
|
||||
update.set(field.getFieldData().name, field.get(value))
|
||||
}
|
||||
return uncheckedCast()
|
||||
}
|
||||
}
|
@ -3,13 +3,14 @@
|
||||
* @author 王景阔
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
@file:OptIn(UncheckedCast::class)
|
||||
|
||||
package cn.tursom.database
|
||||
package cn.tursom.database.mybatisplus
|
||||
|
||||
import cn.tursom.core.UncheckedCast
|
||||
import cn.tursom.core.allFieldsSequence
|
||||
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
|
||||
@ -20,40 +21,53 @@ 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.sql.SQLException
|
||||
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("cn.tursom.database")
|
||||
|
||||
val select: Query<*, *, Any>.(Array<out Any>) -> Any = Query<*, *, Any>::select
|
||||
val selectMethod: 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)
|
||||
inline fun <reified T, Children : Wrapper<T>, Q> Query<Children, T, Q>.select(
|
||||
columns: Collection<String>,
|
||||
): Children = select(T::class.java) {
|
||||
it.column in columns
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T, Children : Wrapper<T>, Q> Query<Children, T, Q>.select(
|
||||
columns: Sequence<String>,
|
||||
): Children = select(columns.toSet())
|
||||
|
||||
/**
|
||||
* 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)
|
||||
): Children = select(columns = columns as Array<out KProperty<*>>)
|
||||
|
||||
fun <T, Children : Wrapper<T>> Query<Children, T, String>.select(
|
||||
inline fun <reified T, Children : Wrapper<T>> Query<Children, T, String>.select(
|
||||
vararg columns: KProperty<*>,
|
||||
): Children = fullSelect(*columns)
|
||||
): Children = select(columns.mapNotNull {
|
||||
it.getFieldData()?.field?.name
|
||||
}.toSet())
|
||||
|
||||
fun <T, Children : Wrapper<T>> Query<Children, T, String>.fullSelect(
|
||||
inline fun <reified T, Children : Wrapper<T>> Query<Children, T, String>.fullSelect(
|
||||
vararg columns: KProperty<*>,
|
||||
): Children = select(columns.fullTableField)
|
||||
): Children = selectMethod(uncheckedCast(), columns.mapNotNull {
|
||||
it.getFieldData()?.selectionName
|
||||
}.toTypedArray()).uncheckedCast()
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Query<Children, T, String>.joinSelect(
|
||||
vararg columns: KProperty<*>,
|
||||
): Children = fullSelect(columns = columns)
|
||||
|
||||
/**
|
||||
* QueryWrapper<T>().eq(T::fieldName, value)
|
||||
@ -61,26 +75,37 @@ fun <T, Children : Wrapper<T>> Query<Children, T, String>.fullSelect(
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.eq(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any,
|
||||
): Children = eq(column.directTableField, value)
|
||||
): Children = eq(column.getFieldData()!!.name, value)
|
||||
|
||||
fun <T, Children : Wrapper<T>> Compare<Children, String>.eq(
|
||||
column: KProperty<*>,
|
||||
value: Any,
|
||||
): Children = eq(column.directTableField, value)
|
||||
): Children = eq(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.eq(
|
||||
column: Pair<KProperty1<T, *>, Any?>,
|
||||
): Children = eq(column.first.directTableField, column.second)
|
||||
): Children = eq(column.first.getFieldData()!!.name, column.second)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.eq(
|
||||
vararg pair: Pair<KProperty1<T, *>, Any?>,
|
||||
): Children = allEq(pair.tableField)
|
||||
): Children = eq(pair.asSequence())
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.eq(
|
||||
pair: Collection<Pair<KProperty1<T, *>, Any>>,
|
||||
): Children = allEq(pair.tableField)
|
||||
): Children = eq(pair.asSequence())
|
||||
|
||||
fun <Children> Compare<Children, String>.eq(vararg pair: Pair<KProperty<*>, *>): Children = allEq(pair.fullTableField)
|
||||
fun <Children> Compare<Children, String>.eq(
|
||||
pair: Sequence<Pair<KProperty<*>, *>>,
|
||||
): Children = allEq(
|
||||
pair.mapNotNull { (property, value) ->
|
||||
val fieldData = property.getFieldData() ?: return@mapNotNull null
|
||||
fieldData.name to value
|
||||
}.associate {
|
||||
it
|
||||
}
|
||||
)
|
||||
|
||||
fun <Children> Compare<Children, String>.eq(vararg pair: Pair<KProperty<*>, *>): Children = eq(pair.asSequence())
|
||||
|
||||
inline fun <reified T : Any, Children : Wrapper<T>> Compare<Children, String>.eq(entity: T): Children {
|
||||
val eqs = LinkedList<Pair<KProperty1<T, *>, Any>>()
|
||||
@ -91,6 +116,18 @@ inline fun <reified T : Any, Children : Wrapper<T>> Compare<Children, String>.eq
|
||||
return eq(eqs)
|
||||
}
|
||||
|
||||
@JvmName("eqMapEntry")
|
||||
fun <Children> Compare<Children, String>.eq(
|
||||
pair: Sequence<Map.Entry<KProperty<*>, *>>,
|
||||
): Children = allEq(
|
||||
pair.mapNotNull { (property, value) ->
|
||||
val fieldData = property.getFieldData() ?: return@mapNotNull null
|
||||
fieldData.name to value
|
||||
}.associate {
|
||||
it
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* QueryWrapper<T>().allEq(mapOf(
|
||||
* T::fieldName1 to value1,
|
||||
@ -99,144 +136,141 @@ inline fun <reified T : Any, Children : Wrapper<T>> Compare<Children, String>.eq
|
||||
* ))
|
||||
*/
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.allEq(map: Map<out KProperty1<T, *>, *>): Children =
|
||||
allEq(map.tableField)
|
||||
eq(map.asSequence())
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.allEq(vararg pair: Pair<KProperty1<T, *>, *>): Children =
|
||||
allEq(pair.tableField)
|
||||
eq(pair.asSequence())
|
||||
|
||||
fun <Children> Compare<Children, String>.allEq(vararg pair: Pair<KProperty<*>, *>): Children =
|
||||
allEq(pair.fullTableField)
|
||||
eq(pair.asSequence())
|
||||
|
||||
fun <Children> Compare<Children, String>.allFullEq(vararg pair: Pair<KProperty<*>, *>): Children =
|
||||
allEq(pair.fullTableField)
|
||||
eq(pair.asSequence())
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.ne(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = ne(column.directTableField, value)
|
||||
): Children = ne(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.gt(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = gt(column.directTableField, value)
|
||||
): Children = gt(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.ge(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = ge(column.directTableField, value)
|
||||
): Children = ge(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.lt(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = lt(column.directTableField, value)
|
||||
): Children = lt(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.le(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = le(column.directTableField, value)
|
||||
): Children = le(column.getFieldData()!!.name, 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)
|
||||
): Children = between(column.getFieldData()!!.name, 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)
|
||||
): Children = notBetween(column.getFieldData()!!.name, val1, val2)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.like(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = like(column.directTableField, value)
|
||||
): Children = like(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.notLike(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = notLike(column.directTableField, value)
|
||||
): Children = notLike(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.likeLeft(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = likeLeft(column.directTableField, value)
|
||||
): Children = likeLeft(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Compare<Children, String>.likeRight(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = likeRight(column.directTableField, value)
|
||||
): Children = likeRight(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.having(
|
||||
column: KProperty1<T, *>,
|
||||
vararg value: Any?,
|
||||
): Children = having(column.directTableField, value)
|
||||
): Children = having(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.isNull(column: KProperty1<T, *>): Children =
|
||||
isNull(column.directTableField)
|
||||
isNull(column.getFieldData()!!.name)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.isNotNull(column: KProperty1<T, *>): Children =
|
||||
isNotNull(column.directTableField)
|
||||
isNotNull(column.getFieldData()!!.name)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.`in`(
|
||||
column: KProperty1<T, *>,
|
||||
value: Any?,
|
||||
): Children = `in`(column.directTableField, value)
|
||||
): Children = `in`(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.`in`(
|
||||
column: KProperty1<T, *>,
|
||||
value: Collection<Any?>,
|
||||
): Children = `in`(column.directTableField, value)
|
||||
): Children = `in`(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.`in`(
|
||||
column: KProperty1<T, *>,
|
||||
vararg value: Any,
|
||||
): Children = `in`(column.directTableField, value)
|
||||
): Children = `in`(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.notIn(
|
||||
column: KProperty1<T, *>,
|
||||
value: Collection<Any?>,
|
||||
): Children = notIn(column.directTableField, value)
|
||||
): Children = notIn(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.notIn(
|
||||
column: KProperty1<T, *>,
|
||||
vararg value: Any,
|
||||
): Children = notIn(column.directTableField, value)
|
||||
): Children = notIn(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.inSql(
|
||||
column: KProperty1<T, *>,
|
||||
value: String?,
|
||||
): Children = inSql(column.directTableField, value)
|
||||
): Children = inSql(column.getFieldData()!!.name, value)
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.notInSql(
|
||||
column: KProperty1<T, *>,
|
||||
value: String?,
|
||||
): Children = notInSql(column.directTableField, value)
|
||||
): Children = notInSql(column.getFieldData()!!.name, 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)
|
||||
groupBy(column.getFieldData()!!.name)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.groupBy(vararg column: KProperty1<T, *>): Children =
|
||||
groupBy(column.directTableField.asList()) as Children
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.groupBy(vararg columns: KProperty1<T, *>): Children =
|
||||
groupBy(columns.map { column -> column.getFieldData()!!.name }) 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)
|
||||
orderByAsc(column.getFieldData()!!.name)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByAsc(vararg column: KProperty1<T, *>): Children =
|
||||
orderByAsc(column.directTableField.asList()) as Children
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByAsc(vararg columns: KProperty1<T, *>): Children =
|
||||
orderByAsc(columns.map { column -> column.getFieldData()!!.name }) 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)
|
||||
orderByDesc(column.getFieldData()!!.name)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByDesc(vararg column: KProperty1<T, *>): Children =
|
||||
orderByDesc(column.directTableField.asList()) as Children
|
||||
inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByDesc(vararg columns: KProperty1<T, *>): Children =
|
||||
orderByDesc(columns.map { column -> column.getFieldData()!!.name }) as Children
|
||||
|
||||
|
||||
/**
|
||||
@ -248,27 +282,24 @@ inline fun <reified T, Children : Wrapper<T>> Func<Children, String>.orderByDesc
|
||||
*/
|
||||
fun <Children> Join<Children>.limit1(): Children = last("LIMIT 1")
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Update<Children, String>.set(
|
||||
fun <Children> Join<Children>.limit(count: Int): Children = last("LIMIT $count")
|
||||
fun <Children> Join<Children>.limit(start: Int, count: Int): Children = last("LIMIT $start, $count")
|
||||
|
||||
fun <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()
|
||||
if (column.getFieldData()?.exist == false) {
|
||||
logger.warn(
|
||||
"cannot get field data for {}, javaField: {}, kPropertyFieldDataMap: {}",
|
||||
column, column.javaField, kPropertyFieldDataMap[column]
|
||||
)
|
||||
throw SQLException("using non exist field ${column.name}")
|
||||
}
|
||||
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)
|
||||
return set(column.getFieldData()!!.name, value)
|
||||
}
|
||||
|
||||
inline fun <reified T, Children : Wrapper<T>> Update<Children, String>.set(vararg values: Pair<KProperty1<T, *>, Any?>): Children {
|
||||
fun <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 {
|
||||
@ -278,23 +309,13 @@ inline fun <reified T, Children : Wrapper<T>> Update<Children, String>.set(varar
|
||||
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()
|
||||
fun <Children> Update<Children, String>.set(value: Any?): Children {
|
||||
value ?: return uncheckedCast()
|
||||
value.javaClass.allFieldsSequence.filterNotExists.forEach { field ->
|
||||
field.isAccessible = true
|
||||
set(field.getFieldData().name, field.get(value))
|
||||
}
|
||||
return uncheckedCast()
|
||||
}
|
||||
|
||||
object Regexp : ISqlSegment {
|
||||
@ -310,9 +331,10 @@ object WrapperEnhance : AbstractWrapper<Any, String, WrapperEnhance>() {
|
||||
initNeed()
|
||||
}
|
||||
|
||||
fun <T, W : AbstractWrapper<T, String, W>> regex(wrapper: W, column: String, value: Any): W {
|
||||
fun <T, W : AbstractWrapper<T, String, out 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()
|
||||
val genParamName =
|
||||
Constants.WRAPPER_PARAM + (paramNameSeqField.get(wrapper) as AtomicInteger).incrementAndGet()
|
||||
wrapper.paramNameValuePairs[genParamName] = value
|
||||
"#{${Constants.WRAPPER}${Constants.WRAPPER_PARAM_MIDDLE}$genParamName}"
|
||||
})
|
||||
@ -325,8 +347,8 @@ fun <T, W : AbstractWrapper<T, String, W>> W.regex(column: String, value: Any):
|
||||
|
||||
inline fun <reified T, W : AbstractWrapper<T, String, W>> W.regex(
|
||||
column: KProperty1<T, *>, value: Any,
|
||||
): W = WrapperEnhance.regex(this, column.directTableField, value)
|
||||
): W = WrapperEnhance.regex(this, column.getFieldData()!!.name, 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())
|
||||
): W = WrapperEnhance.regex(this, column.getFieldData()!!.name, regex.toString())
|
@ -1,5 +1,6 @@
|
||||
package cn.tursom.web.router
|
||||
|
||||
import cn.tursom.core.allMethodsSequence
|
||||
import cn.tursom.core.buffer.ByteBuffer
|
||||
import cn.tursom.core.json.JsonWorkerImpl
|
||||
import cn.tursom.core.lambda
|
||||
@ -55,7 +56,9 @@ open class RoutedHttpHandler(
|
||||
if ((target.isEmpty())) {
|
||||
addRouter(this)
|
||||
} else {
|
||||
target.forEach(::addRouter)
|
||||
target.forEach {
|
||||
addRouter(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,9 +93,8 @@ open class RoutedHttpHandler(
|
||||
|
||||
open fun addRouter(handler: Any) {
|
||||
log?.info("add router {}", handler)
|
||||
@Suppress("LeakingThis")
|
||||
val clazz = handler.javaClass
|
||||
clazz.methods.forEach { method ->
|
||||
handler.javaClass.allMethodsSequence.forEach { method ->
|
||||
method.isAccessible = true
|
||||
method.parameterTypes.let {
|
||||
if (!(it.size == 1 && HttpContent::class.java.isAssignableFrom(it[0])) && it.isNotEmpty()) {
|
||||
return@forEach
|
||||
@ -134,7 +136,7 @@ open class RoutedHttpHandler(
|
||||
val mapping = obj::class.java.getAnnotation(Mapping::class.java)?.route ?: arrayOf("")
|
||||
method.annotations.forEach { annotation ->
|
||||
val (routes, router) = getRoutes(annotation) ?: return@forEach
|
||||
log?.info("mapping {} => {}", routes, method)
|
||||
log?.info("mapping {} {} => {}", getRouteMethod(annotation), routes, method)
|
||||
routes.forEach { route ->
|
||||
if (mapping.isEmpty()) {
|
||||
addRouter(obj, method, route, router)
|
||||
@ -211,7 +213,7 @@ open class RoutedHttpHandler(
|
||||
method.annotations.forEach { annotation ->
|
||||
val (routes, router) = getRoutes(annotation) ?: return@forEach
|
||||
routes.forEach { route ->
|
||||
log?.info("delete route {} => {}", route, method)
|
||||
log?.info("delete route {} {} => {}", getRouteMethod(annotation), route, method)
|
||||
if (mapping.isEmpty()) {
|
||||
deleteMapping(obj, route, router)
|
||||
} else mapping.forEach {
|
||||
@ -228,8 +230,22 @@ open class RoutedHttpHandler(
|
||||
}
|
||||
}
|
||||
|
||||
protected fun getRouteMethod(annotation: Annotation): String? = when (annotation) {
|
||||
is Mapping -> annotation.method.ifEmpty { annotation.methodEnum.method }
|
||||
is GetMapping -> "GET"
|
||||
is PostMapping -> "POST"
|
||||
is PutMapping -> "PUT"
|
||||
is DeleteMapping -> "DELETE"
|
||||
is PatchMapping -> "PATCH"
|
||||
is TraceMapping -> "TRACE"
|
||||
is HeadMapping -> "HEAD"
|
||||
is OptionsMapping -> "OPTIONS"
|
||||
is ConnectMapping -> "CONNECT"
|
||||
else -> null
|
||||
}
|
||||
|
||||
protected fun getRoutes(annotation: Annotation) = when (annotation) {
|
||||
is Mapping -> annotation.route to getRouter(annotation.method.let { if (it.isEmpty()) annotation.methodEnum.method else it })
|
||||
is Mapping -> annotation.route to getRouter(annotation.method.ifEmpty { annotation.methodEnum.method })
|
||||
is GetMapping -> annotation.route to getRouter("GET")
|
||||
is PostMapping -> annotation.route to getRouter("POST")
|
||||
is PutMapping -> annotation.route to getRouter("PUT")
|
||||
@ -245,7 +261,7 @@ open class RoutedHttpHandler(
|
||||
protected fun getRouter(method: String): Router<Pair<Any?, (HttpContent) -> Any?>> = when {
|
||||
method.isEmpty() -> router
|
||||
else -> {
|
||||
val upperCaseMethod = method.toUpperCase()
|
||||
val upperCaseMethod = method.uppercase()
|
||||
var router = routerMap[upperCaseMethod]
|
||||
if (router == null) {
|
||||
router = routerMaker()
|
||||
|
@ -7,6 +7,7 @@ plugins {
|
||||
dependencies {
|
||||
implementation(project(":"))
|
||||
implementation(project(":ts-web"))
|
||||
implementation(project(":ts-core"))
|
||||
implementation(project(":ts-core:ts-buffer"))
|
||||
implementation(project(":ts-core:ts-json"))
|
||||
implementation(group = "org.slf4j", name = "slf4j-api", version = "1.7.32")
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.tursom.web.router
|
||||
|
||||
import cn.tursom.core.allMethodsSequence
|
||||
import cn.tursom.web.HttpContent
|
||||
import cn.tursom.web.MutableHttpContent
|
||||
import cn.tursom.web.mapping.*
|
||||
@ -11,16 +12,18 @@ import kotlinx.coroutines.launch
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.PrintStream
|
||||
import java.util.*
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.jvm.jvmErasure
|
||||
import kotlin.reflect.jvm.kotlinFunction
|
||||
|
||||
@Suppress("ProtectedInFinal", "unused", "MemberVisibilityCanBePrivate")
|
||||
open class AsyncRoutedHttpHandler(
|
||||
vararg target: Any,
|
||||
routerMaker: () -> Router<Pair<Any?, (HttpContent) -> Any?>> = { SimpleRouter() },
|
||||
val asyncRouterMaker: () -> Router<Pair<Any?, suspend (HttpContent) -> Unit>> = { SimpleRouter() }
|
||||
) : RoutedHttpHandler(target, routerMaker) {
|
||||
) : RoutedHttpHandler(target = target, routerMaker = routerMaker) {
|
||||
protected val asyncRouter: Router<Pair<Any?, suspend (HttpContent) -> Unit>> = asyncRouterMaker()
|
||||
protected val asyncRouterMap: HashMap<String, Router<Pair<Any?, suspend (HttpContent) -> Unit>>> = HashMap()
|
||||
|
||||
@ -82,15 +85,21 @@ open class AsyncRoutedHttpHandler(
|
||||
|
||||
override fun addRouter(handler: Any) {
|
||||
super.addRouter(handler)
|
||||
handler::class.members.forEach { member ->
|
||||
if (member.isSuspend) {
|
||||
member.parameters.let {
|
||||
handler.javaClass.allMethodsSequence.forEach { method ->
|
||||
val function = try {
|
||||
method.kotlinFunction ?: return@forEach
|
||||
} catch (e: Exception) {
|
||||
return@forEach
|
||||
}
|
||||
method.isAccessible = true
|
||||
if (function.isSuspend) {
|
||||
function.parameters.let {
|
||||
if (it.size != 1 && !(it.size == 2 && HttpContent::class.java.isAssignableFrom(it[1].type.jvmErasure.java))) {
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
log?.trace("mapping {} {}", member, member.parameters)
|
||||
insertMapping(handler, member)
|
||||
log?.trace("mapping {} {}", function, function.parameters)
|
||||
insertMapping(handler, function)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,7 +109,7 @@ open class AsyncRoutedHttpHandler(
|
||||
method.annotations.forEach { annotation ->
|
||||
val (routes, router) = getAsyncRoutes(annotation) ?: return@forEach
|
||||
@Suppress("DuplicatedCode")
|
||||
log?.info("mapping {} => {}", routes, method)
|
||||
log?.info("mapping {} {} => {}", getRouteMethod(annotation), routes, method)
|
||||
routes.forEach { route ->
|
||||
if (mapping.isEmpty()) {
|
||||
addRouter(obj, method, route, router)
|
||||
@ -174,7 +183,7 @@ open class AsyncRoutedHttpHandler(
|
||||
protected fun getAsyncRouter(method: String): Router<Pair<Any?, suspend (HttpContent) -> Unit>> = when {
|
||||
method.isEmpty() -> asyncRouter
|
||||
else -> {
|
||||
val upperCaseMethod = method.toUpperCase()
|
||||
val upperCaseMethod = method.uppercase(Locale.getDefault())
|
||||
var router = asyncRouterMap[upperCaseMethod]
|
||||
if (router == null) {
|
||||
router = asyncRouterMaker()
|
||||
|
Loading…
Reference in New Issue
Block a user