Created
July 19, 2020 06:22
-
-
Save deusaquilus/e04f385b1c90cc8247ce4b3e40a7a656 to your computer and use it in GitHub Desktop.
Runtime Entity Quat Using Java Reflection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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