-
Notifications
You must be signed in to change notification settings - Fork 0
/
encoding.scala
75 lines (65 loc) · 2.03 KB
/
encoding.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*
* Copyright 2021 Erlend Hamnaberg
*
* SPDX-License-Identifier: Apache-2.0
*/
package net.hamnaberg.schema
package internal
import cats._
import cats.data.Chain
import cats.syntax.all._
import cats.free.FreeApplicative
import io.circe.{Encoder, Json, JsonObject}
import io.circe.syntax._
object encoding {
import structure._
def fromSchema[A](schema: Schema[A]): Encoder[A] = schema match {
case Meta(s, _, _, _) =>
fromSchema(s)
case SInt(_, _) =>
Encoder.encodeJsonNumber
case SNum(_, _) =>
Encoder.encodeJsonNumber
case SBool =>
Encoder.encodeBoolean
case Str(_, _, _, _) =>
Encoder.encodeString
case Enumeration(_) =>
Encoder.encodeString
case Sequence(value, _, _, _) =>
encodeList(value)
case Record(rec) =>
Encoder.instance(encodeObject(rec).andThen(_.asJson))
case Isos(xmap) =>
fromSchema(xmap.schema).contramap(xmap.w)
case Defer(f) => fromSchema(f())
case Custom(_, encoder, _) => encoder
case Sum(alts) => encodeAlternatives(alts)
case AllOf(all, sOpt) =>
val s = sOpt.getOrElse(all.head)
fromSchema(s)
case AnyOf(chain, sOpt) =>
val s = sOpt.getOrElse(chain.head)
fromSchema(s)
}
def encodeList[A](schema: Schema[A]): Encoder[List[A]] =
Encoder.encodeList[A](fromSchema[A](schema))
def encodeObject[R](record: FreeApplicative[Field[R, *], R]) = {
type Target[A] = R => List[(String, Json)]
record
.analyze {
new (Field[R, *] ~> Target) {
override def apply[A](fa: Field[R, A]): Target[A] =
fa.encode
}
}
.andThen(JsonObject.fromIterable(_))
}
def encodeAlternatives[A](alts: Chain[Alt[A]]): Encoder[A] = Encoder.instance { superType =>
implicit def orElse[T]: Monoid[Option[T]] =
MonoidK[Option].algebra
val maybe =
alts.foldMap(alt => alt.prism.tryGet(superType).map(caseValue => fromSchema(alt.caseSchema).apply(caseValue)))
maybe.getOrElse(sys.error("Unable to create json value from alternative"))
}
}