Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
KuceraMartin committed Jan 7, 2024
1 parent a96df75 commit 2145ddd
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 2 deletions.
2 changes: 1 addition & 1 deletion build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import de.tobiasroeser.mill.vcs.version.VcsVersion
import com.goyeau.mill.scalafix.ScalafixModule
import mill._, scalalib._, publish._

val scalaVersions = Seq("2.13.12"/*, "3.3.1"*/)
val scalaVersions = Seq("2.13.12", "3.3.1")

trait Common extends CrossScalaModule with PublishModule with ScalafixModule{
def scalaVersion = crossScalaVersion
Expand Down
127 changes: 127 additions & 0 deletions scalasql/query/src-3/TableMacro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package scalasql.query

import scala.quoted.*
import scalasql.query.Table.Metadata
import scalasql.core.DialectTypeMappers
import scalasql.core.Queryable
import scalasql.core.{Sc, TypeMapper}
import scalasql.core.{Expr => SqlExpr}
import scalasql.core.Queryable.Row
import scalasql.core.Queryable.ResultSetIterator

object TableMacros:

def metadataImpl[V[_[_]] : Type](using Quotes): Expr[Table.Metadata[V]] =
import quotes.reflect.*

val classSymbol = TypeRepr.of[V[Column]].classSymbol.get
val constructor = classSymbol.primaryConstructor
val constructorTypeParameters = constructor.paramSymss(0)
val constructorParameters = constructor.paramSymss(1)

def columnParams(tableRef: Expr[TableRef]) =
// TODO if isTypeParamType
for param <- constructorParameters yield
val nameExpr = Expr(param.name)
param.typeRef.translucentSuperType match
case AppliedType(_, List(tp)) => tp.asType match
case '[t] =>
Expr.summon[TypeMapper[t]] match
case Some(mappedType) =>
'{ Column[t]($tableRef, Table.columnNameOverride($tableRef.value)($nameExpr))($mappedType) }.asTerm
case None =>
report.errorAndAbort(s"TypeMapper[$tp] not found.", Position.ofMacroExpansion)

def constructorCall__(tableRef: Expr[TableRef]) =
val ownerType = TypeTree.of[V[Column]]
val ownerTypeArgs = ownerType.tpe.typeArgs
val baseConstructorTerm = Select(New(ownerType), constructor)
val typeAppliedConstructorTerm = TypeApply(baseConstructorTerm, ownerTypeArgs.map(t => TypeTree.ref(t.typeSymbol)))
Apply(typeAppliedConstructorTerm, columnParams(tableRef)).asExprOf[V[Column]]

def constructorCall[T[_] : Type](params: List[Term]) =
val ownerType = TypeTree.of[V[T]]
val ownerTypeArgs = ownerType.tpe.typeArgs
val baseConstructorTerm = Select(New(ownerType), constructor)
val typeAppliedConstructorTerm = TypeApply(baseConstructorTerm, ownerTypeArgs.map(t => TypeTree.ref(t.typeSymbol)))
Apply(typeAppliedConstructorTerm, params).asExprOf[V[T]]

def subParam[T[_] : Type](tp: TypeRef) =
tp.translucentSuperType match
case AppliedType(_, List(t)) =>
t.asType match
case '[t] => TypeRepr.of[T[t]]

def queryables =
Expr.ofList(
for param <- constructorParameters yield
val tpe = subParam[Sc](param.typeRef)
val tpe2 = subParam[SqlExpr](param.typeRef)
(tpe.asType, tpe2.asType) match
case ('[t1], '[t2]) => Expr.summon[Row[t2, t1]].get
)

val labels = Expr(constructorParameters.map(_.name)) // TODO isTypeParamType

def flattenExprs(queryable: Expr[Metadata.QueryableProxy], table: Expr[V[SqlExpr]]) =
val exprs =
for (param, i) <- constructorParameters.zipWithIndex yield
val iExpr = Expr(i)
val tpe = subParam[Sc](param.typeRef)
val tpe2 = subParam[SqlExpr](param.typeRef)
(tpe.asType, tpe2.asType) match
case ('[t1], '[t2]) =>
val q = Select(table.asTerm, classSymbol.fieldMember(param.name)).asExprOf[t2]
'{ $queryable.apply[t2, t1]($iExpr).walkExprs($q) }
exprs.reduceLeft: (l, r) =>
'{ $l ++ $r }

def construct(queryable: Expr[Metadata.QueryableProxy], args: Expr[ResultSetIterator]) =
val ownerType = TypeTree.of[V[Sc]]
val ownerTypeArgs = ownerType.tpe.typeArgs // TODO incorrect corret for some reason
val constructor = ownerType.tpe.classSymbol.get.primaryConstructor
val constructorTypeParameters = constructor.paramSymss(0)
val constructorParameters = constructor.paramSymss(1)

val params = for (param, i) <- constructorParameters.zipWithIndex yield
val iExpr = Expr(i)
val tpe = subParam[Sc](param.typeRef)
val tpe2 = subParam[SqlExpr](param.typeRef)
(tpe.asType, tpe2.asType) match
case ('[t1], '[t2]) =>
'{ $queryable.apply[t2, t1]($iExpr).construct($args) : Sc[t1] }.asTerm

val baseConstructorTerm = Select(New(ownerType), constructor)
val typeAppliedConstructorTerm = TypeApply(baseConstructorTerm, ownerTypeArgs.map(t => TypeTree.ref(t.typeSymbol)))
Apply(typeAppliedConstructorTerm, params).asExprOf[V[Sc]]

val queryablesExpr = '{
(dialect: DialectTypeMappers, i: Int) =>
import dialect.given
$queryables(i)
}

val walkLabelsExpr = '{ () => $labels }

val queryableExpr = '{
(walkLabels0: () => Seq[String], dialect: DialectTypeMappers, queryable: Metadata.QueryableProxy) =>
import dialect.given
Table.Internal.TableQueryable[V[SqlExpr], V[Sc]](
walkLabels0,
walkExprs0 = (table: V[SqlExpr]) => ${ flattenExprs('queryable, 'table) },
construct0 = (args: ResultSetIterator) => ${ construct('queryable, 'args) },
deconstruct0 = ??? // TODO
)
}

val vExpr0 = '{
(tableRef: TableRef, dialect: DialectTypeMappers, queryable: Metadata.QueryableProxy) =>
import dialect.given
${ constructorCall__('tableRef) }
}

'{ Metadata($queryablesExpr, $walkLabelsExpr, $queryableExpr, $vExpr0) }


trait TableMacros:
inline given metadata[V[_[_]]]: Table.Metadata[V] = ${ TableMacros.metadataImpl[V] }
2 changes: 1 addition & 1 deletion scalasql/query/src/Table.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ object Table {
}

object Internal {
class TableQueryable[Q, R <: scala.Product](
class TableQueryable[Q, R](
walkLabels0: () => Seq[String],
walkExprs0: Q => Seq[Expr[_]],
construct0: Queryable.ResultSetIterator => R,
Expand Down

0 comments on commit 2145ddd

Please sign in to comment.