Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate freestyle to mu #26

Merged
merged 3 commits into from
Nov 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Contributing

Discussion around Skeuomorph happens in the [Gitter channel](https://gitter.im/47deg/freestyle) as well as on
[GitHub issues](https://github.com/47deg/freestyle/issues) and [pull requests](https://github.com/47deg/freestyle/pulls).
Discussion around Skeuomorph happens in the [Gitter channel]() as well as on
[GitHub issues](https://github.com/higherkindness/skeuomorph/issues) and [pull requests](https://github.com/higherkindness/skeuomorph/pulls).

Feel free to open an issue if you notice a bug, have an idea for a feature, or have a question about
the code. Pull requests are also welcome.
Expand Down
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Skeuomorph is a library for transforming different schemas in Scala.
It provides schema definitions as non-recursive ADTs, and
transformations & optimizations via recursion schemes.

This library is primarily intended to be used at [freestyle-rpc][], but
This library is primarily intended to be used at [mu][], but
it's completely independent from it, so anybody can use it.

Skeuomorph depends heavily on [cats][] and [droste][].
Expand All @@ -21,11 +21,11 @@ Skeuomorph depends heavily on [cats][] and [droste][].
Currently skeuomorph supports 3 different schemas:
- [Avro][]
- [Protobuf][]
- [freestyle-rpc][]
- [mu][]

And provides conversions between them. This means that you can get a
`org.apache.avro.Schema` value, and convert it to protobuf, for
example. Or to a freestyle service description.
example. Or to a mu service description.


## Installation
Expand All @@ -35,7 +35,7 @@ You can install skeuomorph as follows:
[comment]: # (Start Replace)

```scala
libraryDependencies += "io.frees" %% "skeuomorph" % "0.0.1"
libraryDependencies += "io.higherkindness" %% "skeuomorph" % "0.0.1"
```

[comment]: # (End Replace)
Expand All @@ -45,11 +45,12 @@ libraryDependencies += "io.frees" %% "skeuomorph" % "0.0.1"
### parsing an avro schema and then converting it to scala:

```tut

import org.apache.avro._
import skeuomorph._
import skeuomorph.freestyle.Transform.transformAvro
import skeuomorph.freestyle.FreesF
import skeuomorph.freestyle.FreesF.render
import skeuomorph.mu.Transform.transformAvro
import skeuomorph.mu.MuF
import skeuomorph.mu.MuF.render
import skeuomorph.avro.AvroF.fromAvro
import qq.droste._
import qq.droste.data._
Expand Down Expand Up @@ -87,9 +88,9 @@ val definition = """

val schema: Schema = new Schema.Parser().parse(definition)

val parseAvro: Schema => Mu[FreesF] =
scheme.hylo(transformAvro[Mu[FreesF]].algebra, fromAvro)
val printSchema: Mu[FreesF] => String =
val parseAvro: Schema => Mu[MuF] =
scheme.hylo(transformAvro[Mu[MuF]].algebra, fromAvro)
val printSchema: Mu[MuF] => String =
scheme.cata(render)

(parseAvro >>> print)(schema)
Expand All @@ -102,13 +103,13 @@ val printSchema: Mu[FreesF] => String =
If you wish to add your library here please consider a PR to include
it in the list below.

| **Name** | **Description** |
|-----------------------------------------------|----------------------------------------------------------------------------------------------------|
| [**freestyle-rpc**](http://frees.io/docs/rpc) | purely functional library for building RPC endpoint based services with support for RPC and HTTP/2 |
| **Name** | **Description** |
|------------------------------------------------|----------------------------------------------------------------------------------------------------|
| [**mu**](https://higherkindness.github.io/mu/) | purely functional library for building RPC endpoint based services with support for RPC and HTTP/2 |

[Avro]: https://avro.apache.org/
[Protobuf]: https://developers.google.com/protocol-buffers/
[freestyle-rpc]: http://frees.io/docs/rpc/quickstart
[mu]: https://higherkindness.github.io/mu/
[cats]: http://typelevel.org/cats
[droste]: http://github.com/andyscott/droste

Expand Down
18 changes: 9 additions & 9 deletions docs/src/main/tut/optimizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import qq.droste._
import qq.droste.data._
import qq.droste.implicits._

import skeuomorph.freestyle._
import skeuomorph.freestyle.FreesF._
import skeuomorph.mu._
import skeuomorph.mu.MuF._
```

We found that when we wanted to render a schema to its string
Expand All @@ -43,10 +43,10 @@ case class Product(field1: String, field2: OtherField)

We solve this by substituting nested product types by its name when
they're inside a product themselves. And we do this with the
`namedTypes` combinator (in `skeuomorph.freestyle.Optimize`):
`namedTypes` combinator (in `skeuomorph.mu.Optimize`):

```scala
def nestedNamedTypesTrans[T](implicit T: Basis[FreesF, T]): Trans[FreesF, FreesF, T] = Trans {
def nestedNamedTypesTrans[T](implicit T: Basis[MuF, T]): Trans[MuF, MuF, T] = Trans {
case TProduct(name, fields) =>
def nameTypes(f: Field[T]): Field[T] = f.copy(tpe = namedTypes(T)(f.tpe))
TProduct[T](
Expand All @@ -56,25 +56,25 @@ def nestedNamedTypesTrans[T](implicit T: Basis[FreesF, T]): Trans[FreesF, FreesF
case other => other
}

def namedTypesTrans[T]: Trans[FreesF, FreesF, T] = Trans {
def namedTypesTrans[T]: Trans[MuF, MuF, T] = Trans {
case TProduct(name, _) => TNamedType[T](name)
case TSum(name, _) => TNamedType[T](name)
case other => other
}

def namedTypes[T: Basis[FreesF, ?]]: T => T = scheme.cata(namedTypesTrans.algebra)
def nestedNamedTypes[T: Basis[FreesF, ?]]: T => T = scheme.cata(nestedNamedTypesTrans.algebra)
def namedTypes[T: Basis[MuF, ?]]: T => T = scheme.cata(namedTypesTrans.algebra)
def nestedNamedTypes[T: Basis[MuF, ?]]: T => T = scheme.cata(nestedNamedTypesTrans.algebra)

```

and then apply the `namedTypes` combinator to the AST:

```tut:invisible
def ast = Mu(TNull[Mu[FreesF]]())
def ast = Mu(TNull[Mu[MuF]]())
```

```tut
val optimization = Optimize.namedTypes[Mu[FreesF]]
val optimization = Optimize.namedTypes[Mu[MuF]]

optimization(ast)
```
14 changes: 0 additions & 14 deletions docs/src/main/tut/rendering.md

This file was deleted.

14 changes: 7 additions & 7 deletions docs/src/main/tut/schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ Currently in skeuomorph there are schemas defined for different cases:

- [Avro][]
- [Protobuf][]
- [freestyle-rpc][]
- [mu][]

## Schema conversions


| from\to | **Avro** | **Protobuf** | **freestyle-rpc** |
|-------------------|----------------------------------|----------------------------------|------------------------------------|
| **Avro** | | | `avro.transCata(fromAvro)` |
| **Protobuf** | | | `protobuf.transCata(fromProtobuf)` |
| **freestyle-rpc** | `frees.transCata(fromFreestyle)` | `frees.transCata(fromFreestyle)` | |
| from\to | **Avro** | **Protobuf** | **mu** |
|---------------|---------------------------|------------------------|------------------------------------|
| **Avro** | | | `avro.transCata(fromAvro)` |
| **Protobuf** | | | `protobuf.transCata(fromProtobuf)` |
| **mu** | `mu.transCata(fromMu)` | `mu.transCata(fromMu)` | |


[Avro]: https://avro.apache.org/
[Protobuf]: https://developers.google.com/protocol-buffers/
[freestyle-rpc]: http://frees.io/docs/rpc/quickstart
[mu]: https://higherkindness.github.io/mu/
43 changes: 21 additions & 22 deletions src/main/scala/avro/Protocol.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import cats.syntax.option._
import cats.data.NonEmptyList
import qq.droste._
import qq.droste.syntax.all._
import freestyle.{FreesF, SerializationType}
import mu.{MuF, SerializationType}
import io.circe.Json

final case class Protocol[A](
Expand Down Expand Up @@ -81,25 +81,25 @@ object Protocol {
)
}

def fromFreesFSchema[T](implicit T: Basis[AvroF, T]): Trans[FreesF, AvroF, T] = Trans {
case FreesF.TNull() => tNull()
case FreesF.TDouble() => tDouble()
case FreesF.TFloat() => tFloat()
case FreesF.TInt() => tInt()
case FreesF.TLong() => tLong()
case FreesF.TBoolean() => tBoolean()
case FreesF.TString() => tString()
case FreesF.TByteArray() => tBytes()
case FreesF.TNamedType(name) => tNamedType(name)
case FreesF.TOption(value) => tUnion(NonEmptyList(tNull[T]().embed, List(value)))
case FreesF.TEither(left, right) => tUnion(NonEmptyList(left, List(right)))
case FreesF.TList(value) => tArray(value)
case FreesF.TMap(value) => tMap(value)
case FreesF.TGeneric(_, _) => ??? // WAT
case FreesF.TRequired(t) => T.coalgebra(t)
case FreesF.TCoproduct(invariants) => TUnion(invariants)
case FreesF.TSum(name, fields) => TEnum(name, none[String], Nil, none[String], fields)
case FreesF.TProduct(name, fields) =>
def fromFreesFSchema[T](implicit T: Basis[AvroF, T]): Trans[MuF, AvroF, T] = Trans {
case MuF.TNull() => tNull()
case MuF.TDouble() => tDouble()
case MuF.TFloat() => tFloat()
case MuF.TInt() => tInt()
case MuF.TLong() => tLong()
case MuF.TBoolean() => tBoolean()
case MuF.TString() => tString()
case MuF.TByteArray() => tBytes()
case MuF.TNamedType(name) => tNamedType(name)
case MuF.TOption(value) => tUnion(NonEmptyList(tNull[T]().embed, List(value)))
case MuF.TEither(left, right) => tUnion(NonEmptyList(left, List(right)))
case MuF.TList(value) => tArray(value)
case MuF.TMap(value) => tMap(value)
case MuF.TGeneric(_, _) => ??? // WAT
case MuF.TRequired(t) => T.coalgebra(t)
case MuF.TCoproduct(invariants) => TUnion(invariants)
case MuF.TSum(name, fields) => TEnum(name, none[String], Nil, none[String], fields)
case MuF.TProduct(name, fields) =>
TRecord(
name,
none[String],
Expand All @@ -108,8 +108,7 @@ object Protocol {
fields.map(f => Field(f.name, Nil, none[String], none[Order], f.tpe)))
}

def fromFreesFProtocol[T, U](
proto: freestyle.Protocol[T])(implicit T: Basis[FreesF, T], U: Basis[AvroF, U]): Protocol[U] = {
def fromFreesFProtocol[T, U](proto: mu.Protocol[T])(implicit T: Basis[MuF, T], U: Basis[AvroF, U]): Protocol[U] = {
def fromFreestyle: T => U = scheme.cata(fromFreesFSchema.algebra)
val services: List[Message[U]] = proto.services
.filter(_.serializationType == SerializationType.Avro)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
*/

package skeuomorph
package freestyle
package mu

import qq.droste._
import FreesF._
import MuF._
import cats.data.NonEmptyList

/**
Expand All @@ -43,7 +43,7 @@ object Optimize {
* case class Product(field1: String, field2: OtherField)
* }}}
*/
def nestedNamedTypesTrans[T](implicit T: Basis[FreesF, T]): Trans[FreesF, FreesF, T] = Trans {
def nestedNamedTypesTrans[T](implicit T: Basis[MuF, T]): Trans[MuF, MuF, T] = Trans {
case TProduct(name, fields) =>
def nameTypes(f: Field[T]): Field[T] = f.copy(tpe = namedTypes(T)(f.tpe))
TProduct[T](
Expand All @@ -53,14 +53,14 @@ object Optimize {
case other => other
}

def namedTypesTrans[T]: Trans[FreesF, FreesF, T] = Trans {
def namedTypesTrans[T]: Trans[MuF, MuF, T] = Trans {
case TProduct(name, _) => TNamedType[T](name)
case TSum(name, _) => TNamedType[T](name)
case other => other
}

def namedTypes[T: Basis[FreesF, ?]]: T => T = scheme.cata(namedTypesTrans.algebra)
def nestedNamedTypes[T: Basis[FreesF, ?]]: T => T = scheme.cata(nestedNamedTypesTrans.algebra)
def namedTypes[T: Basis[MuF, ?]]: T => T = scheme.cata(namedTypesTrans.algebra)
def nestedNamedTypes[T: Basis[MuF, ?]]: T => T = scheme.cata(nestedNamedTypesTrans.algebra)

/**
* micro-optimization to convert known coproducts to named types
Expand All @@ -79,7 +79,7 @@ object Optimize {
* case class Product(field1: Either[Int, String], field2: Option[Int])
* }}}
*/
def knownCoproductTypesTrans[T](implicit B: Basis[FreesF, T]): Trans[FreesF, FreesF, T] = Trans {
def knownCoproductTypesTrans[T](implicit B: Basis[MuF, T]): Trans[MuF, MuF, T] = Trans {
case TCoproduct(NonEmptyList(x, List(y))) =>
(B.coalgebra(x), B.coalgebra(y)) match {
case (_, TNull()) => TOption[T](x)
Expand All @@ -89,5 +89,5 @@ object Optimize {
case other => other
}

def knownCoproductTypes[T: Basis[FreesF, ?]]: T => T = scheme.cata(knownCoproductTypesTrans.algebra)
def knownCoproductTypes[T: Basis[MuF, ?]]: T => T = scheme.cata(knownCoproductTypesTrans.algebra)
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@
*/

package skeuomorph
package freestyle
package mu

import qq.droste.Trans
import protobuf.ProtobufF
import avro.AvroF

object Transform {

import FreesF._
import MuF._

/**
* transform Protobuf schema into Freestyle schema
*/
def transformProto[A]: Trans[ProtobufF, FreesF, A] = Trans {
def transformProto[A]: Trans[ProtobufF, MuF, A] = Trans {
case ProtobufF.TDouble() => TDouble()
case ProtobufF.TFloat() => TFloat()
case ProtobufF.TInt32() => TInt()
Expand All @@ -52,7 +52,7 @@ object Transform {
case ProtobufF.TMessage(name, fields, _) => TProduct(name, fields.map(f => Field(f.name, f.tpe)))
}

def transformAvro[A]: Trans[AvroF, FreesF, A] = Trans {
def transformAvro[A]: Trans[AvroF, MuF, A] = Trans {
case AvroF.TNull() => TNull()
case AvroF.TBoolean() => TBoolean()
case AvroF.TInt() => TInt()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@
*/

package skeuomorph
package freestyle
package mu

import Optimize.namedTypes
import cats.instances.function._
import cats.syntax.compose._

import qq.droste._
import FreesF._
import MuF._
import catz.contrib.ContravariantMonoidalSyntax._
import catz.contrib.Decidable._
import Printer._
import SerializationType._

object print {

def schema[T: Basis[FreesF, ?]]: Printer[T] = {
val algebra: Algebra[FreesF, String] = Algebra {
def schema[T: Basis[MuF, ?]]: Printer[T] = {
val algebra: Algebra[MuF, String] = Algebra {
case TNull() => "Null"
case TDouble() => "Double"
case TFloat() => "Float"
Expand Down Expand Up @@ -71,7 +71,7 @@ object print {
*/
def protoTuple[T](
proto: Protocol[T]
): ((((Option[String], List[(String, String)]), String), List[T]), List[skeuomorph.freestyle.Service[T]]) =
): ((((Option[String], List[(String, String)]), String), List[T]), List[skeuomorph.mu.Service[T]]) =
proto match {
case Protocol(name, pkg, options, declarations, services) =>
((((pkg, options), name), declarations), services)
Expand Down Expand Up @@ -118,20 +118,20 @@ object print {
def serializationType: Printer[SerializationType] =
(protobuf >|< avro >|< avroWithSchema).contramap(serTypeEither)

def operation[T](implicit T: Basis[FreesF, T]): Printer[Service.Operation[T]] =
def operation[T](implicit T: Basis[MuF, T]): Printer[Service.Operation[T]] =
((konst("def ") *< string) >*< (konst("(req: ") *< Printer(namedTypes[T] >>> schema.print)) >*< (konst("): ") *< Printer(
namedTypes[T] >>> schema.print)))
.contramap(opTuple)

def service[T](implicit T: Basis[FreesF, T]): Printer[Service[T]] =
def service[T](implicit T: Basis[MuF, T]): Printer[Service[T]] =
((konst("@service(") *< serializationType >* konst(") trait ")) >*<
(string >* konst("[F[_]] {") >* newLine) >*<
(sepBy(operation, "\n") >* newLine >* konst("}"))).contramap(serviceTuple)

def option: Printer[(String, String)] =
(konst("@option(name = ") *< string) >*< (konst(", value = ") *< string >* konst(")"))

def proto[T](implicit T: Basis[FreesF, T]): Printer[Protocol[T]] = {
def proto[T](implicit T: Basis[MuF, T]): Printer[Protocol[T]] = {
val lineFeed = "\n"
val doubleLineFeed = "\n\n "
((konst("package ") *< optional(string) >* (newLine >* newLine)) >*<
Expand Down
Loading