package gs.predicate.v0.kv import cats.Functor import cats.syntax.all.* import gs.predicate.v0.api.Messages import gs.predicate.v0.api.Predicate import gs.predicate.v0.serde.json.JsonKeys import io.circe.Decoder import io.circe.DecodingFailure import io.circe.Encoder import io.circe.Json /** Predicate that matches if some [[KeyValueProvider]] contains the given key, * and the value associated with that key is not equal to the given value. * * @param id * The unique identifier of this [[Predicate]]. * @param key * The key that should exist. * @param value * The value that must not be associated with the key. */ final class ValueNotEquals[F[_]: Functor: KeyValueProvider]( val key: String, val value: String ) extends Predicate[F]: /** @inheritDocs */ override def predicateType: String = ValueNotEquals.PredicateType /** @inheritDocs */ override def eval(): F[Predicate.Result] = KeyValueProvider[F].get(key).map { case Some(v) => Predicate.Result(v != value) case _ => Predicate.Result.missed() } object ValueNotEquals: final val PredicateType: String = "kv-value-not-equals" def apply[F[_]: Functor: KeyValueProvider]( key: String, value: String ): ValueNotEquals[F] = new ValueNotEquals[F](key, value) given valueNotEqualsEncoder[F[_]]: Encoder[ValueNotEquals[F]] = Encoder.instance[ValueNotEquals[F]] { p => Json.obj( (JsonKeys.predicateType, Json.fromString(PredicateType)), (JsonKeys.key, Json.fromString(p.key)), (JsonKeys.value, Json.fromString(p.value)) ) } given valueNotEqualsDecoder[F[_]: Functor: KeyValueProvider] : Decoder[ValueNotEquals[F]] = Decoder.instance[ValueNotEquals[F]] { cursor => cursor.downField(JsonKeys.predicateType).as[String].flatMap { case PredicateType => for key <- cursor.downField(JsonKeys.key).as[String] value <- cursor.downField(JsonKeys.value).as[String] yield new ValueNotEquals(key, value) case candidate => Left( DecodingFailure( Messages.invalidPredicateType(candidate, PredicateType), Nil ) ) } } end ValueNotEquals