Skip to content

Commit

Permalink
Merge pull request #3 from Primetalk/feature/quill2
Browse files Browse the repository at this point in the history
Feature/quill2
  • Loading branch information
Primetalk authored Mar 11, 2024
2 parents ce8934d + c616f23 commit 3bbd078
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import io.getquill.norm.TranspileConfig
import ru.primetalk.typed.ontology.simple.meta.{
annotated,
RecordSchema,
RecordSchemaValueType,
SchemaLike,
SchemaValueType,
TableBuilder,
#@
}
import ru.primetalk.typed.ontology.utils.nameOf
import ru.primetalk.typed.ontology.simple.relalg.Relation
import io.getquill.generic.GenericDecoder
import io.getquill.generic.DecodingType
Expand All @@ -29,6 +31,7 @@ import io.getquill.querySchema
// def apply[S <: SchemaLike, T](tableName: String, svt: SchemaValueType[S, T]) =
// new OntEntityQuery[S, T, svt.AValue](tableName, svt)
// }
import ru.primetalk.typed.ontology.simple.meta.SimpleTypes.{given, *}

class OntEntityQuery[S <: SchemaLike, T, AV](val tableName: String, val svt: SchemaValueType[S, T])
extends EntityQuery[T] {
Expand All @@ -40,23 +43,13 @@ class OntEntityQuery[S <: SchemaLike, T, AV](val tableName: String, val svt: Sch
object MyTestEntity
object MyTestEntity2

// extension [T <: TableBuilder](t: T)
// inline def query(using
// svt: SchemaValueType.Aux1[t.TableSchema],
extension [T <: TableBuilder](t: T)
inline def quillQuery[V <: Tuple] = //(using rsvt: RecordSchemaValueType[t.TableSchema, V])
ontquery[t.TableSchema, V](nameOf(t))//t.tableNameI)

// )= //: OntEntityQuery[t.TableSchema, svt.Value, svt.AValue] =
// ontquery[t.TableSchema, svt.Value, svt.AValue](t.tableName)

transparent inline def ontquery[S <: SchemaLike, T <: Tuple, AV <: T#@S](tableName: String)(using
svt: SchemaValueType[S, T]
) = ${
SchemaBasedParserMacros.ontqueryImpl[S, T, AV]('tableName, 'svt)
transparent inline def ontquery[S <: RecordSchema, T <: Tuple](inline tableName: String) = ${
SchemaBasedParserMacros.ontqueryImpl2[S, T]('tableName)
}
// querySchema[T](tableName)
// .map{t =>
// tupleConverter(t)
// }
// new OntEntityQuery[S, T, AV](tableName, svt) // NonQuotedException()

class SchemaBasedParser(val rootParse: Parser)(using Quotes, TranspileConfig)
extends Parser(rootParse)
Expand Down Expand Up @@ -92,7 +85,11 @@ class SchemaBasedParser(val rootParse: Parser)(using Quotes, TranspileConfig)
// val svtV = svtFromExpr[s, t].unapply(svt).getOrElse(error(svt))
// val tpe = TypeRepr.of[svtV.AValue]
// val quat = InferQuat.ofType(tpe).probit
val quat = Quat.Product.apply("unknown", Quat.Product.Type.Abstract, Iterable.empty[(String, Quat)])// InferQuat.ofType(tpe).probit
val quat = Quat.Product.apply(
"unknown",
Quat.Product.Type.Abstract,
Iterable.empty[(String, Quat)]
) // InferQuat.ofType(tpe).probit
val name1: String = FromExpr.StringFromExpr[String].unapply(name).getOrElse(error(name))
// warnVerifyNoBranches(VerifyNoBranches.in(quat), expr)
val res = Entity.Opinionated(name1, List(), quat, Renameable.Fixed)
Expand Down Expand Up @@ -127,7 +124,7 @@ object SchemaBasedParser extends ParserLibrary:
ParserChain.attempt(SchemaBasedParser(_)) orElse
ParserChain.attempt(QueryParser(_))
// (using svt: SchemaValueType[S, V])

inline given svtGenericDecoder[S <: SchemaLike: Type, V <: Tuple: Type, ResultRow: Type, Session]
: GenericDecoder[ResultRow, Session, TupleConverter[V] #@ S, DecodingType.Specific] =
new:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,24 @@ import io.getquill.querySchema
import scala.quoted.*
import ru.primetalk.typed.ontology.simple.meta.{#@, #:, EmptySchema, SchemaLike, SchemaValueType}
import io.getquill.EntityQuery
import ru.primetalk.typed.ontology.simple.meta.RecordSchema

object SchemaBasedParserMacros:
def ontqueryImpl[S <: SchemaLike: Type, T <: Tuple: Type, AV <: T #@ S: Type](
tableName: Expr[String],
svt: Expr[SchemaValueType[S, T]]
)(using Quotes) =
def ontqueryImpl2[S <: RecordSchema: Type, T <: Tuple: Type](
tableName: Expr[String]
)(using Quotes): Expr[EntityQuery[T]] =
import quotes.reflect.*
val tpe = Type.of[S]
tpe match
case '[p #: s] =>
val seqArgs = Expr.ofSeq(propertyAliases[S, T]())
Apply(
TypeApply(Ref(Symbol.requiredMethod("io.getquill.querySchema")), List(TypeTree.of[T])),
List(
tableName.asTerm,
Typed(
Inlined(
None,
Nil,
Repeated(
// List(Literal(IntConstant(10)), Literal(StringConstant("str")), Literal(DoubleConstant(5.2))),
propertyAliases[S, T]().map(_.asTerm),
TypeTree.of[T => (Any, String)]
)
),
Applied(TypeIdent(defn.RepeatedParamClass), List(TypeTree.of[T => (Any, String)]))
)
)
).asExprOf[EntityQuery[T]]
// '{
// querySchema[T]($tableName, ${seqArgs}*)
// }

val seqArgs = Expr.ofSeq(propertyAliases[S, T]())
val args: List[Term] = propertyAliases[S, T]().map(_.asTerm)
val tree = Apply(
TypeApply(Ref(Symbol.requiredMethod("io.getquill.querySchema")), List(TypeTree.of[T])),
List(
tableName.asTerm,
varArgTerm[T => (Any, String)](args)
)
)
tree.asExprOf[EntityQuery[T]]

def propertyAliases[S <: SchemaLike: Type, T <: Tuple: Type](
i: Int = 0,
Expand All @@ -47,7 +33,10 @@ object SchemaBasedParserMacros:
case '[EmptySchema] =>
accum.reverse
case '[p #: s] =>
propertyAliases[s, T](i + 1, propertyAlias(i, s"column$i") :: accum)
val name = TypeTree.of[p] match
case ColumnName(name) => name
case _ => TypeTree.of[p].show
propertyAliases[s, T](i + 1, propertyAlias(i, name) :: accum)

/** Формируем переименования в соответствии с PropertyAliasExpr
*/
Expand All @@ -63,9 +52,34 @@ object SchemaBasedParserMacros:
mtpe,
{ case (methSym, List(arg1: Term)) =>
val _1 = Select(arg1, Symbol.requiredMethod(s"_${i + 1}")).asExprOf[Any]
val _2 = Literal(StringConstant(s"column${i + 1}")).asExprOf[String]
val tu = makeTuple2OfAnyString(_1, _2)
val _2 = Literal(StringConstant(name)).asExprOf[String]
'{ $_1 -> $_2 }.asTerm
}
)
lambda.asExprOf[T => (Any, String)]

/** Извлекаем имя колонки из типа свойства. */
object ColumnName:

def unapply(using Quotes)(t: quotes.reflect.TypeTree): Option[String] =
import quotes.reflect.*
t.tpe match
case TermRef(typeRepr, name) => Some(name)
case _ => Some("\"invalid_column_name_" +t.show +"\"")
end ColumnName

/** Make an instance of RepeatedParamClass that is used to represent var args. */
def varArgTerm[T: Type](using Quotes)(args: List[quotes.reflect.Term]): quotes.reflect.Typed =
import quotes.reflect.*
Typed(
Inlined(
None,
Nil,
Repeated(
args,
TypeTree.of[T]
)
),
Applied(TypeIdent(defn.RepeatedParamClass), List(TypeTree.of[T]))
)
end SchemaBasedParserMacros
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package ru.primetalk.typed.ontology.dbquill.parser
*/
type TupleConverter[T <: Tuple] =
T match
case EmptyTuple => EmptyTuple
case a *: EmptyTuple => Tuple1[a]
case a *: b *: EmptyTuple => (a, b)
case a *: b *: c *: EmptyTuple => (a, b, c)
Expand All @@ -16,6 +17,7 @@ type TupleConverter[T <: Tuple] =

inline def tupleConverter[T<:Tuple](t: T): TupleConverter[T] =
inline t match
case _: (EmptyTuple) => EmptyTuple
case _: (a *: EmptyTuple) => val tt = t.asInstanceOf[a*: EmptyTuple];Tuple1(tt._1)
case _: (a *: b *: EmptyTuple) => val tt = t.asInstanceOf[a *: b *: EmptyTuple];(tt._1, tt._2)
case _: (a *: b *: c *: EmptyTuple) => val tt = t.asInstanceOf[a *: b *: c *: EmptyTuple];(tt._1, tt._2, tt._3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ru.primetalk.typed.ontology.simple.meta.SchemaProvider
import ru.primetalk.typed.ontology.dbquill.parser.SchemaBasedParser
import ru.primetalk.typed.ontology.dbquill.parser.MyTestEntity
import ru.primetalk.typed.ontology.dbquill.parser.ontquery
import ru.primetalk.typed.ontology.dbquill.parser.quillQuery
import ru.primetalk.typed.ontology.simple.meta.SimpleTypes.{given, *}
import ru.primetalk.typed.ontology.simple.meta.{#@, annotated, SchemaValueType}
import java.time.LocalDateTime
Expand Down Expand Up @@ -64,7 +65,8 @@ object OntPerson {
inline def orderQuery = quote {
// Order.query(using Order.svt)
// либо для произвольной схемы:
ontquery[Order.TableSchema, Order.Row, Order.svt.AValue]("order")//(using Order.svt)
Order.quillQuery[Order.Row]// тип передаём временно, из-за проблемы, что quill не поддерживает сконструированные Tuple'ы *:
// ontquery[Order.TableSchema, TupleConverter[Order.svt.Value], Order.svt.AValue]("order")//(using Order.svt)
}
// inline given svtGenericDecoder[ResultRow: Type, Session]
// : GenericDecoder[ResultRow, Session, Order.Row, DecodingType.Specific] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
package ru.primetalk.typed.ontology.utils

import scala.quoted.{Expr, Type, Quotes, quotes}

/** Определяет имя переданного объекта. */
inline def nameOf(o: Any): String = ${ObjectNameImpl.nameOfImpl('o)}

/**
* Вычисляет имя объекта на основе имени класса.
*/
def objectName(o: Any): String =
val simpleName = o.getClass.getSimpleName
val l = simpleName.length
if simpleName(l - 1) == '$' then simpleName.substring(0, l - 1)
else simpleName

object ObjectNameImpl:
def nameOfImpl(o: Expr[Any])(using Quotes): Expr[String] =
import quotes.reflect.*
o.asTerm match
case Inlined(_, _, Ident(name)) =>
Expr(name)
case t =>
report.errorAndAbort(s"Couldn't determine name of $t")
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import scala.quoted.Type
import scala.quoted.Quotes
import scala.quoted.Varargs
import ru.primetalk.typed.ontology.utils.objectName
import ru.primetalk.typed.ontology.utils.ObjectNameImpl

trait RecordSchemaBuilderBase:
type RecordType
Expand Down Expand Up @@ -116,4 +117,6 @@ abstract class TableBuilder extends PropertiesBuilder with ForeignKeyBuilder wit
transparent inline def infer[S <: RecordSchema]: S = RecordSchema.constSchema[S]
val tableSchema: TableSchema

val tableName = objectName(this)
val tableName = objectName

inline def tableNameI: String = ${ObjectNameImpl.nameOfImpl('this)}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,13 @@ trait TupleSchemaValueType[S <: TupleSchema]:
* Scala 3.4.0 wasn't able to disambiguate plain SchemaValueType of two types that have Value <:
* Tuple.
*/
trait RecordSchemaValueType[S <: RecordSchema]:
class RecordSchemaValueType[S <: RecordSchema, V <: Tuple]:
type Schema = S
type Value <: Tuple
type Value = V
type AValue = V #@ S

object RecordSchemaValueType:
type Aux1[S <: RecordSchema] = RecordSchemaValueType[S, ?]

/** Type class that returns the type of property value.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ trait ConversionSimpleTypes:
): SchemaValueType[S, tsvt.Value] =
new SchemaValueType[S, tsvt.Value]

transparent inline given recordSchemaValueType[S <: RecordSchema](using
rsvt: RecordSchemaValueType[S]
): SchemaValueType[S, rsvt.Value] =
new SchemaValueType[S, rsvt.Value]
transparent inline given recordSchemaValueType[S <: RecordSchema, V<: Tuple](using
rsvt: RecordSchemaValueType[S, V]
): SchemaValueType[S, V] =
new SchemaValueType[S, V]

/** Provide storage types (tuples) for tuple schemas.
*/
Expand Down Expand Up @@ -73,29 +73,24 @@ trait RecordSchemaSimpleTypes:
transparent inline given emptySchemaSVT: SchemaValueType[EmptySchema.type, EmptyTuple] =
new SchemaValueType[EmptySchema.type, EmptyTuple]

transparent inline given emptySchemaRSVT: RecordSchemaValueType[EmptySchema.type] =
new:
type Schema = EmptySchema.type
type Value = EmptyTuple
transparent inline given emptySchemaRSVT: RecordSchemaValueType[EmptySchema.type, EmptyTuple.type] =
new RecordSchemaValueType

transparent inline given tuple1Schema[VP, P <: SimplePropertyId[?, VP]](using
svtp: RecordPropertyValueType[P, VP]
): RecordSchemaValueType[SchemaCons[P, EmptySchema]] =
new RecordSchemaValueType[SchemaCons[P, EmptySchema]]:
type Value = Tuple1[VP]
): RecordSchemaValueType[SchemaCons[P, EmptySchema], Tuple1[VP]] =
new RecordSchemaValueType

transparent inline given nonEmptySchema[
VP,
P <: SimplePropertyId[?, VP],
VP,
S <: NonEmptySchema,
// RS <: P #: S
VS <: Tuple
](using
svtp: RecordPropertyValueType[P, VP],
svts: RecordSchemaValueType[S]
): RecordSchemaValueType[P #: svts.Schema] =
new:
type Schema = P #: svts.Schema
type Value = VP *: svts.Value
svts: RecordSchemaValueType[S, VS]
): RecordSchemaValueType[P #: svts.Schema, VP *: VS] =
new RecordSchemaValueType

// Projectors
trait ProjectorSimpleTypes extends RecordSchemaSimpleTypes:
Expand Down Expand Up @@ -187,16 +182,16 @@ trait ProjectorSimpleTypes extends RecordSchemaSimpleTypes:
prj(v)

trait TableBuilderSimpleTypes:
final case class TableBuilderExtensionR[S <: RecordSchema](
final case class TableBuilderExtensionR[S <: RecordSchema, V <: Tuple](
schema: S,
svt: RecordSchemaValueType[S]
svt: RecordSchemaValueType[S, V]
):
type Row = svt.Value
type Row = V

implicit def tableBuilderExtension[T <: TableBuilder](t: T)(using
svt1: RecordSchemaValueType[t.TableSchema]
): TableBuilderExtensionR[t.TableSchema] =
TableBuilderExtensionR[t.TableSchema](t.tableSchema, svt1)
implicit def tableBuilderExtension[T <: TableBuilder, V <: Tuple](t: T)(using
svt1: RecordSchemaValueType[t.TableSchema, V]
): TableBuilderExtensionR[t.TableSchema, V] =
TableBuilderExtensionR[t.TableSchema, V](t.tableSchema, svt1)

trait ConcatenatorSimpleTypes extends RecordSchemaSimpleTypes:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ object Product extends TableBuilder:

val fullSchema = infer[TableSchema]
val priceP = summon[RecordPropertyValueType.Aux1[Price]]
val svt = summon[RecordSchemaValueType[TableSchema]]
val svt = summon[RecordSchemaValueType.Aux1[TableSchema]]
type Row = svt.Value
end Product
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,22 @@ class ProductSpec extends BaseSpec:
summon[SchemaValueType.Aux1[id.Schema]] // (using scalarSchema1svt[Int, id.Schema])

val idRecordSvt1 = tuple1Schema[Int, id.type]
val idRecordSvt = summon[RecordSchemaValueType[IdRecord]] // (using tuple1Schema)
val idRecordSvt0: RecordSchemaValueType[IdRecord] = idRecordSvt
val idRecordSvt = summon[RecordSchemaValueType.Aux1[IdRecord]] // (using tuple1Schema)
val idRecordSvt0: RecordSchemaValueType.Aux1[IdRecord] = idRecordSvt
val i: idRecordSvt.Value = Tuple1(10)

val ev2 = summon[idRecordSvt.Value =:= Tuple1[Int]]

val nameSvt = summon[RecordSchemaValueType[name.type #: EmptySchema]] // (using tuple1Schema)
val svt2 = summon[RecordSchemaValueType[id.type #: name.type #: EmptySchema]]
val nameSvt = summon[RecordSchemaValueType.Aux1[name.type #: EmptySchema]] // (using tuple1Schema)
val svt2 = summon[RecordSchemaValueType.Aux1[id.type #: name.type #: EmptySchema]]

val svt = summon[RecordSchemaValueType[id.type #: name.type #: price.type #: EmptySchema]]
val svt = summon[RecordSchemaValueType.Aux1[id.type #: name.type #: price.type #: EmptySchema]]
val product1: svt.Value = (1, "product1", BigInt(10))

val svt1 = Product.svt
val product2: svt1.Value = (2, "product1", BigInt(10))

val svt3 = summon[RecordSchemaValueType[Product.TableSchema]]
val svt3 = summon[RecordSchemaValueType.Aux1[Product.TableSchema]]
val product3: svt3.Value = (1, "product1", BigInt(10))

val product4: Product.Row = (3, "product1", BigInt(10))
Expand Down

0 comments on commit 3bbd078

Please sign in to comment.