vec.TerminationFunctions.kt Maven / Gradle / Ivy
/*
* Copyright (c) 2023-Present, Mybatis-Flex-Kotlin ([email protected]).
*
* 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.mybatisflex.kotlin.vec
import com.mybatisflex.core.query.*
import com.mybatisflex.core.row.Db
import com.mybatisflex.core.row.Row
import com.mybatisflex.kotlin.extensions.kproperty.column
import com.mybatisflex.kotlin.extensions.sql.not
import java.math.BigDecimal
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
fun QueryVector.toList(): List = mapper.selectListByQuery(wrapper)
fun QueryVector.toRows(): List = mapper.selectRowsByQuery(wrapper)
inline val QueryVector.values: List get() = toRows().flatMap { it.values }
inline val QueryVector.keys: Set get() = toRows().flatMapTo(HashSet()) { it.keys }
@OptIn(ExperimentalContracts::class)
inline fun > QueryVector.maxOf(selector: (E) -> KProperty): R {
contract {
callsInPlace(selector, InvocationKind.EXACTLY_ONCE)
}
val column = selector(entity)
return funOf(column) {
max(it)
}
}
@OptIn(ExperimentalContracts::class)
inline fun > QueryVector.maxBy(selector: (E) -> KProperty): E? {
contract {
callsInPlace(selector, InvocationKind.EXACTLY_ONCE)
}
val column = selector(entity).column
val maxValue = QueryWrapper().select(QueryFunctions.max(column)).from(queryTable)
return find { column.eq(maxValue) }
}
@OptIn(ExperimentalContracts::class)
inline fun > QueryVector.minOf(selector: (E) -> KProperty): R {
contract {
callsInPlace(selector, InvocationKind.EXACTLY_ONCE)
}
val column = selector(entity)
return funOf(column) {
min(it)
}
}
@OptIn(ExperimentalContracts::class)
inline fun > QueryVector.minBy(selector: (E) -> KProperty): E? {
contract {
callsInPlace(selector, InvocationKind.EXACTLY_ONCE)
}
val column = selector(entity).column
val minValue = QueryWrapper().select(QueryFunctions.min(column)).from(queryTable)
return find { column.eq(minValue) }
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.avgOf(selector: (E) -> KProperty): BigDecimal {
contract {
callsInPlace(selector, InvocationKind.EXACTLY_ONCE)
}
val column = selector(entity).column
val wrapper = wrapper
CPI.setSelectColumns(wrapper, mutableListOf())
wrapper.select(QueryMethods.avg(column))
return mapper.selectObjectByQueryAs(wrapper, BigDecimal::class.java)
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.sumOf(selector: (E) -> KProperty): BigDecimal {
contract {
callsInPlace(selector, InvocationKind.EXACTLY_ONCE)
}
val column = selector(entity).column
val wrapper = wrapper
CPI.setSelectColumns(wrapper, mutableListOf())
wrapper.select(QueryMethods.sum(column))
return mapper.selectObjectByQueryAs(wrapper, BigDecimal::class.java)
}
fun QueryVector.count() = mapper.selectCountByQuery(QueryWrapper().from(wrapper).`as`(data.tableAlias))
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.count(predicate: (E) -> QueryCondition): Long {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return filter(predicate).count()
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.all(predicate: (E) -> QueryCondition): Boolean {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return none { !predicate(entity) }
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.any(predicate: (E) -> QueryCondition): Boolean {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return count(predicate) > 0L
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.none(predicate: (E) -> QueryCondition): Boolean {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return count(predicate) == 0L
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.funOf(
column: KProperty,
selector: QueryFunctions.(QueryColumn) -> QueryColumn
): R {
contract {
callsInPlace(selector, InvocationKind.EXACTLY_ONCE)
}
val wrapper = wrapper
CPI.setSelectColumns(wrapper, mutableListOf())
wrapper.select(QueryFunctions.selector(column.column))
return mapper.selectObjectByQueryAs(wrapper, R::class.java)
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.find(predicate: (E) -> QueryCondition): E? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return firstOrNull(predicate)
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.findLast(predicate: (E) -> QueryCondition): E? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return lastOrNull(predicate)
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.first(predicate: (E) -> QueryCondition): E {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return requireNotNull(firstOrNull(predicate))
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.firstOrNull(predicate: (E) -> QueryCondition): E? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return filter(predicate).elementAt(0)
}
inline fun QueryVector.first(): E = requireNotNull(firstOrNull())
inline fun QueryVector.firstOrNull(): E? = elementAt(0)
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.last(predicate: (E) -> QueryCondition): E {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
return requireNotNull(lastOrNull(predicate))
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.lastOrNull(predicate: (E) -> QueryCondition): E? {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
val filter = filter(predicate)
val rows = filter.data.rows
return filter.elementAt((if (rows < 1) Db.selectCountByQuery(filter.wrapper) else rows) - 1)
}
inline fun QueryVector.last(): E = requireNotNull(lastOrNull())
inline fun QueryVector.lastOrNull(): E? =
elementAt((if (data.rows < 1) Db.selectCountByQuery(wrapper) else data.rows) - 1)
inline fun QueryVector.elementAt(index: Long): E? {
val idx = data.offset + index
val wrapper = wrapper.limit(idx, 1)
return try {
mapper.selectOneByQuery(wrapper)
} catch (_: Throwable) {
null
}
}
inline operator fun QueryVector.get(index: Long): E = requireNotNull(elementAt(index))
inline operator fun QueryVector.get(range: IntRange): List =
limit(range.first.toLong(), (range.last + 1).toLong()).toList()
fun QueryVector.isEmpty(): Boolean = count() == 0L
fun QueryVector.isNotEmpty(): Boolean = !isEmpty()
inline fun QueryVector.push(entity: E, vararg columns: KProperty1): Int {
if (entity is Row) {
return Db.insert(queryTable.schema, queryTable.name, entity)
}
return if (columns.isEmpty()) {
mapper.insert(entity, false)
} else {
val row = columns.associateTo(Row()) {
it.column.name to it(entity)
}
Db.insert(queryTable.schema, queryTable.name, row)
}
}
@OptIn(ExperimentalContracts::class)
inline fun QueryVector.removeIf(predicate: (E) -> QueryCondition): Int {
contract {
callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
}
val condition = predicate(entity)
return mapper.deleteByCondition(condition)
}