Coverage Summary for Class: InsertClause (com.kotlinorm.orm.insert)
Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
InsertClause |
72.7%
(8/11)
|
44.1%
(15/34)
|
84.8%
(67/79)
|
77.7%
(366/471)
|
InsertClause$Companion |
9.1%
(1/11)
|
0%
(0/4)
|
9.1%
(1/11)
|
10.7%
(14/131)
|
InsertClause$WhenMappings |
|
Total |
40.9%
(9/22)
|
39.5%
(15/38)
|
75.6%
(68/90)
|
63.1%
(380/602)
|
/**
* Copyright 2022-2025 kronos-orm
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kotlinorm.orm.insert
import com.kotlinorm.beans.dsl.Field
import com.kotlinorm.beans.dsl.KTableForReference.Companion.afterReference
import com.kotlinorm.beans.generator.SnowflakeIdGenerator
import com.kotlinorm.beans.generator.UUIDGenerator
import com.kotlinorm.beans.generator.customIdGenerator
import com.kotlinorm.beans.task.KronosActionTask
import com.kotlinorm.beans.task.KronosActionTask.Companion.merge
import com.kotlinorm.beans.task.KronosAtomicActionTask
import com.kotlinorm.beans.task.KronosOperationResult
import com.kotlinorm.cache.fieldsMapCache
import com.kotlinorm.cache.insertSqlCache
import com.kotlinorm.cache.kPojoAllColumnsCache
import com.kotlinorm.cache.kPojoCreateTimeCache
import com.kotlinorm.cache.kPojoLogicDeleteCache
import com.kotlinorm.cache.kPojoOptimisticLockCache
import com.kotlinorm.cache.kPojoPrimaryKeyCache
import com.kotlinorm.cache.kPojoUpdateTimeCache
import com.kotlinorm.database.SqlManager.getInsertSql
import com.kotlinorm.enums.KOperationType
import com.kotlinorm.enums.PrimaryKeyType
import com.kotlinorm.exceptions.EmptyFieldsException
import com.kotlinorm.interfaces.KPojo
import com.kotlinorm.interfaces.KronosDataSourceWrapper
import com.kotlinorm.orm.cascade.CascadeInsertClause
import com.kotlinorm.types.ToReference
import com.kotlinorm.utils.DataSourceUtil.orDefault
import com.kotlinorm.utils.execute
import com.kotlinorm.utils.processParams
class InsertClause<T : KPojo>(val pojo: T) {
private val paramMap = pojo.toDataMap()
private val tableName = pojo.kronosTableName()
private var kClass = pojo.kClass()
private var createTimeStrategy = kPojoCreateTimeCache[kClass]
private var updateTimeStrategy = kPojoUpdateTimeCache[kClass]
private var logicDeleteStrategy = kPojoLogicDeleteCache[kClass]
private var optimisticStrategy = kPojoOptimisticLockCache[kClass]
internal var allColumns = kPojoAllColumnsCache[kClass]!!
private var cascadeEnabled = true
var stash = mutableMapOf<String, Any?>()
/**
* cascadeAllowed
*
* Fields that are allowed to use cascade, if not set, all fields are allowed to use cascade
*
* 允许级联的字段,若为空则允许所有字段级联
*/
internal var cascadeAllowed: Set<Field>? = null
fun cascade(enabled: Boolean): InsertClause<T> {
cascadeEnabled = enabled
return this
}
fun cascade(someFields: ToReference<T, Any?>): InsertClause<T> {
someFields ?: throw EmptyFieldsException()
cascadeEnabled = true
pojo.afterReference {
someFields(it)
if (fields.isEmpty()) throw EmptyFieldsException()
cascadeAllowed = fields.toSet()
}
return this
}
fun build(wrapper: KronosDataSourceWrapper? = null): KronosActionTask {
var useIdentity = false
val paramMapNew = mutableMapOf<String, Any?>()
val fieldsMap = fieldsMapCache[kClass]!!
val toInsertFields = mutableListOf<Field>()
val primaryKeyField = kPojoPrimaryKeyCache[kClass]!!
when (primaryKeyField.primaryKey) {
PrimaryKeyType.UUID -> paramMap[primaryKeyField.name] = UUIDGenerator.nextId()
PrimaryKeyType.SNOWFLAKE -> paramMap[primaryKeyField.name] = SnowflakeIdGenerator.nextId()
PrimaryKeyType.CUSTOM -> paramMap[primaryKeyField.name] = customIdGenerator?.nextId()
PrimaryKeyType.IDENTITY -> useIdentity = true
else -> {}
}
if (paramMap[primaryKeyField.name] != null || primaryKeyField.defaultValue != null) {
useIdentity = false
}
stash["useIdentity"] = useIdentity
allColumns.forEach {
if (it.defaultValue != null && paramMap[it.name] == null) {
paramMap[it.name] = it.defaultValue
}
if (it.isColumn && !(it.primaryKey == PrimaryKeyType.IDENTITY && paramMap[it.name] == null)) {
toInsertFields.add(it)
}
}
if(useIdentity && !paramMap.containsKey(primaryKeyField.name)){
toInsertFields.remove(primaryKeyField)
}
arrayOf(
createTimeStrategy to true,
updateTimeStrategy to true,
logicDeleteStrategy to false,
optimisticStrategy to false
).forEach {
it.first?.execute(it.second) { field, value ->
paramMap[field.name] = value
}
}
paramMap.forEach { (key, value) ->
val field = fieldsMap[key]
if (field != null && value != null) {
paramMapNew[key] = processParams(wrapper.orDefault(), field, value)
} else {
paramMapNew[key] = value
}
}
val sql = insertSqlCache[kClass to useIdentity, {
getInsertSql(
wrapper.orDefault(),
tableName,
toInsertFields
).also {
insertSqlCache[kClass to useIdentity] = it
}
}]
return CascadeInsertClause.build(
cascadeEnabled,
cascadeAllowed,
pojo,
KronosAtomicActionTask(
sql,
paramMapNew,
operationType = KOperationType.INSERT,
actionInfo = InsertClauseInfo(
kClass,
tableName
),
stash = stash
)
)
}
fun execute(wrapper: KronosDataSourceWrapper? = null): KronosOperationResult {
return build().execute(wrapper)
}
companion object {
fun <T : KPojo> Iterable<InsertClause<T>>.cascade(
enabled: Boolean
): Iterable<InsertClause<T>> {
return this.onEach { it.cascade(enabled) }
}
fun <T : KPojo> Iterable<InsertClause<T>>.cascade(
someFields: ToReference<T, Any?>
): Iterable<InsertClause<T>> {
return this.onEach { it.cascade(someFields) }
}
/**
* Builds a KronosActionTask for each InsertClause in the list.
*
* This function maps each InsertClause in the Iterable to a KronosActionTask by calling the build function of the InsertClause.
* It then merges all the KronosActionTasks into a single KronosActionTask using the merge function and returns it.
*
* @return KronosActionTask returns a single KronosActionTask that represents the merged tasks for all the InsertClauses in the Iterable.
*/
fun <T : KPojo> Iterable<InsertClause<T>>.build(): KronosActionTask {
return this.map { it.build() }.merge()
}
/**
* Executes the KronosActionTask built for each InsertClause in the Iterable.
*
* This function first builds a KronosActionTask for each InsertClause in the Iterable by calling the build function.
* It then executes the built KronosActionTask and returns the result.
*
* @param wrapper KronosDataSourceWrapper? (optional) the data source wrapper to use for the execution. If not provided, the default data source wrapper is used.
* @return KronosOperationResult returns the result of the execution of the KronosActionTask.
*/
fun <T : KPojo> Iterable<InsertClause<T>>.execute(wrapper: KronosDataSourceWrapper? = null): KronosOperationResult {
return build().execute(wrapper)
}
fun <T : KPojo> Array<InsertClause<T>>.cascade(enabled: Boolean): Array<out InsertClause<T>> {
return this.onEach { it.cascade(enabled) }
}
fun <T : KPojo> Array<InsertClause<T>>.cascade(someFields: ToReference<T, Any?>): Array<out InsertClause<T>> {
return this.onEach { it.cascade(someFields) }
}
/**
* Builds a KronosActionTask for each InsertClause in the Array.
*
* This function maps each InsertClause in the Iterable to a KronosActionTask by calling the build function of the InsertClause.
* It then merges all the KronosActionTasks into a single KronosActionTask using the merge function and returns it.
*
* @return KronosActionTask returns a single KronosActionTask that represents the merged tasks for all the InsertClauses in the Iterable.
*/
fun <T : KPojo> Array<InsertClause<T>>.build(wrapper: KronosDataSourceWrapper? = null): KronosActionTask {
return this.map { it.build(wrapper) }.merge()
}
/**
* Executes the KronosActionTask built for each InsertClause in the array.
*
* This function first builds a KronosActionTask for each InsertClause in the Iterable by calling the build function.
* It then executes the built KronosActionTask and returns the result.
*
* @param wrapper KronosDataSourceWrapper? (optional) the data source wrapper to use for the execution. If not provided, the default data source wrapper is used.
* @return KronosOperationResult returns the result of the execution of the KronosActionTask.
*/
fun <T : KPojo> Array<InsertClause<T>>.execute(wrapper: KronosDataSourceWrapper? = null): KronosOperationResult {
return build().execute(wrapper)
}
}
}