From 3a9d15f015eb77ada76d70592d080d521c866d79 Mon Sep 17 00:00:00 2001 From: jilen Date: Sun, 22 Jun 2025 21:20:23 +0800 Subject: [PATCH] Try add insert support --- src/main/scala/minisql/Quoted.scala | 68 +++++++++++++++++-- .../scala/minisql/mirror/QuotedSuite.scala | 4 ++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/main/scala/minisql/Quoted.scala b/src/main/scala/minisql/Quoted.scala index b1ddb0c..af3b4c6 100644 --- a/src/main/scala/minisql/Quoted.scala +++ b/src/main/scala/minisql/Quoted.scala @@ -28,6 +28,28 @@ opaque type Action[E] <: Quoted = Quoted opaque type Insert <: Action[Long] = Quoted +private inline def quotedLift[X](x: X)(using + e: ParamEncoder[X] +): ast.ScalarValueLift = ${ + quotedLiftImpl[X]('x, 'e) +} + +private def quotedLiftImpl[X: Type]( + x: Expr[X], + e: Expr[ParamEncoder[X]] +)(using Quotes): Expr[ast.ScalarValueLift] = { + import quotes.reflect.* + val name = x.asTerm.symbol.fullName + val liftId = x.asTerm.symbol.owner.fullName + "@" + name + '{ + ast.ScalarValueLift( + ${ Expr(name) }, + ${ Expr(liftId) }, + Some(($x, $e)) + ) + } +} + object Query { extension [E](inline e: Query[E]) { @@ -62,12 +84,50 @@ object EntityQuery { } inline def insert(v: E)(using m: Mirror.ProductOf[E]): Insert = { - ??? + val entity = e.asInstanceOf[ast.Entity] + val assignments = transformCaseClassToAssignments[E](v, entity.name) + ast.Insert(entity, assignments) } - } } +private inline def transformCaseClassToAssignments[E]( + v: E, + entityName: String +)(using m: Mirror.ProductOf[E]): List[ast.Assignment] = ${ + transformCaseClassToAssignmentsImpl[E]('v, 'entityName) +} + +private def transformCaseClassToAssignmentsImpl[E: Type]( + v: Expr[E], + entityName: Expr[String] +)(using Quotes): Expr[List[ast.Assignment]] = { + import quotes.reflect.* + + val fields = TypeRepr.of[E].typeSymbol.caseFields + val assignments = fields.map { field => + val fieldName = field.name + val fieldType = field.tree match { + case v: ValDef => v.tpt.tpe + case _ => report.errorAndAbort(s"Expected ValDef for field $fieldName") + } + fieldType.asType match { + case '[t] => + '{ + ast.Assignment( + ast.Ident($entityName), + ast.Property(ast.Ident($entityName), ${ Expr(fieldName) }), + quotedLift[t](${ Select.unique(v.asTerm, fieldName).asExprOf[t] })( + using summonInline[ParamEncoder[t]] + ) + ) + } + } + } + + Expr.ofList(assignments) +} + private inline def transform[A, B](inline q1: Quoted)( inline f: A => B )(inline fast: (Ast, Ident, Ast) => Ast): Quoted = { @@ -102,9 +162,7 @@ def lift[X](x: X)(using e: ParamEncoder[X]): X = throw NonQuotedException() class NonQuotedException extends Exception("Cannot be used at runtime") private[minisql] inline def compileTimeAst(inline q: Quoted): Option[String] = - ${ - compileTimeAstImpl('q) - } + ${ compileTimeAstImpl('q) } private def compileTimeAstImpl(e: Expr[Quoted])(using Quotes diff --git a/src/test/scala/minisql/mirror/QuotedSuite.scala b/src/test/scala/minisql/mirror/QuotedSuite.scala index 1d89348..e8f4b39 100644 --- a/src/test/scala/minisql/mirror/QuotedSuite.scala +++ b/src/test/scala/minisql/mirror/QuotedSuite.scala @@ -24,4 +24,8 @@ class QuotedSuite extends munit.FunSuite { o } + test("Insert") { + ??? + } + }