diff --git a/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/SchemaBasedParser.scala b/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/SchemaBasedParser.scala index dd0fc71..6a7a3d8 100644 --- a/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/SchemaBasedParser.scala +++ b/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/SchemaBasedParser.scala @@ -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 @@ -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] { @@ -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) @@ -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) @@ -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: diff --git a/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/SchemaBasedParserMacros.scala b/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/SchemaBasedParserMacros.scala index 4e7abe1..5928c5e 100644 --- a/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/SchemaBasedParserMacros.scala +++ b/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/SchemaBasedParserMacros.scala @@ -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, @@ -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 */ @@ -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 diff --git a/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/TupleConverter.scala b/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/TupleConverter.scala index 2066791..10cb014 100644 --- a/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/TupleConverter.scala +++ b/ontology-quill-parser/src/main/scala/ru/primetalk/typed/ontology/dbquill/parser/TupleConverter.scala @@ -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) @@ -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) diff --git a/ontology-quill/src/main/scala/ru/primetalk/typed/ontology/dbquill/OntPerson.scala b/ontology-quill/src/main/scala/ru/primetalk/typed/ontology/dbquill/OntPerson.scala index f8dcf49..82fc2ab 100644 --- a/ontology-quill/src/main/scala/ru/primetalk/typed/ontology/dbquill/OntPerson.scala +++ b/ontology-quill/src/main/scala/ru/primetalk/typed/ontology/dbquill/OntPerson.scala @@ -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 @@ -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] = diff --git a/typed-ontology-metameta/src/main/scala/ru/primetalk/typed/ontology/utils/objectName.scala b/typed-ontology-metameta/src/main/scala/ru/primetalk/typed/ontology/utils/objectName.scala index 5946cfe..e907fa6 100644 --- a/typed-ontology-metameta/src/main/scala/ru/primetalk/typed/ontology/utils/objectName.scala +++ b/typed-ontology-metameta/src/main/scala/ru/primetalk/typed/ontology/utils/objectName.scala @@ -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") diff --git a/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SchemaBuilders.scala b/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SchemaBuilders.scala index 7656f27..be43cdd 100644 --- a/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SchemaBuilders.scala +++ b/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SchemaBuilders.scala @@ -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 @@ -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)} diff --git a/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SchemaValueType.scala b/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SchemaValueType.scala index 9ebbcf4..8335fd6 100644 --- a/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SchemaValueType.scala +++ b/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SchemaValueType.scala @@ -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. */ diff --git a/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SimpleTypes.scala b/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SimpleTypes.scala index ab6aec3..4fcda54 100644 --- a/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SimpleTypes.scala +++ b/typed-ontology-simple-meta/src/main/scala/ru/primetalk/typed/ontology/simple/meta/SimpleTypes.scala @@ -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. */ @@ -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: @@ -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: diff --git a/typed-ontology-simple-meta/src/test/scala/ru/primetalk/typed/ontology/simple/meta/Product.scala b/typed-ontology-simple-meta/src/test/scala/ru/primetalk/typed/ontology/simple/meta/Product.scala index 1fbd4b6..3cf1856 100644 --- a/typed-ontology-simple-meta/src/test/scala/ru/primetalk/typed/ontology/simple/meta/Product.scala +++ b/typed-ontology-simple-meta/src/test/scala/ru/primetalk/typed/ontology/simple/meta/Product.scala @@ -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 diff --git a/typed-ontology-simple-meta/src/test/scala/ru/primetalk/typed/ontology/simple/meta/ProductSpec.scala b/typed-ontology-simple-meta/src/test/scala/ru/primetalk/typed/ontology/simple/meta/ProductSpec.scala index 6d272a2..668b84f 100644 --- a/typed-ontology-simple-meta/src/test/scala/ru/primetalk/typed/ontology/simple/meta/ProductSpec.scala +++ b/typed-ontology-simple-meta/src/test/scala/ru/primetalk/typed/ontology/simple/meta/ProductSpec.scala @@ -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))