package gs.predicate.v0.api import cats.Applicative import cats.syntax.all.* import gs.predicate.v0.serde.json.JsonKeys import io.circe.Decoder import io.circe.DecodingFailure import io.circe.Encoder import io.circe.Json import io.circe.syntax.* /** Implements logical OR. * * @param ps * The predicates to evaluate. */ final class Or[F[_]: Applicative]( val ps: List[Predicate[F]] ) extends Predicate[F]: /** @inheritDocs */ override def predicateType: String = Or.PredicateType /** @inheritDocs */ override def eval(): F[Predicate.Result] = ps.map(_.eval()).sequence.map(_.anyMatch()) object Or: final val PredicateType: String = "or" def empty[F[_]: Applicative]: Predicate[F] = False[F] def apply[F[_]: Applicative, A](ps: Predicate[F]*): Predicate[F] = ps.toList match case Nil => False[F] case p :: Nil => p case list => new Or(list) given orEncoder[F[_]]( using Encoder[Predicate[F]] ): Encoder[Or[F]] = Encoder.instance[Or[F]] { p => Json.obj( (JsonKeys.predicateType, Json.fromString(PredicateType)), (JsonKeys.predicates, p.ps.asJson) ) } given orDecoder[F[_]: Applicative]( using Decoder[Predicate[F]] ): Decoder[Or[F]] = Decoder.instance[Or[F]] { cursor => cursor.downField(JsonKeys.predicateType).as[String].flatMap { case PredicateType => for ps <- cursor.downField(JsonKeys.predicates).as[List[Predicate[F]]] yield new Or(ps) case candidate => Left( DecodingFailure( Messages.invalidPredicateType(candidate, PredicateType), Nil ) ) } } end Or