gs-predicate/src/main/scala/gs/predicate/v0/api/Or.scala

72 lines
1.7 KiB
Scala

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