commonMain.com.apollographql.apollo3.api.BooleanExpression.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of apollo-api-jvm Show documentation
Show all versions of apollo-api-jvm Show documentation
Apollo GraphQL API classes
@file:JvmName("BooleanExpressions")
package com.apollographql.apollo3.api
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince.Version.v3_2_1
import kotlin.jvm.JvmName
import kotlin.reflect.KClass
/**
* A boolean expression
*
* @param T the type of the variable elements. This allows representing BooleanExpression that only contain variables and
* other that may also contain possibleTypes
*/
sealed class BooleanExpression {
/**
* This is not super well defined but works well enough for our simple use cases
*/
abstract fun simplify(): BooleanExpression
object True : BooleanExpression() {
override fun simplify() = this
}
object False : BooleanExpression() {
override fun simplify() = this
}
data class Not(val operand: BooleanExpression) : BooleanExpression() {
override fun simplify() = when (this.operand) {
is True -> False
is False -> True
else -> this
}
}
data class Or(val operands: Set>) : BooleanExpression() {
constructor(vararg operands: BooleanExpression) : this(operands.toSet())
init {
check(operands.isNotEmpty()) {
"Apollo: cannot create a 'Or' condition from an empty list"
}
}
override fun simplify() = operands.filter {
it != False
}.map { it.simplify() }
.let {
when {
it.contains(True) -> True
it.isEmpty() -> False
it.size == 1 -> it.first()
else -> {
Or(it.toSet())
}
}
}
override fun toString() = operands.joinToString(" | ")
}
data class And(val operands: Set>) : BooleanExpression() {
constructor(vararg operands: BooleanExpression) : this(operands.toSet())
init {
check(operands.isNotEmpty()) {
"Apollo: cannot create a 'And' condition from an empty list"
}
}
override fun simplify() = operands.filter {
it != True
}.map { it.simplify() }
.let {
when {
it.contains(False) -> False
it.isEmpty() -> True
it.size == 1 -> it.first()
else -> {
And(it.toSet())
}
}
}
}
data class Element(
val value: T,
) : BooleanExpression() {
override fun simplify() = this
}
}
fun BooleanExpression.or(vararg other: BooleanExpression): BooleanExpression = BooleanExpression.Or((other.toList() + this).toSet())
fun BooleanExpression.and(vararg other: BooleanExpression): BooleanExpression = BooleanExpression.And((other.toList() + this).toSet())
fun or(vararg other: BooleanExpression): BooleanExpression = BooleanExpression.Or((other.toList()).toSet())
fun and(vararg other: BooleanExpression): BooleanExpression = BooleanExpression.And((other.toList()).toSet())
fun not(other: BooleanExpression): BooleanExpression = BooleanExpression.Not(other)
fun variable(name: String): BooleanExpression = BooleanExpression.Element(BVariable(name))
fun label(label: String? = null): BooleanExpression = BooleanExpression.Element(BLabel(label))
fun possibleTypes(vararg typenames: String): BooleanExpression = BooleanExpression.Element(BPossibleTypes(typenames.toSet()))
fun BooleanExpression.evaluate(block: (T) -> Boolean): Boolean {
return when (this) {
BooleanExpression.True -> true
BooleanExpression.False -> false
is BooleanExpression.Not -> !operand.evaluate(block)
is BooleanExpression.Or -> operands.any { it.evaluate(block) }
is BooleanExpression.And -> operands.all { it.evaluate(block) }
is BooleanExpression.Element -> block(value)
}
}
@Deprecated("Kept for binary compatibility with generated code from older versions")
@ApolloDeprecatedSince(v3_2_1)
@Suppress("DeprecatedCallableAddReplaceWith")
fun BooleanExpression.evaluate(variables: Set, typename: String?): Boolean {
return evaluate {
when (it) {
is BVariable -> variables.contains(it.name)
is BPossibleTypes -> it.possibleTypes.contains(typename)
is BLabel -> error("Unexpected boolean expression term type")
}
}
}
fun BooleanExpression.evaluate(
variables: Set,
typename: String?,
adapterContext: AdapterContext,
path: List?,
): Boolean {
// Remove "data" from the path
val croppedPath = path?.drop(1)
return evaluate {
when (it) {
is BVariable -> !variables.contains(it.name)
is BLabel -> adapterContext.hasDeferredFragment(croppedPath!!, it.label)
is BPossibleTypes -> it.possibleTypes.contains(typename)
}
}
}
/**
* A generic term in a [BooleanExpression]
*/
sealed class BTerm
/**
* A term that comes from @include/@skip or @defer directives and that needs to be matched against operation variables
*/
data class BVariable(val name: String, val defaultValue: Boolean?) : BTerm() {
constructor(name: String): this(name, true)
fun copy(name: String = this.name) = BVariable(name, defaultValue)
}
/**
* A term that comes from @defer directives and that needs to be matched against label and current JSON path
*/
data class BLabel(val label: String?) : BTerm()
/**
* A term that comes from a fragment type condition and that needs to be matched against __typename
*/
data class BPossibleTypes(val possibleTypes: Set) : BTerm() {
constructor(vararg types: String) : this(types.toSet())
}
fun BooleanExpression.containsPossibleTypes(): Boolean {
return when (this) {
BooleanExpression.True -> false
BooleanExpression.False -> false
is BooleanExpression.Not -> operand.containsPossibleTypes()
is BooleanExpression.Or -> operands.any { it.containsPossibleTypes() }
is BooleanExpression.And -> operands.any { it.containsPossibleTypes() }
is BooleanExpression.Element -> value is BPossibleTypes
}
}
fun BooleanExpression.firstElementOfType(type: KClass): U? {
return when (this) {
BooleanExpression.True -> null
BooleanExpression.False -> null
is BooleanExpression.Element -> @Suppress("UNCHECKED_CAST") if (type.isInstance(this.value)) this.value as U else null
is BooleanExpression.Not -> this.operand.firstElementOfType(type)
is BooleanExpression.And -> (this.operands.firstOrNull { it.firstElementOfType(type) != null })?.firstElementOfType(type)
is BooleanExpression.Or -> (this.operands.firstOrNull { it.firstElementOfType(type) != null })?.firstElementOfType(type)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy