use opaque type to encoding dsl
This commit is contained in:
parent
87e0213b06
commit
b0ec98b6a2
2 changed files with 27 additions and 44 deletions
|
@ -300,7 +300,8 @@ private def fromBlock(using
|
|||
given astFromExpr: FromExpr[Ast] = new FromExpr[Ast] {
|
||||
|
||||
def unapply(e: Expr[Ast])(using Quotes): Option[Ast] = {
|
||||
e match {
|
||||
val t = extractTerm(e.toTerm)
|
||||
t.asExpr match {
|
||||
case '{ $x: Query } => x.value
|
||||
case '{ $x: ScalarValueLift } => x.value
|
||||
case '{ $x: Property } => x.value
|
||||
|
@ -312,7 +313,10 @@ given astFromExpr: FromExpr[Ast] = new FromExpr[Ast] {
|
|||
case '{ $x: Action } => x.value
|
||||
case '{ $x: If } => x.value
|
||||
case '{ $x: Infix } => x.value
|
||||
case o => None
|
||||
case o =>
|
||||
import quotes.reflect.*
|
||||
report.warning(s"Cannot get value from ${o.show}", o.asTerm.pos)
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,69 +1,44 @@
|
|||
package minisql.dsl
|
||||
|
||||
import minisql.*
|
||||
import minisql.parsing
|
||||
import minisql.parsing.*
|
||||
import minisql.ast.{Ast, Entity, Map, Property, Ident, given}
|
||||
import scala.quoted.*
|
||||
import scala.compiletime.*
|
||||
import scala.compiletime.ops.string.*
|
||||
import scala.collection.immutable.{Map => IMap}
|
||||
|
||||
sealed trait Quoted {
|
||||
def ast: Ast
|
||||
def lifts: IMap[String, (Any, ParamEncoder[?])] = IMap.empty
|
||||
}
|
||||
opaque type Quoted <: Ast = Ast
|
||||
|
||||
trait Query[E] extends Quoted
|
||||
opaque type Query[E] <: Quoted = Quoted
|
||||
|
||||
case class EntityQuery[E](ast: Ast) extends Query[E]
|
||||
opaque type EntityQuery[E] <: Query[E] = Query[E]
|
||||
|
||||
extension [E](inline e: EntityQuery[E]) {
|
||||
inline def map[E1](inline f: E => E1): EntityQuery[E1] = {
|
||||
transform(e.ast)(f)(Map.apply)(EntityQuery.apply[E1])
|
||||
transform(e)(f)(Map.apply)
|
||||
}
|
||||
}
|
||||
|
||||
private inline def transform[D1 <: Quoted, D2 <: Quoted, A, B](inline ast: Ast)(
|
||||
private inline def transform[A, B](inline q1: Quoted)(
|
||||
inline f: A => B
|
||||
)(inline fast: (Ast, Ident, Ast) => Ast)(inline f2: Ast => D2): D2 = {
|
||||
f2(fast(ast, f.param0, f.body))
|
||||
)(inline fast: (Ast, Ident, Ast) => Ast): Quoted = {
|
||||
fast(q1, f.param0, f.body)
|
||||
}
|
||||
|
||||
private given FromExpr[EntityQuery[?]] with {
|
||||
def unapply(x: Expr[EntityQuery[?]])(using Quotes): Option[EntityQuery[?]] = {
|
||||
x match {
|
||||
case '{
|
||||
val x: Ast = ${ Expr(ast) }
|
||||
EntityQuery(x)
|
||||
} =>
|
||||
Some(EntityQuery(ast))
|
||||
case '{ EntityQuery(${ Expr(ast) }) } =>
|
||||
Some(EntityQuery(ast))
|
||||
case _ =>
|
||||
import quotes.reflect.*
|
||||
println(s"cannot unlift ${x.show}: ${x.asTerm.getClass}")
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
private given FromExpr[Quoted] with {
|
||||
def unapply(x: Expr[Quoted])(using Quotes): Option[Quoted] = {
|
||||
import quotes.reflect.*
|
||||
x match {
|
||||
case '{ ($x: EntityQuery[?]) } => x.value
|
||||
}
|
||||
}
|
||||
inline def query[E](inline table: String): EntityQuery[E] =
|
||||
Entity(table, Nil)
|
||||
|
||||
inline def compile(inline x: Ast): Option[String] = ${
|
||||
compileImpl('{ x })
|
||||
}
|
||||
|
||||
inline def query[E](inline table: String) =
|
||||
EntityQuery[E](Entity(table, Nil))
|
||||
|
||||
inline def compile(inline x: Quoted): Option[String] = ${ compileImpl('x) }
|
||||
|
||||
private def compileImpl(x: Expr[Quoted])(using Quotes): Expr[Option[String]] = {
|
||||
private def compileImpl(
|
||||
x: Expr[Ast]
|
||||
)(using Quotes): Expr[Option[String]] = {
|
||||
import quotes.reflect.*
|
||||
x.value match {
|
||||
case Some(xv) => '{ Some(${ Expr(xv.ast.toString()) }) }
|
||||
case Some(xv) => '{ Some(${ Expr(xv.toString()) }) }
|
||||
case None => '{ None }
|
||||
}
|
||||
}
|
||||
|
@ -78,3 +53,7 @@ extension [A1, A2, B](inline f1: (A1, A2) => B) {
|
|||
private inline def param1 = parsing.parseParamAt(f1, 1)
|
||||
private inline def body = parsing.parseBody(f1)
|
||||
}
|
||||
|
||||
case class Foo(id: Int)
|
||||
|
||||
inline def queryFooId = query[Foo]("foo").map(_.id)
|
||||
|
|
Loading…
Reference in a new issue