All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.apollographql.apollo.api.BooleanExpression.kt Maven / Gradle / Ivy

The newest version!
@file:JvmName("BooleanExpressions")

package com.apollographql.apollo.api

import com.apollographql.apollo.annotations.ApolloDeprecatedSince
import com.apollographql.apollo.annotations.ApolloDeprecatedSince.Version.v4_0_0
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 {
  @Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
  @ApolloDeprecatedSince(v4_0_0)
  abstract fun simplify(): BooleanExpression

  object True : BooleanExpression() {
    @Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
    @ApolloDeprecatedSince(v4_0_0)
    override fun simplify() = this
  }

  object False : BooleanExpression() {
    @Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
    @ApolloDeprecatedSince(v4_0_0)
    override fun simplify() = this
  }

  data class Not(val operand: BooleanExpression) : BooleanExpression() {
    @Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
    @ApolloDeprecatedSince(v4_0_0)
    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"
      }
    }

    @Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
    @ApolloDeprecatedSince(v4_0_0)
    @Suppress("DEPRECATION_ERROR")
    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"
      }
    }

    @Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
    @ApolloDeprecatedSince(v4_0_0)
    @Suppress("DEPRECATION_ERROR")
    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() {
    @Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
    @ApolloDeprecatedSince(v4_0_0)
    @Suppress("DEPRECATION_ERROR")
    override fun simplify() = this
  }
}

@Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
fun  BooleanExpression.or(vararg other: BooleanExpression): BooleanExpression = BooleanExpression.Or((other.toList() + this).toSet())

@Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
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()))

@Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@Suppress("DEPRECATION_ERROR")
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)
  }
}

@Suppress("DEPRECATION_ERROR")
fun BooleanExpression.evaluate(
    variables: Set?,
    typename: String?,
    deferredFragmentIdentifiers: Set?,
    path: List?,
): Boolean {
  // Remove "data" from the path
  val croppedPath = path?.drop(1)
  return evaluate {
    when (it) {
      is BVariable -> !(variables?.contains(it.name) ?: false)
      is BLabel -> hasDeferredFragment(deferredFragmentIdentifiers, croppedPath!!, it.label)
      is BPossibleTypes -> it.possibleTypes.contains(typename)
    }
  }
}

private fun hasDeferredFragment(deferredFragmentIdentifiers: Set?, path: List, label: String?): Boolean {
  if (deferredFragmentIdentifiers == null) {
    // By default, parse all deferred fragments - this is the case when parsing from the normalized cache.
    return true
  }
  return deferredFragmentIdentifiers.contains(DeferredFragmentIdentifier(path, label))
}

/**
 * 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) : BTerm()

/**
 * 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())
}

@Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@Suppress("DEPRECATION_ERROR")
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
  }
}

@Deprecated(message = "This was only used in internal API and shouldn't have been part of the public API. If you needed this, please open an issue.", level = DeprecationLevel.ERROR)
@ApolloDeprecatedSince(v4_0_0)
@Suppress("DEPRECATION_ERROR")
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 - 2024 Weber Informatics LLC | Privacy Policy