Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace scala-reflect with izumi-reflect #668

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ lazy val commonSettings = Seq(
def mainDependencies(scalaVersion: String) = {
Seq (
"org.scala-lang.modules" %% "scala-parser-combinators" % "2.3.0",
"org.scala-lang" % "scala-reflect" % scalaVersion,
"dev.zio" %% "izumi-reflect" % "2.3.8",
"com.typesafe.slick" %% "slick" % "3.5.0-M4",
"org.postgresql" % "postgresql" % "42.6.0",
"org.scala-lang.modules" %% "scala-collection-compat" % "2.11.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,23 @@ package com.github.tminglei.slickpg.utils

import slick.util.Logging

import izumi.reflect.{Tag => TTag}
import scala.reflect.ClassTag
import slick.jdbc.{GetResult, PositionedResult, SetParameter, PositionedParameters}

import scala.reflect.runtime.{universe => u}

object PlainSQLUtils extends Logging {
import SimpleArrayUtils._
private[slickpg] var nextArrayConverters = Map.empty[String, PositionedResult => Option[Seq[_]]]

/** used to support 'nextArray[T]/nextArrayOption[T]' in PgArraySupport */
def addNextArrayConverter[T](conv: PositionedResult => Option[Seq[T]])(implicit ttag: u.TypeTag[T]) = {
logger.info(s"\u001B[36m >>> adding next array converter for ${u.typeOf[T]} \u001B[0m")
nextArrayConverters.synchronized {
val convKey = u.typeOf[T].toString
def addNextArrayConverter[T](conv: PositionedResult => Option[Seq[T]])(implicit ttag: TTag[T]) = {
logger.info(s"\u001B[36m >>> adding next array converter for ${ttag.tag.shortName} \u001B[0m")
val convKey = ttag.tag.shortName
val existed = nextArrayConverters.get(convKey)
if (existed.isDefined) logger.warn(
s"\u001B[31m >>> DUPLICATED next array converter for ${u.typeOf[T]}!!! \u001B[36m If it's expected, pls ignore it.\u001B[0m"
s"\u001B[31m >>> DUPLICATED next array converter for ${ttag.tag.shortName}!!! \u001B[36m If it's expected, pls ignore it.\u001B[0m"
)
nextArrayConverters += (convKey -> conv)
}
}

///
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.github.tminglei.slickpg
package utils

import izumi.reflect.{Tag => TTag}
import izumi.reflect.macrortti.LightTypeTag
import slick.util.Logging
import scala.reflect.runtime.{universe => u}
import java.sql.{Date, Time, Timestamp}
import java.time.{LocalDate, LocalDateTime, LocalTime}
import java.util.UUID

object TypeConverters extends Logging {
case class ConvConfig(from: u.Type, to: u.Type, var conv: (_ => _))
case class ConvConfig(from: LightTypeTag, to: LightTypeTag, var conv: (_ => _))

private var convConfigList = List[ConvConfig]()

Expand All @@ -35,19 +36,17 @@ object TypeConverters extends Logging {
register((v: LocalTime) => v.toString)
register((v: LocalDateTime) => v.toString)

def register[FROM,TO](convert: (FROM => TO))(implicit from: u.TypeTag[FROM], to: u.TypeTag[TO]) = {
logger.info(s"register converter for ${from.tpe.erasure} => ${to.tpe.erasure}")
convConfigList.synchronized {
find(from.tpe, to.tpe).map(_.conv = convert).orElse({
convConfigList :+= ConvConfig(from.tpe, to.tpe, convert)
None
})
}
def register[FROM,TO](convert: (FROM => TO))(implicit from: TTag[FROM], to: TTag[TO]) = {
logger.info(s"register converter for ${from.tag.shortName} => ${to.tag.shortName}")
find(from.tag, to.tag).map(_.conv = convert).orElse({
convConfigList :+= ConvConfig(from.tag, to.tag, convert)
None
})
}

def converter[FROM,TO](implicit from: u.TypeTag[FROM], to: u.TypeTag[TO]): (FROM => TO) = {
find(from.tpe, to.tpe).map(_.conv.asInstanceOf[(FROM => TO)])
.getOrElse(throw new IllegalArgumentException(s"Converter NOT FOUND for ${from.tpe} => ${to.tpe}"))
def converter[FROM,TO](implicit from: TTag[FROM], to: TTag[TO]): (FROM => TO) = {
find(from.tag, to.tag).map(_.conv.asInstanceOf[(FROM => TO)])
.getOrElse(throw new IllegalArgumentException(s"Converter NOT FOUND for ${from.tag} => ${to.tag}"))
}

///
Expand All @@ -58,8 +57,8 @@ object TypeConverters extends Logging {
case _ => s
}

def find(from: u.Type, to: u.Type): Option[ConvConfig] = {
logger.debug(s"get converter for ${from.erasure} => ${to.erasure}")
def find(from: LightTypeTag, to: LightTypeTag): Option[ConvConfig] = {
logger.debug(s"get converter for ${from.shortName} => ${to.shortName}")
convConfigList.find(e => (e.from =:= from && e.to =:= to)).orElse({
if (from <:< to) {
Some(ConvConfig(from, to, (v: Any) => v))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.github.tminglei.slickpg

import izumi.reflect.{Tag => TTag}
import java.util.UUID
import java.sql.{Date, Time, Timestamp}
import slick.jdbc.{GetResult, JdbcType, PositionedResult, PostgresProfile, SetParameter}
import scala.reflect.runtime.{universe => u}
import scala.reflect.classTag

trait PgArraySupport extends array.PgArrayExtensions with array.PgArrayJdbcTypes { driver: PostgresProfile =>
Expand Down Expand Up @@ -63,9 +63,9 @@ trait PgArraySupport extends array.PgArrayExtensions with array.PgArrayJdbcTypes
}

implicit class PgArrayPositionedResult(r: PositionedResult) {
def nextArray[T]()(implicit tpe: u.TypeTag[T]): Seq[T] = nextArrayOption[T]().getOrElse(Nil)
def nextArrayOption[T]()(implicit ttag: u.TypeTag[T]): Option[Seq[T]] = {
nextArrayConverters.get(u.typeOf[T].toString).map(_.apply(r))
def nextArray[T]()(implicit tpe: TTag[T]): Seq[T] = nextArrayOption[T]().getOrElse(Nil)
def nextArrayOption[T]()(implicit ttag: TTag[T]): Option[Seq[T]] = {
nextArrayConverters.get(ttag.tag.shortName).map(_.apply(r))
.getOrElse(simpleNextArray[T](r)).asInstanceOf[Option[Seq[T]]]
}
}
Expand Down
56 changes: 28 additions & 28 deletions src/main/scala/com/github/tminglei/slickpg/PgCompositeSupport.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.tminglei.slickpg

import scala.reflect.runtime.{universe => u}
import izumi.reflect.macrortti.LightTypeTag
import izumi.reflect.{Tag => TTag}
import scala.reflect.ClassTag
import composite.Struct
import slick.jdbc.{PositionedResult, PostgresProfile}
Expand All @@ -11,39 +12,39 @@ trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcT
protected lazy val emptyMembersAsNull = true

//---
def createCompositeJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: u.TypeTag[T], tag: ClassTag[T]) = {
def createCompositeJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = {
val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull)
new GenericJdbcType[T](sqlTypeName, util.mkCompositeFromString[T], util.mkStringFromComposite[T])
}

def createCompositeArrayJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: u.TypeTag[T], tag: ClassTag[T]) = {
def createCompositeArrayJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = {
val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull)
new AdvancedArrayJdbcType[T](sqlTypeName, util.mkCompositeSeqFromString[T], util.mkStringFromCompositeSeq[T])
}

/// Plain SQL support
def nextComposite[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: u.TypeTag[T], tag: ClassTag[T]) = {
def nextComposite[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = {
val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull)
r.nextStringOption().map(util.mkCompositeFromString[T])
}
def nextCompositeArray[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: u.TypeTag[T], tag: ClassTag[T]) = {
def nextCompositeArray[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = {
val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull)
r.nextStringOption().map(util.mkCompositeSeqFromString[T])
}

def createCompositeSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: u.TypeTag[T], tag: ClassTag[T]) = {
def createCompositeSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = {
val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull)
utils.PlainSQLUtils.mkSetParameter[T](sqlTypeName, util.mkStringFromComposite[T])
}
def createCompositeOptionSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: u.TypeTag[T], tag: ClassTag[T]) = {
def createCompositeOptionSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = {
val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull)
utils.PlainSQLUtils.mkOptionSetParameter[T](sqlTypeName, util.mkStringFromComposite[T])
}
def createCompositeArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: u.TypeTag[T], tag: ClassTag[T]) = {
def createCompositeArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = {
val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull)
utils.PlainSQLUtils.mkArraySetParameter[T](sqlTypeName, seqToStr = Some(util.mkStringFromCompositeSeq[T]))
}
def createCompositeOptionArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: u.TypeTag[T], tag: ClassTag[T]) = {
def createCompositeOptionArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = {
val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull)
utils.PlainSQLUtils.mkArrayOptionSetParameter[T](sqlTypeName, seqToStr = Some(util.mkStringFromCompositeSeq[T]))
}
Expand All @@ -53,56 +54,55 @@ class PgCompositeSupportUtils(cl: ClassLoader, emptyMembersAsNull: Boolean) {
import utils.PgTokenHelper._
import utils.TypeConverters._

def mkCompositeFromString[T <: Struct](implicit ev: u.TypeTag[T]): (String => T) = {
val converter = mkTokenConverter(u.typeOf[T])
def mkCompositeFromString[T <: Struct](implicit ev: TTag[T]): (String => T) = {
val converter = mkTokenConverter(ev.tag)
(input: String) => {
val root = grouping(Tokenizer.tokenize(input))
converter.fromToken(root).asInstanceOf[T]
}
}

def mkStringFromComposite[T <: Struct](implicit ev: u.TypeTag[T]): (T => String) = {
val converter = mkTokenConverter(u.typeOf[T])
def mkStringFromComposite[T <: Struct](implicit ev: TTag[T]): (T => String) = {
val converter = mkTokenConverter(ev.tag)
(value: T) => {
createString(converter.toToken(value))
}
}

def mkCompositeSeqFromString[T <: Struct](implicit ev: u.TypeTag[Seq[T]]): (String => Seq[T]) = {
val converter = mkTokenConverter(u.typeOf[Seq[T]])
def mkCompositeSeqFromString[T <: Struct](implicit ev: TTag[Seq[T]]): (String => Seq[T]) = {
val converter = mkTokenConverter(ev.tag)
(input: String) => {
val root = grouping(Tokenizer.tokenize(input))
converter.fromToken(root).asInstanceOf[Seq[T]]
}
}

def mkStringFromCompositeSeq[T <: Struct](implicit ev: u.TypeTag[Seq[T]]): (Seq[T] => String) = {
val converter = mkTokenConverter(u.typeOf[Seq[T]])
def mkStringFromCompositeSeq[T <: Struct](implicit ev: TTag[Seq[T]]): (Seq[T] => String) = {
val converter = mkTokenConverter(ev.tag)
(vList: Seq[T]) => {
createString(converter.toToken(vList))
}
}

///
def mkTokenConverter(theType: u.Type, level: Int = -1)(implicit ev: u.TypeTag[String]): TokenConverter = {
def mkTokenConverter(theType: LightTypeTag, level: Int = -1)(implicit ev: TTag[String]): TokenConverter = {
theType match {
case tpe if tpe <:< u.typeOf[Struct] => {
val constructor = tpe.decl(u.termNames.CONSTRUCTOR).asMethod
val convList = constructor.paramLists.head.map(_.typeSignature).map(mkTokenConverter(_, level +1))
case tpe if tpe <:< TTag[Struct].tag => {
val convList = tpe.typeArgs.map(x => mkTokenConverter(x, level +1))
CompositeConverter(tpe, convList)
}
case tpe if tpe.typeConstructor =:= u.typeOf[Option[_]].typeConstructor => {
val pType = tpe.asInstanceOf[u.TypeRef].args(0)
case tpe if tpe =:= TTag[Option[_]].tag => {
val pType = tpe.typeArgs(0)
OptionConverter(mkTokenConverter(pType, level))
}
case tpe if tpe.typeConstructor <:< u.typeOf[Seq[_]].typeConstructor => {
val eType = tpe.asInstanceOf[u.TypeRef].args(0)
case tpe if tpe <:< TTag[Seq[_]].tag => {
val eType = tpe.typeArgs(0)
SeqConverter(mkTokenConverter(eType, level +1))
}
case tpe => {
val fromString = find(u.typeOf[String], tpe).map(_.conv.asInstanceOf[(String => Any)])
val fromString = find(TTag[String].tag, tpe).map(_.conv.asInstanceOf[(String => Any)])
.getOrElse(throw new IllegalArgumentException(s"Converter NOT FOUND for 'String' => '$tpe'"))
val ToString = find(tpe, u.typeOf[String]).map(_.conv.asInstanceOf[(Any => String)])
val ToString = find(tpe, TTag[String].tag).map(_.conv.asInstanceOf[(Any => String)])
.getOrElse((v: Any) => v.toString)
SimpleConverter(fromString, ToString, level)
}
Expand All @@ -122,7 +122,7 @@ class PgCompositeSupportUtils(cl: ClassLoader, emptyMembersAsNull: Boolean) {
if (value == null) Null else Chunk(ToString(value))
}

case class CompositeConverter(theType: u.Type, convList: List[TokenConverter]) extends TokenConverter {
case class CompositeConverter(theType: LightTypeTag, convList: List[TokenConverter]) extends TokenConverter {
private val constructor = theType.decl(u.termNames.CONSTRUCTOR).asMethod
private val fieldList = constructor.paramLists.head.map(t => theType.decl(t.name).asTerm)

Expand Down