Coverage Summary for Class: KronosActionTask (com.kotlinorm.beans.task)

Class Method, % Branch, % Line, % Instruction, %
KronosActionTask 90.9% (10/11) 63.6% (14/22) 84.6% (33/39) 76.1% (204/268)
KronosActionTask$Companion 60% (3/5) 75% (9/12) 100% (14/14) 94.6% (122/129)
Total 81.2% (13/16) 67.6% (23/34) 88.7% (47/53) 82.1% (326/397)


 /**
  * 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.beans.task
 
 import com.kotlinorm.interfaces.KronosDataSourceWrapper
 import com.kotlinorm.utils.DataSourceUtil.orDefault
 import com.kotlinorm.utils.execute
 
 /**
  * KronosActionTask class represents a Kronos action task used to execute multiple Kronos atomic action tasks.
  */
 class KronosActionTask {
     internal val atomicTasks: MutableList<KronosAtomicActionTask> = mutableListOf() //原子任务列表
     private var beforeExecute: (KronosActionTask.(KronosDataSourceWrapper) -> Unit)? = null //在执行之前执行的操作
     var afterExecute: (KronosOperationResult.(KronosDataSourceWrapper) -> Unit)? =
         null //在执行之后执行的操作(返回一个新的KronosActionTask)
 
     fun doBeforeExecute(beforeExecute: KronosActionTask.(KronosDataSourceWrapper) -> Unit): KronosActionTask { //设置在执行之前执行的操作
         this.beforeExecute = beforeExecute
         return this
     }
 
     fun doAfterExecute(afterExecute: (KronosOperationResult.(KronosDataSourceWrapper) -> Unit)?): KronosActionTask { //设置在执行之前执行的操作
         this.afterExecute = afterExecute
         return this
     }
 
     /**
      * Groups a list of KronosAtomicActionTask by their SQL statements.
      *
      * This function takes a list of KronosAtomicActionTask as input and groups them by their SQL statements.
      * It uses the fold function to iterate over the list of tasks and groups them into sublists.
      * If the accumulator list is empty or the SQL statement of the last task in the last sublist is not the same as the SQL statement of the current task,
      * it adds a new sublist to the accumulator list with the current task as its first element.
      * Otherwise, it adds the current task to the last sublist in the accumulator list.
      * The function returns the accumulator list which is a list of sub lists of tasks grouped by their SQL statements.
      *
      * 保证只有连续的sql语句才会被分组,[a, a, b, b, b, c, c, a, a] => [[a, a], [b, b, b], [c, c], [a, a]]
      *
      * @param listOfTask List<KronosAtomicActionTask> the list of KronosAtomicActionTask to group.
      * @return List<List<KronosAtomicActionTask>> returns a list of sub lists of KronosAtomicActionTask grouped by their SQL statements.
      */
     private fun groupBySql(listOfTask: List<KronosAtomicActionTask>): List<List<KronosAtomicActionTask>> {
         return listOfTask.fold(mutableListOf<MutableList<KronosAtomicActionTask>>()) { acc, task ->
             if (acc.isEmpty() || acc.last().last().sql != task.sql) {
                 acc.add(mutableListOf(task))
             } else {
                 acc.last().add(task)
             }
             acc
         }
     }
 
     fun execute(wrapper: KronosDataSourceWrapper? = null): KronosOperationResult {
         val dataSource = wrapper.orDefault() //获取数据源
         beforeExecute?.invoke(this, dataSource) // 在执行之前执行的操作
 
         val groupedTasks = groupBySql(atomicTasks).map { //按照sql分组
             val first = it.first()
             if (it.size > 1) { //如果有多个任务
                 KronosAtomicBatchTask( //创建一个批量任务
                     first.sql,
                     it.map { task -> task.paramMap }.toTypedArray(),
                     first.operationType,
                     first.actionInfo
                 )
             } else { //如果只有一个任务
                 first
             }
         }
 
         @Suppress("UNCHECKED_CAST")
         val results = dataSource.transact { //执行事务
             groupedTasks.map {
                 it.execute(dataSource)
             }
         } as List<KronosOperationResult>
         val affectRows = results.sumOf { it.affectedRows } //受影响的行数
         return KronosOperationResult(affectRows).apply {
             afterExecute?.invoke(this, dataSource) //在执行之后执行的操作
             if(results.isNotEmpty()) {
                 stash.putAll(results.last().stash) //将最后一个结果的stash放入当前结果
             }
         }
     }
 
     companion object {
         fun List<KronosAtomicActionTask>.toKronosActionTask(): KronosActionTask {
             return KronosActionTask().also {
                 it.atomicTasks.addAll(this)
             }
         }
 
         /**
          * Converts a KronosAtomicActionTask to a KronosActionTask.
          *
          * This function creates a new KronosActionTask and adds the current KronosAtomicActionTask to it.
          * It also copies the stash from the current task to the new task.
          *
          * @receiver KronosAtomicActionTask the current KronosAtomicActionTask to convert.
          * @return KronosActionTask returns a new KronosActionTask with the current task added to it.
          */
         fun KronosAtomicActionTask.toKronosActionTask(): KronosActionTask {
             return KronosActionTask().also {
                 it.atomicTasks.add(this)
                 it.atomicTasks.forEach { task -> task.stash.putAll(stash) }
             }
         }
 
         /**
          * Merges a list of KronosActionTask into a single KronosActionTask.
          *
          * This function creates a new KronosActionTask and adds all the atomic tasks from each KronosActionTask in the list to it.
          * It uses the flatMap function to flatten the list of atomic tasks from each KronosActionTask into a single list.
          * The flattened list of atomic tasks is then added to the atomic tasks of the new KronosActionTask.
          *
          * @receiver List<KronosActionTask> the list of KronosActionTask to merge.
          * @return KronosActionTask returns a new KronosActionTask with all the atomic tasks from each KronosActionTask in the list.
          */
         fun List<KronosActionTask>.merge(): KronosActionTask {
             return KronosActionTask().apply {
                 atomicTasks.addAll(flatMap { it.atomicTasks })
                 if(any { it.beforeExecute != null }) {
                     beforeExecute = { wrapper -> forEach { it.beforeExecute?.invoke(this, wrapper) } }
                 }
                 if (any { it.afterExecute != null }) {
                     afterExecute = { wrapper -> forEach { it.afterExecute?.invoke(this, wrapper) } }
                 }
             }
         }
     }
 
     private val firstTask by lazy { atomicTasks.firstOrNull() }
 
     operator fun component1(): String {
         return firstTask?.sql ?: ""
     }
 
     operator fun component2(): Map<String, Any?> {
         return firstTask?.paramMap ?: mapOf()
     }
 
     operator fun component3(): MutableList<KronosAtomicActionTask> {
         return atomicTasks
     }
 }