228 lines
8.9 KiB
Scala
228 lines
8.9 KiB
Scala
package gs.predicate.v0.serde.json
|
|
|
|
import cats.Applicative
|
|
import gs.predicate.v0.api.And
|
|
import gs.predicate.v0.api.False
|
|
import gs.predicate.v0.api.Messages
|
|
import gs.predicate.v0.api.Or
|
|
import gs.predicate.v0.api.Predicate
|
|
import gs.predicate.v0.api.True
|
|
import gs.predicate.v0.json.JsonComparison
|
|
import gs.predicate.v0.json.JsonProvider
|
|
import gs.predicate.v0.json.JsonQueryComparison
|
|
import gs.predicate.v0.kv.KeyExists
|
|
import gs.predicate.v0.kv.KeyValueProvider
|
|
import gs.predicate.v0.kv.ValueContains
|
|
import gs.predicate.v0.kv.ValueEndsWith
|
|
import gs.predicate.v0.kv.ValueEquals
|
|
import gs.predicate.v0.kv.ValueNotEquals
|
|
import gs.predicate.v0.kv.ValueStartsWith
|
|
import io.circe.*
|
|
import io.circe.syntax.*
|
|
|
|
/** Given some [[And]] predicate, encode it as a JSON blob.
|
|
*
|
|
* @param and
|
|
* The [[And]] predicate.
|
|
* @return
|
|
* The JSON blob representing the [[And]].
|
|
*/
|
|
def encodeAnd[F[_]](and: And[F]): Json =
|
|
Json.obj(
|
|
(JsonKeys.predicateType, Json.fromString(And.PredicateType)),
|
|
(JsonKeys.predicates, and.ps.asJson)
|
|
)
|
|
|
|
/** Given some [[Or]] predicate, encode it as a JSON blob.
|
|
*
|
|
* @param and
|
|
* The [[Or]] predicate.
|
|
* @return
|
|
* The JSON blob representing the [[Or]].
|
|
*/
|
|
def encodeOr[F[_]](and: Or[F]): Json =
|
|
Json.obj(
|
|
(JsonKeys.predicateType, Json.fromString(Or.PredicateType)),
|
|
(JsonKeys.predicates, and.ps.asJson)
|
|
)
|
|
|
|
/** @return
|
|
* Generic encoder for any [[Predicate]].
|
|
*/
|
|
given predicateEncoder[F[_]]: Encoder[Predicate[F]] =
|
|
Encoder.instance {
|
|
case p: True[F] => Encoder[True[F]].apply(p)
|
|
case p: False[F] => Encoder[False[F]].apply(p)
|
|
case p: And[F] => encodeAnd[F](p)
|
|
case p: Or[F] => encodeOr[F](p)
|
|
case p: KeyExists[F] => Encoder[KeyExists[F]].apply(p)
|
|
case p: ValueEquals[F] => Encoder[ValueEquals[F]].apply(p)
|
|
case p: ValueContains[F] => Encoder[ValueContains[F]].apply(p)
|
|
case p: ValueStartsWith[F] => Encoder[ValueStartsWith[F]].apply(p)
|
|
case p: ValueEndsWith[F] => Encoder[ValueEndsWith[F]].apply(p)
|
|
case p: JsonQueryComparison[F] => Encoder[JsonQueryComparison[F]].apply(p)
|
|
case p =>
|
|
throw new IllegalArgumentException(
|
|
s"Unsupported predicate type: '${p.predicateType}'"
|
|
)
|
|
}
|
|
|
|
given jsonComparisonEncoder: Encoder[JsonComparison] =
|
|
Encoder.instance[JsonComparison] {
|
|
case jc: JsonComparison.Eq => Encoder[JsonComparison.Eq].apply(jc)
|
|
case jc: JsonComparison.Neq => Encoder[JsonComparison.Neq].apply(jc)
|
|
case jc: JsonComparison.StringContains =>
|
|
Encoder[JsonComparison.StringContains].apply(jc)
|
|
case jc: JsonComparison.StringPrefix =>
|
|
Encoder[JsonComparison.StringPrefix].apply(jc)
|
|
case jc: JsonComparison.StringSuffix =>
|
|
Encoder[JsonComparison.StringSuffix].apply(jc)
|
|
case jc: JsonComparison.IntLessThan =>
|
|
Encoder[JsonComparison.IntLessThan].apply(jc)
|
|
case jc: JsonComparison.IntLessThanOrEqualTo =>
|
|
Encoder[JsonComparison.IntLessThanOrEqualTo].apply(jc)
|
|
case jc: JsonComparison.IntGreaterThan =>
|
|
Encoder[JsonComparison.IntGreaterThan].apply(jc)
|
|
case jc: JsonComparison.IntGreaterThanOrEqualTo =>
|
|
Encoder[JsonComparison.IntGreaterThanOrEqualTo].apply(jc)
|
|
case jc: JsonComparison.IntBetweenInclusive =>
|
|
Encoder[JsonComparison.IntBetweenInclusive].apply(jc)
|
|
case jc: JsonComparison.IntBetweenExclusive =>
|
|
Encoder[JsonComparison.IntBetweenExclusive].apply(jc)
|
|
case jc: JsonComparison.DateEq => Encoder[JsonComparison.DateEq].apply(jc)
|
|
case jc: JsonComparison.DateBefore =>
|
|
Encoder[JsonComparison.DateBefore].apply(jc)
|
|
case jc: JsonComparison.DateAfter =>
|
|
Encoder[JsonComparison.DateAfter].apply(jc)
|
|
case jc: JsonComparison.DateBetweenInclusive =>
|
|
Encoder[JsonComparison.DateBetweenInclusive].apply(jc)
|
|
case jc: JsonComparison.DateBetweenExclusive =>
|
|
Encoder[JsonComparison.DateBetweenExclusive].apply(jc)
|
|
case jc =>
|
|
throw new IllegalArgumentException(
|
|
s"Unsupported JSON comparison: '${jc.name}'"
|
|
)
|
|
}
|
|
|
|
/** Given some JSON cursor, decode a logical [[And]] predicate.
|
|
*
|
|
* @param cursor
|
|
* The cursor that points to some JSON value.
|
|
* @return
|
|
* The [[And]] predicate or a decoding failure.
|
|
*/
|
|
def decodeAnd[F[_]: Applicative: KeyValueProvider: JsonProvider](
|
|
cursor: HCursor
|
|
): Either[DecodingFailure, And[F]] =
|
|
for ps <- cursor.downField(JsonKeys.predicates).as[List[Predicate[F]]]
|
|
yield new And(ps)
|
|
|
|
/** Given some JSON cursor, decode a logical [[Or]] predicate.
|
|
*
|
|
* @param cursor
|
|
* The cursor that points to some JSON value.
|
|
* @return
|
|
* The [[Or]] predicate or a decoding failure.
|
|
*/
|
|
def decodeOr[F[_]: Applicative: KeyValueProvider: JsonProvider](cursor: HCursor)
|
|
: Either[DecodingFailure, Or[F]] =
|
|
for ps <- cursor.downField(JsonKeys.predicates).as[List[Predicate[F]]]
|
|
yield new Or(ps)
|
|
|
|
/** Given some JSON cursor, decode any known [[Predicate]].
|
|
*
|
|
* @param cursor
|
|
* The cursor that points to some JSON value.
|
|
* @return
|
|
* The decoded [[Predicate]] or some decoding failure.
|
|
*/
|
|
def decodePredicate[F[_]: Applicative: KeyValueProvider: JsonProvider](
|
|
cursor: HCursor
|
|
): Either[DecodingFailure, Predicate[F]] =
|
|
for
|
|
predicateType <- cursor.downField(JsonKeys.predicateType).as[String]
|
|
predicate <- predicateType match
|
|
case True.PredicateType => Right(True[F])
|
|
case False.PredicateType => Right(False[F])
|
|
case And.PredicateType => decodeAnd[F](cursor)
|
|
case Or.PredicateType => decodeOr[F](cursor)
|
|
case KeyExists.PredicateType => Decoder[KeyExists[F]].apply(cursor)
|
|
case ValueEquals.PredicateType => Decoder[ValueEquals[F]].apply(cursor)
|
|
case ValueNotEquals.PredicateType =>
|
|
Decoder[ValueNotEquals[F]].apply(cursor)
|
|
case ValueContains.PredicateType =>
|
|
Decoder[ValueContains[F]].apply(cursor)
|
|
case ValueStartsWith.PredicateType =>
|
|
Decoder[ValueStartsWith[F]].apply(cursor)
|
|
case ValueEndsWith.PredicateType =>
|
|
Decoder[ValueEndsWith[F]].apply(cursor)
|
|
case JsonQueryComparison.PredicateType =>
|
|
Decoder[JsonQueryComparison[F]].apply(cursor)
|
|
case _ =>
|
|
Left(
|
|
DecodingFailure(
|
|
Messages.unrecognizedPredicateType(predicateType),
|
|
Nil
|
|
)
|
|
)
|
|
yield predicate
|
|
|
|
/** @return
|
|
* Generic decoder for any [[Predicate]].
|
|
*/
|
|
given predicateDecoder[F[_]: Applicative: KeyValueProvider: JsonProvider]
|
|
: Decoder[Predicate[F]] =
|
|
Decoder.instance[Predicate[F]](cursor => decodePredicate[F](cursor))
|
|
|
|
/** Given some JSON cursor, decode any known JSON comparison.
|
|
*
|
|
* @param cursor
|
|
* The cursor.
|
|
* @return
|
|
* The decoded [[JsonComparison]] or a decoding failure.
|
|
*/
|
|
def decodeJsonComparison(cursor: HCursor)
|
|
: Either[DecodingFailure, JsonComparison] =
|
|
for
|
|
name <- cursor.downField(JsonKeys.name).as[String]
|
|
comparison <- name match
|
|
case JsonComparison.Eq.Name => Decoder[JsonComparison.Eq].apply(cursor)
|
|
case JsonComparison.Neq.Name => Decoder[JsonComparison.Neq].apply(cursor)
|
|
case JsonComparison.StringContains.Name =>
|
|
Decoder[JsonComparison.StringContains].apply(cursor)
|
|
case JsonComparison.StringPrefix.Name =>
|
|
Decoder[JsonComparison.StringPrefix].apply(cursor)
|
|
case JsonComparison.StringSuffix.Name =>
|
|
Decoder[JsonComparison.StringSuffix].apply(cursor)
|
|
case JsonComparison.IntLessThan.Name =>
|
|
Decoder[JsonComparison.IntLessThan].apply(cursor)
|
|
case JsonComparison.IntLessThanOrEqualTo.Name =>
|
|
Decoder[JsonComparison.IntLessThanOrEqualTo].apply(cursor)
|
|
case JsonComparison.IntGreaterThan.Name =>
|
|
Decoder[JsonComparison.IntGreaterThan].apply(cursor)
|
|
case JsonComparison.IntGreaterThanOrEqualTo.Name =>
|
|
Decoder[JsonComparison.IntGreaterThanOrEqualTo].apply(cursor)
|
|
case JsonComparison.IntBetweenInclusive.Name =>
|
|
Decoder[JsonComparison.IntBetweenInclusive].apply(cursor)
|
|
case JsonComparison.IntBetweenExclusive.Name =>
|
|
Decoder[JsonComparison.IntBetweenExclusive].apply(cursor)
|
|
case JsonComparison.DateEq.Name =>
|
|
Decoder[JsonComparison.DateEq].apply(cursor)
|
|
case JsonComparison.DateBefore.Name =>
|
|
Decoder[JsonComparison.DateBefore].apply(cursor)
|
|
case JsonComparison.DateAfter.Name =>
|
|
Decoder[JsonComparison.DateAfter].apply(cursor)
|
|
case JsonComparison.DateBetweenInclusive.Name =>
|
|
Decoder[JsonComparison.DateBetweenInclusive].apply(cursor)
|
|
case JsonComparison.DateBetweenExclusive.Name =>
|
|
Decoder[JsonComparison.DateBetweenExclusive].apply(cursor)
|
|
case _ =>
|
|
Left(
|
|
DecodingFailure(Messages.unrecognizedJsonComparison(name), Nil)
|
|
)
|
|
yield comparison
|
|
|
|
/** Generic decoder for any [[JsonComparison]].
|
|
*/
|
|
given jsonComparisonDecoder: Decoder[JsonComparison] =
|
|
Decoder.instance[JsonComparison](decodeJsonComparison)
|