package gs.predicate.v0.json 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 the JSON provider contains a JSON blob with the * given key. * * @param key * The name of the JSON value that should exist. */ final class JsonExists[F[_]: Functor: JsonProvider]( val key: String ) extends JsonPredicate[F]: /** @inheritDocs */ final override val predicateType: String = JsonExists.PredicateType /** @inheritDocs */ override def eval(): F[Predicate.Result] = getJson(key).map(_.isDefined).map(Predicate.Result.apply) object JsonExists: final val PredicateType: String = "json-exists" def apply[F[_]: Functor: JsonProvider](key: String): JsonExists[F] = new JsonExists[F](key) given jsonExistsEncoder[F[_]]: Encoder[JsonExists[F]] = Encoder.instance[JsonExists[F]] { p => Json.obj( (JsonKeys.predicateType, Json.fromString(PredicateType)), (JsonKeys.key, Json.fromString(p.key)) ) } given jsonExistsDecoder[F[_]: Functor: JsonProvider]: Decoder[JsonExists[F]] = Decoder.instance[JsonExists[F]] { cursor => cursor.downField(JsonKeys.predicateType).as[String].flatMap { case PredicateType => for key <- cursor.downField(JsonKeys.key).as[String] yield new JsonExists(key) case candidate => Left( DecodingFailure( Messages.invalidPredicateType(candidate, PredicateType), Nil ) ) } } end JsonExists