Skip to content

Commit

Permalink
Merge pull request #2 from frees-io/droste
Browse files Browse the repository at this point in the history
Migrate from turtles to droste
  • Loading branch information
pepegar committed Aug 2, 2018
2 parents f3add8a + ad035d2 commit 368e786
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 391 deletions.
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ libraryDependencies += "io.frees" %% "skeuomorph" % "0.1.0"
```tut
import org.apache.avro._
import skeuomorph._
import turtles._
import turtles.data.Mu
import turtles.implicits._
import skeuomorph.freestyle.Transform.transformAvro
import skeuomorph.freestyle.Schema.render
import skeuomorph.avro.Schema.fromAvro
import qq.droste._
import qq.droste.data._
import qq.droste.implicits._
import cats.implicits._
val definition = """
{
Expand Down Expand Up @@ -81,10 +86,12 @@ val definition = """
val schema: Schema = new Schema.Parser().parse(definition)
schema.
ana[Mu[avro.Schema]](avro.util.fromAvro). // org.apache.avro.Schema => skeuomorph.avro.Schema.
transCata[Mu[freestyle.Schema]](freestyle.util.transformAvro). // skeuomorph.avro.Schema => skeuomorph.freestyle.Schema.
cata(freestyle.util.render) // skeuomorph.freestyle.Schema => String
val parseAvroSchema: Schema => Mu[freestyle.Schema] =
scheme.hylo(transformAvro[Mu[freestyle.Schema]].algebra.run, fromAvro.run)
val printSchema: Mu[freestyle.Schema] => String =
scheme.cata(render)
(parseAvroSchema >>> printSchema)(schema)
```


Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ lazy val commonSettings = Seq(
ThisBuild / scalacOptions -= "-Xplugin-require:macroparadise",
libraryDependencies ++= Seq(
%%("cats-core"),
"org.technomadic" %% "turtles-core" % "0.1.0",
"io.higherkindness" %% "droste-core" % "0.3.1",
"org.apache.avro" % "avro" % "1.8.2",
%%("specs2-core") % Test,
%%("specs2-scalacheck") % Test,
Expand Down
53 changes: 30 additions & 23 deletions docs/src/main/tut/optimizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ mechanisms to apply that function to the AST correctly. Let's see
## NamedTypes

```tut:invisible
import turtles._
import turtles.data._
import turtles.implicits._
import qq.droste._
import qq.droste.data._
import qq.droste.implicits._
import skeuomorph.freestyle._
import skeuomorph.freestyle.Schema._
```
Expand All @@ -42,32 +43,38 @@ case class Product(field1: String, field2: OtherField)

We solve this by substituting nested product types by it's name when
they're inside a product themselves. And we do this with the
`namedTypes` combinator:

```tut:silent
def namedTypes[T](t: T)(implicit T: Birecursive.Aux[T, Schema]): T =
t.project match {
case TProduct(name, fields) =>
TProduct[T](
name,
fields.map { f: Field[T] =>
f.copy(tpe = f.tpe.transCataT(_.project match {
case TProduct(name, _) => TNamedType[T](name).embed
case TSum(name, _) => TNamedType[T](name).embed
case other => other.embed
}))
}
).embed
case other => other.embed
}
`namedTypes` combinator (in `skeuomorph.freestyle.Optimize`):

```scala
def nestedNamedTypesTrans[T](implicit T: Basis[Schema, T]): Trans[Schema, Schema, T] = Trans {
case TProduct(name, fields) =>
def nameTypes(f: Field[T]): Field[T] = f.copy(tpe = namedTypes(T)(f.tpe))
TProduct[T](
name,
fields.map(nameTypes)
)
case other => other
}

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

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

```

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

```tut:invisible
def ast[T](implicit T: Birecursive.Aux[T, Schema]): T = TNull[T]().embed
def ast = Mu(TNull[Mu[Schema]]())
```

```tut
ast[Mu[Schema]].transCataT(namedTypes)
val optimization = Optimize.namedTypes[Mu[Schema]]
optimization(ast)
```
9 changes: 0 additions & 9 deletions docs/src/main/tut/schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@ position: 1

# Schemas

> Examples in this page expects you to have the following imports in
> place:
```tut:silent
import turtles.data._
import turtles.implicits._
import skeuomorph._
```

Currently in skeuomorph there are schemas defined for different cases:

- [Avro][]
Expand Down
50 changes: 50 additions & 0 deletions src/main/scala/avro/Protocol.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2018 47 Degrees, LLC. <http://www.47deg.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package skeuomorph
package avro

import org.apache.avro.{Schema => AvroSchema, Protocol => AvroProtocol}
import scala.collection.JavaConverters._

import qq.droste._

case class Protocol[A](
name: String,
namespace: Option[String],
types: List[A],
messages: List[Protocol.Message[A]]
)

object Protocol {
import Schema._

case class Message[A](name: String, request: A, response: A)

def fromProto[T](proto: AvroProtocol)(implicit T: Embed[Schema, T]): Protocol[T] = {
val toAvroSchema: AvroSchema => T = scheme.ana(fromAvro)
def toMessage(kv: (String, AvroProtocol#Message)): Message[T] =
Message[T](kv._2.getName, toAvroSchema(kv._2.getRequest), toAvroSchema(kv._2.getResponse))

Protocol(
proto.getName,
Option(proto.getNamespace),
proto.getTypes.asScala.toList.map(toAvroSchema),
proto.getMessages.asScala.toList.map(toMessage)
)
}

}
75 changes: 67 additions & 8 deletions src/main/scala/avro/schema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,17 @@
package skeuomorph
package avro

import scala.collection.JavaConverters._

import cats.Functor
import cats.data.NonEmptyList
import org.apache.avro.{Schema => AvroSchema}
import org.apache.avro.Schema.{Type => AvroType}
import qq.droste.Coalgebra

sealed trait Schema[A]
object Schema {

case class Message[A](name: String, request: A, response: A)
case class Protocol[A](
name: String,
namespace: Option[String],
types: List[A],
messages: List[Message[A]]
)

sealed trait Order
object Order {
case object Ascending extends Order
Expand Down Expand Up @@ -97,4 +94,66 @@ object Schema {
case Schema.TFixed(name, namespace, aliases, size) => Schema.TFixed(name, namespace, aliases, size)
}
}

/**
* Convert [[org.apache.avro.Schema]] to [[skeuomorph.avro.AvroSchema]]
*/
def fromAvro: Coalgebra[Schema, AvroSchema] = Coalgebra { sch =>
sch.getType match {
case AvroType.STRING => Schema.TString()
case AvroType.BOOLEAN => Schema.TBoolean()
case AvroType.BYTES => Schema.TBytes()
case AvroType.DOUBLE => Schema.TDouble()
case AvroType.FLOAT => Schema.TFloat()
case AvroType.INT => Schema.TInt()
case AvroType.LONG => Schema.TLong()
case AvroType.NULL => Schema.TNull()
case AvroType.MAP => Schema.TMap(sch.getValueType)
case AvroType.ARRAY => Schema.TArray(sch.getElementType)
case AvroType.RECORD =>
Schema.TRecord(
sch.getName,
Option(sch.getNamespace),
sch.getAliases.asScala.toList,
Option(sch.getDoc),
sch.getFields.asScala.toList.map(field2Field)
)
case AvroType.ENUM =>
val symbols = sch.getEnumSymbols.asScala.toList
Schema.TEnum(
sch.getName,
Option(sch.getNamespace),
sch.getAliases.asScala.toList,
Option(sch.getDoc),
symbols
)
case AvroType.UNION =>
val types = sch.getTypes.asScala.toList
Schema.TUnion(
NonEmptyList.fromListUnsafe(types)
)
case AvroType.FIXED =>
Schema.TFixed(
sch.getName,
Option(sch.getNamespace),
sch.getAliases.asScala.toList,
sch.getFixedSize
)
}
}

def order2Order(avroO: AvroSchema.Field.Order): Order = avroO match {
case AvroSchema.Field.Order.ASCENDING => Order.Ascending
case AvroSchema.Field.Order.DESCENDING => Order.Descending
case AvroSchema.Field.Order.IGNORE => Order.Ignore
}

def field2Field(avroF: AvroSchema.Field): Field[AvroSchema] = Field(
avroF.name,
avroF.aliases.asScala.toList,
Option(avroF.doc),
Option(order2Order(avroF.order)),
avroF.schema
)

}
107 changes: 0 additions & 107 deletions src/main/scala/avro/util.scala

This file was deleted.

0 comments on commit 368e786

Please sign in to comment.