1
This commit is contained in:
parent
63a18f1dbd
commit
5b1efdf6e3
@ -1,116 +1,125 @@
|
||||
---
|
||||
description: PostgreSQL SQL生成,pgsql生成
|
||||
description: PostgreSQL数据库迁移工具, PostgreSQL SQL生成,pgsql生成
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# Kotlin实体到PostgreSQL SQL生成专家
|
||||
|
||||
# PostgreSQL数据库迁移工具
|
||||
|
||||
## 角色定义
|
||||
你是一位精通Kotlin编程和PostgreSQL数据库的专业工程师,专门负责分析Kotlin实体类及其注解,并生成对应的PostgreSQL SQL建表语句和常用操作语句。你具备深入理解对象关系映射(ORM)原理的能力,能够准确识别各类数据库相关注解并转换为高效、符合最佳实践的SQL语句。当遇到缺少必要注解的情况时,你能够根据命名约定和常见实践自动补充合理的默认配置。
|
||||
你是一个专业的PostgreSQL数据库迁移工具,负责根据Kotlin实体类及其注解自动生成数据库迁移脚本。你能够智能识别实体类变更,生成精确的差异SQL,并维护数据库版本演进记录。
|
||||
|
||||
## 专业知识
|
||||
- 精通Kotlin语言特性及其反射机制
|
||||
- 深入理解各类ORM框架的注解系统(如JPA、自定义注解等)
|
||||
- 熟悉PostgreSQL特有的数据类型、约束和索引功能
|
||||
- 掌握数据库设计最佳实践和性能优化技巧
|
||||
- 了解各种字段类型映射关系和转换规则
|
||||
- 熟悉命名约定和代码规范,能够推断缺失的注解信息
|
||||
- 精通实体类到数据库表的自动映射规则
|
||||
- 精通PostgreSQL数据库SQL语法和最佳实践
|
||||
- 熟悉Kotlin实体类结构和常用ORM注解(如JPA、Hibernate等)
|
||||
- 掌握数据库版本控制和迁移管理概念
|
||||
- 了解XML格式数据存储和解析
|
||||
- 具备文件操作和版本号管理能力
|
||||
|
||||
## 目标
|
||||
根据用户提供的Kotlin实体类及其注解,生成完整、准确的PostgreSQL建表语句和基本CRUD操作SQL。对于缺少必要注解的情况,能够自动补充合理的默认值,确保生成的SQL语句完整可用,同时提供索引和约束建议,确保数据库结构优化且符合最佳实践。
|
||||
为用户提供一个自动化工具,根据Kotlin实体类生成PostgreSQL数据库迁移脚本,实现数据库结构与代码模型的同步演进,减少手动维护数据库脚本的工作量。
|
||||
|
||||
## 约束
|
||||
- 严格遵循PostgreSQL语法规范,不混用其他数据库的特有功能
|
||||
- 确保生成的SQL语句语法正确,可直接执行不会报错
|
||||
- 对缺失的注解信息做出合理推断,并明确指出做了哪些推断
|
||||
- 不对实体类结构提出主观评价,专注于SQL转换工作
|
||||
- 保持生成的SQL简洁高效,避免冗余构造
|
||||
- 提供必要的SQL注释以提高可读性和可维护性
|
||||
1. 仅生成PostgreSQL兼容的SQL语句
|
||||
2. 遵循数据库迁移最佳实践,确保生成的SQL安全可靠
|
||||
3. 不删除或修改用户自定义的SQL文件
|
||||
4. 确保版本号按顺序递增,避免版本混乱
|
||||
5. 操作前对实体类进行验证,防止生成错误的SQL
|
||||
|
||||
## 工作流程
|
||||
1. 分析输入的Kotlin实体类代码及其注解
|
||||
2. 识别实体类名称和映射表名(通过@TableName等注解)
|
||||
- 若缺少@TableName,则使用类名转下划线命名作为表名
|
||||
3. 解析所有字段及其对应的属性(字段名、类型、是否主键等)
|
||||
4. 识别特殊注解如@TableId、@TableField、@TableIndex等
|
||||
- 若缺少@TableId,尝试识别命名为id、entityId等的字段作为主键
|
||||
- 若缺少@TableField,使用字段名转下划线命名作为列名
|
||||
5. 将Kotlin数据类型映射到PostgreSQL数据类型
|
||||
6. 生成CREATE TABLE语句,包含所有必要的约束和索引
|
||||
7. 根据需要生成基本的CRUD操作SQL模板
|
||||
8. 提供其他可能有用的SQL片段(视图、存储过程等)
|
||||
9. 明确指出为缺失注解自动补充的默认配置
|
||||
|
||||
## 输入格式
|
||||
提供一个或多个Kotlin实体类的代码,包含数据库相关注解(部分注解可能缺失):
|
||||
```kotlin
|
||||
// 可能缺少@TableName
|
||||
class User {
|
||||
// 可能缺少@TableId
|
||||
var id: Long = 0L
|
||||
|
||||
// 可能缺少@TableField
|
||||
var name: String = ""
|
||||
|
||||
var email: String = ""
|
||||
|
||||
// 其他字段...
|
||||
}
|
||||
```
|
||||
1. **扫描与解析**:扫描项目中的Kotlin实体类及其注解
|
||||
2. **版本确认**:检查resource/dbmigration/model目录状态
|
||||
- 如果为空,准备生成初始化脚本(1.0版本)
|
||||
- 如果不为空,读取最新版本的XML文件,确定下一个版本号
|
||||
3. **差异分析**:
|
||||
- 初始化场景:收集所有实体类信息,生成完整建表SQL
|
||||
- 更新场景:比对XML记录与当前实体类,识别添加/删除/修改的字段或表
|
||||
4. **SQL生成**:根据差异分析结果生成对应的SQL语句
|
||||
5. **文件生成**:
|
||||
- 在resource/dbmigration目录生成SQL文件
|
||||
- 在resource/dbmigration/model目录生成XML模型文件
|
||||
- 使用正确的版本号命名文件(例如:1.0__initial.sql或1.1.sql)
|
||||
|
||||
## 输出格式
|
||||
生成的结果包含以下几个部分:
|
||||
工具将生成两种类型的文件:
|
||||
|
||||
### 1. 补充的注解信息
|
||||
```
|
||||
【注解补充说明】
|
||||
- 缺少@TableName,已将类名"User"转换为表名"user"
|
||||
- 缺少@TableId,已将字段"id"识别为主键,采用ASSIGN_ID策略
|
||||
- 缺少@TableField,已将字段"name"映射为列名"name"
|
||||
```
|
||||
|
||||
### 2. 建表语句
|
||||
1. **SQL文件**:
|
||||
```sql
|
||||
-- 为实体 User 创建表
|
||||
CREATE TABLE "user" (
|
||||
id BIGINT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
-- 其他字段...
|
||||
-- 版本: X.Y
|
||||
-- 生成时间: YYYY-MM-DD HH:MM:SS
|
||||
-- 描述: [初始化/更新描述]
|
||||
|
||||
-- [表操作类型:创建/修改/删除] 表 [表名]
|
||||
CREATE TABLE user_info (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(200) UNIQUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- [更多SQL语句...]
|
||||
```
|
||||
|
||||
### 3. 索引创建语句
|
||||
```sql
|
||||
-- 创建推荐的索引
|
||||
CREATE INDEX idx_user_email ON "user" (email);
|
||||
2. **XML模型文件**:
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database-model version="X.Y" timestamp="YYYY-MM-DD HH:MM:SS">
|
||||
<entities>
|
||||
<entity name="UserInfo" table="user_info">
|
||||
<fields>
|
||||
<field name="id" type="Long" column="id" primary-key="true" auto-increment="true"/>
|
||||
<field name="username" type="String" column="username" nullable="false" length="100"/>
|
||||
<field name="email" type="String" column="email" unique="true" length="200"/>
|
||||
<field name="createdAt" type="Date" column="created_at" default="CURRENT_TIMESTAMP"/>
|
||||
</fields>
|
||||
</entity>
|
||||
<!-- 更多实体定义 -->
|
||||
</entities>
|
||||
</database-model>
|
||||
```
|
||||
|
||||
### 5. 字段类型映射说明
|
||||
提供Kotlin类型到PostgreSQL类型的映射说明,特别是特殊类型的处理方法。
|
||||
## 交互模式
|
||||
1. **配置阶段**:
|
||||
- 指定实体类包路径
|
||||
- 设置输出目录(默认为resource/dbmigration)
|
||||
- 配置特殊处理规则(可选)
|
||||
|
||||
## 注解识别与补充规则
|
||||
能够识别并正确处理以下注解,同时为缺失的注解提供合理默认值:
|
||||
- @TableName:表名映射
|
||||
- 缺失时:将类名转为下划线命名作为表名
|
||||
- @TableId:主键定义
|
||||
- 缺失时:识别命名为id、xxxId的字段为主键,默认使用ASSIGN_ID策略
|
||||
- @TableField:字段名映射和填充策略
|
||||
- 缺失时:将字段名转为下划线命名作为列名
|
||||
- @TableIndex:索引定义
|
||||
- 缺失时:为可能需要索引的字段(如email、phone、username等)建议添加索引
|
||||
- 其他自定义注解
|
||||
2. **执行阶段**:
|
||||
- 触发扫描和生成过程
|
||||
- 显示进度和结果摘要
|
||||
|
||||
## 类型映射规则
|
||||
提供详细的Kotlin类型到PostgreSQL类型的映射规则,例如:
|
||||
- String → VARCHAR(255)
|
||||
- Long → BIGINT
|
||||
- Int → INTEGER
|
||||
- Boolean → BOOLEAN
|
||||
- LocalDateTime/Timestamp → TIMESTAMP
|
||||
- 枚举类型 → VARCHAR或自定义enum类型
|
||||
- 等等
|
||||
3. **反馈阶段**:
|
||||
- 报告生成结果(生成文件路径、版本号)
|
||||
- 提供差异摘要(新增表、修改的字段等)
|
||||
- 显示警告或建议(如有)
|
||||
|
||||
## 示例
|
||||
针对用户提供的每个实体类,生成完整的SQL定义和操作语句,同时明确指出补充了哪些缺失的注解信息。
|
||||
**用户输入**:
|
||||
```
|
||||
扫描实体类并生成数据库迁移脚本:
|
||||
- 实体类包路径: com.example.domain.entity
|
||||
- 输出目录: src/main/resources/dbmigration
|
||||
```
|
||||
|
||||
**工具输出**:
|
||||
```
|
||||
===== 数据库迁移脚本生成报告 =====
|
||||
|
||||
检测到model目录为空,准备生成初始化脚本。
|
||||
|
||||
扫描到的实体类:
|
||||
- UserEntity → user
|
||||
- ProductEntity → product
|
||||
- OrderEntity → order
|
||||
|
||||
生成的文件:
|
||||
- src/main/resources/dbmigration/1.0__initial.sql
|
||||
- src/main/resources/dbmigration/model/1.0__initial.model.xml
|
||||
|
||||
初始化脚本包含:
|
||||
- 3个表创建语句
|
||||
- 5个索引创建语句
|
||||
- 2个外键约束
|
||||
|
||||
脚本生成完成!
|
||||
```
|
||||
|
||||
@ -110,6 +110,9 @@ dependencies {
|
||||
// doc
|
||||
implementation("io.swagger.core.v3:swagger-core:2.2.27")
|
||||
|
||||
// XML解析库
|
||||
implementation("javax.xml.bind:jaxb-api:2.3.1")
|
||||
|
||||
testImplementation("io.vertx:vertx-junit5")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:$junitJupiterVersion")
|
||||
testImplementation("org.mockito:mockito-core:5.15.2")
|
||||
|
||||
@ -85,7 +85,7 @@ class SqlAnnotationMapperGenerator {
|
||||
|
||||
// 获取表名
|
||||
mapper.tableName?.let { tableNameMapping ->
|
||||
val annotation = entityClass.annotations.find { it.annotationClass == tableNameMapping.annotationClass.java }
|
||||
val annotation = entityClass.annotations.find { it.annotationClass.toString() == tableNameMapping.annotationClass.toString() }
|
||||
annotation?.let {
|
||||
val method = it.javaClass.getMethod(tableNameMapping.propertyName)
|
||||
sqlInfo.tableName = method.invoke(it) as String
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
package org.aikrai.vertx.db
|
||||
|
||||
object SqlHelper {
|
||||
|
||||
fun retBool(result: Int?): Boolean {
|
||||
return null != result && result >= 1
|
||||
}
|
||||
}
|
||||
@ -1,239 +0,0 @@
|
||||
package org.aikrai.vertx.db.annotation
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.hasAnnotation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
/**
|
||||
* SQL注解映射中间类
|
||||
* 用于从实体类及其注解中提取信息以生成SQL
|
||||
* 支持多套注解系统的映射配置
|
||||
*/
|
||||
class SqlAnnotationMapper {
|
||||
// 表名注解配置
|
||||
var tableNameAnnotationClass: KClass<out Annotation> = TableName::class
|
||||
var tableNameProperty: String = "value"
|
||||
var tableNameDefaultMapper: (KClass<*>) -> String = { klass -> camelToSnake(klass.simpleName!!) }
|
||||
|
||||
// 主键注解配置
|
||||
var tableIdAnnotationClass: KClass<out Annotation> = TableId::class
|
||||
var tableIdNameProperty: String = "value"
|
||||
var tableIdTypeProperty: String = "type"
|
||||
var tableIdDefaultMapper: (KProperty<*>) -> Boolean = { property ->
|
||||
property.name == "id" || property.name.endsWith("Id")
|
||||
}
|
||||
|
||||
// 字段注解配置
|
||||
var tableFieldAnnotationClass: KClass<out Annotation> = TableField::class
|
||||
var tableFieldNameProperty: String = "value"
|
||||
var tableFieldFillProperty: String = "fill"
|
||||
var tableFieldDefaultMapper: (KProperty<*>) -> String = { property -> camelToSnake(property.name) }
|
||||
|
||||
// 索引注解配置
|
||||
var tableIndexAnnotationClass: KClass<out Annotation> = TableIndex::class
|
||||
var tableIndexNameProperty: String = "name"
|
||||
var tableIndexUniqueProperty: String = "unique"
|
||||
var tableIndexColumnsProperty: String = "columnNames"
|
||||
|
||||
// 枚举值注解配置
|
||||
var enumValueAnnotationClass: KClass<out Annotation> = EnumValue::class
|
||||
|
||||
/**
|
||||
* 从实体类中获取表名
|
||||
* @param entityClass 实体类
|
||||
* @return 表名
|
||||
*/
|
||||
fun getTableName(entityClass: KClass<*>): String {
|
||||
// 获取所有注解
|
||||
val annotations = entityClass.annotations.filter { it.annotationClass == tableNameAnnotationClass }
|
||||
|
||||
return if (annotations.isNotEmpty()) {
|
||||
val annotation = annotations.first()
|
||||
// 通过反射获取注解的value属性值
|
||||
val method = annotation::class.java.getMethod(tableNameProperty)
|
||||
val value = method.invoke(annotation) as String
|
||||
|
||||
if (value.isNotEmpty()) value else tableNameDefaultMapper(entityClass)
|
||||
} else {
|
||||
tableNameDefaultMapper(entityClass)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断属性是否为主键
|
||||
* @param property 属性
|
||||
* @return 是否为主键
|
||||
*/
|
||||
fun isTableId(property: KProperty<*>): Boolean {
|
||||
val hasAnnotation = property.annotations.any { it.annotationClass == tableIdAnnotationClass }
|
||||
return hasAnnotation || tableIdDefaultMapper(property)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取属性对应的列名
|
||||
* @param property 属性
|
||||
* @return 列名
|
||||
*/
|
||||
fun getColumnName(property: KProperty<*>): String {
|
||||
val annotations = property.annotations.filter { it.annotationClass == tableFieldAnnotationClass }
|
||||
|
||||
return if (annotations.isNotEmpty()) {
|
||||
val annotation = annotations.first()
|
||||
// 通过反射获取注解的value属性值
|
||||
val method = annotation::class.java.getMethod(tableFieldNameProperty)
|
||||
val value = method.invoke(annotation) as String
|
||||
|
||||
if (value.isNotEmpty()) value else tableFieldDefaultMapper(property)
|
||||
} else {
|
||||
tableFieldDefaultMapper(property)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主键类型
|
||||
* @param property 属性
|
||||
* @return 主键类型(如果有)
|
||||
*/
|
||||
fun getIdType(property: KProperty<*>): Any? {
|
||||
val annotations = property.annotations.filter { it.annotationClass == tableIdAnnotationClass }
|
||||
if (annotations.isEmpty()) return null
|
||||
|
||||
val annotation = annotations.first()
|
||||
// 通过反射获取注解的type属性值
|
||||
val method = annotation::class.java.getMethod(tableIdTypeProperty)
|
||||
return method.invoke(annotation)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段填充策略
|
||||
* @param property 属性
|
||||
* @return 填充策略(如果有)
|
||||
*/
|
||||
fun getFieldFill(property: KProperty<*>): Any? {
|
||||
val annotations = property.annotations.filter { it.annotationClass == tableFieldAnnotationClass }
|
||||
if (annotations.isEmpty()) return null
|
||||
|
||||
val annotation = annotations.first()
|
||||
// 通过反射获取注解的fill属性值
|
||||
val method = annotation::class.java.getMethod(tableFieldFillProperty)
|
||||
return method.invoke(annotation)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体类的所有索引配置
|
||||
* @param entityClass 实体类
|
||||
* @return 索引配置列表
|
||||
*/
|
||||
fun getTableIndices(entityClass: KClass<*>): List<TableIndexInfo> {
|
||||
val annotations = entityClass.annotations.filter { it.annotationClass == tableIndexAnnotationClass }
|
||||
|
||||
return annotations.map { annotation ->
|
||||
val nameMethod = annotation::class.java.getMethod(tableIndexNameProperty)
|
||||
val uniqueMethod = annotation::class.java.getMethod(tableIndexUniqueProperty)
|
||||
val columnsMethod = annotation::class.java.getMethod(tableIndexColumnsProperty)
|
||||
|
||||
val name = nameMethod.invoke(annotation) as String
|
||||
val unique = uniqueMethod.invoke(annotation) as Boolean
|
||||
val columns = columnsMethod.invoke(annotation) as Array<*>
|
||||
|
||||
TableIndexInfo(
|
||||
name = name,
|
||||
unique = unique,
|
||||
columnNames = columns.map { it.toString() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体类的所有属性信息
|
||||
* @param entityClass 实体类
|
||||
* @return 属性信息列表
|
||||
*/
|
||||
fun getEntityProperties(entityClass: KClass<*>): List<PropertyInfo> {
|
||||
return entityClass.memberProperties.map { property ->
|
||||
PropertyInfo(
|
||||
property = property,
|
||||
columnName = getColumnName(property),
|
||||
isPrimary = isTableId(property),
|
||||
idType = getIdType(property),
|
||||
fieldFill = getFieldFill(property)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从实体类中提取所有SQL相关信息
|
||||
* @param entityClass 实体类
|
||||
* @return 实体类SQL信息
|
||||
*/
|
||||
fun extractEntityInfo(entityClass: KClass<*>): EntityInfo {
|
||||
return EntityInfo(
|
||||
entityClass = entityClass,
|
||||
tableName = getTableName(entityClass),
|
||||
properties = getEntityProperties(entityClass),
|
||||
indices = getTableIndices(entityClass)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰命名转下划线命名
|
||||
* @param name 驼峰命名
|
||||
* @return 下划线命名
|
||||
*/
|
||||
private fun camelToSnake(name: String): String {
|
||||
return name.replace(Regex("([a-z0-9])([A-Z])"), "$1_$2").lowercase()
|
||||
}
|
||||
|
||||
/**
|
||||
* 表索引信息
|
||||
*/
|
||||
data class TableIndexInfo(
|
||||
val name: String,
|
||||
val unique: Boolean,
|
||||
val columnNames: List<String>
|
||||
)
|
||||
|
||||
/**
|
||||
* 属性信息
|
||||
*/
|
||||
data class PropertyInfo(
|
||||
val property: KProperty<*>,
|
||||
val columnName: String,
|
||||
val isPrimary: Boolean,
|
||||
val idType: Any?,
|
||||
val fieldFill: Any?
|
||||
)
|
||||
|
||||
/**
|
||||
* 实体类SQL信息
|
||||
*/
|
||||
data class EntityInfo(
|
||||
val entityClass: KClass<*>,
|
||||
val tableName: String,
|
||||
val properties: List<PropertyInfo>,
|
||||
val indices: List<TableIndexInfo>
|
||||
)
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 创建默认配置的SQL注解映射器
|
||||
* @return SQL注解映射器
|
||||
*/
|
||||
fun createDefault(): SqlAnnotationMapper {
|
||||
return SqlAnnotationMapper()
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建自定义配置的SQL注解映射器
|
||||
* @param configure 配置函数
|
||||
* @return SQL注解映射器
|
||||
*/
|
||||
fun create(configure: SqlAnnotationMapper.() -> Unit): SqlAnnotationMapper {
|
||||
val mapper = SqlAnnotationMapper()
|
||||
mapper.configure()
|
||||
return mapper
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,152 +0,0 @@
|
||||
package org.aikrai.vertx.db.annotation
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.createInstance
|
||||
|
||||
/**
|
||||
* SqlAnnotationMapper 使用示例
|
||||
*/
|
||||
class SqlAnnotationMapperExample {
|
||||
|
||||
/**
|
||||
* 使用默认配置的中间类示例
|
||||
*/
|
||||
fun defaultMapperExample(entityClass: KClass<*>) {
|
||||
// 创建默认配置的SQL注解映射器
|
||||
val mapper = SqlAnnotationMapper.createDefault()
|
||||
|
||||
// 从实体类中提取信息
|
||||
val entityInfo = mapper.extractEntityInfo(entityClass)
|
||||
|
||||
// 输出实体信息
|
||||
println("表名: ${entityInfo.tableName}")
|
||||
println("字段:")
|
||||
entityInfo.properties.forEach { prop ->
|
||||
println(" ${prop.columnName} - 主键: ${prop.isPrimary} - 类型: ${prop.property.returnType}")
|
||||
if (prop.idType != null) {
|
||||
println(" ID类型: ${prop.idType}")
|
||||
}
|
||||
if (prop.fieldFill != null) {
|
||||
println(" 填充策略: ${prop.fieldFill}")
|
||||
}
|
||||
}
|
||||
|
||||
println("索引:")
|
||||
entityInfo.indices.forEach { index ->
|
||||
println(" ${index.name} - 唯一: ${index.unique} - 列: ${index.columnNames.joinToString(", ")}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置自定义注解映射示例
|
||||
*/
|
||||
fun customMapperExample(entityClass: KClass<*>) {
|
||||
// 创建自定义配置的SQL注解映射器
|
||||
val mapper = SqlAnnotationMapper.create {
|
||||
// 假设我们使用了另一套注解系统,例如JPA注解
|
||||
|
||||
// 配置表名注解 - 使用JPA的@Table注解
|
||||
tableNameAnnotationClass = Table::class
|
||||
tableNameProperty = "name"
|
||||
|
||||
// 配置主键注解 - 使用JPA的@Id注解
|
||||
tableIdAnnotationClass = Id::class
|
||||
|
||||
// 配置字段注解 - 使用JPA的@Column注解
|
||||
tableFieldAnnotationClass = Column::class
|
||||
tableFieldNameProperty = "name"
|
||||
|
||||
// 自定义名称转换规则
|
||||
tableNameDefaultMapper = { kClass -> kClass.simpleName!!.lowercase() }
|
||||
tableFieldDefaultMapper = { property -> property.name.lowercase() }
|
||||
}
|
||||
|
||||
// 从实体类中提取信息
|
||||
val entityInfo = mapper.extractEntityInfo(entityClass)
|
||||
|
||||
// 输出实体信息
|
||||
println("表名: ${entityInfo.tableName}")
|
||||
println("字段:")
|
||||
entityInfo.properties.forEach { prop ->
|
||||
println(" ${prop.columnName} - 主键: ${prop.isPrimary}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL生成器示例,展示如何根据提取的信息生成SQL
|
||||
*/
|
||||
fun sqlGeneratorExample(entityClass: KClass<*>) {
|
||||
// 创建SQL注解映射器
|
||||
val mapper = SqlAnnotationMapper.createDefault()
|
||||
|
||||
// 提取实体信息
|
||||
val entityInfo = mapper.extractEntityInfo(entityClass)
|
||||
|
||||
// 生成建表SQL
|
||||
val createTableSql = generateCreateTableSql(entityInfo)
|
||||
println("建表SQL:")
|
||||
println(createTableSql)
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成建表SQL
|
||||
*/
|
||||
private fun generateCreateTableSql(entityInfo: SqlAnnotationMapper.EntityInfo): String {
|
||||
val sb = StringBuilder()
|
||||
|
||||
sb.append("CREATE TABLE IF NOT EXISTS ${entityInfo.tableName} (\n")
|
||||
|
||||
// 添加字段定义
|
||||
val columns = entityInfo.properties.map { prop ->
|
||||
val primaryKey = if (prop.isPrimary) " PRIMARY KEY" else ""
|
||||
" ${prop.columnName} ${mapTypeToPostgresType(prop)} ${primaryKey}"
|
||||
}
|
||||
|
||||
sb.append(columns.joinToString(",\n"))
|
||||
sb.append("\n);")
|
||||
|
||||
// 添加索引
|
||||
entityInfo.indices.forEach { index ->
|
||||
val unique = if (index.unique) "UNIQUE " else ""
|
||||
sb.append("\n\nCREATE ${unique}INDEX IF NOT EXISTS ${index.name} ON ${entityInfo.tableName} (${index.columnNames.joinToString(", ")});")
|
||||
}
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 将属性类型映射为PostgreSQL类型(简化示例)
|
||||
*/
|
||||
private fun mapTypeToPostgresType(property: SqlAnnotationMapper.PropertyInfo): String {
|
||||
val typeName = property.property.returnType.toString()
|
||||
|
||||
return when {
|
||||
typeName.contains("String") -> "VARCHAR(255)"
|
||||
typeName.contains("Int") -> "INTEGER"
|
||||
typeName.contains("Long") -> "BIGINT"
|
||||
typeName.contains("Boolean") -> "BOOLEAN"
|
||||
typeName.contains("Double") -> "DOUBLE PRECISION"
|
||||
typeName.contains("Float") -> "REAL"
|
||||
typeName.contains("java.sql.Timestamp") || typeName.contains("java.util.Date") -> "TIMESTAMP"
|
||||
typeName.contains("LocalDateTime") -> "TIMESTAMP"
|
||||
typeName.contains("LocalDate") -> "DATE"
|
||||
typeName.contains("Char") -> "CHAR(1)"
|
||||
else -> "JSONB" // 默认复杂类型存储为JSON
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JPA注解模拟 - 仅用于示例
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class Table(val name: String = "")
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FIELD)
|
||||
annotation class Id
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.FIELD)
|
||||
annotation class Column(val name: String = "")
|
||||
Loading…
x
Reference in New Issue
Block a user