Coverage Summary for Class: CascadeInsertClause (com.kotlinorm.orm.cascade)

Class Class, % Method, % Branch, % Line, % Instruction, %
CascadeInsertClause 100% (1/1) 100% (4/4) 38.9% (7/18) 61.1% (11/18) 59.1% (81/137)


 /**
  * 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.cascade
 
 import com.kotlinorm.beans.dsl.Field
 import com.kotlinorm.interfaces.KPojo
 import com.kotlinorm.beans.task.KronosActionTask.Companion.toKronosActionTask
 import com.kotlinorm.beans.task.KronosAtomicActionTask
 import com.kotlinorm.cache.kPojoPrimaryKeyCache
 import com.kotlinorm.enums.KOperationType
 import com.kotlinorm.enums.PrimaryKeyType
 import com.kotlinorm.orm.cascade.NodeOfKPojo.Companion.toTreeNode
 import com.kotlinorm.orm.insert.insert
 import com.kotlinorm.plugins.LastInsertIdPlugin.lastInsertId
 import com.kotlinorm.plugins.LastInsertIdPlugin.withId
 import com.kotlinorm.utils.getTypeSafeValue
 
 /**
  * Used to build a cascade insert clause.
  *
  * 构建级联插入子句。
  *
  * This object is used to construct a cascade insert clause for a database operation.
  * It contains a nested Counter class for counting operations, a nested ValidCascade data class for storing cascades and cascaded POJOs,
  * and several functions for building the cascade insert clause and generating SQL statements.
  *
  * The main function is build, which takes a POJO, a cascade flag, a list of allowed properties, and a root task,
  * and returns a KronosAtomicActionTask object representing the cascade insert operation.
  *
  * The other function is generateTask, which generates a task for the cascade insert operation.
  *
  */
 object CascadeInsertClause {
     /**
      * Build a cascade insert clause.
      * 构建级联插入子句。
      *
      * @param cascade Whether the cascade is enabled.
      * @param cascadeAllowed The properties that are allowed to cascade.
      * @param pojo The POJO to insert.
      * @param rootTask The root task.
      * @return A KronosAtomicActionTask object representing the cascade insert operation.
      */
     fun <T : KPojo> build(
         cascade: Boolean,
         cascadeAllowed: Set<Field>?,
         pojo: T, rootTask: KronosAtomicActionTask
     ) =
         if (cascade) generateTask(cascadeAllowed, pojo, rootTask) else rootTask.toKronosActionTask()
 
     /**
      * Generate a task for the cascade insert operation.
      * 为级联插入操作生成任务。
      *
      * @param cascadeAllowed The properties that are allowed to cascade.
      * @param pojo The POJO to insert.
      * @param prevTask The previous task.
      * @return A KronosAtomicActionTask object representing the cascade insert operation.
      */
     private fun generateTask(
         cascadeAllowed: Set<Field>?,
         pojo: KPojo,
         prevTask: KronosAtomicActionTask
     ) = prevTask.toKronosActionTask().doAfterExecute { wrapper ->
         //因为子插入任务需要等待父插入任务执行完毕,才能获取到父插入任务的主键值(若使用了自增主键),因此级联操作放在doAfterExecute中执行:
         val operationResult = this //当前任务的执行结果, 用于获取自增主键值
         pojo.toTreeNode(NodeInfo(true), cascadeAllowed, KOperationType.INSERT) {
             val identity = kPojoPrimaryKeyCache[kPojo.kClass()].takeIf { it!!.primaryKey == PrimaryKeyType.IDENTITY } ?: return@toTreeNode // 若没有自增主键,直接返回
             if(insertIgnore) return@toTreeNode // 若有子节点提升到本节点的父节点,在此层级不需要执行插入操作,而是在insertIgnore为true的子节点的下一层级执行插入操作
             val lastInsertId = if (kPojo != pojo) { // 判断当前进行的插入操作是否为最外层的插入操作
                 kPojo.insert().cascade(enabled = false).withId().execute(wrapper) // 若不是最外层的插入操作,执行当前任务,获取当前任务的执行结果
             } else {
                 operationResult // 若是最外层的插入操作,直接获取当前任务的执行结果
             }.lastInsertId
             val propName = identity.name
             if (lastInsertId != null && lastInsertId != 0L && dataMap[propName] == null) { // 若自增主键值不为空且未被赋值
                 val typeSafeId =
                     getTypeSafeValue(
                         identity.kClass!!.qualifiedName!!,
                         lastInsertId
                     ) // 获取自增主键值的类型安全值,如将Long转为Int/Short等
                 dataMap[propName] = typeSafeId // 将自增主键值赋给当前插入任务的数据映射
                 kPojo[propName] = typeSafeId // 将自增主键值赋给当前插入任务的POJO
             }
         }
     }
 }