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

Class Method, % Branch, % Line, % Instruction, %
CascadeJoinClause 40% (2/5) 26.7% (4/15) 42.6% (23/54) 60.3% (120/199)
CascadeJoinClause$WhenMappings
Total 40% (2/5) 26.7% (4/15) 42.6% (23/54) 60.3% (120/199)


 /**
  * 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.beans.task.KronosAtomicQueryTask
 import com.kotlinorm.beans.task.KronosQueryTask
 import com.kotlinorm.beans.task.KronosQueryTask.Companion.toKronosQueryTask
 import com.kotlinorm.cache.kPojoAllFieldsCache
 import com.kotlinorm.enums.KOperationType
 import com.kotlinorm.enums.QueryType.QueryList
 import com.kotlinorm.enums.QueryType.QueryOne
 import com.kotlinorm.enums.QueryType.QueryOneOrNull
 import com.kotlinorm.interfaces.KPojo
 import com.kotlinorm.orm.cascade.CascadeSelectClause.setValues
 import kotlin.reflect.KClass
 
 /**
  * Defines the logic for building and executing cascade join clauses in the context of ORM operations.
  *
  * This object encapsulates methods for constructing and executing tasks that perform cascading operations
  * on database entities. It supports operations where cascading is conditional based on the presence of
  * cascade flags and limit constraints. The primary functionality includes generating tasks for cascading
  * operations and setting values on target entities based on the results of these operations.
  */
 object CascadeJoinClause {
     /**
      * Builds a task for performing cascading operations based on the provided parameters.
      *
      * This function decides whether to proceed with generating a cascading task based on the `cascade` flag
      * and the `limit` parameter. If cascading is enabled and the limit is not zero, it generates a task
      * that performs cascading operations. Otherwise, it returns the root task without modifications.
      *
      * 根据提供的参数构建执行级联操作的任务。
      *
      * 此函数根据 `cascade` 标志 和 `limit` 参数决定是否继续生成级联任务。如果启用了级联且限制不为零,它将生成执行级联操作的任务。否则,它将返回不经修改的根任务。
      *
      * @param cascade Indicates whether cascading should be performed.
      * @param cascadeAllowed The maximum depth of cascading. A limit of 0 indicates no cascading.
      * @param listOfPojo A list of [KPojo] instances on which cascading operations are to be performed.
      * @param rootTask The root [KronosAtomicQueryTask] from which cascading operations may be initiated.
      * @param selectFields A map of field names to [Field] instances that are to be considered for cascading operations.
      * @return A [KronosQueryTask] that represents the task to be executed, potentially including cascading operations.
      */
     fun build(
         cascade: Boolean,
         cascadeAllowed: Set<Field>? = null,
         listOfPojo: List<Pair<KClass<KPojo>, KPojo>>,
         rootTask: KronosAtomicQueryTask,
         operationType: KOperationType,
         selectFields: MutableMap<String, Field>,
         cascadeSelectedProps: Set<Field>
     ) =
         if (cascade) generateTask(
             cascadeAllowed,
             cascadeSelectedProps,
             listOfPojo.map {
                 Triple(
                     it.first,
                     it.second,
                     kPojoAllFieldsCache[it.first]!!.filter { col -> selectFields.values.contains(col) }
                 )
             },
             operationType,
             rootTask
         ) else rootTask.toKronosQueryTask()
 
     /**
      * Generates a task for performing cascading operations based on the provided parameters.
      *
      * This function constructs a task that performs cascading operations on a list of [KPojo] instances.
      *
      * 根据提供的参数生成执行级联操作的任务。
      *
      * 此函数构造一个任务,对 [KPojo] 实例列表执行级联操作。
      *
      * @param cascadeAllowed The maximum depth of cascading. A limit of 0 indicates no cascading.
      * @param listOfColumns A list of [KPojo] instances and their associated columns to be considered for cascading operations.
      * @param operationType The type of operation to be performed on the [KPojo] instances.
      * @param prevTask The previous task in the chain of operations.
      * @return A [KronosQueryTask] that represents the task to be executed, potentially including cascading operations.
      */
     @Suppress("UNCHECKED_CAST")
     private fun generateTask(
         cascadeAllowed: Set<Field>? = null,
         cascadeSelectedProps: Set<Field>,
         listOfColumns: List<Triple<KClass<KPojo>, KPojo, List<Field>>>,
         operationType: KOperationType,
         prevTask: KronosAtomicQueryTask
     ): KronosQueryTask {
         val listOfValidReferences = listOfColumns.map { columns ->
             findValidRefs(
                 columns.first,
                 columns.third,
                 KOperationType.SELECT,
                 cascadeAllowed?.filter { it.tableName == columns.second.kronosTableName() }?.map { it.name }?.toSet(),
                 cascadeAllowed.isNullOrEmpty()
             ) // 获取所有的非数据库列、有关联注解且用于删除操作
         }
         val validReferences = listOfValidReferences.flatten()
         return prevTask.toKronosQueryTask().apply {
             // 若没有关联信息,返回空(在deleteClause的build中,有对null值的判断和默认值处理)
             // 为何不直接返回deleteTask: 因为此处的deleteTask构建sql语句时带有表名,而普通的deleteTask不带表名,因此需要重新构建
             if (validReferences.isEmpty()) return@apply // 如果没有级联,直接返回
             doAfterQuery { queryType, wrapper ->
                 validReferences.forEach { validRef ->
                     when (queryType) {
                         QueryList -> { // 若是查询KPojo列表
                             val lastStepResult = this as List<KPojo> // this为主表查询的结果
                             if (lastStepResult.isEmpty()) return@forEach // 如果没有查询结果,直接返回
                             val propName = validRef.field.name // 获取级联字段的属性如:GroupClass.students
                             lastStepResult.forEach rowMapper@{
                                 setValues(
                                     it,
                                     propName,
                                     validRef,
                                     cascadeAllowed,
                                     cascadeSelectedProps,
                                     operationType,
                                     wrapper
                                 )
                             }
                         }
 
                         QueryOne, QueryOneOrNull -> {
                             val lastStepResult = this as KPojo? // this为主表查询的结果
                             if (lastStepResult == null) return@forEach // 如果没有查询结果,直接返回
                             val propName = validRef.field.name // 获取级联字段的属性如:GroupClass.students
                             setValues(
                                 lastStepResult,
                                 propName,
                                 validRef,
                                 cascadeAllowed,
                                 cascadeSelectedProps,
                                 operationType,
                                 wrapper
                             )
                         }
 
                         else -> {}
                     }
                 }
             }
         }
     }
 }