Skip to content

Instantly share code, notes, and snippets.

@deusaquilus
Created July 19, 2020 06:22
Show Gist options
  • Save deusaquilus/e04f385b1c90cc8247ce4b3e40a7a656 to your computer and use it in GitHub Desktop.
Save deusaquilus/e04f385b1c90cc8247ce4b3e40a7a656 to your computer and use it in GitHub Desktop.
Runtime Entity Quat Using Java Reflection
/**
* Only runtime, only for Direct entity Types. Do not support things with generic parameters like Query[T] etc...
* This is needed because the quill-core/quill-sql JS use Scala JS which does not support TypeTags via the Dynamic Query API,
* (the Macro API is fine to use them).
*/
object RuntimeEntityQuat {
def apply[T](implicit ct: ClassTag[T]): Quat =
forClassTopLevel(ct.runtimeClass)
object Final {
def unapply(cls: Class[_]): Boolean =
Modifier.isFinal(cls.getModifiers)
}
// TODO Quat Test dynamic query schema with embedded Quat generation
object Embedded {
def unapply(cls: Class[_]): Option[List[Method]] =
if (cls.getInterfaces.contains(classOf[Embedded]))
cls match {
case CaseClass(methods) => Some(methods)
case _ => None
}
else
None
}
object CaseClass {
// Common methods to exclude from object fields
val exclude = classOf[Product].getMethods.map(_.getName).toSet ++ classOf[Object].getMethods.map(_.getName).toSet
def unapply(cls: Class[_]): Option[List[Method]] =
if (cls.getInterfaces.contains(classOf[Product])) {
val methods = cls.getMethods.filter(r => r.getName() != "copy" && !r.getName.startsWith("copy$default") && !exclude.contains(r.getName)).toList
Some(methods)
} else {
None
}
}
object Tuple {
def unapply(cls: Class[_]): Boolean =
cls.getName.startsWith("scala.Tuple")
}
def forClass(cls: Class[_]): Quat =
cls match {
case Final() => Quat.Value
case Embedded(methods) =>
Quat.Product(methods.map(m => (m.getName, forClass(m.getReturnType))))
// If we are here we are already inside of a product which means if we are not a embedded, we have to be value-level
case _ => Quat.Value
}
def forClassTopLevel(cls: Class[_]): Quat =
cls match {
case Final() => Quat.Value
// Embedded object can be a top-level entity
case Embedded(methods) =>
Quat.Product(methods.map(m => (m.getName, forClass(m.getReturnType))))
case Tuple() =>
throw new IllegalArgumentException("Tuple are not supported with Dynamic Query Schemas.")
case CaseClass(methods) =>
Quat.Product(methods.map(m => (m.getName, forClass(m.getReturnType))))
case _ =>
Quat.Value
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment