Add missing changes from #1496

Koitharu 1 year ago
parent 3b91a3883e
commit 29263ff59b
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -14,7 +14,7 @@ public data class MangaSearchQueryCapabilities internal constructor(
@InternalParsersApi
public fun validate(query: MangaSearchQuery) {
val strictFields = capabilities.filter { !it.otherCriteria }.mapToSet { it.field }
val strictFields = capabilities.filter { it.isExclusive }.mapToSet { it.field }
val usedStrictFields = query.criteria.mapToSet { it.field }.intersect(strictFields)
if (usedStrictFields.isNotEmpty() && query.criteria.size > 1) {
@ -34,7 +34,7 @@ public data class MangaSearchQueryCapabilities internal constructor(
}
// Ensure single value per criterion if supportMultiValue is false
if (!capability.multiValue) {
if (!capability.isMultiple) {
when (criterion) {
is Include<*> -> if (criterion.values.size > 1)
throw IllegalArgumentException("Multiple values are not allowed for field ${criterion.field}")

@ -15,6 +15,17 @@ public sealed interface QueryCriteria<T> {
override fun hashCode(): Int
/**
* Represents an inclusion criterion that allows search results based on a set of allowed values.
*
* @param T The type of value being included in the search.
* @property values The set of values that should be included in the search results.
*
* ### Example Usage:
* ```kotlin
* val genreFilter = QueryCriteria.Include(SearchableField.STATE, setOf(MangaState.ONGOING, MangaState.FINISHED))
* ```
*/
public data class Include<T : Any>(
public override val field: SearchableField,
@JvmField public val values: Set<T>,
@ -25,6 +36,17 @@ public sealed interface QueryCriteria<T> {
}
}
/**
* Represents an exclusion criterion that exclude results containing certain values.
*
* @param T The type of value being excluded from the search.
* @property values The set of values that should be excluded from the search results.
*
* ### Example Usage:
* ```kotlin
* val excludeTag = QueryCriteria.Exclude(SearchableField.TAG, setOf(MangaTag(key, title, source)))
* ```
*/
public data class Exclude<T : Any>(
public override val field: SearchableField,
@JvmField public val values: Set<T>,
@ -35,6 +57,18 @@ public sealed interface QueryCriteria<T> {
}
}
/**
* Represents a range criterion that allows search based on a range of values.
*
* @param T The type of value used in the range (must be comparable).
* @property from The starting value of the range (inclusive).
* @property to The ending value of the range (inclusive).
*
* ### Example Usage:
* ```kotlin
* val yearRange = QueryCriteria.Range(SearchableField.PUBLICATION_YEAR, 2000, 2020)
* ```
*/
public data class Range<T : Comparable<T>>(
public override val field: SearchableField,
@JvmField public val from: T,
@ -47,6 +81,18 @@ public sealed interface QueryCriteria<T> {
}
}
/**
* Represents a match criterion that search results based on an exact match of a value.
*
* @param T The type of value being matched.
* @property value The exact value that must be matched.
*
* ### Example Usage:
* ```kotlin
* val titleMatch = QueryCriteria.Match(SearchableField.TITLE, "manga title")
* ```
*/
public data class Match<T : Any>(
public override val field: SearchableField,
@JvmField public val value: T,

@ -2,9 +2,32 @@ package org.koitharu.kotatsu.parsers.model.search
import kotlin.reflect.KClass
public data class SearchCapability (
/**
* Defines the search capabilities of a given field in the manga search query.
*
* @property field The searchable field that this capability applies to.
* Example values:
* - `SearchableField.TITLE_NAME` for searching by title.
* - `SearchableField.AUTHOR` for searching by author names.
* - `SearchableField.TAG` for filtering by tags.
* @property criteriaTypes The set of supported criteria types for the field.
* Example values:
* - `setOf(Include::class, Exclude::class)` selected field supports inclusion/exclusion criteria.
* - `setOf(Range::class)` selected field support numerical range criteria.
* @property isMultiValue Indicates whether the field supports multiple values.
* - `true` if multiple values can be provided (e.g., multiple tags or authors).
* - `false` if only a single value is allowed (e.g., only one tag or author).
* @property isExclusive Specifies whether the field can be used alongside other criteria.
* - `true` if this field can be used with other search criteria.
* - `false` if using this field requires it to be the only criterion in query.
*/
public data class SearchCapability(
/** The searchable field that this capability applies to. */
@JvmField public val field: SearchableField,
/** The set of supported criteria types for this field. */
@JvmField public val criteriaTypes: Set<KClass<out QueryCriteria<*>>>,
@JvmField public val multiValue: Boolean,
@JvmField public val otherCriteria: Boolean,
/** Indicates whether the field supports multiple values. */
@JvmField public val isMultiple: Boolean,
/** Specifies whether the field can be used alongside other criteria. */
@JvmField public val isExclusive: Boolean = false,
)

@ -73,62 +73,52 @@ internal class MangaDexParser(context: MangaLoaderContext) : AbstractMangaParser
SearchCapability(
field = TAG,
criteriaTypes = setOf(Include::class, Exclude::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = TITLE_NAME,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
SearchCapability(
field = STATE,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = AUTHOR,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = CONTENT_TYPE,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = CONTENT_RATING,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = DEMOGRAPHIC,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = ORIGINAL_LANGUAGE,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = LANGUAGE,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = PUBLICATION_YEAR,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
)

@ -41,26 +41,23 @@ internal abstract class MangaboxParser(
SearchCapability(
field = TAG,
criteriaTypes = setOf(Include::class, Exclude::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = TITLE_NAME,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
SearchCapability(
field = STATE,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = AUTHOR,
criteriaTypes = setOf(Include::class),
multiValue = false,
otherCriteria = false,
isMultiple = false,
isExclusive = true,
),
)

@ -43,20 +43,18 @@ internal class Mangairo(context: MangaLoaderContext) :
SearchCapability(
field = TAG,
criteriaTypes = setOf(Include::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
SearchCapability(
field = TITLE_NAME,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = false,
isMultiple = false,
isExclusive = true,
),
SearchCapability(
field = STATE,
criteriaTypes = setOf(Include::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
)

@ -32,20 +32,18 @@ internal class Mangakakalot(context: MangaLoaderContext) :
SearchCapability(
field = TAG,
criteriaTypes = setOf(Include::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
SearchCapability(
field = TITLE_NAME,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = false,
isMultiple = false,
isExclusive = true,
),
SearchCapability(
field = STATE,
criteriaTypes = setOf(Include::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
)

@ -35,20 +35,18 @@ internal class MangakakalotTv(context: MangaLoaderContext) :
SearchCapability(
field = TAG,
criteriaTypes = setOf(Include::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
SearchCapability(
field = TITLE_NAME,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = false,
isMultiple = false,
isExclusive = true,
),
SearchCapability(
field = STATE,
criteriaTypes = setOf(Include::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
),
)

@ -87,10 +87,10 @@ internal fun convertToMangaListFilter(searchQuery: MangaSearchQuery): MangaListF
}
internal fun MangaSearchQueryCapabilities.toMangaListFilterCapabilities() = MangaListFilterCapabilities(
isMultipleTagsSupported = capabilities.any { x -> x.field == TAG && x.multiValue },
isMultipleTagsSupported = capabilities.any { x -> x.field == TAG && x.isMultiple },
isTagsExclusionSupported = capabilities.any { x -> x.field == TAG && x.criteriaTypes.contains(Exclude::class) },
isSearchSupported = capabilities.any { x -> x.field == TITLE_NAME },
isSearchWithFiltersSupported = capabilities.any { x -> x.field == TITLE_NAME && x.otherCriteria },
isSearchWithFiltersSupported = capabilities.any { x -> x.field == TITLE_NAME && !x.isExclusive },
isYearSupported = capabilities.any { x -> x.field == PUBLICATION_YEAR && x.criteriaTypes.contains(Match::class) },
isYearRangeSupported = capabilities.any { x -> x.field == PUBLICATION_YEAR && x.criteriaTypes.contains(Range::class) },
isOriginalLocaleSupported = capabilities.any { x -> x.field == ORIGINAL_LANGUAGE },
@ -102,80 +102,76 @@ internal fun MangaListFilterCapabilities.toMangaSearchQueryCapabilities(): Manga
capabilities = setOfNotNull(
isMultipleTagsSupported.takeIf { it }?.let {
SearchCapability(
field = TAG, criteriaTypes = setOf(Include::class), multiValue = true, otherCriteria = true,
field = TAG,
criteriaTypes = setOf(Include::class),
isMultiple = true,
)
},
isTagsExclusionSupported.takeIf { it }?.let {
SearchCapability(
field = TAG, criteriaTypes = setOf(Exclude::class), multiValue = true, otherCriteria = true,
field = TAG,
criteriaTypes = setOf(Exclude::class),
isMultiple = true,
)
},
isSearchSupported.takeIf { it }?.let {
SearchCapability(
field = TITLE_NAME,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = false,
isMultiple = false,
isExclusive = true,
)
},
isSearchWithFiltersSupported.takeIf { it }?.let {
SearchCapability(
field = TITLE_NAME,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
)
},
isYearSupported.takeIf { it }?.let {
SearchCapability(
field = PUBLICATION_YEAR,
criteriaTypes = setOf(Match::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
)
},
isYearRangeSupported.takeIf { it }?.let {
SearchCapability(
field = PUBLICATION_YEAR,
criteriaTypes = setOf(Range::class),
multiValue = false,
otherCriteria = true,
isMultiple = false,
)
},
isOriginalLocaleSupported.takeIf { it }?.let {
SearchCapability(
field = ORIGINAL_LANGUAGE,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
)
},
SearchCapability(
field = LANGUAGE,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = STATE, criteriaTypes = setOf(Include::class), multiValue = true, otherCriteria = true,
field = STATE, criteriaTypes = setOf(Include::class), isMultiple = true,
),
SearchCapability(
field = CONTENT_TYPE,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = CONTENT_RATING,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
SearchCapability(
field = DEMOGRAPHIC,
criteriaTypes = setOf(Include::class),
multiValue = true,
otherCriteria = true,
isMultiple = true,
),
),
)

@ -14,10 +14,10 @@ class MangaSearchQueryCapabilitiesTest {
private val capabilities = MangaSearchQueryCapabilities(
capabilities = setOf(
SearchCapability(TITLE_NAME, setOf(Match::class), multiValue = false, otherCriteria = false),
SearchCapability(TAG, setOf(Include::class, Exclude::class), multiValue = true, otherCriteria = true),
SearchCapability(PUBLICATION_YEAR, setOf(Range::class), multiValue = false, otherCriteria = true),
SearchCapability(STATE, setOf(Include::class), multiValue = false, otherCriteria = true),
SearchCapability(TITLE_NAME, setOf(Match::class), isMultiple = false, isExclusive = true),
SearchCapability(TAG, setOf(Include::class, Exclude::class), isMultiple = true, isExclusive = false),
SearchCapability(PUBLICATION_YEAR, setOf(Range::class), isMultiple = false, isExclusive = false),
SearchCapability(STATE, setOf(Include::class), isMultiple = false, isExclusive = false),
),
)

Loading…
Cancel
Save