Skip to content

Instantly share code, notes, and snippets.

@ahoy-jon
Created January 3, 2019 23:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahoy-jon/8aed3243a21d143b37b381fb10b856f5 to your computer and use it in GitHub Desktop.
Save ahoy-jon/8aed3243a21d143b37b381fb10b856f5 to your computer and use it in GitHub Desktop.
package io.univalence
import io.univalence.Fk.Encoder.{BindedTypedExprEncoder, SimpleEncoder}
import io.univalence.Fk.Expr.Ops
import io.univalence.Fk.TypedExpr.TypedOr
import org.json4s.JsonAST.{JArray, JString, JValue}
import scala.language.{dynamics, implicitConversions}
object Fk {
sealed trait Expr {
}
trait LowPriority {
implicit def antiArrowAssocExpr[A: SimpleEncoder](t: (A, Expr)): (Expr, Expr) = (lit(t._1), t._2)
implicit def antiArrowAssocExpr2[A: SimpleEncoder, B: SimpleEncoder](t: (A, B)): (Expr, Expr) =
(lit(t._1), lit(t._2))
implicit def toLit[T: SimpleEncoder](t: T): Expr = lit(t)
implicit class ExprOps(expr: Expr) {
def first: Expr = Ops.First(expr)
def as[T: Encoder]: TypedExpr[T] = TypedExpr.TypeCasted(expr, implicitly[Encoder[T]])
def or(expr2: Expr):Expr = Ops.Or(expr,expr2)
def #>[T:SimpleEncoder](f: JValue => T):TypedExpr[T] = TypedExpr.JsonMap(expr,f,implicitly[SimpleEncoder[T]])
def when(ife: (Expr, Expr), ifes: (Expr, Expr)*): Expr = Ops.CaseWhen(ife, ifes: _*)
}
}
object Expr extends LowPriority {
sealed trait Ops extends Expr
object Ops {
case class Or(expr: Expr,expr2: Expr) extends Ops
case class First(expr: Expr) extends Ops
case class CaseWhen(ife: (Expr, Expr), ifes: (Expr, Expr)*) extends Ops
}
}
case class FieldPath(pathParts: Seq[String]) extends Dynamic with Expr {
def selectDynamic(field: String): FieldPath = FieldPath(pathParts :+ field)
}
sealed trait Encoder[T] {
type ScalaType
def scalaEnc: Encoder[ScalaType]
}
object Encoder {
sealed trait SimpleEncoder[T] extends Encoder[T] {
final type ScalaType = T
def scalaEnc: Encoder[T] = this
}
implicit case object str extends SimpleEncoder[String]
implicit case object int extends SimpleEncoder[Int]
implicit case object bool extends SimpleEncoder[Boolean]
implicit def opt[T: Encoder]: Encoder[Option[T]] = ???
case class BindedTypedExprEncoder[T](scalaEnc: Encoder[T]) extends Encoder[TypedExpr[T]] {
override type ScalaType = T
}
implicit def bindedTypedExprEncoder[T](implicit scalaEnc: Encoder[T]): BindedTypedExprEncoder[T] =
BindedTypedExprEncoder(scalaEnc)
}
sealed abstract class TypedExpr[T](enc: Encoder[T]) extends Expr {
def or(typedExpr2: TypedExpr[T])(implicit encoder: Encoder[T]):TypedExpr[T] = TypedOr(this,typedExpr2,encoder)
import TypedExpr._
def |>[B](f: T => B)(implicit enc: Encoder[B]): TypedExpr[enc.ScalaType] =
enc match {
case se: SimpleEncoder[B] => DirectMap[T, B](this, f, se).asInstanceOf[TypedExpr[enc.ScalaType]]
case bt: BindedTypedExprEncoder[enc.ScalaType] =>
BindMap[T, enc.ScalaType](this, f.asInstanceOf[T => TypedExpr[enc.ScalaType]], bt)
}
}
object TypedExpr {
case class TypedOr[T](value: TypedExpr[T], value1: TypedExpr[T],enc:Encoder[T]) extends TypedExpr[T](enc)
abstract class Tx[A, B](enc: Encoder[B]) extends TypedExpr[B](enc)
case class TypeCasted[Scala](source: Expr, enc: Encoder[Scala]) extends TypedExpr[Scala](enc)
case class JsonMap[O](source:Expr, f : JValue => O, encoder: SimpleEncoder[O]) extends TypedExpr[O](encoder)
case class BindMap[S, O](source: TypedExpr[S], f: S => TypedExpr[O], bte: BindedTypedExprEncoder[O])
extends TypedExpr[O](bte.scalaEnc)
case class DirectMap[S, O](source: TypedExpr[S], f: S => O, enc: SimpleEncoder[O]) extends TypedExpr[O](enc)
case class MappedExpr[S, O, Scala](source: TypedExpr[S], f: S => O, enc: Encoder[Scala])
extends TypedExpr[Scala](enc)
case class Lit[T](value: T, simpleEncoder: SimpleEncoder[T]) extends TypedExpr[T](simpleEncoder)
}
def lit[T: SimpleEncoder](t: T): TypedExpr[T] = TypedExpr.Lit(t, implicitly[SimpleEncoder[T]])
object in extends Dynamic {
def selectDynamic(field: String): FieldPath = FieldPath(Vector(field))
}
}
object Test {
def main(args: Array[String]): Unit = {
import Fk._
val toto = in.toto
val expr1 = toto.first.as[Int] |> (_ % 3 == 0)
val expr2 = in.tata.first.as[Boolean] |> {
case true => toto.as[Int]
case false => lit(1)
}
val expr3Typed: TypedExpr[Int] = toto.as[Int] or expr2
val expr3Untype: Expr = toto or expr2
val expr4 = in.tata.when(1 -> "1", 2 -> "3", 3 -> in.toto)
println(expr1)
println(expr2)
println(expr3Typed)
println(expr3Untype)
println(expr4)
val expr5 = in.nestedField #> {
case JArray(arr) => arr.count({
case JString(s) => s.contains("XYZ")
case _ => false
})
}
println(expr5)
/*
DirectMap(TypeCasted(First(FieldPath(Vector(toto))),int),<function1>,bool)
BindMap(TypeCasted(First(FieldPath(Vector(tata))),bool),<function1>,BindedTypedExprEncoder(int))
TypedOr(TypeCasted(FieldPath(Vector(toto)),int),BindMap(TypeCasted(First(FieldPath(Vector(tata))),bool),<function1>,BindedTypedExprEncoder(int)),int)
Or(FieldPath(Vector(toto)),BindMap(TypeCasted(First(FieldPath(Vector(tata))),bool),<function1>,BindedTypedExprEncoder(int)))
CaseWhen((Lit(1,int),Lit(1,str)),WrappedArray((Lit(2,int),Lit(3,str)), (Lit(3,int),FieldPath(Vector(toto)))))
JsonMap(FieldPath(Vector(nestedField)),<function1>,int)
*/
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment