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

com.sxtanna.database.task.KueryTask.kt Maven / Gradle / Ivy

package com.sxtanna.database.task

import com.sxtanna.database.Kuery
import com.sxtanna.database.ext.*
import com.sxtanna.database.struct.base.Duo
import com.sxtanna.database.struct.obj.Duplicate
import com.sxtanna.database.struct.obj.Duplicate.Ignore
import com.sxtanna.database.struct.obj.Sort
import com.sxtanna.database.struct.obj.SqlType
import com.sxtanna.database.struct.obj.Target
import com.sxtanna.database.task.builder.*
import com.sxtanna.database.type.base.SqlObject
import java.sql.Connection
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.util.function.Consumer
import kotlin.reflect.KProperty1
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.isAccessible

@Suppress("UNCHECKED_CAST")
class KueryTask(private val kuery : Kuery, override val resource : Connection) : DatabaseTask() {

	private lateinit var resultSet : ResultSet
	private lateinit var preparedStatement : PreparedStatement


	@JvmSynthetic
	fun query(query : String, vararg values : Any?, block : ResultSet.() -> Unit) {
		if (kuery.debug) kuery.logger.info("Query '$query'")

		preparedStatement = resource.prepareStatement(query)
		values.forEachIndexed { index, any -> preparedStatement.setObject(index + 1, any) }

		resultSet = preparedStatement.executeQuery()
		resultSet.block()
	}

	@JvmOverloads
	fun query(query : String, vararg values : Any? = emptyArray(), block : Consumer) = query(query, *values) { block.accept(this) }


	fun execute(query : String, vararg values : Any?) {
		if (kuery.debug) kuery.logger.info("Statement '$query'")

		preparedStatement = resource.prepareStatement(query)
		if (values.isNotEmpty()) values.forEachIndexed { index, any -> preparedStatement.setObject(index + 1, any) }

		preparedStatement.execute()
	}


	@SafeVarargs
	@Deprecated("Use Create", ReplaceWith("Create.table(name).cos(*columns)", "com.sxtanna.database.task.builder.Create"))
	fun create(name : String, vararg columns : Duo) {
		execute("CREATE TABLE IF NOT EXISTS $name ${columns.map { "${it.name} ${it.value}" }.joinToString(prefix = "(", postfix = ")")}")
	}


	@JvmSynthetic
	@Deprecated("Use Select")
	fun select(table : String, columns : Array = ALL_ROWS, target : Array = NO_WHERE, order : Array = NO_SORTS, block : ResultSet.() -> Unit) {
		val statement = "SELECT ${columns.joinToString()} FROM $table${target.isNotEmpty().value(" WHERE ${target.joinToString(" AND ")}")}${order.isNotEmpty().value(" ORDER BY ${order.joinToString()}")}"

		if (kuery.debug) kuery.logger.info("Select '$statement'")

		preparedStatement = resource.prepareStatement(statement)

		var offSet = 0
		target.forEachIndexed { i, data -> offSet += data.prep(preparedStatement, i + 1 + offSet) }

		resultSet = preparedStatement.executeQuery()
		if (resultSet.isBeforeFirst.not()) return resultSet.close()

		block(resultSet)
	}

	@JvmOverloads
	@Deprecated("Use Select")
	fun select(table : String, columns : Array = ALL_ROWS, target : Array = NO_WHERE, order : Array = NO_SORTS, block : Consumer) {
		select(table, columns, target, order) { block.accept(this) }
	}

	@JvmSynthetic
	@Deprecated("Use Select")
	fun select(table : String, order : Array, block : ResultSet.() -> Unit) = select(table, ALL_ROWS, NO_WHERE, order, block)

	@JvmSynthetic
	@Deprecated("Use Select")
	fun select(table : String, target : Array, block : ResultSet.() -> Unit) = select(table, ALL_ROWS, target, NO_SORTS, block)

	@Deprecated("Use Select")
	fun select(table : String, order : Array, block : Consumer) = select(table, ALL_ROWS, NO_WHERE, order, block)

	@Deprecated("Use Select")
	fun select(table : String, target : Array, block : Consumer) = select(table, ALL_ROWS, target, NO_SORTS, block)


	@JvmOverloads
	@Deprecated("Use Insert")
	fun insert(table : String, vararg columns : Duo, duplicateKey : Duplicate? = null) {
		val ignore = duplicateKey is Ignore
		val insertStatement = "INSERT ${ignore.value("IGNORE ")}INTO $table (${columns.map { it.name }.joinToString()}) VALUES ${values(columns.size)}${ignore.not().value(" ${duplicateKey?.invoke(columns[0].name)}")}"

		execute(insertStatement, *columns.map { it.value }.toTypedArray())
	}


	@JvmOverloads
	@Deprecated("Use Update")
	fun update(table : String, columns : Array>, vararg where : Target = emptyArray()) : Int {
		val updateStatement = "UPDATE $table SET ${columns.joinToString { "${it.name}=?" }}${where.isNotEmpty().value(" WHERE ${where.joinToString(" AND ")}")}"

		if (kuery.debug) kuery.logger.info("Update '$updateStatement'")

		preparedStatement = resource.prepareStatement(updateStatement)
		columns.forEachIndexed { i, data -> preparedStatement.setObject(i + 1, data.value) }

		var offSet = columns.size
		where.forEachIndexed { i, data -> offSet += data.prep(preparedStatement, i + 1 + offSet) }

		return preparedStatement.executeUpdate()
	}


    @JvmOverloads
    @Deprecated("Use Delete")
    fun delete(table : String, vararg where : Target = emptyArray()) {
        val deleteStatement = "DELETE FROM $table ${where.isNotEmpty().value("WHERE ${where.joinToString(" AND ")}")}"

        if (kuery.debug) kuery.logger.info("Delete '$deleteStatement'")

        preparedStatement = resource.prepareStatement(deleteStatement)
        where.forEachIndexed { i, data -> data.prep(preparedStatement, i + 1) }

        preparedStatement.execute()
    }


	//region Building Functions
	@JvmSynthetic
	operator fun Create.invoke() = create(table, *columns.toTypedArray())

	fun execute(create : Create) = create.invoke()


	@JvmSynthetic
	operator fun  Select.invoke(handler : T.() -> Unit) {
		select(table, ALL_ROWS, where.toTypedArray(), sorts.toTypedArray()) {
			val creator = checkNotNull(kuery.creators[clazz] as? ResultSet.() -> T) { "Creator for type $clazz doesn't exist" }
			mapWhileNext(creator).forEach(handler)
		}
	}

	fun  execute(select : Select, handler : Consumer) = select.invoke { handler.accept(this) }


	@JvmSynthetic
	operator fun  Insert.invoke(obj : T) {
		val columns = clazz.declaredMemberProperties.map { it.name co obj.retrieve(it) }.toTypedArray()
		insert(table, *columns, duplicateKey = if (ignore) Ignore() else if (update.isNotEmpty()) Duplicate.Update(*update) else null)
	}

	fun  execute(insert : Insert, obj : T) = insert.invoke(obj)


	@JvmSynthetic
	operator fun  Update.invoke(obj : T) : Int {
		val columns = clazz.declaredMemberProperties.filterNot { it.name.toLowerCase() in ignoring }.map { it.name co obj.retrieve(it) }.toTypedArray()
		return update(table, columns, *where.toTypedArray())
	}

	fun  execute(update : Update, obj : T) = update.invoke(obj)

    @JvmSynthetic
    operator fun  Delete.invoke(obj : T? = null) {
        val where = obj?.let { o -> clazz.declaredMemberProperties.map { Target.equals(it.name, o.retrieve(it)) } } ?: where
        return delete(table, *where.toTypedArray())
    }

    /**
     * If an object is supplied, it will use the data from that object,
     * if not, it will fallback to the clauses specified in the statement
     * If no conditions are supplied, it will delete every row
     */
    @JvmOverloads
    fun  execute(delete : Delete, obj : T? = null) = delete.invoke(obj)
	//endregion


	private fun values(count : Int) = Array(count, { "?" }).joinToString(prefix = "(", postfix = ")")

	private fun  T.retrieve(property : KProperty1) : R {
		val state = property.isAccessible

		property.isAccessible = true
		val obj = property.get(this)
		property.isAccessible = state

		return obj
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy