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

query.delete.Delete.kt Maven / Gradle / Ivy

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

import ast.expr.SqlIdentifierExpr
import ast.statement.delete.SqlDelete
import dsl.column
import database.DB
import dsl.Query
import dsl.QueryTableColumn
import dsl.TableSchema
import query.ReviseQuery
import util.toSqlString
import visitor.getQueryExpr
import java.sql.Connection
import java.sql.SQLException
import kotlin.reflect.full.companionObjectInstance
import kotlin.reflect.full.declaredMemberProperties

/**
 * delete语句dsl类
 * @property db DB 数据库类型
 * @property conn Connection? 数据库连接
 * @property isTransaction Boolean 是否是事务
 * @property sqlDelete SqlDelete delete语法树
 */
class Delete(
    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 sqlDelete = SqlDelete()

    /**
     * delete from子句
     * 例如:Delete() from "t1"
     * @param table String 表名
     * @return Delete 删除dsl
     */
    infix fun from(table: String): Delete {
        sqlDelete.table = SqlIdentifierExpr(table)
        return this
    }

    /**
     * delete from子句
     * 例如:Delete() from Table
     * @param table T 实体类伴生对象名
     * @return Delete 删除dsl
     */
    infix fun  from(table: T): Delete {
        return from(table.tableName)
    }

    /**
     * 根据实体数据生成按主键删除数据的sql
     * 例如:Delete() delete entity
     * @param entity Any 实体数据
     * @return Delete 删除dsl
     */
    infix fun delete(entity: Any): Delete {
        val clazz = entity::class
        val fields = clazz.declaredMemberProperties
            .map { it.name to it.getter.call(entity) }
            .toMap()

        val companion = clazz.companionObjectInstance ?: throw Exception("实体类需要添加伴生对象")
        val companionClass = companion::class
        val table = companion as TableSchema
        from(table.tableName)

        val pkCols = companionClass.declaredMemberProperties
            .asSequence()
            .map { it.name to it.getter.call(companion) }
            .filter { it.second is QueryTableColumn }
            .map { it.first to (it.second as QueryTableColumn) }
            .filter { it.second.primaryKey }
            .map { it.second.column to fields[it.first] }
            .toMap()

        if (pkCols.isEmpty()) {
            throw SQLException("实体类的伴生对象中没有设置主键字段")
        }

        pkCols.forEach {
            if (it.value == null) {
                throw SQLException("主键为空")
            } else {
                where(column(it.key) eq it.value)
            }
        }
        return this
    }

    /**
     * 生成按主键删除数据的sql
     * 例如:Delete().delete(1)
     * @param primaryKey Any 主键的值
     * @return Delete 删除dsl
     */
    @JvmName("deleteById")
    inline infix fun  delete(primaryKey: Any): Delete {
        val companion = T::class.companionObjectInstance ?: throw Exception("实体类需要添加伴生对象")

        val tableName = (companion as TableSchema).tableName

        val companionClass = companion::class
        val pkCols = companionClass.declaredMemberProperties
            .map { it.getter.call(companion) }
            .filterIsInstance()
            .filter { it.primaryKey }

        if (pkCols.isEmpty()) {
            throw SQLException("实体类的伴生对象中没有设置主键字段")
        }

        if (pkCols.size > 1) {
            throw SQLException("主键字段数量和传入的参数不匹配")
        }

        val pkCol = pkCols[0]

        return from(tableName).where(pkCol eq primaryKey)
    }

    /**
     * 生成按主键删除数据的sql(联合主键)
     * @param primaryKeys List> 主键的值
     * @return Delete 删除dsl
     */
    inline fun  delete(primaryKeys: List>): Delete {
        val companion = T::class.companionObjectInstance ?: throw Exception("实体类需要添加伴生对象")

        val tableName = (companion as TableSchema).tableName

        val companionClass = companion::class
        val pkCols = companionClass.declaredMemberProperties
            .map { it.name to it.getter.call(companion) }
            .filter { it.second is QueryTableColumn }
            .map { it.first to it.second as QueryTableColumn }
            .filter { it.second.primaryKey }
            .toMap()

        if (pkCols.isEmpty()) {
            throw SQLException("实体类的伴生对象中没有设置主键字段")
        }

        if (pkCols.size != primaryKeys.size) {
            throw SQLException("主键字段数量和传入的参数不匹配")
        }

        from(tableName)
        primaryKeys.forEach {
            if (pkCols.containsKey(it.first)) {
                where(pkCols[it.first]!! eq it.second)
            }
        }

        return this
    }

    /**
     * 生成按主键删除数据的sql(联合主键)
     * @param primaryKeys Map 主键的值
     * @return Delete 删除dsl
     */
    inline fun  delete(primaryKeys: Map): Delete {
        return delete(primaryKeys.map { it.key to it.value })
    }

    /**
     * where子句(如果有多个where调用,会使用AND拼接条件)
     * @param condition Query where条件中的表达式
     * @return Delete 删除dsl
     */
    infix fun where(condition: Query): Delete {
        this.sqlDelete.addCondition(getQueryExpr(condition, this.db).expr)
        return this
    }

    /**
     * where子句(当前面的lambda返回值为true的时候将条件拼接进sql)
     * @param test Function0 当此参数返回值为true时将condition拼接进sql
     * @param condition Query 条件表达式
     * @return Delete 删除dsl
     */
    fun where(test: () -> Boolean, condition: Query): Delete {
        if (test()) {
            where(condition)
        }

        return this
    }

    /**
     * where子句(当前面的参数为true的时候将条件拼接进sql)
     * @param test Boolean 当此参数为true时将condition拼接进sql
     * @param condition Query 条件表达式
     * @return Delete 删除dsl
     */
    fun where(test: Boolean, condition: Query): Delete {
        if (test) {
            where(condition)
        }

        return this
    }

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