In May 2018 the SpartanZ Project was started. A public call for contributors, followed by a myriad of projects propositions that people could choose and pick from to work on under the umbrella of ScalaZ. Scalaz-Schema is one of these projects and is based on another Library called Xenomorph. In its core it is about describing ADTs and from that deriving all sorts of useful implementations. From SerDes to Generators, forward/backwards compatibility between Schemas, Diffing and even querrying capabilites. In many Scala Libraries such derivations are currently done directly from the involved Datatypes using Macros or dependencies such as Shapeless. However these have various drawbacks that arise from coupling implementation with protocol. Refactoring your internal representations will inherently affect your public facing protocols. During this presentation I'll be talking about the Schema datatype is built using GADTs and Free constructions, how the derivations from the result
package object types { | |
type RecordTypeString = String Refined Equal[RecordTypeName] | |
type EnumTypeString = String Refined Equal[EnumTypeName] | |
type ArrayTypeString = String Refined Equal[ArrayTypeName] | |
type MapTypeString = String Refined Equal[MapTypeName] | |
type FixedTypeString = String Refined Equal[FixedTypeName] |
import shapeless.{CNil, :+:} | |
import io.circe._ | |
import io.circe.generic.auto._ | |
import io.circe.parser._ | |
import io.circe.shapes._ | |
import io.circe.parser.decode | |
import io.circe.syntax._ | |
import io.circe.generic.semiauto._ | |
sealed trait Foo |
trait RecordMapper[B]{ | |
def apply(dt:SupportedAvroDatatype)(key:String, value:dt.I):B | |
} | |
def nameMe[B] | |
(record: Map[String, Option[AnyRef]], lookup: SortedMap[String, SupportedAvroDatatype]) | |
(f: RecordMapper[B]): List[Either[ErrorMessage,B]] = | |
record.map( | |
kv => { | |
val key = kv._1 |
package ch.avro.schema | |
import eu.timepit.refined.W | |
import eu.timepit.refined.api.Refined | |
import eu.timepit.refined.generic.Equal | |
object AvroTypes{ | |
type RecordTypeName = W.`"record"`.T |
sealed trait AvroType[A] | |
sealed trait AvroPrimitiveType[A] extends AvroType[A] | |
final case class AvroNull[A]() extends AvroPrimitiveType[A] | |
final case class AvroBoolean[A]() extends AvroPrimitiveType[A] | |
final case class AvroInt[A]() extends AvroPrimitiveType[A] | |
final case class AvroLong[A]() extends AvroPrimitiveType[A] | |
final case class AvroFloat[A]() extends AvroPrimitiveType[A] | |
final case class AvroDouble[A]() extends AvroPrimitiveType[A] | |
final case class AvroBytes[A]() extends AvroPrimitiveType[A] |
{-# LANGUAGE GADTs #-} | |
{-# LANGUAGE RankNTypes #-} | |
{-# LANGUAGE TypeOperators #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
module Lib | |
( personSchema | |
, main | |
) where |
package scalaz | |
package schema | |
import Liskov._ | |
trait JsonModule extends SchemaModule { | |
type JSON = String | |
type Encoder[A] = A => JSON |
Lets say
{
Viewer = 1 // 00001
Subscriber = 2 //00010
Mod = 4 //00100
I have a bit of a brainteaser and was hoping someone has a bit of time to be my rubberduck.
So I am working on a DSL and want to build a Runtime for that language to be executed in.
A program in that DSL is effectively a function from Runtime => Runtime
(modulo error/io monad).
The Runtime contains all the bindings that the programs can read and are writing.
Each program defines the bindings it requires as well as the ones it adds.
Besides that I have a couple combinators AndThen
for sequential programs where the rhs has access to what lhs writes.
Choice
for a finite, exhaustive if-like things. And all
for combining n programs that are run against the same runtime instance and whose results are aggregates.
so e.g my current compiler for AndThen
just does function composition. It's fairly straight forwards.