-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #476 from FxRayHughes/database-orm
[Easy-ORM] ORMLite的包装框架
- Loading branch information
Showing
7 changed files
with
528 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# ORM-Lite 拓展工具 | ||
|
||
# 文档: https://taboolib.feishu.cn/wiki/N8S2wFXH6ioimpkc6mdcxrCJn7G?from=from_copylink |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
dependencies { | ||
compileOnly("com.zaxxer:HikariCP:4.0.3") | ||
compileOnly("com.j256.ormlite:ormlite-core:6.1") | ||
compileOnly("com.j256.ormlite:ormlite-jdbc:6.1") | ||
compileOnly(project(":common")) | ||
compileOnly(project(":common-env")) | ||
compileOnly(project(":common-reflex")) | ||
compileOnly(project(":common-platform-api")) | ||
compileOnly(project(":common-util")) | ||
compileOnly(project(":module:basic:basic-configuration")) | ||
compileOnly(project(":module:database")) | ||
} |
20 changes: 20 additions & 0 deletions
20
module/database/database-orm/src/main/kotlin/taboolib/expansion/orm/DaoGetter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package taboolib.expansion.orm | ||
|
||
import com.j256.ormlite.dao.Dao | ||
import kotlin.reflect.KProperty | ||
|
||
/** | ||
* 用于获取Dao的代理类 | ||
*/ | ||
class DaoGetter<K, ID>(val entity: Class<K>, val id: Class<ID>) { | ||
|
||
// 拎出来进行加载 节省性能 | ||
private val daoValue by lazy { | ||
EasyORM.dao[entity.name] as Dao<K, ID> | ||
} | ||
|
||
operator fun getValue(ref: Any?, property: KProperty<*>): Dao<K, ID> { | ||
return daoValue | ||
} | ||
|
||
} |
25 changes: 25 additions & 0 deletions
25
module/database/database-orm/src/main/kotlin/taboolib/expansion/orm/DaoTable.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package taboolib.expansion.orm | ||
|
||
import com.j256.ormlite.dao.Dao | ||
import com.j256.ormlite.misc.BaseDaoEnabled | ||
import java.lang.reflect.ParameterizedType | ||
|
||
/** | ||
* DaoTable 的代理 | ||
* 将数据类继承此类后 | ||
* 可通过数据对象进行Dao的操作 | ||
*/ | ||
open class DaoTable<T, ID> : BaseDaoEnabled<T, ID>() { | ||
|
||
val type: Class<T> | ||
|
||
init { | ||
@Suppress("UNCHECKED_CAST") | ||
type = (javaClass.genericSuperclass as ParameterizedType) | ||
.actualTypeArguments[0] as Class<T> | ||
|
||
dao = EasyORM.dao[type.name] as Dao<T, ID> | ||
} | ||
|
||
|
||
} |
169 changes: 169 additions & 0 deletions
169
module/database/database-orm/src/main/kotlin/taboolib/expansion/orm/EasyORM.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
package taboolib.expansion.orm | ||
|
||
import com.j256.ormlite.dao.Dao | ||
import com.j256.ormlite.dao.DaoManager | ||
import com.j256.ormlite.field.DatabaseField | ||
import com.j256.ormlite.jdbc.DataSourceConnectionSource | ||
import com.j256.ormlite.table.DatabaseTable | ||
import com.j256.ormlite.table.TableUtils | ||
import com.zaxxer.hikari.HikariConfig | ||
import com.zaxxer.hikari.HikariDataSource | ||
import org.tabooproject.reflex.ClassField | ||
import org.tabooproject.reflex.ReflexClass | ||
import taboolib.common.Inject | ||
import taboolib.common.LifeCycle | ||
import taboolib.common.env.RuntimeDependencies | ||
import taboolib.common.env.RuntimeDependency | ||
import taboolib.common.inject.ClassVisitor | ||
import taboolib.common.platform.Awake | ||
import taboolib.module.database.Database | ||
import taboolib.module.database.Host | ||
import java.io.Closeable | ||
import java.util.* | ||
import java.util.concurrent.ConcurrentHashMap | ||
|
||
|
||
@Inject | ||
@Awake | ||
@RuntimeDependencies( | ||
RuntimeDependency(value = "!com.j256.ormlite:ormlite-core:6.1"), | ||
RuntimeDependency(value = "!com.j256.ormlite:ormlite-jdbc:6.1"), | ||
) | ||
object EasyORM : ClassVisitor(0), Closeable { | ||
|
||
private lateinit var dataSource: HikariDataSource | ||
lateinit var connectionSource: DataSourceConnectionSource | ||
|
||
lateinit var databaseHost: Host<*> | ||
|
||
/** | ||
* 初始化数据库连接,应该在 Enable 及以前完成 | ||
*/ | ||
fun init(host: Host<*>, hikariConfig: HikariConfig? = null) { | ||
databaseHost = host | ||
dataSource = Database.createDataSource(host, hikariConfig) as HikariDataSource | ||
connectionSource = DataSourceConnectionSource(dataSource, databaseHost.connectionUrl) | ||
register() | ||
} | ||
|
||
/** | ||
* 数据表列表 | ||
* key: 表名 | ||
* value: 表对应的类 | ||
*/ | ||
val tables = ConcurrentHashMap<String, ReflexClass>() | ||
|
||
/** | ||
* 数据表列 | ||
* key: 数据对象的类 | ||
* value: 列 | ||
*/ | ||
val tablesColumn = ConcurrentHashMap<Class<*>, MutableMap<String, TableColumn>>() | ||
|
||
/** | ||
* 代表数据表对象的列 | ||
*/ | ||
data class TableColumn( | ||
val owner: Class<*>, | ||
val fieldName: String, | ||
val field: ClassField, | ||
// 原始名字 | ||
val originalName: String, | ||
// 注解种的名字 没有则为原始名字 | ||
val columnName: String, | ||
// 处理过的名字 | ||
val columnNameProcessed: String | ||
) | ||
|
||
/** | ||
* 数据表的DAO | ||
* key: 表名 | ||
* value: DAO | ||
*/ | ||
val dao = ConcurrentHashMap<String, Dao<*, *>>() | ||
|
||
override fun getLifeCycle(): LifeCycle { | ||
return LifeCycle.LOAD | ||
} | ||
|
||
override fun visitStart(clazz: ReflexClass) { | ||
if (clazz.hasAnnotation(DatabaseTable::class.java)) { | ||
val annotation = clazz.getAnnotation(DatabaseTable::class.java) | ||
val tableName = annotation.enum("tableName", "none") | ||
if (tableName != "none") { | ||
tables[tableName] = clazz | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* 注册 | ||
* 1. 获取表名 | ||
* 2. 注册 Dao 单例对象 | ||
* 3. 判断表是否存在,不存在则创建 | ||
* 4. 注册列 | ||
*/ | ||
private fun register() { | ||
tables.forEach { (name, clazz) -> | ||
val clazzType = runCatching { Class.forName(clazz.name) }.getOrNull() ?: return@forEach | ||
// 获取ID | ||
val idField = clazzType.declaredFields.firstOrNull { | ||
it.isAnnotationPresent(DatabaseField::class.java) && ( | ||
it.getAnnotation(DatabaseField::class.java).id || | ||
it.getAnnotation(DatabaseField::class.java).generatedId || | ||
it.getAnnotation(DatabaseField::class.java).uniqueIndex | ||
) | ||
} | ||
if (idField == null) { | ||
error("Data table $name ID field not found") | ||
} | ||
val id = idField.type | ||
val type = clazzType | ||
val createDao = createDaoFromClass(connectionSource, type, id) | ||
if (!createDao.isTableExists) { | ||
TableUtils.createTable(connectionSource, clazzType) | ||
} | ||
// 开始注册列 | ||
val columnMap = mutableMapOf<String, TableColumn>() | ||
clazz.structure.fields.forEach { field -> | ||
if (field.isAnnotationPresent(DatabaseField::class.java)) { | ||
val annotation = field.getAnnotation(DatabaseField::class.java) | ||
val columnName = annotation.enum("columnName", field.name) | ||
columnMap[field.name] = TableColumn( | ||
clazzType, | ||
field.name, | ||
field, | ||
field.name, | ||
columnName, | ||
camelToSnake(columnName) | ||
) | ||
} | ||
} | ||
tablesColumn[clazzType] = columnMap | ||
} | ||
} | ||
|
||
override fun close() { | ||
dataSource.close() | ||
} | ||
|
||
/** | ||
* 用于骗过编译器的方法 | ||
*/ | ||
fun <T, D> createDaoFromClass(connectionSource: DataSourceConnectionSource, clazz: Class<T>, id: Class<D>): Dao<T, D> { | ||
val createDao = DaoManager.createDao(connectionSource, clazz) | ||
dao[clazz.name] = createDao as Dao<*, *> | ||
return createDao as Dao<T, D> | ||
} | ||
|
||
fun camelToSnake(name: String): String { | ||
val regex = Regex("([a-z0-9])([A-Z])") | ||
// 将大写字母与小写字母相连的位置插入下划线,并转换为小写 | ||
return name.replace(regex) { matchResult -> | ||
"${matchResult.groups[1]!!.value}_${matchResult.groups[2]!!.value}" | ||
}.lowercase(Locale.getDefault()) | ||
} | ||
|
||
|
||
} | ||
|
Oops, something went wrong.