gs-predicate/src/main/scala/gs/predicate/v0/json/JsonExists.scala

63 lines
1.7 KiB
Scala

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