All Downloads are FREE. Search and download functionalities are using the official Maven repository.

query.insert.Insert.kt Maven / Gradle / Ivy

There is a newer version: 1.1.10
Show newest version
package query.insert

import ast.expr.SqlIdentifierExpr
import ast.statement.insert.SqlInsert
import database.DB
import dsl.QueryTableColumn
import dsl.TableSchema
import query.ReviseQuery
import util.toSqlString
import visitor.getExpr
import java.sql.Connection
import kotlin.reflect.KProperty
import kotlin.reflect.full.companionObjectInstance
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.declaredMembers
import kotlin.reflect.jvm.javaField

/**
 * insert语句dsl类
 * @property db DB 数据库类型
 * @property conn Connection? 数据库连接
 * @property isTransaction Boolean 是否是事务
 * @property sqlInsert SqlInsert insert语法树
 * @property columns MutableList 插入字段名列表
 * @property records MutableList 插入记录列表
 * @property incrKey String 自增主键名
 */
class Insert(
    var db: DB = DB.MYSQL,
    override var conn: Connection? = null,
    override var isTransaction: Boolean = false
) : ReviseQuery() {
    constructor(db: DB) : this(db, null, false)

    private var sqlInsert = SqlInsert()

    private var columns = mutableListOf()

    private var records = mutableListOf()

    private var incrKey = ""

    private var autoGenerateKey = ""

    private var generateKeyFunction: () -> Any = {}

    /**
     * insert into子句
     * 例如:Insert() into Table
     * @param table TableSchema 实体类伴生对象名
     * @return Insert 插入dsl
     */
    infix fun  into(table: T): Insert {
        sqlInsert.table = SqlIdentifierExpr(table.tableName)

        val clazz = table::class
        val declaredMemberProperties = clazz.declaredMemberProperties

        val properties = declaredMemberProperties.map { it.name to it.getter.call(table) }
            .filter { it.second is QueryTableColumn }
            .map { it.first to it.second as QueryTableColumn }
            .filter {
                if (it.second.incr) {
                    incrKey = it.first
                }
                !it.second.incr
            }

        properties.forEach {
            if (it.second.autoGenerateKey) {
                autoGenerateKey = it.first
                generateKeyFunction = it.second.generateFunction
            }

            columns.add(it.first)
            sqlInsert.columns.add(SqlIdentifierExpr(it.second.column))
        }

        return this
    }

    /**
     * 使用实体数据生成sql(实体类需要定义正确的伴生对象)
     * 例如:Insert() into entity
     * @param entity Any 实体数据
     * @return Insert 插入dsl
     */
    infix fun insert(entity: Any): Insert {
        val clazz = entity::class
        val companion = clazz.companionObjectInstance ?: throw Exception("实体类需要添加伴生对象")
        into(companion as TableSchema)

        value(entity)

        return this
    }

    /**
     * 使用实体数据列表生成sql(实体类需要定义正确的伴生对象)
     * 例如:Insert() into listOf(entity1, entity2)
     * @param entity List 实体数据列表
     * @return Insert 插入dsl
     */
    infix fun insert(entity: List): Insert {
        if (entity.isNotEmpty()) {
            val clazz = entity[0]::class
            val companion = clazz.companionObjectInstance ?: throw Exception("实体类需要添加伴生对象")
            into(companion as TableSchema)

            values(entity)
        }

        return this
    }

    /**
     * values子句
     * 例如:Insert() into Table value entity
     * @param obj Any 实体对象
     * @return Insert 插入dsl
     */
    infix fun value(obj: Any): Insert {
        val clazz = obj::class
        val properties = clazz.declaredMemberProperties.map { it.name to it.getter.call(obj) }.toMap()
        val value = columns.map {
            if (it == autoGenerateKey) {
                val key = generateKeyFunction()
                val field = (clazz.declaredMembers.find { c -> c.name == autoGenerateKey } as KProperty).javaField
                field?.isAccessible = true
                field?.set(obj, key)

                getExpr(key)
            } else {
                getExpr(properties[it])
            }
        }

        sqlInsert.values.add(value)

        records.add(obj)

        return this
    }

    /**
     * values子句(批量)
     * 例如:Insert() into Table values listOf(entity1, entity2)
     * @param objList List 实体对象列表
     * @return Insert 插入dsl
     */
    infix fun  values(objList: List): Insert {
        objList.forEach {
            value(it)
        }

        return this
    }

    /**
     * values子句(批量)
     * 例如:Insert().into(Table).values(entity1, entity2)
     * @param obj Array 实体对象列表
     * @return Insert 插入dsl
     */
    fun  values(vararg obj: T): Insert {
        return values(obj.toList())
    }

    /**
     * 生成sql语句
     * @return String sql语句
     */
    override fun sql() = toSqlString(sqlInsert, db)

    /**
     * 执行插入语句并返回受影响行数(如果实体类伴生对象定义了自增主键,插入成功后会替换掉实体对象中对应字段的值)
     * @return Int 受影响行数
     */
    override fun exec(): Int {
        val result = database.execReturnKey(conn!!, this.sql())
        if (!isTransaction) {
            conn!!.close()
        }

        result.forEachIndexed { index, item ->
            val clazz = records[index]::class
            val field = (clazz.declaredMembers.find { it.name == incrKey } as KProperty).javaField
            field?.isAccessible = true
            val convert = convertIncrKey(item, field?.type?.typeName!!)
            field.set(records[index], convert)
        }
        return this.sqlInsert.values.size
    }

    /**
     * @param key Long
     * @param javaType String
     * @return Any
     */
    private fun convertIncrKey(key: Long, javaType: String): Any {
        return when (javaType) {
            "java.lang.Byte" -> key.toByte()
            "java.lang.Short" -> key.toShort()
            "java.lang.Integer" -> key.toInt()
            "java.lang.Long" -> key
            else -> key.toString()
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy