1
This commit is contained in:
parent
d126bd5783
commit
63a18f1dbd
146
vertx-demo/src/main/kotlin/app/example/SqlAnnotationExample.kt
Normal file
146
vertx-demo/src/main/kotlin/app/example/SqlAnnotationExample.kt
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package app.example
|
||||||
|
|
||||||
|
import app.util.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表名注解示例
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class TableName(val value: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列名注解示例
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.FIELD)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class Column(val value: String, val type: String = "VARCHAR(255)")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键注解示例
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.FIELD)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class Id(val value: Boolean = true)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 非空注解示例
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.FIELD)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class NotNull(val value: Boolean = true)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认值注解示例
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.FIELD)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class DefaultValue(val value: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户实体类示例
|
||||||
|
*/
|
||||||
|
@TableName("tb_user")
|
||||||
|
class User {
|
||||||
|
@Id
|
||||||
|
@Column("id", "SERIAL")
|
||||||
|
@NotNull
|
||||||
|
var id: Long = 0
|
||||||
|
|
||||||
|
@Column("username")
|
||||||
|
@NotNull
|
||||||
|
var username: String = ""
|
||||||
|
|
||||||
|
@Column("email")
|
||||||
|
var email: String? = null
|
||||||
|
|
||||||
|
@Column("created_at", "TIMESTAMP")
|
||||||
|
@DefaultValue("CURRENT_TIMESTAMP")
|
||||||
|
var createdAt: String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL注解映射示例
|
||||||
|
*/
|
||||||
|
class SqlAnnotationExample {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* 创建注解映射器
|
||||||
|
*/
|
||||||
|
fun createMapper(): SqlAnnotationMapper {
|
||||||
|
val mapper = SqlAnnotationMapper()
|
||||||
|
|
||||||
|
// 设置表名映射
|
||||||
|
mapper.tableName = AnnotationMapping(
|
||||||
|
annotationClass = TableName::class,
|
||||||
|
propertyName = "value"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 设置列名映射
|
||||||
|
mapper.addColumnMapping(ColumnMapping(
|
||||||
|
nameMapping = AnnotationMapping(
|
||||||
|
annotationClass = Column::class,
|
||||||
|
propertyName = "value"
|
||||||
|
),
|
||||||
|
typeMapping = AnnotationMapping(
|
||||||
|
annotationClass = Column::class,
|
||||||
|
propertyName = "type"
|
||||||
|
),
|
||||||
|
nullableMapping = AnnotationMapping(
|
||||||
|
annotationClass = NotNull::class,
|
||||||
|
propertyName = "value"
|
||||||
|
),
|
||||||
|
defaultValueMapping = AnnotationMapping(
|
||||||
|
annotationClass = DefaultValue::class,
|
||||||
|
propertyName = "value"
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
// 设置主键映射
|
||||||
|
mapper.primaryKeyMapping = AnnotationMapping(
|
||||||
|
annotationClass = Id::class,
|
||||||
|
propertyName = "value"
|
||||||
|
)
|
||||||
|
|
||||||
|
return mapper
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试SQL生成
|
||||||
|
*/
|
||||||
|
fun testSqlGeneration() {
|
||||||
|
// 创建注解映射器
|
||||||
|
val mapper = createMapper()
|
||||||
|
|
||||||
|
// 生成各种SQL
|
||||||
|
val createTableSql = SqlGenerator.generateCreateTableSql(User::class, mapper)
|
||||||
|
val insertSql = SqlGenerator.generateInsertSql(User::class, mapper)
|
||||||
|
val updateSql = SqlGenerator.generateUpdateSql(User::class, mapper)
|
||||||
|
val deleteSql = SqlGenerator.generateDeleteSql(User::class, mapper)
|
||||||
|
val selectSql = SqlGenerator.generateSelectSql(User::class, mapper)
|
||||||
|
val selectByPkSql = SqlGenerator.generateSelectByPrimaryKeySql(User::class, mapper)
|
||||||
|
|
||||||
|
// 打印SQL
|
||||||
|
println("Create Table SQL:")
|
||||||
|
println(createTableSql)
|
||||||
|
println("\nInsert SQL:")
|
||||||
|
println(insertSql)
|
||||||
|
println("\nUpdate SQL:")
|
||||||
|
println(updateSql)
|
||||||
|
println("\nDelete SQL:")
|
||||||
|
println(deleteSql)
|
||||||
|
println("\nSelect SQL:")
|
||||||
|
println(selectSql)
|
||||||
|
println("\nSelect By PK SQL:")
|
||||||
|
println(selectByPkSql)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主函数,用于演示
|
||||||
|
*/
|
||||||
|
fun main() {
|
||||||
|
SqlAnnotationExample.testSqlGeneration()
|
||||||
|
}
|
||||||
187
vertx-demo/src/main/kotlin/app/util/SqlAnnotationMapper.kt
Normal file
187
vertx-demo/src/main/kotlin/app/util/SqlAnnotationMapper.kt
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
package app.util
|
||||||
|
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL注解映射中间类
|
||||||
|
* 用于记录从哪些注解获取SQL生成所需的信息
|
||||||
|
*/
|
||||||
|
class SqlAnnotationMapper {
|
||||||
|
/**
|
||||||
|
* 表名映射信息
|
||||||
|
*/
|
||||||
|
var tableName: AnnotationMapping? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列名映射信息列表
|
||||||
|
*/
|
||||||
|
var columnMappings: MutableList<ColumnMapping> = mutableListOf()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键映射信息
|
||||||
|
*/
|
||||||
|
var primaryKeyMapping: AnnotationMapping? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 其他自定义映射
|
||||||
|
*/
|
||||||
|
var customMappings: MutableMap<String, AnnotationMapping> = mutableMapOf()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个列映射
|
||||||
|
*/
|
||||||
|
fun addColumnMapping(columnMapping: ColumnMapping) {
|
||||||
|
columnMappings.add(columnMapping)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个自定义映射
|
||||||
|
*/
|
||||||
|
fun addCustomMapping(key: String, mapping: AnnotationMapping) {
|
||||||
|
customMappings[key] = mapping
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注解映射类
|
||||||
|
* 记录从哪个注解的哪个属性获取信息
|
||||||
|
*/
|
||||||
|
data class AnnotationMapping(
|
||||||
|
/** 注解类 */
|
||||||
|
val annotationClass: KClass<out Annotation>,
|
||||||
|
/** 注解属性名 */
|
||||||
|
val propertyName: String = "value"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列映射信息
|
||||||
|
*/
|
||||||
|
data class ColumnMapping(
|
||||||
|
/** 字段名称映射 */
|
||||||
|
val nameMapping: AnnotationMapping,
|
||||||
|
/** 字段类型映射,可选 */
|
||||||
|
val typeMapping: AnnotationMapping? = null,
|
||||||
|
/** 是否可为空映射,可选 */
|
||||||
|
val nullableMapping: AnnotationMapping? = null,
|
||||||
|
/** 默认值映射,可选 */
|
||||||
|
val defaultValueMapping: AnnotationMapping? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL注解映射生成器
|
||||||
|
* 用于生成和使用SQL注解映射中间类
|
||||||
|
*/
|
||||||
|
class SqlAnnotationMapperGenerator {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* 从实体类获取SQL信息
|
||||||
|
* @param entityClass 实体类
|
||||||
|
* @param mapper 注解映射中间类
|
||||||
|
* @return SQL信息
|
||||||
|
*/
|
||||||
|
fun extractSqlInfo(entityClass: KClass<*>, mapper: SqlAnnotationMapper): SqlInfo {
|
||||||
|
val sqlInfo = SqlInfo()
|
||||||
|
|
||||||
|
// 获取表名
|
||||||
|
mapper.tableName?.let { tableNameMapping ->
|
||||||
|
val annotation = entityClass.annotations.find { it.annotationClass == tableNameMapping.annotationClass.java }
|
||||||
|
annotation?.let {
|
||||||
|
val method = it.javaClass.getMethod(tableNameMapping.propertyName)
|
||||||
|
sqlInfo.tableName = method.invoke(it) as String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取实体类的所有字段
|
||||||
|
entityClass.java.declaredFields.forEach { field ->
|
||||||
|
// 获取列信息
|
||||||
|
val columnInfo = ColumnInfo()
|
||||||
|
|
||||||
|
// 处理每个列映射
|
||||||
|
mapper.columnMappings.forEach { columnMapping ->
|
||||||
|
val nameAnnotation = field.annotations.find {
|
||||||
|
it.annotationClass.java == columnMapping.nameMapping.annotationClass.java
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameAnnotation != null) {
|
||||||
|
val nameMethod = nameAnnotation.javaClass.getMethod(columnMapping.nameMapping.propertyName)
|
||||||
|
columnInfo.name = nameMethod.invoke(nameAnnotation) as String? ?: field.name
|
||||||
|
|
||||||
|
// 处理类型映射
|
||||||
|
columnMapping.typeMapping?.let { typeMapping ->
|
||||||
|
val typeAnnotation = field.annotations.find {
|
||||||
|
it.annotationClass.java == typeMapping.annotationClass.java
|
||||||
|
}
|
||||||
|
if (typeAnnotation != null) {
|
||||||
|
val typeMethod = typeAnnotation.javaClass.getMethod(typeMapping.propertyName)
|
||||||
|
columnInfo.type = typeMethod.invoke(typeAnnotation) as String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理可空映射
|
||||||
|
columnMapping.nullableMapping?.let { nullableMapping ->
|
||||||
|
val nullableAnnotation = field.annotations.find {
|
||||||
|
it.annotationClass.java == nullableMapping.annotationClass.java
|
||||||
|
}
|
||||||
|
if (nullableAnnotation != null) {
|
||||||
|
val nullableMethod = nullableAnnotation.javaClass.getMethod(nullableMapping.propertyName)
|
||||||
|
columnInfo.nullable = nullableMethod.invoke(nullableAnnotation) as Boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理默认值映射
|
||||||
|
columnMapping.defaultValueMapping?.let { defaultValueMapping ->
|
||||||
|
val defaultValueAnnotation = field.annotations.find {
|
||||||
|
it.annotationClass.java == defaultValueMapping.annotationClass.java
|
||||||
|
}
|
||||||
|
if (defaultValueAnnotation != null) {
|
||||||
|
val defaultValueMethod = defaultValueAnnotation.javaClass.getMethod(defaultValueMapping.propertyName)
|
||||||
|
columnInfo.defaultValue = defaultValueMethod.invoke(defaultValueAnnotation) as String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlInfo.columns.add(columnInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理主键
|
||||||
|
mapper.primaryKeyMapping?.let { pkMapping ->
|
||||||
|
val pkAnnotation = field.annotations.find {
|
||||||
|
it.annotationClass.java == pkMapping.annotationClass.java
|
||||||
|
}
|
||||||
|
if (pkAnnotation != null) {
|
||||||
|
val pkMethod = pkAnnotation.javaClass.getMethod(pkMapping.propertyName)
|
||||||
|
val isPk = pkMethod.invoke(pkAnnotation)
|
||||||
|
if (isPk is Boolean && isPk) {
|
||||||
|
columnInfo.isPrimaryKey = true
|
||||||
|
sqlInfo.primaryKeys.add(columnInfo.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL信息类
|
||||||
|
* 存储从实体类中提取的SQL相关信息
|
||||||
|
*/
|
||||||
|
data class SqlInfo(
|
||||||
|
var tableName: String = "",
|
||||||
|
val columns: MutableList<ColumnInfo> = mutableListOf(),
|
||||||
|
val primaryKeys: MutableList<String> = mutableListOf()
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列信息类
|
||||||
|
*/
|
||||||
|
data class ColumnInfo(
|
||||||
|
var name: String = "",
|
||||||
|
var type: String = "",
|
||||||
|
var nullable: Boolean = true,
|
||||||
|
var defaultValue: String = "",
|
||||||
|
var isPrimaryKey: Boolean = false
|
||||||
|
)
|
||||||
182
vertx-demo/src/main/kotlin/app/util/SqlGenerator.kt
Normal file
182
vertx-demo/src/main/kotlin/app/util/SqlGenerator.kt
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package app.util
|
||||||
|
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PostgreSQL SQL生成工具类
|
||||||
|
*/
|
||||||
|
class SqlGenerator {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* 生成创建表SQL
|
||||||
|
* @param entityClass 实体类
|
||||||
|
* @param mapper 注解映射中间类
|
||||||
|
* @return 创建表SQL语句
|
||||||
|
*/
|
||||||
|
fun generateCreateTableSql(entityClass: KClass<*>, mapper: SqlAnnotationMapper): String {
|
||||||
|
val sqlInfo = SqlAnnotationMapperGenerator.extractSqlInfo(entityClass, mapper)
|
||||||
|
val tableName = sqlInfo.tableName
|
||||||
|
val columns = sqlInfo.columns
|
||||||
|
|
||||||
|
if (tableName.isEmpty() || columns.isEmpty()) {
|
||||||
|
throw IllegalArgumentException("无法生成SQL,表名或列信息为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
val sb = StringBuilder()
|
||||||
|
sb.append("CREATE TABLE IF NOT EXISTS $tableName (\n")
|
||||||
|
|
||||||
|
// 添加列定义
|
||||||
|
val columnDefinitions = columns.map { column ->
|
||||||
|
val nullable = if (column.nullable) "" else " NOT NULL"
|
||||||
|
val defaultValue = if (column.defaultValue.isNotEmpty()) " DEFAULT ${column.defaultValue}" else ""
|
||||||
|
" ${column.name} ${column.type}$nullable$defaultValue"
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append(columnDefinitions.joinToString(",\n"))
|
||||||
|
|
||||||
|
// 添加主键
|
||||||
|
if (sqlInfo.primaryKeys.isNotEmpty()) {
|
||||||
|
sb.append(",\n PRIMARY KEY (${sqlInfo.primaryKeys.joinToString(", ")})")
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("\n);")
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成插入SQL
|
||||||
|
* @param entityClass 实体类
|
||||||
|
* @param mapper 注解映射中间类
|
||||||
|
* @return 插入SQL语句模板
|
||||||
|
*/
|
||||||
|
fun generateInsertSql(entityClass: KClass<*>, mapper: SqlAnnotationMapper): String {
|
||||||
|
val sqlInfo = SqlAnnotationMapperGenerator.extractSqlInfo(entityClass, mapper)
|
||||||
|
val tableName = sqlInfo.tableName
|
||||||
|
val columns = sqlInfo.columns
|
||||||
|
|
||||||
|
if (tableName.isEmpty() || columns.isEmpty()) {
|
||||||
|
throw IllegalArgumentException("无法生成SQL,表名或列信息为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
val columnNames = columns.map { it.name }
|
||||||
|
val placeholders = columns.mapIndexed { index, _ -> "$$${index + 1}" }
|
||||||
|
|
||||||
|
return "INSERT INTO $tableName (${columnNames.joinToString(", ")}) VALUES (${placeholders.joinToString(", ")});"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成更新SQL
|
||||||
|
* @param entityClass 实体类
|
||||||
|
* @param mapper 注解映射中间类
|
||||||
|
* @return 更新SQL语句模板
|
||||||
|
*/
|
||||||
|
fun generateUpdateSql(entityClass: KClass<*>, mapper: SqlAnnotationMapper): String {
|
||||||
|
val sqlInfo = SqlAnnotationMapperGenerator.extractSqlInfo(entityClass, mapper)
|
||||||
|
val tableName = sqlInfo.tableName
|
||||||
|
val columns = sqlInfo.columns.filter { !it.isPrimaryKey }
|
||||||
|
val primaryKeys = sqlInfo.columns.filter { it.isPrimaryKey }
|
||||||
|
|
||||||
|
if (tableName.isEmpty() || columns.isEmpty() || primaryKeys.isEmpty()) {
|
||||||
|
throw IllegalArgumentException("无法生成SQL,表名、列信息或主键为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
val sb = StringBuilder()
|
||||||
|
sb.append("UPDATE $tableName SET ")
|
||||||
|
|
||||||
|
// 设置列
|
||||||
|
val setStatements = columns.mapIndexed { index, column ->
|
||||||
|
"${column.name} = $$${index + 1}"
|
||||||
|
}
|
||||||
|
sb.append(setStatements.joinToString(", "))
|
||||||
|
|
||||||
|
// 添加条件
|
||||||
|
sb.append(" WHERE ")
|
||||||
|
val whereStatements = primaryKeys.mapIndexed { index, pk ->
|
||||||
|
"${pk.name} = $$${columns.size + index + 1}"
|
||||||
|
}
|
||||||
|
sb.append(whereStatements.joinToString(" AND "))
|
||||||
|
|
||||||
|
sb.append(";")
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成删除SQL
|
||||||
|
* @param entityClass 实体类
|
||||||
|
* @param mapper 注解映射中间类
|
||||||
|
* @return 删除SQL语句模板
|
||||||
|
*/
|
||||||
|
fun generateDeleteSql(entityClass: KClass<*>, mapper: SqlAnnotationMapper): String {
|
||||||
|
val sqlInfo = SqlAnnotationMapperGenerator.extractSqlInfo(entityClass, mapper)
|
||||||
|
val tableName = sqlInfo.tableName
|
||||||
|
val primaryKeys = sqlInfo.columns.filter { it.isPrimaryKey }
|
||||||
|
|
||||||
|
if (tableName.isEmpty() || primaryKeys.isEmpty()) {
|
||||||
|
throw IllegalArgumentException("无法生成SQL,表名或主键为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
val sb = StringBuilder()
|
||||||
|
sb.append("DELETE FROM $tableName WHERE ")
|
||||||
|
|
||||||
|
// 添加条件
|
||||||
|
val whereStatements = primaryKeys.mapIndexed { index, pk ->
|
||||||
|
"${pk.name} = $$${index + 1}"
|
||||||
|
}
|
||||||
|
sb.append(whereStatements.joinToString(" AND "))
|
||||||
|
|
||||||
|
sb.append(";")
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成查询SQL
|
||||||
|
* @param entityClass 实体类
|
||||||
|
* @param mapper 注解映射中间类
|
||||||
|
* @return 查询SQL语句
|
||||||
|
*/
|
||||||
|
fun generateSelectSql(entityClass: KClass<*>, mapper: SqlAnnotationMapper): String {
|
||||||
|
val sqlInfo = SqlAnnotationMapperGenerator.extractSqlInfo(entityClass, mapper)
|
||||||
|
val tableName = sqlInfo.tableName
|
||||||
|
val columns = sqlInfo.columns
|
||||||
|
|
||||||
|
if (tableName.isEmpty() || columns.isEmpty()) {
|
||||||
|
throw IllegalArgumentException("无法生成SQL,表名或列信息为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
val columnNames = columns.map { it.name }
|
||||||
|
|
||||||
|
return "SELECT ${columnNames.joinToString(", ")} FROM $tableName;"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成根据主键查询SQL
|
||||||
|
* @param entityClass 实体类
|
||||||
|
* @param mapper 注解映射中间类
|
||||||
|
* @return 根据主键查询SQL语句
|
||||||
|
*/
|
||||||
|
fun generateSelectByPrimaryKeySql(entityClass: KClass<*>, mapper: SqlAnnotationMapper): String {
|
||||||
|
val sqlInfo = SqlAnnotationMapperGenerator.extractSqlInfo(entityClass, mapper)
|
||||||
|
val tableName = sqlInfo.tableName
|
||||||
|
val columns = sqlInfo.columns
|
||||||
|
val primaryKeys = sqlInfo.columns.filter { it.isPrimaryKey }
|
||||||
|
|
||||||
|
if (tableName.isEmpty() || columns.isEmpty() || primaryKeys.isEmpty()) {
|
||||||
|
throw IllegalArgumentException("无法生成SQL,表名、列信息或主键为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
val columnNames = columns.map { it.name }
|
||||||
|
|
||||||
|
val sb = StringBuilder()
|
||||||
|
sb.append("SELECT ${columnNames.joinToString(", ")} FROM $tableName WHERE ")
|
||||||
|
|
||||||
|
// 添加条件
|
||||||
|
val whereStatements = primaryKeys.mapIndexed { index, pk ->
|
||||||
|
"${pk.name} = $$${index + 1}"
|
||||||
|
}
|
||||||
|
sb.append(whereStatements.joinToString(" AND "))
|
||||||
|
|
||||||
|
sb.append(";")
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,63 +0,0 @@
|
|||||||
package app.util.sql
|
|
||||||
|
|
||||||
import org.aikrai.vertx.gen.SqlGen
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SqlGen工具类使用示例
|
|
||||||
*/
|
|
||||||
object SqlGenExample {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 示例方法
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
// 指定要扫描的包路径,例如"app.data.domain"
|
|
||||||
val packageName = "app.data.domain"
|
|
||||||
|
|
||||||
// // 方式一:一步生成所有SQL
|
|
||||||
// val sqlMap = SqlGen.generateSql(packageName)
|
|
||||||
//
|
|
||||||
// // 打印生成的SQL
|
|
||||||
// println("=== 生成的SQL语句 ===")
|
|
||||||
// sqlMap.forEach { (key: String, sql: String) ->
|
|
||||||
// println("\n--- $key ---")
|
|
||||||
// println(sql)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 方式二:分步骤生成
|
|
||||||
println("\n\n=== 分步骤生成SQL ===")
|
|
||||||
val sqlGen = SqlGen()
|
|
||||||
|
|
||||||
// 1. 扫描实体类
|
|
||||||
println("1. 开始扫描实体类...")
|
|
||||||
val entities = sqlGen.scanEntities(packageName)
|
|
||||||
println("发现 ${entities.size} 个实体类:")
|
|
||||||
entities.forEach { entity: KClass<*> ->
|
|
||||||
println("- ${entity.simpleName}")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 解析实体类信息到缓存
|
|
||||||
println("\n2. 解析实体类信息...")
|
|
||||||
sqlGen.parseEntities(entities)
|
|
||||||
|
|
||||||
// 3. 生成建表SQL
|
|
||||||
println("\n3. 生成建表SQL...")
|
|
||||||
val createTableSql = sqlGen.generateCreateTableSql()
|
|
||||||
createTableSql.forEach { sql: String ->
|
|
||||||
println(sql)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 生成CRUD SQL
|
|
||||||
println("\n4. 生成CRUD SQL...")
|
|
||||||
val crudSql = sqlGen.generateCrudSql()
|
|
||||||
crudSql.forEach { (entityClass: KClass<*>, crud: SqlGen.CrudSql) ->
|
|
||||||
println("\n--- ${entityClass.simpleName} ---")
|
|
||||||
println("INSERT: ${crud.insertSql}")
|
|
||||||
println("SELECT: ${crud.selectByIdSql}")
|
|
||||||
println("UPDATE: ${crud.updateSql}")
|
|
||||||
println("DELETE: ${crud.deleteSql}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,338 +0,0 @@
|
|||||||
package org.aikrai.vertx.gen
|
|
||||||
|
|
||||||
import org.aikrai.vertx.db.annotation.*
|
|
||||||
import java.sql.Timestamp
|
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
import kotlin.reflect.KProperty1
|
|
||||||
import kotlin.reflect.full.findAnnotation
|
|
||||||
import kotlin.reflect.full.memberProperties
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SQL生成工具类
|
|
||||||
* 根据Kotlin实体类生成PostgreSQL SQL语句
|
|
||||||
*/
|
|
||||||
class SqlGen {
|
|
||||||
|
|
||||||
// 注解扫描器
|
|
||||||
private val scanner = AnnotationScanner.create<TableName, String>(
|
|
||||||
valueProperty = TableName::value,
|
|
||||||
defaultValueMapper = { klass -> camelToSnake(klass.simpleName!!) }
|
|
||||||
)
|
|
||||||
|
|
||||||
// 实体类缓存
|
|
||||||
private val entityCache = mutableMapOf<KClass<*>, EntityCache>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 扫描指定包路径下的所有带有@TableName注解的类
|
|
||||||
* @param packageName 包名,例如 "app.data.domain"
|
|
||||||
* @return 带有@TableName注解的类列表
|
|
||||||
*/
|
|
||||||
fun scanEntities(packageName: String): List<KClass<*>> {
|
|
||||||
return scanner.scanClasses(packageName)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析实体类并缓存信息
|
|
||||||
* @param entityClasses 实体类列表
|
|
||||||
*/
|
|
||||||
fun parseEntities(entityClasses: List<KClass<*>>) {
|
|
||||||
// 使用scanner解析类
|
|
||||||
scanner.parseClasses(entityClasses)
|
|
||||||
|
|
||||||
// 将scanner的结果转换为entityCache
|
|
||||||
scanner.getAnnotatedClasses().forEach { (klass, annotatedClass) ->
|
|
||||||
val fields = mutableListOf<FieldCache>()
|
|
||||||
val indices = mutableListOf<IndexCache>()
|
|
||||||
|
|
||||||
// 解析字段
|
|
||||||
annotatedClass.properties.forEach { propertyInfo ->
|
|
||||||
val fieldCache = parseField(propertyInfo.property as KProperty<*>)
|
|
||||||
fields.add(fieldCache)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析索引
|
|
||||||
val tableIndices = klass.findAnnotation<TableIndex>()
|
|
||||||
if (tableIndices != null) {
|
|
||||||
val indexCache = IndexCache(
|
|
||||||
name = tableIndices.name.ifEmpty { "idx_${annotatedClass.value}_${tableIndices.columnNames.joinToString("_")}" },
|
|
||||||
unique = tableIndices.unique,
|
|
||||||
concurrent = tableIndices.concurrent,
|
|
||||||
columnNames = tableIndices.columnNames.toList(),
|
|
||||||
definition = tableIndices.definition
|
|
||||||
)
|
|
||||||
indices.add(indexCache)
|
|
||||||
}
|
|
||||||
|
|
||||||
entityCache[klass] = EntityCache(
|
|
||||||
entityClass = klass,
|
|
||||||
tableName = annotatedClass.value,
|
|
||||||
fields = fields,
|
|
||||||
indices = indices
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析字段
|
|
||||||
*/
|
|
||||||
private fun parseField(property: KProperty<*>): FieldCache {
|
|
||||||
val tableId = property.findAnnotation<TableId>()
|
|
||||||
val tableField = property.findAnnotation<TableField>()
|
|
||||||
|
|
||||||
val isPrimary = tableId != null
|
|
||||||
val idType = tableId?.type ?: IdType.NONE
|
|
||||||
val columnName = tableField?.value?.ifEmpty { camelToSnake(property.name) } ?: camelToSnake(property.name)
|
|
||||||
val fieldFill = tableField?.fill ?: FieldFill.DEFAULT
|
|
||||||
|
|
||||||
val returnType = property.returnType
|
|
||||||
|
|
||||||
return FieldCache(
|
|
||||||
property = property,
|
|
||||||
columnName = columnName,
|
|
||||||
isPrimary = isPrimary,
|
|
||||||
idType = idType,
|
|
||||||
fieldFill = fieldFill,
|
|
||||||
returnType = returnType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成所有实体类的建表SQL
|
|
||||||
* @return 建表SQL语句列表
|
|
||||||
*/
|
|
||||||
fun generateCreateTableSql(): List<String> {
|
|
||||||
return entityCache.values.map { generateCreateTableSql(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 为单个实体生成建表SQL
|
|
||||||
*/
|
|
||||||
private fun generateCreateTableSql(entityCache: EntityCache): String {
|
|
||||||
val sb = StringBuilder()
|
|
||||||
|
|
||||||
sb.appendLine("-- 为实体 ${entityCache.entityClass.simpleName} 创建表")
|
|
||||||
sb.appendLine("CREATE TABLE IF NOT EXISTS \"${entityCache.tableName}\" (")
|
|
||||||
|
|
||||||
// 添加字段定义
|
|
||||||
entityCache.fields.forEachIndexed { index, field ->
|
|
||||||
sb.append(" \"${field.columnName}\" ${mapKotlinTypeToPostgresType(field)}")
|
|
||||||
|
|
||||||
// 主键约束
|
|
||||||
if (field.isPrimary) {
|
|
||||||
sb.append(" PRIMARY KEY")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 非空约束 (根据Kotlin类型是否为可空)
|
|
||||||
if (!field.returnType.isMarkedNullable && !field.isPrimary) {
|
|
||||||
sb.append(" NOT NULL")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自增约束
|
|
||||||
if (field.isPrimary && field.idType == IdType.AUTO) {
|
|
||||||
sb.append(" GENERATED BY DEFAULT AS IDENTITY")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认值
|
|
||||||
when (field.fieldFill) {
|
|
||||||
FieldFill.INSERT, FieldFill.INSERT_UPDATE -> {
|
|
||||||
if (field.returnType.classifier == Timestamp::class ||
|
|
||||||
field.returnType.classifier == LocalDateTime::class ||
|
|
||||||
field.returnType.classifier == LocalDate::class) {
|
|
||||||
sb.append(" DEFAULT CURRENT_TIMESTAMP")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < entityCache.fields.size - 1) {
|
|
||||||
sb.appendLine(",")
|
|
||||||
} else {
|
|
||||||
sb.appendLine()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.appendLine(");")
|
|
||||||
|
|
||||||
// 添加索引
|
|
||||||
entityCache.indices.forEach { index ->
|
|
||||||
sb.appendLine()
|
|
||||||
sb.append("-- 创建索引: ${index.name}")
|
|
||||||
sb.appendLine()
|
|
||||||
sb.append("CREATE ")
|
|
||||||
if (index.unique) sb.append("UNIQUE ")
|
|
||||||
sb.append("INDEX ")
|
|
||||||
if (index.concurrent) sb.append("CONCURRENTLY ")
|
|
||||||
sb.append("IF NOT EXISTS ${index.name} ON \"${entityCache.tableName}\" ")
|
|
||||||
if (index.definition.isNotEmpty()) {
|
|
||||||
sb.append(index.definition)
|
|
||||||
} else {
|
|
||||||
sb.append("(${index.columnNames.joinToString(", ") { "\"$it\"" }})")
|
|
||||||
}
|
|
||||||
sb.appendLine(";")
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成基本的CRUD SQL语句
|
|
||||||
*/
|
|
||||||
fun generateCrudSql(): Map<KClass<*>, CrudSql> {
|
|
||||||
return entityCache.mapValues { (_, entityCache) ->
|
|
||||||
val tableName = entityCache.tableName
|
|
||||||
val fields = entityCache.fields
|
|
||||||
|
|
||||||
val primaryKeyField = fields.find { it.isPrimary }
|
|
||||||
val regularFields = fields.filter { !it.isPrimary }
|
|
||||||
|
|
||||||
val insertFields = regularFields.filter { field ->
|
|
||||||
when (field.fieldFill) {
|
|
||||||
FieldFill.INSERT, FieldFill.INSERT_UPDATE -> true
|
|
||||||
else -> true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val updateFields = regularFields.filter { field ->
|
|
||||||
when (field.fieldFill) {
|
|
||||||
FieldFill.UPDATE, FieldFill.INSERT_UPDATE -> true
|
|
||||||
else -> true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val fieldList = fields.joinToString(", ") { "\"${it.columnName}\"" }
|
|
||||||
val primaryKeyColumn = primaryKeyField?.columnName ?: "id"
|
|
||||||
|
|
||||||
val insertFieldList = insertFields.joinToString(", ") { "\"${it.columnName}\"" }
|
|
||||||
val insertValuesList = insertFields.joinToString(", ") { ":${it.property.name}" }
|
|
||||||
|
|
||||||
val updateSetList = updateFields.joinToString(", ") { "\"${it.columnName}\" = :${it.property.name}" }
|
|
||||||
|
|
||||||
CrudSql(
|
|
||||||
insertSql = "INSERT INTO \"$tableName\" ($insertFieldList) VALUES ($insertValuesList);",
|
|
||||||
selectByIdSql = "SELECT $fieldList FROM \"$tableName\" WHERE \"$primaryKeyColumn\" = :id;",
|
|
||||||
updateSql = "UPDATE \"$tableName\" SET $updateSetList WHERE \"$primaryKeyColumn\" = :id;",
|
|
||||||
deleteSql = "DELETE FROM \"$tableName\" WHERE \"$primaryKeyColumn\" = :id;"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将驼峰命名转换为下划线命名
|
|
||||||
*/
|
|
||||||
private fun camelToSnake(name: String): String {
|
|
||||||
return name.replace(Regex("([a-z0-9])([A-Z])"), "$1_$2").toLowerCase()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将Kotlin类型映射为PostgreSQL类型
|
|
||||||
*/
|
|
||||||
private fun mapKotlinTypeToPostgresType(field: FieldCache): String {
|
|
||||||
val type = field.returnType.classifier
|
|
||||||
return when (type) {
|
|
||||||
String::class -> "VARCHAR(255)"
|
|
||||||
Int::class, Integer::class -> "INTEGER"
|
|
||||||
Long::class -> "BIGINT"
|
|
||||||
Double::class -> "DOUBLE PRECISION"
|
|
||||||
Float::class -> "REAL"
|
|
||||||
Boolean::class -> "BOOLEAN"
|
|
||||||
Timestamp::class, java.util.Date::class -> "TIMESTAMP"
|
|
||||||
LocalDateTime::class -> "TIMESTAMP"
|
|
||||||
LocalDate::class -> "DATE"
|
|
||||||
Char::class -> "CHAR(1)"
|
|
||||||
else -> {
|
|
||||||
// 处理枚举类型
|
|
||||||
if (type is KClass<*> && type.java.isEnum) {
|
|
||||||
"VARCHAR(50)"
|
|
||||||
} else {
|
|
||||||
"JSONB" // 默认复杂类型存储为JSON
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实体缓存类
|
|
||||||
*/
|
|
||||||
data class EntityCache(
|
|
||||||
val entityClass: KClass<*>,
|
|
||||||
val tableName: String,
|
|
||||||
val fields: List<FieldCache>,
|
|
||||||
val indices: List<IndexCache>
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字段缓存类
|
|
||||||
*/
|
|
||||||
data class FieldCache(
|
|
||||||
val property: KProperty<*>,
|
|
||||||
val columnName: String,
|
|
||||||
val isPrimary: Boolean,
|
|
||||||
val idType: IdType,
|
|
||||||
val fieldFill: FieldFill,
|
|
||||||
val returnType: kotlin.reflect.KType
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 索引缓存类
|
|
||||||
*/
|
|
||||||
data class IndexCache(
|
|
||||||
val name: String,
|
|
||||||
val unique: Boolean,
|
|
||||||
val concurrent: Boolean,
|
|
||||||
val columnNames: List<String>,
|
|
||||||
val definition: String
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CRUD SQL语句
|
|
||||||
*/
|
|
||||||
data class CrudSql(
|
|
||||||
val insertSql: String,
|
|
||||||
val selectByIdSql: String,
|
|
||||||
val updateSql: String,
|
|
||||||
val deleteSql: String
|
|
||||||
)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* 快速生成指定包下所有实体类的SQL
|
|
||||||
*/
|
|
||||||
fun generateSql(packageName: String): Map<String, String> {
|
|
||||||
val sqlGen = SqlGen()
|
|
||||||
val entities = sqlGen.scanEntities(packageName)
|
|
||||||
sqlGen.parseEntities(entities)
|
|
||||||
|
|
||||||
val createTableSql = sqlGen.generateCreateTableSql()
|
|
||||||
val crudSql = sqlGen.generateCrudSql()
|
|
||||||
|
|
||||||
val result = mutableMapOf<String, String>()
|
|
||||||
|
|
||||||
entities.forEachIndexed { index, entity ->
|
|
||||||
val tableName = sqlGen.scanner.getAnnotatedClass(entity)?.value
|
|
||||||
?: camelToSnake(entity.simpleName!!)
|
|
||||||
|
|
||||||
result["$tableName-create"] = createTableSql[index]
|
|
||||||
|
|
||||||
val crud = crudSql[entity]
|
|
||||||
if (crud != null) {
|
|
||||||
result["$tableName-insert"] = crud.insertSql
|
|
||||||
result["$tableName-select"] = crud.selectByIdSql
|
|
||||||
result["$tableName-update"] = crud.updateSql
|
|
||||||
result["$tableName-delete"] = crud.deleteSql
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将驼峰命名转换为下划线命名
|
|
||||||
*/
|
|
||||||
private fun camelToSnake(name: String): String {
|
|
||||||
return name.replace(Regex("([a-z0-9])([A-Z])"), "$1_$2").toLowerCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,153 +0,0 @@
|
|||||||
package org.aikrai.vertx.gen
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SqlGen命令行工具
|
|
||||||
*
|
|
||||||
* 用法:
|
|
||||||
* SqlGenCli <packageName> <outputDir>
|
|
||||||
*
|
|
||||||
* 参数:
|
|
||||||
* packageName - 要扫描的包名,例如 app.data.domain
|
|
||||||
* outputDir - SQL文件输出目录,可选,默认为 ./sql-gen
|
|
||||||
*/
|
|
||||||
object SqlGenCli {
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
if (args.isEmpty() || args[0] == "-h" || args[0] == "--help") {
|
|
||||||
printHelp()
|
|
||||||
exitProcess(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val packageName = args[0]
|
|
||||||
val outputDir = if (args.size > 1) args[1] else "./sql-gen"
|
|
||||||
|
|
||||||
println("开始从包 $packageName 生成SQL...")
|
|
||||||
println("输出目录: $outputDir")
|
|
||||||
|
|
||||||
// 创建输出目录
|
|
||||||
val outputDirFile = File(outputDir)
|
|
||||||
if (!outputDirFile.exists()) {
|
|
||||||
outputDirFile.mkdirs()
|
|
||||||
println("创建输出目录: $outputDir")
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 生成SQL
|
|
||||||
val sqlMap: Map<String, String> = SqlGen.generateSql(packageName)
|
|
||||||
|
|
||||||
// 按类型组织SQL
|
|
||||||
val createTableSql = mutableListOf<String>()
|
|
||||||
val insertSql = mutableListOf<String>()
|
|
||||||
val selectSql = mutableListOf<String>()
|
|
||||||
val updateSql = mutableListOf<String>()
|
|
||||||
val deleteSql = mutableListOf<String>()
|
|
||||||
|
|
||||||
// 分类SQL语句
|
|
||||||
sqlMap.forEach { (key: String, sql: String) ->
|
|
||||||
when {
|
|
||||||
key.endsWith("-create") -> createTableSql.add(sql)
|
|
||||||
key.endsWith("-insert") -> insertSql.add(sql)
|
|
||||||
key.endsWith("-select") -> selectSql.add(sql)
|
|
||||||
key.endsWith("-update") -> updateSql.add(sql)
|
|
||||||
key.endsWith("-delete") -> deleteSql.add(sql)
|
|
||||||
else -> {} // 忽略其他类型
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入各类SQL文件
|
|
||||||
File(outputDirFile, "tables.sql").writeText(createTableSql.joinToString("\n\n"))
|
|
||||||
File(outputDirFile, "inserts.sql").writeText(insertSql.joinToString("\n\n"))
|
|
||||||
File(outputDirFile, "selects.sql").writeText(selectSql.joinToString("\n\n"))
|
|
||||||
File(outputDirFile, "updates.sql").writeText(updateSql.joinToString("\n\n"))
|
|
||||||
File(outputDirFile, "deletes.sql").writeText(deleteSql.joinToString("\n\n"))
|
|
||||||
|
|
||||||
// 写入完整SQL文件
|
|
||||||
val allSql = """
|
|
||||||
|-- ====================
|
|
||||||
|-- 建表语句
|
|
||||||
|-- ====================
|
|
||||||
|
|
|
||||||
|${createTableSql.joinToString("\n\n")}
|
|
||||||
|
|
|
||||||
|-- ====================
|
|
||||||
|-- 插入语句
|
|
||||||
|-- ====================
|
|
||||||
|
|
|
||||||
|${insertSql.joinToString("\n\n")}
|
|
||||||
|
|
|
||||||
|-- ====================
|
|
||||||
|-- 查询语句
|
|
||||||
|-- ====================
|
|
||||||
|
|
|
||||||
|${selectSql.joinToString("\n\n")}
|
|
||||||
|
|
|
||||||
|-- ====================
|
|
||||||
|-- 更新语句
|
|
||||||
|-- ====================
|
|
||||||
|
|
|
||||||
|${updateSql.joinToString("\n\n")}
|
|
||||||
|
|
|
||||||
|-- ====================
|
|
||||||
|-- 删除语句
|
|
||||||
|-- ====================
|
|
||||||
|
|
|
||||||
|${deleteSql.joinToString("\n\n")}
|
|
||||||
""".trimMargin()
|
|
||||||
|
|
||||||
File(outputDirFile, "all.sql").writeText(allSql)
|
|
||||||
|
|
||||||
// 为每个实体类生成单独的SQL文件
|
|
||||||
val tableNames = sqlMap.keys
|
|
||||||
.filter { k: String -> k.endsWith("-create") }
|
|
||||||
.map { k: String -> k.substring(0, k.length - 7) }
|
|
||||||
|
|
||||||
tableNames.forEach { tableName: String ->
|
|
||||||
val entitySql = """
|
|
||||||
|-- 表结构
|
|
||||||
|${sqlMap["$tableName-create"] ?: ""}
|
|
||||||
|
|
|
||||||
|-- 插入操作
|
|
||||||
|${sqlMap["$tableName-insert"] ?: ""}
|
|
||||||
|
|
|
||||||
|-- 查询操作
|
|
||||||
|${sqlMap["$tableName-select"] ?: ""}
|
|
||||||
|
|
|
||||||
|-- 更新操作
|
|
||||||
|${sqlMap["$tableName-update"] ?: ""}
|
|
||||||
|
|
|
||||||
|-- 删除操作
|
|
||||||
|${sqlMap["$tableName-delete"] ?: ""}
|
|
||||||
""".trimMargin()
|
|
||||||
|
|
||||||
File(outputDirFile, "$tableName.sql").writeText(entitySql)
|
|
||||||
}
|
|
||||||
|
|
||||||
println("SQL生成完成!")
|
|
||||||
println("成功生成 ${tableNames.size} 个实体类的SQL脚本到目录: $outputDir")
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
System.err.println("生成SQL时发生错误: ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
exitProcess(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printHelp() {
|
|
||||||
println("""
|
|
||||||
|SqlGen - Kotlin实体类SQL生成工具
|
|
||||||
|
|
|
||||||
|用法: SqlGenCli <packageName> [outputDir]
|
|
||||||
|
|
|
||||||
|参数:
|
|
||||||
| packageName 要扫描的包名,例如 app.data.domain
|
|
||||||
| outputDir SQL文件输出目录,可选,默认为 ./sql-gen
|
|
||||||
|
|
|
||||||
|示例:
|
|
||||||
| SqlGenCli app.data.domain ./sql/generated
|
|
||||||
""".trimMargin())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user