Basically finish MangaQuery, only paging left

This commit is contained in:
Syer10
2023-04-03 22:04:46 -04:00
parent e8c2bad187
commit a6dddf311c
3 changed files with 455 additions and 89 deletions

View File

@@ -9,23 +9,34 @@ package suwayomi.tachidesk.graphql.queries
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
import graphql.schema.DataFetchingEnvironment import graphql.schema.DataFetchingEnvironment
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.andWhere import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.graphql.queries.util.GreaterOrLessThanLong import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
import suwayomi.tachidesk.graphql.queries.util.andWhereGreaterOrLessThen import suwayomi.tachidesk.graphql.queries.filter.Filter
import suwayomi.tachidesk.graphql.queries.filter.IntFilter
import suwayomi.tachidesk.graphql.queries.filter.LongFilter
import suwayomi.tachidesk.graphql.queries.filter.OpAnd
import suwayomi.tachidesk.graphql.queries.filter.StringFilter
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompare
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareEntity
import suwayomi.tachidesk.graphql.queries.filter.andFilterWithCompareString
import suwayomi.tachidesk.graphql.queries.filter.getOp
import suwayomi.tachidesk.graphql.types.MangaNodeList import suwayomi.tachidesk.graphql.types.MangaNodeList
import suwayomi.tachidesk.graphql.types.MangaNodeList.Companion.toNodeList import suwayomi.tachidesk.graphql.types.MangaNodeList.Companion.toNodeList
import suwayomi.tachidesk.graphql.types.MangaType import suwayomi.tachidesk.graphql.types.MangaType
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.MangaStatus
import suwayomi.tachidesk.manga.model.table.MangaTable import suwayomi.tachidesk.manga.model.table.MangaTable
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
/** /**
* TODO Queries * TODO Queries
* - Query options(optionally query the title, description, or/and)
* *
* TODO Mutations * TODO Mutations
* - Favorite * - Favorite
@@ -43,62 +54,130 @@ class MangaQuery {
return dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id) return dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
} }
enum class MangaSort { enum class MangaOrderBy {
ID, ID,
TITLE, TITLE,
IN_LIBRARY_AT, IN_LIBRARY_AT,
LAST_FETCHED_AT LAST_FETCHED_AT
} }
data class MangaQueryInput( data class MangaCondition(
val ids: List<Int>? = null, val id: Int? = null,
val categoryIds: List<Int>? = null, val sourceId: Long? = null,
val sourceIds: List<Long>? = null, val url: String? = null,
val title: String? = null,
val thumbnailUrl: String? = null,
val initialized: Boolean? = null,
val artist: String? = null,
val author: String? = null,
val description: String? = null,
val genre: List<String>? = null,
val status: MangaStatus? = null,
val inLibrary: Boolean? = null, val inLibrary: Boolean? = null,
val inLibraryAt: GreaterOrLessThanLong? = null, val inLibraryAt: Long? = null,
val sort: MangaSort? = null, val realUrl: String? = null,
val sortOrder: SortOrder? = null, var lastFetchedAt: Long? = null,
val page: Int? = null, var chaptersLastFetchedAt: Long? = null
val count: Int? = null ) {
) fun getOp(): Op<Boolean>? {
val opAnd = OpAnd()
fun <T> eq(value: T?, column: Column<T>) = opAnd.andWhere(value) { column eq it }
fun <T : Comparable<T>> eq(value: T?, column: Column<EntityID<T>>) = opAnd.andWhere(value) { column eq it }
eq(id, MangaTable.id)
eq(sourceId, MangaTable.sourceReference)
eq(url, MangaTable.url)
eq(title, MangaTable.title)
eq(thumbnailUrl, MangaTable.thumbnail_url)
eq(initialized, MangaTable.initialized)
eq(artist, MangaTable.artist)
eq(author, MangaTable.author)
eq(description, MangaTable.description)
eq(genre?.joinToString(), MangaTable.genre)
eq(status?.value, MangaTable.status)
eq(inLibrary, MangaTable.inLibrary)
eq(inLibraryAt, MangaTable.inLibraryAt)
eq(realUrl, MangaTable.realUrl)
eq(lastFetchedAt, MangaTable.lastFetchedAt)
eq(chaptersLastFetchedAt, MangaTable.chaptersLastFetchedAt)
fun mangas(input: MangaQueryInput? = null): MangaNodeList { return opAnd.op
}
}
data class MangaFilter(
val id: IntFilter? = null,
val sourceId: LongFilter? = null,
val url: StringFilter? = null,
val title: StringFilter? = null,
val thumbnailUrl: StringFilter? = null,
val initialized: BooleanFilter? = null,
val artist: StringFilter? = null,
val author: StringFilter? = null,
val description: StringFilter? = null,
// val genre: List<String>? = null, // todo
// val status: MangaStatus? = null, // todo
val inLibrary: BooleanFilter? = null,
val inLibraryAt: LongFilter? = null,
val realUrl: StringFilter? = null,
var lastFetchedAt: LongFilter? = null,
var chaptersLastFetchedAt: LongFilter? = null,
val category: IntFilter? = null,
override val and: List<MangaFilter>? = null,
override val or: List<MangaFilter>? = null,
override val not: MangaFilter? = null
) : Filter<MangaFilter> {
override fun getOpList(): List<Op<Boolean>> {
return listOfNotNull(
andFilterWithCompareEntity(MangaTable.id, id),
andFilterWithCompare(MangaTable.sourceReference, sourceId),
andFilterWithCompareString(MangaTable.url, url),
andFilterWithCompareString(MangaTable.title, title),
andFilterWithCompareString(MangaTable.thumbnail_url, thumbnailUrl),
andFilterWithCompare(MangaTable.initialized, initialized),
andFilterWithCompareString(MangaTable.artist, artist),
andFilterWithCompareString(MangaTable.author, author),
andFilterWithCompareString(MangaTable.description, description),
andFilterWithCompare(MangaTable.inLibrary, inLibrary),
andFilterWithCompare(MangaTable.inLibraryAt, inLibraryAt),
andFilterWithCompareString(MangaTable.realUrl, realUrl),
andFilterWithCompare(MangaTable.inLibraryAt, lastFetchedAt),
andFilterWithCompare(MangaTable.inLibraryAt, chaptersLastFetchedAt)
)
}
fun getCategoryOp() = andFilterWithCompareEntity(CategoryMangaTable.category, category)
}
fun mangas(
condition: MangaCondition? = null,
filter: MangaFilter? = null,
orderBy: MangaOrderBy? = null,
orderByType: SortOrder? = null
): MangaNodeList {
val results = transaction { val results = transaction {
var res = MangaTable.selectAll() var res = MangaTable.selectAll()
if (input != null) { val categoryOp = filter?.getCategoryOp()
if (input.categoryIds != null) { if (categoryOp != null) {
res = MangaTable.innerJoin(CategoryMangaTable) res = MangaTable.innerJoin(CategoryMangaTable)
.select { CategoryMangaTable.category inList input.categoryIds } .select { categoryOp }
} }
if (input.ids != null) { val conditionOp = condition?.getOp()
res.andWhere { MangaTable.id inList input.ids } if (conditionOp != null) {
} res.andWhere { conditionOp }
if (input.sourceIds != null) { }
res.andWhere { MangaTable.sourceReference inList input.sourceIds } val filterOp = filter?.getOp()
} if (filterOp != null) {
if (input.inLibrary != null) { res.andWhere { filterOp }
res.andWhere { MangaTable.inLibrary eq input.inLibrary } }
} if (orderBy != null) {
if (input.inLibraryAt != null) { val orderByColumn = when (orderBy) {
res.andWhereGreaterOrLessThen( MangaOrderBy.ID -> MangaTable.id
column = MangaTable.inLibraryAt, MangaOrderBy.TITLE -> MangaTable.title
greaterOrLessThan = input.inLibraryAt MangaOrderBy.IN_LIBRARY_AT -> MangaTable.inLibraryAt
) MangaOrderBy.LAST_FETCHED_AT -> MangaTable.lastFetchedAt
}
if (input.sort != null) {
val orderBy = when (input.sort) {
MangaSort.ID -> MangaTable.id
MangaSort.TITLE -> MangaTable.title
MangaSort.IN_LIBRARY_AT -> MangaTable.inLibraryAt
MangaSort.LAST_FETCHED_AT -> MangaTable.lastFetchedAt
}
res.orderBy(orderBy, order = input.sortOrder ?: SortOrder.ASC)
}
if (input.count != null) {
val offset = if (input.page == null) 0 else (input.page * input.count).toLong()
res.limit(input.count, offset)
} }
res.orderBy(orderByColumn, order = orderByType ?: SortOrder.ASC)
} }
res.toList() res.toList()

View File

@@ -0,0 +1,329 @@
package suwayomi.tachidesk.graphql.queries.filter
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.ComparisonOp
import org.jetbrains.exposed.sql.Expression
import org.jetbrains.exposed.sql.ExpressionWithColumnType
import org.jetbrains.exposed.sql.LikeEscapeOp
import org.jetbrains.exposed.sql.LikePattern
import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.sql.QueryBuilder
import org.jetbrains.exposed.sql.SqlExpressionBuilder
import org.jetbrains.exposed.sql.SqlExpressionBuilder.wrap
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.not
import org.jetbrains.exposed.sql.or
import org.jetbrains.exposed.sql.stringParam
import org.jetbrains.exposed.sql.upperCase
class ILikeEscapeOp(expr1: Expression<*>, expr2: Expression<*>, like: Boolean, val escapeChar: Char?) : ComparisonOp(expr1, expr2, if (like) "ILIKE" else "NOT ILIKE") {
override fun toQueryBuilder(queryBuilder: QueryBuilder) {
super.toQueryBuilder(queryBuilder)
if (escapeChar != null) {
with(queryBuilder) {
+" ESCAPE "
+stringParam(escapeChar.toString())
}
}
}
companion object {
fun <T : String?> iLike(expression: Expression<T>, pattern: String): LikeEscapeOp = iLike(expression, LikePattern(pattern))
fun <T : String?> iNotLike(expression: Expression<T>, pattern: String): LikeEscapeOp = iNotLike(expression, LikePattern(pattern))
fun <T : String?> iLike(expression: Expression<T>, pattern: LikePattern): LikeEscapeOp = LikeEscapeOp(expression, stringParam(pattern.pattern), true, pattern.escapeChar)
fun <T : String?> iNotLike(expression: Expression<T>, pattern: LikePattern): LikeEscapeOp = LikeEscapeOp(expression, stringParam(pattern.pattern), false, pattern.escapeChar)
}
}
class DistinctFromOp(expr1: Expression<*>, expr2: Expression<*>, not: Boolean) : ComparisonOp(expr1, expr2, if (not) "IS NOT DISTINCT FROM" else "IS DISTINCT FROM") {
companion object {
fun <T> distinctFrom(expression: ExpressionWithColumnType<T>, t: T): DistinctFromOp = DistinctFromOp(
expression,
with(SqlExpressionBuilder) {
expression.wrap(t)
},
false
)
fun <T> notDistinctFrom(expression: ExpressionWithColumnType<T>, t: T): DistinctFromOp = DistinctFromOp(
expression,
with(SqlExpressionBuilder) {
expression.wrap(t)
},
true
)
fun <T : Comparable<T>> distinctFrom(expression: ExpressionWithColumnType<EntityID<T>>, t: T): DistinctFromOp = DistinctFromOp(
expression,
with(SqlExpressionBuilder) {
expression.wrap(t)
},
false
)
fun <T : Comparable<T>> notDistinctFrom(expression: ExpressionWithColumnType<EntityID<T>>, t: T): DistinctFromOp = DistinctFromOp(
expression,
with(SqlExpressionBuilder) {
expression.wrap(t)
},
true
)
}
}
interface Filter<T : Filter<T>> {
val and: List<T>?
val or: List<T>?
val not: T?
fun getOpList(): List<Op<Boolean>>
}
interface ScalarFilter<T> {
val isNull: Boolean?
val equalTo: T?
val notEqualTo: T?
val distinctFrom: T?
val notDistinctFrom: T?
val `in`: List<T>?
val notIn: List<T>?
}
interface ComparableScalarFilter<T : Comparable<T>> : ScalarFilter<T> {
val lessThan: T?
val lessThanOrEqualTo: T?
val greaterThan: T?
val greaterThanOrEqualTo: T?
}
data class LongFilter(
override val isNull: Boolean? = null,
override val equalTo: Long? = null,
override val notEqualTo: Long? = null,
override val distinctFrom: Long? = null,
override val notDistinctFrom: Long? = null,
override val `in`: List<Long>? = null,
override val notIn: List<Long>? = null,
override val lessThan: Long? = null,
override val lessThanOrEqualTo: Long? = null,
override val greaterThan: Long? = null,
override val greaterThanOrEqualTo: Long? = null
) : ComparableScalarFilter<Long>
data class BooleanFilter(
override val isNull: Boolean? = null,
override val equalTo: Boolean? = null,
override val notEqualTo: Boolean? = null,
override val distinctFrom: Boolean? = null,
override val notDistinctFrom: Boolean? = null,
override val `in`: List<Boolean>? = null,
override val notIn: List<Boolean>? = null,
override val lessThan: Boolean? = null,
override val lessThanOrEqualTo: Boolean? = null,
override val greaterThan: Boolean? = null,
override val greaterThanOrEqualTo: Boolean? = null
) : ComparableScalarFilter<Boolean>
data class IntFilter(
override val isNull: Boolean? = null,
override val equalTo: Int? = null,
override val notEqualTo: Int? = null,
override val distinctFrom: Int? = null,
override val notDistinctFrom: Int? = null,
override val `in`: List<Int>? = null,
override val notIn: List<Int>? = null,
override val lessThan: Int? = null,
override val lessThanOrEqualTo: Int? = null,
override val greaterThan: Int? = null,
override val greaterThanOrEqualTo: Int? = null
) : ComparableScalarFilter<Int>
data class StringFilter(
override val isNull: Boolean? = null,
override val equalTo: String? = null,
override val notEqualTo: String? = null,
override val distinctFrom: String? = null,
override val notDistinctFrom: String? = null,
override val `in`: List<String>? = null,
override val notIn: List<String>? = null,
override val lessThan: String? = null,
override val lessThanOrEqualTo: String? = null,
override val greaterThan: String? = null,
override val greaterThanOrEqualTo: String? = null,
val includes: String? = null,
val notIncludes: String? = null,
val includesInsensitive: String? = null,
val notIncludesInsensitive: String? = null,
val startsWith: String? = null,
val notStartsWith: String? = null,
val startsWithInsensitive: String? = null,
val notStartsWithInsensitive: String? = null,
val endsWith: String? = null,
val notEndsWith: String? = null,
val endsWithInsensitive: String? = null,
val notEndsWithInsensitive: String? = null,
val like: String? = null,
val notLike: String? = null,
val likeInsensitive: String? = null,
val notLikeInsensitive: String? = null,
val distinctFromInsensitive: String? = null,
val notDistinctFromInsensitive: String? = null,
val inInsensitive: List<String>? = null,
val notInInsensitive: List<String>? = null,
val lessThanInsensitive: String? = null,
val lessThanOrEqualToInsensitive: String? = null,
val greaterThanInsensitive: String? = null,
val greaterThanOrEqualToInsensitive: String? = null
) : ComparableScalarFilter<String>
fun <T : String?> andFilterWithCompareString(
column: Column<T>,
filter: StringFilter?
): Op<Boolean>? {
filter ?: return null
val opAnd = OpAnd()
opAnd.andWhere(filter.includes) { column like "%$it%" }
opAnd.andWhere(filter.notIncludes) { column notLike "%$it%" }
opAnd.andWhere(filter.includesInsensitive) { ILikeEscapeOp.iLike(column, "%$it%") }
opAnd.andWhere(filter.notIncludesInsensitive) { ILikeEscapeOp.iNotLike(column, "%$it%") }
opAnd.andWhere(filter.startsWith) { column like "$it%" }
opAnd.andWhere(filter.notStartsWith) { column notLike "$it%" }
opAnd.andWhere(filter.startsWithInsensitive) { ILikeEscapeOp.iLike(column, "$it%") }
opAnd.andWhere(filter.notStartsWithInsensitive) { ILikeEscapeOp.iNotLike(column, "$it%") }
opAnd.andWhere(filter.endsWith) { column like "%$it" }
opAnd.andWhere(filter.notEndsWith) { column notLike "%$it" }
opAnd.andWhere(filter.endsWithInsensitive) { ILikeEscapeOp.iLike(column, "%$it") }
opAnd.andWhere(filter.notEndsWithInsensitive) { ILikeEscapeOp.iNotLike(column, "%$it") }
opAnd.andWhere(filter.like) { column like it }
opAnd.andWhere(filter.notLike) { column notLike it }
opAnd.andWhere(filter.likeInsensitive) { ILikeEscapeOp.iLike(column, it) }
opAnd.andWhere(filter.notLikeInsensitive) { ILikeEscapeOp.iNotLike(column, it) }
opAnd.andWhere(filter.distinctFromInsensitive) { DistinctFromOp.distinctFrom(column.upperCase(), it.uppercase() as T) }
opAnd.andWhere(filter.notDistinctFromInsensitive) { DistinctFromOp.notDistinctFrom(column.upperCase(), it.uppercase() as T) }
opAnd.andWhere(filter.inInsensitive) { column.upperCase() inList (it.map { it.uppercase() } as List<T>) }
opAnd.andWhere(filter.notInInsensitive) { column.upperCase() notInList (it.map { it.uppercase() } as List<T>) }
opAnd.andWhere(filter.lessThanInsensitive) { column.upperCase() less it.uppercase() }
opAnd.andWhere(filter.lessThanOrEqualToInsensitive) { column.upperCase() lessEq it.uppercase() }
opAnd.andWhere(filter.greaterThanInsensitive) { column.upperCase() greater it.uppercase() }
opAnd.andWhere(filter.greaterThanOrEqualToInsensitive) { column.upperCase() greaterEq it.uppercase() }
return opAnd.op
}
class OpAnd(var op: Op<Boolean>? = null) {
fun <T> andWhere(value: T?, andPart: SqlExpressionBuilder.(T) -> Op<Boolean>) {
value ?: return
val expr = Op.build { andPart(value) }
op = if (op == null) expr else (op!! and expr)
}
}
fun <T : Comparable<T>> andFilterWithCompare(
column: Column<T>,
filter: ComparableScalarFilter<T>?
): Op<Boolean>? {
filter ?: return null
val opAnd = OpAnd(andFilter(column, filter))
opAnd.andWhere(filter.lessThan) { column less it }
opAnd.andWhere(filter.lessThanOrEqualTo) { column lessEq it }
opAnd.andWhere(filter.greaterThan) { column greater it }
opAnd.andWhere(filter.greaterThanOrEqualTo) { column greaterEq it }
return opAnd.op
}
fun <T : Comparable<T>> andFilterWithCompareEntity(
column: Column<EntityID<T>>,
filter: ComparableScalarFilter<T>?
): Op<Boolean>? {
filter ?: return null
val opAnd = OpAnd(andFilterEntity(column, filter))
opAnd.andWhere(filter.lessThan) { column less it }
opAnd.andWhere(filter.lessThanOrEqualTo) { column lessEq it }
opAnd.andWhere(filter.greaterThan) { column greater it }
opAnd.andWhere(filter.greaterThanOrEqualTo) { column greaterEq it }
return opAnd.op
}
fun <T : Comparable<T>> andFilter(
column: Column<T>,
filter: ScalarFilter<T>?
): Op<Boolean>? {
filter ?: return null
val opAnd = OpAnd()
opAnd.andWhere(filter.isNull) { if (it) column.isNull() else column.isNotNull() }
opAnd.andWhere(filter.equalTo) { column eq it }
opAnd.andWhere(filter.notEqualTo) { column neq it }
opAnd.andWhere(filter.distinctFrom) { DistinctFromOp.distinctFrom(column, it) }
opAnd.andWhere(filter.notDistinctFrom) { DistinctFromOp.notDistinctFrom(column, it) }
if (!filter.`in`.isNullOrEmpty()) {
opAnd.andWhere(filter.`in`) { column inList it }
}
if (!filter.notIn.isNullOrEmpty()) {
opAnd.andWhere(filter.notIn) { column notInList it }
}
return opAnd.op
}
fun <T : Comparable<T>> andFilterEntity(
column: Column<EntityID<T>>,
filter: ScalarFilter<T>?
): Op<Boolean>? {
filter ?: return null
val opAnd = OpAnd()
opAnd.andWhere(filter.isNull) { if (filter.isNull!!) column.isNull() else column.isNotNull() }
opAnd.andWhere(filter.equalTo) { column eq filter.equalTo!! }
opAnd.andWhere(filter.notEqualTo) { column neq filter.notEqualTo!! }
opAnd.andWhere(filter.distinctFrom) { DistinctFromOp.distinctFrom(column, it) }
opAnd.andWhere(filter.notDistinctFrom) { DistinctFromOp.notDistinctFrom(column, it) }
if (!filter.`in`.isNullOrEmpty()) {
opAnd.andWhere(filter.`in`) { column inList filter.`in`!! }
}
if (!filter.notIn.isNullOrEmpty()) {
opAnd.andWhere(filter.notIn) { column notInList filter.notIn!! }
}
return opAnd.op
}
fun <T : Filter<T>> Filter<T>.getOp(): Op<Boolean>? {
var op: Op<Boolean>? = null
fun newOp(
otherOp: Op<Boolean>?,
operator: (Op<Boolean>, Op<Boolean>) -> Op<Boolean>
) {
when {
op == null && otherOp == null -> Unit
op == null && otherOp != null -> op = otherOp
op != null && otherOp == null -> Unit
op != null && otherOp != null -> op = operator(op!!, otherOp)
}
}
fun andOp(andOp: Op<Boolean>?) {
newOp(andOp, Op<Boolean>::and)
}
fun orOp(orOp: Op<Boolean>?) {
newOp(orOp, Op<Boolean>::or)
}
getOpList().forEach {
andOp(it)
}
and?.forEach {
andOp(it.getOp())
}
or?.forEach {
orOp(it.getOp())
}
if (not != null) {
andOp(not!!.getOp()?.let(::not))
}
return op
}

View File

@@ -1,42 +0,0 @@
package suwayomi.tachidesk.graphql.queries.util
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Query
import org.jetbrains.exposed.sql.andWhere
interface GreaterOrLessThan<T : Comparable<T>> {
val value: T
val type: GreaterOrLessThanType
}
data class GreaterOrLessThanLong(
override val value: Long,
override val type: GreaterOrLessThanType
) : GreaterOrLessThan<Long>
enum class GreaterOrLessThanType {
GREATER_THAN,
GREATER_THAN_OR_EQ,
LESS_THAN,
LESS_THAN_OR_EQ
}
fun <T : Comparable<T>> Query.andWhereGreaterOrLessThen(
column: Column<T>,
greaterOrLessThan: GreaterOrLessThan<T>
) {
when (greaterOrLessThan.type) {
GreaterOrLessThanType.GREATER_THAN -> andWhere {
column greater greaterOrLessThan.value // toValue()
}
GreaterOrLessThanType.GREATER_THAN_OR_EQ -> andWhere {
column greaterEq greaterOrLessThan.value // toValue()
}
GreaterOrLessThanType.LESS_THAN -> andWhere {
column less greaterOrLessThan.value // toValue()
}
GreaterOrLessThanType.LESS_THAN_OR_EQ -> andWhere {
column lessEq greaterOrLessThan.value // toValue()
}
}
}