Skip to content

Instantly share code, notes, and snippets.

@deusaquilus
Created April 9, 2021 18:15
Show Gist options
  • Save deusaquilus/29bffed4abcb8a90fccd7db61227a992 to your computer and use it in GitHub Desktop.
Save deusaquilus/29bffed4abcb8a90fccd7db61227a992 to your computer and use it in GitHub Desktop.
Need to Manually Uninline in Cases with Subclassing
// I first found this in PeopleSpec that was being used by PeoplePostgresAsyncSpec
trait PeopleSpec extends Spec {
inline def peopleInsert =
quote((p: Person) => query[Person].insert(p))
inline def couplesInsert =
quote((c: Couple) => query[Couple].insert(c))
}
// Then this stuff was used in PeoplePostgresAsyncSpec
class PeoplePostgresAsyncSpec extends PeopleSpec {
def beforeAll() =
await {
testContext.transaction { implicit ec =>
for {
// This stuff broke
_ <- testContext.run(liftQuery(peopleEntries).foreach(e => peopleInsert(e)))
_ <- testContext.run(liftQuery(couplesEntries).foreach(e => couplesInsert(e)))
} yield {}
}
}
}
// The error I got looked like this:
// // Malformed batch entity. Batch insertion entities must have the form Insert(Entity, Nil: List[Assignment])
// object DummyEnclosure { // just so formatting won't blow up which it does here anyway but that's a separate issue
// {
// val Context_this: testContext.type = testContext
// (EagerEntitiesPlanter.apply[Person, Any](PeoplePostgresAsyncSpec.this.peopleEntries.asInstanceOf[Iterable[Person]], "aa18eeca-d268-41fc-8257-dfdcf5911052").unquote: Query[Person])
// }.foreach[Insert[Person], Insert[Person]](((e: Person) => (Unquote.apply[Function1[Person, Insert[Person]]]({
// val PeopleSpec_this: PeoplePostgresAsyncSpec.this = PeoplePostgresAsyncSpec.this
// ((Quoted.apply[Function1[Person, Insert[Person]]](Function.apply(List.apply[Ident](Ident.apply("p", io.getquill.quat.Quat.Product.WithRenamesCompact.apply(io.getquill.quat.Quat.Product.Type.Concrete)("name", "age")(io.getquill.quat.Quat.Value, io.getquill.quat.Quat.Value)()())), Insert.apply(Entity.apply("Person", Nil, io.getquill.quat.Quat.Product.WithRenamesCompact.apply(io.getquill.quat.Quat.Product.Type.Concrete)("name", "age")(io.getquill.quat.Quat.Value, io.getquill.quat.Quat.Value)()()), Nil)), Nil, Nil): Quoted[Function1[Person, Insert[Person]]]): Quoted[Function1[Person, Insert[Person]]])
// }, "b8715a3b-cdb7-43a7-b540-2b0897611e19").unquote: Function1[Person, Insert[Person]]).apply(e)))($conforms[Insert[Person]]
// }
// issue here is that there's actually an inline block that 'underlyingArgument' didn't get rid of.
//You can see that in the AST detail there are 'Inline(...)' sections. The simple thing to do use to have something to just
// choose the last argument of the inline:
object Uninline {
def unapply(any: Expr[Any]): Option[Expr[Any]] = Some(Term.apply(any.asTerm).asExpr)
def apply(any: Expr[Any]): Expr[Any] = Term.apply(any.asTerm).asExpr
object Term:
def unapply(any: Term): Option[Term] = Some(Term.apply(any))
def apply(any: Term) =
any match
case Inlined(_, _, v) => v
case _ => any
}
// then use it in ExprModel
object Unquoted {
def apply(expr: Expr[Any])(using Quotes): QuotationLotExpr =
import quotes.reflect._
unapply(expr).getOrElse { quotes.reflect.report.throwError(s"The expression: ${Format(Printer.TreeShortCode.show(expr.asTerm))} is not a valid unquotation of a Quoted Expression (i.e. a [quoted-expression].unqoute) and cannot be unquoted.") }
def unapply(expr: Expr[Any])(using Quotes): Option[QuotationLotExpr] =
import io.getquill.metaprog.Extractors._
expr match {
// In certain situations even after doing 'underlyingArgument', there are still inline blocks
// remaining in the AST.
case `(QuotationLot).unquote`(tmc.Uninline(QuotationLotExpr(vaseExpr))) =>
Some(vaseExpr)
case _ =>
//println("=============== NOT MATCHED ===============")
None
}
}
// Also use it in other places. May need to be more frequent
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment