Skip to content

Repository files navigation

morphling Release Artifacts

Cats-based Scala library for free applicative schemas. Core module of morphling initially was a cats-based port of the excellent Kris Nuttycombe's xenomorph

Getting started

All You need is love:

 libraryDependencies ++= Seq(
"com.github.danslapman" %% "morphling" % "4.0.0", //core module
"com.github.danslapman" %% "morphling-circe" % "4.0.0",
"com.github.danslapman" %% "morphling-reactivemongo" % "4.0.0",
"com.github.danslapman" %% "morphling-typed-schema" % "4.0.0",
"com.github.danslapman" %% "morphling-scalacheck" % "4.0.0",
"com.github.danslapman" %% "morphling-tapir" % "4.0.0"
)

Version compatibility table

morphlingcatscircereactivemongotyped-schemascalachecktofuglasstapir
4.02.80.14.21.0.3 / 1.1.0-RC60.14.31.15.3-0.31.0.0
3.12.80.14.21.0.3 / 1.1.0-RC60.14.31.15.3-0.11.0.0
3.02.80.14.21.0.3 / 1.1.0-RC60.14.31.15.3-0.1-
2.7-glass2.80.13.01.0.30.14.31.15.3-0.1-
2.72.4.20.13.01.0.30.14.31.15.30.10.0--
2.62.4.20.12.30.19.30.12.5.11.14.30.7.9--
2.42.0.00.12.30.19.30.12.5.11.14.30.7.9--
2.12.0.00.12.30.19.30.12.41.14.30.7.4--
2.02.0.00.12.30.19.30.11.11.14.30.6.1--
1.5.12.0.00.12.30.19.30.11.11.14.0---
1.52.0.00.12.30.19.00.11.01.14.0---
1.12.0.00.11.10.17.00.11.0-beta61.14.0---
1.01.6.10.11.10.16.40.11.0-beta61.14.0---

Setting up protocol

First of all, You need to define a set of "scalar" types You like to support. They can be Ints, BigInts, Instants, any type You mean to treat as scalar, actually. You can find an example protocol in tests of core module:

importmorphling.HMutuimportmorphling.Schema._sealedtraitSType[F[_], I]
caseclassSNullT[F[_]]() extendsSType[F, Unit]
caseclassSBoolT[F[_]]() extendsSType[F, Boolean]
caseclassSIntT[F[_]]() extendsSType[F, Int]
caseclassSLongT[F[_]]() extendsSType[F, Long]
caseclassSFloatT[F[_]]() extendsSType[F, Float]
caseclassSDoubleT[F[_]]() extendsSType[F, Double]
caseclassSCharT[F[_]]() extendsSType[F, Char]
caseclassSStrT[F[_]]() extendsSType[F, String]
caseclassSArrayT[F[_], I](elem: F[I]) extendsSType[F, Vector[I]]

Also it will be convenient to define some helper methods (will see their purpose later):

objectSType {
typeSSchema[I] =HMutu[SType, Schema, I]
valsNull= prim(HMutu[SType, Schema, Unit](SNullT()))
valsBool= prim(HMutu[SType, Schema, Boolean](SBoolT()))
valsInt= prim(HMutu[SType, Schema, Int](SIntT()))
valsLong= prim(HMutu[SType, Schema, Long](SLongT()))
valsFloat= prim(HMutu[SType, Schema, Float](SFloatT()))
valsDouble= prim(HMutu[SType, Schema, Double](SDoubleT()))
valsChar= prim(HMutu[SType, Schema, Char](SCharT()))
valsStr= prim(HMutu[SType, Schema, String](SStrT()))
defsArray[I](elem: Schema[SSchema, I]) = prim(HMutu[SType, Schema, Vector[I]](SArrayT(elem)))
}

Creating a Schema

Now we can define a schema for an arbitrary type using our protocol:

importcats.syntax.apply._importmorphling.Schemaimportmorphling.Schema._importglass.macros._importSType._//Defined abovecase@OpticsclassServer(host: String, port: Int)
objectServer {
valserverSchema:Schema[SSchema, Server] = rec(
(
required("host", sStr, Server.host),
required("port", sInt, Server.port)
).mapN(Server.apply)
)
}

That's it.

Generating instances

morphling provides a set of modules which enables generation of typeclasses from schema instances. To use them You need to define an "implementation" of protocol You previously defined. Let's do it for circe Encoding:

importcats._importio.circe.{Decoder, Encoder, Json}
importSType.SSchemaimportmorphling.Schema.SchemadefsTypeEncoder[F[_]:ToJson]: (SType[F, *] ~>Encoder) =new (SType[F, *] ~>Encoder) {
importToJson._overridedefapply[A](st: SType[F, A]):Encoder[A] = st match {
caseSNullT() =>Encoder.encodeUnit
caseSBoolT() =>Encoder.encodeBoolean
caseSIntT() =>Encoder.encodeInt
caseSLongT() =>Encoder.encodeLong
caseSFloatT() =>Encoder.encodeFloat
caseSDoubleT() =>Encoder.encodeDouble
caseSCharT() =>Encoder.encodeChar
caseSStrT() =>Encoder.encodeString
caseSArrayT(elem) =>Encoder.encodeVector(elem.encoder)
}
}
implicitvalprimFromJson:FromJson[SSchema] =newFromJson[SSchema] {
valdecoder=new (SSchema~>Decoder) {
defapply[I](s: SSchema[I]):Decoder[I] = sTypeDecoder[SSchema[I]#Inner].apply(s.unmutu)
}

With such a transformation defined we can derive an Encoder for Server:

valencoder=Server.schema.encoder

About

Cats-based Scala library for free applicative schemas (cats-based port of Xenomorph)

Resources

Stars

36 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages