Basically finish MangaQuery, only paging left
This commit is contained in:
@@ -9,23 +9,34 @@ package suwayomi.tachidesk.graphql.queries
|
||||
|
||||
import com.expediagroup.graphql.server.extensions.getValueFromDataLoader
|
||||
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.andWhere
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import suwayomi.tachidesk.graphql.queries.util.GreaterOrLessThanLong
|
||||
import suwayomi.tachidesk.graphql.queries.util.andWhereGreaterOrLessThen
|
||||
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
||||
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.Companion.toNodeList
|
||||
import suwayomi.tachidesk.graphql.types.MangaType
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaStatus
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* TODO Queries
|
||||
* - Query options(optionally query the title, description, or/and)
|
||||
*
|
||||
* TODO Mutations
|
||||
* - Favorite
|
||||
@@ -43,62 +54,130 @@ class MangaQuery {
|
||||
return dataFetchingEnvironment.getValueFromDataLoader("MangaDataLoader", id)
|
||||
}
|
||||
|
||||
enum class MangaSort {
|
||||
enum class MangaOrderBy {
|
||||
ID,
|
||||
TITLE,
|
||||
IN_LIBRARY_AT,
|
||||
LAST_FETCHED_AT
|
||||
}
|
||||
|
||||
data class MangaQueryInput(
|
||||
val ids: List<Int>? = null,
|
||||
val categoryIds: List<Int>? = null,
|
||||
val sourceIds: List<Long>? = null,
|
||||
data class MangaCondition(
|
||||
val id: Int? = null,
|
||||
val sourceId: 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 inLibraryAt: GreaterOrLessThanLong? = null,
|
||||
val sort: MangaSort? = null,
|
||||
val sortOrder: SortOrder? = null,
|
||||
val page: Int? = null,
|
||||
val count: Int? = null
|
||||
)
|
||||
val inLibraryAt: Long? = null,
|
||||
val realUrl: String? = null,
|
||||
var lastFetchedAt: Long? = null,
|
||||
var chaptersLastFetchedAt: Long? = 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 {
|
||||
var res = MangaTable.selectAll()
|
||||
|
||||
if (input != null) {
|
||||
if (input.categoryIds != null) {
|
||||
res = MangaTable.innerJoin(CategoryMangaTable)
|
||||
.select { CategoryMangaTable.category inList input.categoryIds }
|
||||
}
|
||||
if (input.ids != null) {
|
||||
res.andWhere { MangaTable.id inList input.ids }
|
||||
}
|
||||
if (input.sourceIds != null) {
|
||||
res.andWhere { MangaTable.sourceReference inList input.sourceIds }
|
||||
}
|
||||
if (input.inLibrary != null) {
|
||||
res.andWhere { MangaTable.inLibrary eq input.inLibrary }
|
||||
}
|
||||
if (input.inLibraryAt != null) {
|
||||
res.andWhereGreaterOrLessThen(
|
||||
column = MangaTable.inLibraryAt,
|
||||
greaterOrLessThan = input.inLibraryAt
|
||||
)
|
||||
}
|
||||
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)
|
||||
val categoryOp = filter?.getCategoryOp()
|
||||
if (categoryOp != null) {
|
||||
res = MangaTable.innerJoin(CategoryMangaTable)
|
||||
.select { categoryOp }
|
||||
}
|
||||
val conditionOp = condition?.getOp()
|
||||
if (conditionOp != null) {
|
||||
res.andWhere { conditionOp }
|
||||
}
|
||||
val filterOp = filter?.getOp()
|
||||
if (filterOp != null) {
|
||||
res.andWhere { filterOp }
|
||||
}
|
||||
if (orderBy != null) {
|
||||
val orderByColumn = when (orderBy) {
|
||||
MangaOrderBy.ID -> MangaTable.id
|
||||
MangaOrderBy.TITLE -> MangaTable.title
|
||||
MangaOrderBy.IN_LIBRARY_AT -> MangaTable.inLibraryAt
|
||||
MangaOrderBy.LAST_FETCHED_AT -> MangaTable.lastFetchedAt
|
||||
}
|
||||
res.orderBy(orderByColumn, order = orderByType ?: SortOrder.ASC)
|
||||
}
|
||||
|
||||
res.toList()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user