Coverage Summary for Class: UnionClause (com.kotlinorm.orm.union)
Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
UnionClause |
100%
(1/1)
|
66.7%
(8/12)
|
70%
(14/20)
|
92.2%
(47/51)
|
86.5%
(405/468)
|
/**
* 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.union
import com.kotlinorm.beans.task.KronosQueryTask
import com.kotlinorm.interfaces.KPojo
import com.kotlinorm.interfaces.KronosDataSourceWrapper
import com.kotlinorm.orm.select.SelectClause
import com.kotlinorm.utils.ConditionSqlBuilder
open class UnionClause(tasks: List<SelectClause<out KPojo>>) {
private val tasks = tasks.toMutableList()
private var builtTasks: List<KronosQueryTask> = listOf()
private var safeKeyList: List<String> = listOf()
private val fieldNameMapping = mutableMapOf<String, MutableMap<String, String>>()
fun query(wrapper: KronosDataSourceWrapper? = null): List<Map<String, Any?>> {
return executeQuery { it.query(wrapper) }
}
fun queryMap(wrapper: KronosDataSourceWrapper? = null): Map<String, Any?> {
return executeQuery { listOf(it.queryMap(wrapper)) }.first()
}
fun queryMapOrNull(wrapper: KronosDataSourceWrapper? = null): Map<String, Any?>? {
return executeQuery { listOfNotNull(it.queryMapOrNull(wrapper)) }.firstOrNull()
}
private fun executeQuery(
queryFunction: (KronosQueryTask) -> List<Map<String, Any?>>
): List<Map<String, Any?>> {
prepareTasks()
val safeKeyList = getUniqueTask(ConditionSqlBuilder.KeyCounter())
val resultMap = safeKeyList.mapIndexed { index, safeKey ->
val result = queryFunction(builtTasks[index])
safeKey to result
}.toMap()
return if (resultMap.isEmpty()) emptyList() else union(resultMap)
}
private fun prepareTasks() {
builtTasks = tasks.map { it.build() }
}
private fun getUniqueTask(keyCounters: ConditionSqlBuilder.KeyCounter): List<String> {
val fieldCountMap = mutableMapOf<String, Int>()
safeKeyList = tasks.map { task ->
val safeKey = ConditionSqlBuilder.getSafeKey(
task.pojo::class.simpleName.toString(), keyCounters, mutableMapOf(), task
)
task.selectFields.forEach { field ->
fieldCountMap[field.name] = fieldCountMap.getOrDefault(field.name, 0) + 1
}
safeKey
}
fieldNameMapping.clear()
tasks.forEachIndexed { index, task ->
val safeKey = safeKeyList[index]
fieldNameMapping[safeKey] = task.selectFields.associate { field ->
val fieldName = field.name
fieldName to if (fieldCountMap[fieldName]!! > 1) "$safeKey${capitalizeFirstLetter(fieldName)}" else fieldName
}.toMutableMap()
}
return safeKeyList
}
private fun union(resultMap: Map<String, List<Map<String, Any?>>>): List<Map<String, Any?>> {
val maxRowNum = resultMap.values.maxOfOrNull { it.size } ?: 0
val allFields = resultMap.flatMap { (safeKey, list) ->
list.flatMap { it.keys.map { key -> fieldNameMapping[safeKey]!![key]!! } }
}.toSet()
return List(maxRowNum) { index ->
mutableMapOf<String, Any?>().apply {
allFields.forEach { this[it] = null }
resultMap.forEach { (safeKey, list) ->
val fieldNameMap = fieldNameMapping[safeKey]!!
list.getOrNull(index)?.forEach { (key, value) ->
this[fieldNameMap[key]!!] = value
}
}
}
}
}
private fun capitalizeFirstLetter(s: String): String {
return s.replaceFirstChar { it.uppercaseChar() }
}
}