使用 ZIO 和 Quill 编写简单的 CRUD 应用程序
域模型由用户和角色(一对多)组成
当尝试调用在 quill 上下文中提升的实体之一(或在构建查询的过程中获得)的方法时,我面临编译时异常:
Can't find case class property: typedCode
roleSchema.filter(r => r.typedCode == lift(roleCode)).take(1)
val dc: db.Ctx.type = db.Ctx
import dc._
def findRoleByCode(roleCode: RoleCode): Result[Option[Role]] =
dc.run(
roleSchema.filter(r => r.typedCode == lift(roleCode)).take(1)
).map(_.headOption)
架构如下:
用户实体
case class User(
id: String,
firstName: String,
lastName: String,
age: Int
){
def typedId: UserId = UserId(id)
}
角色实体
case class Role(
code: String,
name: String
){
def typedCode: RoleCode = RoleCode(code)
}
标识符的用户到角色关联和值类
case class UserToRole(roleId: RoleCode, userId: UserId)
case class RoleCode(code: String) extends AnyVal
case class UserId(id: String) extends AnyVal
我目前得出的结论是,不可能对 Quill 上下文中存在的实体调用方法。我想这是由于宏观评估和某种类型替换
问题是——获得房产不是问题。我可以获得
role.code
作为 String
,但无法调用 .typedCode
。同样适用于用户
编辑
尝试将
.typedCode
和 .typedId
转换为接受 Unit
作为参数 typedCode(): RoleCode
typedId(): UserId
的方法会导致另一个异常:
Tree 'r.typedCode()' can't be parsed to 'Ast'
roleSchema.filter(r => r.typedCode() == lift(roleCode)).take(1)
编辑2 在查询中构建值类的实例:
RoleCode(r.code)
结果:
exception during macro expansion:
scala.reflect.macros.TypecheckException: package module4.homework.dao.entity is not a value
at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$3(Typers.scala:44)
at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$2(Typers.scala:38)
at scala.reflect.macros.contexts.Typers.doTypecheck$1(Typers.scala:37)
at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$7(Typers.scala:50)
at scala.reflect.internal.Trees.wrappingIntoTerm(Trees.scala:1891)
at scala.reflect.internal.Trees.wrappingIntoTerm$(Trees.scala:1888)
at scala.reflect.internal.SymbolTable.wrappingIntoTerm(SymbolTable.scala:28)
at scala.reflect.macros.contexts.Typers.typecheck(Typers.scala:50)
at scala.reflect.macros.contexts.Typers.typecheck$(Typers.scala:32)
at scala.reflect.macros.contexts.Context.typecheck(Context.scala:18)
at scala.reflect.macros.contexts.Context.typecheck(Context.scala:18)
at io.getquill.quotation.Parsing$$anonfun$propertyParser$1.applyOrElse(Parsing.scala:540)
at io.getquill.quotation.Parsing$$anonfun$propertyParser$1.applyOrElse(Parsing.scala:526)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:64)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:48)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$Parser.apply(Parsing.scala:35)
at io.getquill.quotation.Parsing$$anonfun$propertyParser$1.applyOrElse(Parsing.scala:546)
at io.getquill.quotation.Parsing$$anonfun$propertyParser$1.applyOrElse(Parsing.scala:526)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:64)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:48)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$functionApplyParser$1.applyOrElse(Parsing.scala:579)
at io.getquill.quotation.Parsing$$anonfun$functionApplyParser$1.applyOrElse(Parsing.scala:578)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$operationParser$1.applyOrElse(Parsing.scala:558)
at io.getquill.quotation.Parsing$$anonfun$operationParser$1.applyOrElse(Parsing.scala:552)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:61)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:48)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$Parser.apply(Parsing.scala:35)
at io.getquill.quotation.Parsing.io$getquill$quotation$Parsing$$equalityWithInnerTypechecksIdiomatic(Parsing.scala:603)
at io.getquill.quotation.Parsing$$anonfun$equalityOperationParser$1.applyOrElse(Parsing.scala:624)
at io.getquill.quotation.Parsing$$anonfun$equalityOperationParser$1.applyOrElse(Parsing.scala:622)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$operationParser$1.applyOrElse(Parsing.scala:553)
at io.getquill.quotation.Parsing$$anonfun$operationParser$1.applyOrElse(Parsing.scala:552)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:61)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:48)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$Parser.apply(Parsing.scala:35)
at io.getquill.quotation.Parsing$$anonfun$queryParser$1.applyOrElse(Parsing.scala:202)
at io.getquill.quotation.Parsing$$anonfun$queryParser$1.applyOrElse(Parsing.scala:187)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:50)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:48)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$Parser.apply(Parsing.scala:35)
at io.getquill.quotation.Parsing$$anonfun$queryParser$1.applyOrElse(Parsing.scala:230)
at io.getquill.quotation.Parsing$$anonfun$queryParser$1.applyOrElse(Parsing.scala:187)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:50)
at io.getquill.quotation.Parsing$$anonfun$astParser$1.applyOrElse(Parsing.scala:48)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:338)
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:334)
at io.getquill.quotation.Parsing$Parser.unapply(Parsing.scala:44)
at io.getquill.quotation.Parsing$Parser.apply(Parsing.scala:35)
at io.getquill.quotation.Quotation.$anonfun$quote$1(Quotation.scala:28)
at io.getquill.util.Interpolator$Traceable.andReturn(Interpolator.scala:145)
at io.getquill.quotation.Quotation.quote(Quotation.scala:28)
at io.getquill.quotation.Quotation.quote$(Quotation.scala:24)
at io.getquill.dsl.QuotationMacro.quote(QuotationDsl.scala:34)
at jdk.internal.reflect.GeneratedMethodAccessor61.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at scala.reflect.macros.runtime.JavaReflectionRuntimes$JavaReflectionResolvers.$anonfun$resolveJavaReflectionRuntime$5(JavaReflectionRuntimes.scala:45)
at scala.tools.nsc.typechecker.Macros.macroExpandWithRuntime(Macros.scala:770)
roleSchema.filter(r => RoleCode(r.code) == lift(roleCode)).take(1)
编辑3 我想设计上就规定我们不能从查询上下文中调用方法。
解决大多数问题的唯一解决方案是更改域模型本身并使用值类作为
User
和 Role
的案例类参数
正如评论中已经回答的那样,Quill 会将字段和案例类翻译为所选的 SQL 方言。没有办法将
RoleCode(code)
转换为 SQL。您应该能够将 typedRole
和 typedCode
设为案例类的字段,并通过重写此特定案例类的 apply
方法来处理该字段。