From e18a32f6dd02ddad1a4ae255e93af87e673ffa12 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Tue, 28 Nov 2023 11:09:08 +0000 Subject: [PATCH 01/14] make some tests compile with scala 3 --- .../slickpg/PgArgonautSupportSuite.scala | 11 ++-- .../slickpg/PgCirceJsonSupportSuite.scala | 11 ++-- .../slickpg/PgJawnJsonSupportSuite.scala | 14 ++--- .../slickpg/PgDateSupportJodaSuite.scala | 9 ++- .../slickpg/PgJson4sSupportSuite.scala | 13 ++-- .../slickpg/PgPostGISSupportSuite.scala | 13 ++-- .../slickpg/PgPostGISSupportSuite.scala | 13 ++-- .../slickpg/PgPlayJsonSupportSuite.scala | 26 ++++---- .../slickpg/PgSprayJsonSupportSuite.scala | 26 ++++---- .../slickpg/PgUPickleJsonSupportSuite.scala | 11 ++-- .../lobj/LargeObjectStreamingDBIOAction.scala | 6 +- .../tminglei/slickpg/PgAggFuncCoreSuite.scala | 2 +- .../slickpg/PgAggFuncSupportSuite.scala | 8 +-- .../slickpg/PgAutoIncSeqColumnSuite.scala | 8 +-- .../tminglei/slickpg/PgInheritsSuite.scala | 4 +- .../tminglei/slickpg/PgUpsertSuite.scala | 10 ++-- .../slickpg/PgWindowFuncCoreSuite.scala | 2 +- .../slickpg/PgWindowFuncSupportSuite.scala | 2 +- .../com/github/tminglei/slickpg/package.scala | 4 +- .../slickpg/str/PgStringSupportSuite.scala | 2 +- .../slickpg/trgm/PgTrgmSupportSuite.scala | 2 +- .../slickpg/PgArraySupportSuite.scala | 41 ++++++------- .../slickpg/PgCompositeSupportSuite.scala | 59 +++++++++---------- .../slickpg/PgDate2SupportSuite.scala | 6 +- .../tminglei/slickpg/PgDateSupportSuite.scala | 2 +- .../tminglei/slickpg/PgEnumSupportSuite.scala | 50 ++++++++-------- .../slickpg/PgHStoreSupportSuite.scala | 4 +- .../tminglei/slickpg/PgJsonSupportSuite.scala | 4 +- .../slickpg/PgLTreeSupportSuite.scala | 4 +- .../tminglei/slickpg/PgNetSupportSuite.scala | 4 +- .../slickpg/PgRangeSupportSuite.scala | 4 +- .../slickpg/PgSearchSupportSuite.scala | 4 +- .../com/github/tminglei/slickpg/package.scala | 4 +- 33 files changed, 182 insertions(+), 201 deletions(-) diff --git a/addons/argonaut/src/test/scala/com/github/tminglei/slickpg/PgArgonautSupportSuite.scala b/addons/argonaut/src/test/scala/com/github/tminglei/slickpg/PgArgonautSupportSuite.scala index f6f1b850..21c351a4 100644 --- a/addons/argonaut/src/test/scala/com/github/tminglei/slickpg/PgArgonautSupportSuite.scala +++ b/addons/argonaut/src/test/scala/com/github/tminglei/slickpg/PgArgonautSupportSuite.scala @@ -1,17 +1,16 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import argonaut.Argonaut._ import argonaut._ import org.scalatest.funsuite.AnyFunSuite import slick.jdbc.{GetResult, PostgresProfile} -import scala.concurrent.{Await, ExecutionContext} +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import scala.concurrent.duration._ class PgArgonautSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) trait MyPostgresProfile extends PostgresProfile with PgArgonautSupport @@ -24,7 +23,7 @@ class PgArgonautSupportSuite extends AnyFunSuite with PostgresContainer { /// trait API extends JdbcAPI with JsonImplicits { - implicit val strListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList) + implicit val strListTypeMapper: DriverJdbcType[List[JsonField]] = new SimpleArrayJdbcType[String]("text").to(_.toList) } } object MyPostgresProfile extends MyPostgresProfile @@ -40,7 +39,7 @@ class PgArgonautSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id", O.AutoInc, O.PrimaryKey) def json = column[Json]("json") - def * = (id, json) <> (JsonBean.tupled, JsonBean.unapply) + def * = (id, json) <> ((JsonBean.apply _).tupled, JsonBean.unapply) } val JsonTests = TableQuery[JsonTestTable] @@ -158,7 +157,7 @@ class PgArgonautSupportSuite extends AnyFunSuite with PostgresContainer { test("Argonaut json Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getJsonBeanResult = GetResult(r => JsonBean(r.nextLong(), r.nextJson())) + implicit val getJsonBeanResult: GetResult[JsonBean] = GetResult(r => JsonBean(r.nextLong(), r.nextJson())) val b = JsonBean(34L, """ { "a":101, "b":"aaa", "c":[3,4,5,9] } """.parseOption.getOrElse(jNull)) diff --git a/addons/circe-json/src/test/scala/com/github/tminglei/slickpg/PgCirceJsonSupportSuite.scala b/addons/circe-json/src/test/scala/com/github/tminglei/slickpg/PgCirceJsonSupportSuite.scala index f843b54a..ead7ffa9 100644 --- a/addons/circe-json/src/test/scala/com/github/tminglei/slickpg/PgCirceJsonSupportSuite.scala +++ b/addons/circe-json/src/test/scala/com/github/tminglei/slickpg/PgCirceJsonSupportSuite.scala @@ -1,18 +1,17 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import cats.syntax.either._ import io.circe._ import io.circe.parser._ import org.scalatest.funsuite.AnyFunSuite import slick.jdbc.{GetResult, PostgresProfile} -import scala.concurrent.{Await, ExecutionContext} +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import scala.concurrent.duration._ class PgCirceJsonSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) trait MyPostgresProfile extends PostgresProfile with PgCirceJsonSupport @@ -25,7 +24,7 @@ class PgCirceJsonSupportSuite extends AnyFunSuite with PostgresContainer { /// trait API extends JdbcAPI with JsonImplicits { - implicit val strListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList) + implicit val strListTypeMapper: DriverJdbcType[List[String]] = new SimpleArrayJdbcType[String]("text").to(_.toList) } } object MyPostgresProfile extends MyPostgresProfile @@ -40,7 +39,7 @@ class PgCirceJsonSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id", O.AutoInc, O.PrimaryKey) def json = column[Json]("json") - def * = (id, json) <> (JsonBean.tupled, JsonBean.unapply) + def * = (id, json) <> ((JsonBean.apply _).tupled, JsonBean.unapply) } val JsonTests = TableQuery[JsonTestTable] @@ -137,7 +136,7 @@ class PgCirceJsonSupportSuite extends AnyFunSuite with PostgresContainer { test("Circe json Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getJsonBeanResult = GetResult(r => JsonBean(r.nextLong(), r.nextJson())) + implicit val getJsonBeanResult: GetResult[JsonBean] = GetResult(r => JsonBean(r.nextLong(), r.nextJson())) val b = JsonBean(34L, parse(""" { "a":101, "b":"aaa", "c":[3,4,5,9] } """).getOrElse(Json.Null)) diff --git a/addons/jawn/src/test/scala/com/github/tminglei/slickpg/PgJawnJsonSupportSuite.scala b/addons/jawn/src/test/scala/com/github/tminglei/slickpg/PgJawnJsonSupportSuite.scala index 74731262..68309139 100644 --- a/addons/jawn/src/test/scala/com/github/tminglei/slickpg/PgJawnJsonSupportSuite.scala +++ b/addons/jawn/src/test/scala/com/github/tminglei/slickpg/PgJawnJsonSupportSuite.scala @@ -1,18 +1,16 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import org.typelevel.jawn._ import org.typelevel.jawn.ast._ - import org.scalatest.funsuite.AnyFunSuite import slick.jdbc.{GetResult, PostgresProfile} -import scala.concurrent.{Await, ExecutionContext} +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import scala.concurrent.duration._ class PgJawnJsonSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) trait MyPostgresProfile extends PostgresProfile with PgJawnJsonSupport @@ -25,8 +23,8 @@ class PgJawnJsonSupportSuite extends AnyFunSuite with PostgresContainer { /// trait API extends JdbcAPI with JsonImplicits { - implicit val strListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList) - implicit val jsonArrayTypeMapper = + implicit val strListTypeMapper: DriverJdbcType[List[String]] = new SimpleArrayJdbcType[String]("text").to(_.toList) + implicit val jsonArrayTypeMapper: DriverJdbcType[List[JValue]] = new AdvancedArrayJdbcType[JValue](pgjson, (s) => utils.SimpleArrayUtils.fromString[JValue](JParser.parseUnsafe(_))(s).orNull, (v) => utils.SimpleArrayUtils.mkString[JValue](_.toString())(v) @@ -47,7 +45,7 @@ class PgJawnJsonSupportSuite extends AnyFunSuite with PostgresContainer { def json = column[JValue]("json", O.Default(JParser.parseUnsafe(""" {"a":"v1","b":2} """))) def jsons = column[List[JValue]]("jsons") - def * = (id, json, jsons) <> (JsonBean.tupled, JsonBean.unapply) + def * = (id, json, jsons) <> ((JsonBean.apply _).tupled, JsonBean.unapply) } val JsonTests = TableQuery[JsonTestTable] @@ -173,7 +171,7 @@ class PgJawnJsonSupportSuite extends AnyFunSuite with PostgresContainer { test("Json Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getJsonBeanResult = GetResult(r => JsonBean1(r.nextLong(), r.nextJson())) + implicit val getJsonBeanResult: GetResult[JsonBean1] = GetResult(r => JsonBean1(r.nextLong(), r.nextJson())) val b = JsonBean1(34L, JParser.parseUnsafe(""" { "a":101, "b":"aaa", "c":[3,4,5,9] } """)) diff --git a/addons/joda-time/src/test/scala/com/github/tminglei/slickpg/PgDateSupportJodaSuite.scala b/addons/joda-time/src/test/scala/com/github/tminglei/slickpg/PgDateSupportJodaSuite.scala index 98ac444f..7c27f9ec 100644 --- a/addons/joda-time/src/test/scala/com/github/tminglei/slickpg/PgDateSupportJodaSuite.scala +++ b/addons/joda-time/src/test/scala/com/github/tminglei/slickpg/PgDateSupportJodaSuite.scala @@ -1,15 +1,14 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import org.joda.time._ import org.scalatest.funsuite.AnyFunSuite import slick.jdbc.{GetResult, PostgresProfile} -import scala.concurrent.{Await, ExecutionContext} +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} class PgDateSupportJodaSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) trait MyPostgresProfile extends PostgresProfile with PgDateSupportJoda { @@ -47,7 +46,7 @@ class PgDateSupportJodaSuite extends AnyFunSuite with PostgresContainer { def interval = column[Period]("interval") def instant = column[Instant]("instant") - def * = (id, date, time, datetime, datetimetz, interval, instant) <> (DatetimeBean.tupled, DatetimeBean.unapply) + def * = (id, date, time, datetime, datetimetz, interval, instant) <> ((DatetimeBean.apply _).tupled, DatetimeBean.unapply) } val Datetimes = TableQuery[DatetimeTable] @@ -248,7 +247,7 @@ class PgDateSupportJodaSuite extends AnyFunSuite with PostgresContainer { test("Joda time Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getDateBean = GetResult(r => DatetimeBean( + implicit val getDateBean: GetResult[DatetimeBean] = GetResult(r => DatetimeBean( r.nextLong(), r.nextLocalDate(), r.nextLocalTime(), r.nextLocalDateTime(), r.nextZonedDateTime(), r.nextPeriod(), r.nextInstant())) val b1 = new DatetimeBean(107L, LocalDate.parse("2010-11-03"), LocalTime.parse("12:33:01.101357"), diff --git a/addons/json4s/src/test/scala/com/github/tminglei/slickpg/PgJson4sSupportSuite.scala b/addons/json4s/src/test/scala/com/github/tminglei/slickpg/PgJson4sSupportSuite.scala index a973638c..6e84946a 100644 --- a/addons/json4s/src/test/scala/com/github/tminglei/slickpg/PgJson4sSupportSuite.scala +++ b/addons/json4s/src/test/scala/com/github/tminglei/slickpg/PgJson4sSupportSuite.scala @@ -1,16 +1,15 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import org.json4s._ import org.scalatest.funsuite.AnyFunSuite import slick.jdbc.{GetResult, PostgresProfile} -import scala.concurrent.{Await, ExecutionContext} +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import scala.concurrent.duration._ class PgJson4sSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) trait MyPostgresProfile extends PostgresProfile with PgJson4sSupport @@ -26,8 +25,8 @@ class PgJson4sSupportSuite extends AnyFunSuite with PostgresContainer { /// trait API extends JdbcAPI with JsonImplicits { - implicit val strListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList) - implicit val json4sJsonArrayTypeMapper = + implicit val strListTypeMapper: DriverJdbcType[List[String]] = new SimpleArrayJdbcType[String]("text").to(_.toList) + implicit val json4sJsonArrayTypeMapper: DriverJdbcType[List[JValue]] = new AdvancedArrayJdbcType[JValue](pgjson, (s) => utils.SimpleArrayUtils.fromString[JValue](jsonMethods.parse(_))(s).orNull, (v) => utils.SimpleArrayUtils.mkString[JValue](j=>jsonMethods.compact(jsonMethods.render(j)))(v) @@ -49,7 +48,7 @@ class PgJson4sSupportSuite extends AnyFunSuite with PostgresContainer { def json = column[JValue]("json") def jsons = column[List[JValue]]("jsons") - def * = (id, json, jsons) <> (JsonBean.tupled, JsonBean.unapply) + def * = (id, json, jsons) <> ((JsonBean.apply _).tupled, JsonBean.unapply) } val JsonTests = TableQuery[JsonTestTable] @@ -175,7 +174,7 @@ class PgJson4sSupportSuite extends AnyFunSuite with PostgresContainer { test("Json4s Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getJsonBeanResult = GetResult(r => JsonBean1(r.nextLong(), r.nextJson())) + implicit val getJsonBeanResult: GetResult[JsonBean1] = GetResult(r => JsonBean1(r.nextLong(), r.nextJson())) val b = JsonBean1(34L, parse(""" { "a":101, "b":"aaa", "c":[3,4,5,9] } """)) diff --git a/addons/jts/src/test/scala/com/github/tminglei/slickpg/PgPostGISSupportSuite.scala b/addons/jts/src/test/scala/com/github/tminglei/slickpg/PgPostGISSupportSuite.scala index 78b64706..1d0af859 100644 --- a/addons/jts/src/test/scala/com/github/tminglei/slickpg/PgPostGISSupportSuite.scala +++ b/addons/jts/src/test/scala/com/github/tminglei/slickpg/PgPostGISSupportSuite.scala @@ -1,19 +1,16 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import scala.concurrent.duration._ -import scala.concurrent.{Await, ExecutionContext} - +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import slick.jdbc.GetResult - import com.vividsolutions.jts.geom.{Geometry, Point} import com.vividsolutions.jts.io.{WKBWriter, WKTReader, WKTWriter} import org.scalatest.funsuite.AnyFunSuite class PgPostGISSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) trait MyPostgresProfile extends ExPostgresProfile with PgPostGISSupport { @@ -41,7 +38,7 @@ class PgPostGISSupportSuite extends AnyFunSuite with PostgresContainer { def geom = column[Geometry]("geom") def geog = column[Geography]("geog") - def * = (id, geom, geog) <> (GeometryBean.tupled, GeometryBean.unapply) + def * = (id, geom, geog) <> ((GeometryBean.apply _).tupled, GeometryBean.unapply) } val GeomTests = TableQuery[GeomTestTable] @@ -52,7 +49,7 @@ class PgPostGISSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id", O.AutoInc, O.PrimaryKey) def point = column[Point]("point") - def * = (id, point) <> (PointBean.tupled, PointBean.unapply) + def * = (id, point) <> ((PointBean.apply _).tupled, PointBean.unapply) } val PointTests = TableQuery[PointTestTable] @@ -830,7 +827,7 @@ class PgPostGISSupportSuite extends AnyFunSuite with PostgresContainer { test("PostGIS Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val GetPointBeanResult = GetResult(r => PointBean(r.nextLong(), r.nextGeometry[Point]())) + implicit val GetPointBeanResult: GetResult[PointBean] = GetResult(r => PointBean(r.nextLong(), r.nextGeometry[Point]())) val b = PointBean(77L, wktReader.read("POINT(4 5)").asInstanceOf[Point]) diff --git a/addons/jts_lt/src/test/scala/com/github/tminglei/slickpg/PgPostGISSupportSuite.scala b/addons/jts_lt/src/test/scala/com/github/tminglei/slickpg/PgPostGISSupportSuite.scala index 5975a41e..636af4e8 100644 --- a/addons/jts_lt/src/test/scala/com/github/tminglei/slickpg/PgPostGISSupportSuite.scala +++ b/addons/jts_lt/src/test/scala/com/github/tminglei/slickpg/PgPostGISSupportSuite.scala @@ -1,19 +1,16 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import scala.concurrent.duration._ -import scala.concurrent.{Await, ExecutionContext} - +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import slick.jdbc.GetResult - import org.locationtech.jts.geom.{Geometry, Point} import org.locationtech.jts.io.{WKBWriter, WKTReader, WKTWriter} import org.scalatest.funsuite.AnyFunSuite class PgPostGISSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) trait MyPostgresProfile extends ExPostgresProfile with PgPostGISSupport { @@ -41,7 +38,7 @@ class PgPostGISSupportSuite extends AnyFunSuite with PostgresContainer { def geom = column[Geometry]("geom") def geog = column[Geography]("geog") - def * = (id, geom, geog) <> (GeometryBean.tupled, GeometryBean.unapply) + def * = (id, geom, geog) <> ((GeometryBean.apply _).tupled, GeometryBean.unapply) } val GeomTests = TableQuery[GeomTestTable] @@ -52,7 +49,7 @@ class PgPostGISSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id", O.AutoInc, O.PrimaryKey) def point = column[Point]("point") - def * = (id, point) <> (PointBean.tupled, PointBean.unapply) + def * = (id, point) <> ((PointBean.apply _).tupled, PointBean.unapply) } val PointTests = TableQuery[PointTestTable] @@ -816,7 +813,7 @@ class PgPostGISSupportSuite extends AnyFunSuite with PostgresContainer { test("PostGIS (lt) Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val GetPointBeanResult = GetResult(r => PointBean(r.nextLong(), r.nextGeometry[Point]())) + implicit val GetPointBeanResult: GetResult[PointBean] = GetResult(r => PointBean(r.nextLong(), r.nextGeometry[Point]())) val b = PointBean(77L, wktReader.read("POINT(4 5)").asInstanceOf[Point]) diff --git a/addons/play-json/src/test/scala/com/github/tminglei/slickpg/PgPlayJsonSupportSuite.scala b/addons/play-json/src/test/scala/com/github/tminglei/slickpg/PgPlayJsonSupportSuite.scala index 30a5ce5e..f9c81fa7 100644 --- a/addons/play-json/src/test/scala/com/github/tminglei/slickpg/PgPlayJsonSupportSuite.scala +++ b/addons/play-json/src/test/scala/com/github/tminglei/slickpg/PgPlayJsonSupportSuite.scala @@ -1,24 +1,22 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import scala.concurrent.duration._ -import scala.concurrent.{Await, ExecutionContext} - +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import play.api.libs.json._ -import slick.jdbc.{GetResult, PostgresProfile} - +import slick.jdbc.{GetResult, JdbcType, PostgresProfile} import com.github.tminglei.slickpg.utils.JsonUtils import org.scalatest.funsuite.AnyFunSuite +import slick.ast.BaseTypedType class PgPlayJsonSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) case class JBean(name: String, count: Int) object JBean { - implicit val jbeanFmt = Json.format[JBean] - implicit val jbeanWrt = Json.writes[JBean] + implicit val jbeanFmt: OFormat[JBean] = Json.format[JBean] + implicit val jbeanWrt: OWrites[JBean] = Json.writes[JBean] } trait MyPostgresProfile extends PostgresProfile @@ -32,14 +30,14 @@ class PgPlayJsonSupportSuite extends AnyFunSuite with PostgresContainer { /// trait API extends JdbcAPI with JsonImplicits { - implicit val strListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList) - implicit val beanJsonTypeMapper = MappedJdbcType.base[JBean, JsValue](Json.toJson(_), _.as[JBean]) - implicit val jsonArrayTypeMapper = + implicit val strListTypeMapper: DriverJdbcType[List[String]] = new SimpleArrayJdbcType[String]("text").to(_.toList) + implicit val beanJsonTypeMapper: JdbcType[JBean] with BaseTypedType[JBean] = MappedJdbcType.base[JBean, JsValue](Json.toJson(_), _.as[JBean]) + implicit val jsonArrayTypeMapper: DriverJdbcType[List[JsValue]] = new AdvancedArrayJdbcType[JsValue](pgjson, (s) => utils.SimpleArrayUtils.fromString[JsValue](Json.parse(_))(s).orNull, (v) => utils.SimpleArrayUtils.mkString[JsValue](_.toString())(v) ).to(_.toList) - implicit val beanArrayTypeMapper = + implicit val beanArrayTypeMapper: DriverJdbcType[List[JBean]] = new AdvancedArrayJdbcType[JBean](pgjson, (s) => utils.SimpleArrayUtils.fromString[JBean](Json.parse(_).as[JBean])(s).orNull, (v) => utils.SimpleArrayUtils.mkString[JBean](b => Json.stringify(Json.toJson(b)))(v) @@ -62,7 +60,7 @@ class PgPlayJsonSupportSuite extends AnyFunSuite with PostgresContainer { def jbean = column[JBean]("jbean") def jbeans = column[List[JBean]]("jbeans") - def * = (id, json, jsons, jbean, jbeans) <> (JsonBean.tupled, JsonBean.unapply) + def * = (id, json, jsons, jbean, jbeans) <> ((JsonBean.apply _).tupled, JsonBean.unapply) } val JsonTests = TableQuery[JsonTestTable] @@ -207,7 +205,7 @@ class PgPlayJsonSupportSuite extends AnyFunSuite with PostgresContainer { test("Json Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getJsonBeanResult = GetResult(r => JsonBean1(r.nextLong(), r.nextJson())) + implicit val getJsonBeanResult: GetResult[JsonBean1] = GetResult(r => JsonBean1(r.nextLong(), r.nextJson())) val b = JsonBean1(34L, Json.parse(""" { "a":101, "b":"aaa", "c":[3,4,5,9] } """)) diff --git a/addons/spray-json/src/test/scala/com/github/tminglei/slickpg/PgSprayJsonSupportSuite.scala b/addons/spray-json/src/test/scala/com/github/tminglei/slickpg/PgSprayJsonSupportSuite.scala index 3f14af20..218ee466 100644 --- a/addons/spray-json/src/test/scala/com/github/tminglei/slickpg/PgSprayJsonSupportSuite.scala +++ b/addons/spray-json/src/test/scala/com/github/tminglei/slickpg/PgSprayJsonSupportSuite.scala @@ -1,20 +1,20 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import org.scalatest.funsuite.AnyFunSuite -import slick.jdbc.{GetResult, PostgresProfile} +import slick.ast.BaseTypedType +import slick.jdbc.{GetResult, JdbcType, PostgresProfile} import spray.json._ -import scala.concurrent.{Await, ExecutionContext} +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import scala.concurrent.duration._ class PgSprayJsonSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) case class JBean(name: String, count: Int) object MyJsonProtocol extends DefaultJsonProtocol { - implicit val jbeanFormat = jsonFormat2(JBean) + implicit val jbeanFormat: RootJsonFormat[JBean] = jsonFormat2(JBean) } trait MyPostgresProfile extends PostgresProfile @@ -29,8 +29,8 @@ class PgSprayJsonSupportSuite extends AnyFunSuite with PostgresContainer { /// trait API extends JdbcAPI with JsonImplicits { import MyJsonProtocol._ - implicit val strListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList) - implicit val beanJsonTypeMapper = MappedJdbcType.base[JBean, JsValue](_.toJson, _.convertTo[JBean]) + implicit val strListTypeMapper: DriverJdbcType[List[String]] = new SimpleArrayJdbcType[String]("text").to(_.toList) + implicit val beanJsonTypeMapper: JdbcType[JBean] with BaseTypedType[JBean] = MappedJdbcType.base[JBean, JsValue](_.toJson, _.convertTo[JBean]) } } object MyPostgresProfile extends MyPostgresProfile @@ -47,7 +47,7 @@ class PgSprayJsonSupportSuite extends AnyFunSuite with PostgresContainer { def json = column[JsValue]("json") def jbean = column[JBean]("jbean") - def * = (id, json, jbean) <> (JsonBean.tupled, JsonBean.unapply) + def * = (id, json, jbean) <> ((JsonBean.apply _).tupled, JsonBean.unapply) } val JsonTests = TableQuery[JsonTestTable] @@ -145,19 +145,19 @@ class PgSprayJsonSupportSuite extends AnyFunSuite with PostgresContainer { ), // || JsonTests.filter(_.id === 33L).map(_.json || """ {"d":"test"} """.parseJson).result.head.map( - r => assert(""" {"a": 101, "b": "aaa", "c": [3, 4, 5, 9], "d": "test"} """.replace(" ", "") === r.toString().replace(" ", "")) + r => assert(""" {"a": 101, "b": "aaa", "c": [3, 4, 5, 9], "d": "test"} """.replace(" ", "") === r.toString.replace(" ", "")) ), // - JsonTests.filter(_.id === 33L).map(_.json - "c".bind).result.head.map( - r => assert(""" {"a": 101, "b": "aaa"} """.replace(" ", "") === r.toString().replace(" ", "")) + r => assert(""" {"a": 101, "b": "aaa"} """.replace(" ", "") === r.toString.replace(" ", "")) ), // #- JsonTests.filter(_.id === 33L).map(_.json #- List("c")).result.head.map( - r => assert(""" {"a": 101, "b": "aaa"} """.replace(" ", "") === r.toString().replace(" ", "")) + r => assert(""" {"a": 101, "b": "aaa"} """.replace(" ", "") === r.toString.replace(" ", "")) ), // #- JsonTests.filter(_.id === 33L).map(_.json.set(List("c"), """ [1] """.parseJson.bind)).result.head.map( - r => assert(""" {"a": 101, "b": "aaa", "c": [1]} """.replace(" ", "") === r.toString().replace(" ", "")) + r => assert(""" {"a": 101, "b": "aaa", "c": [1]} """.replace(" ", "") === r.toString.replace(" ", "")) ) ) ).andFinally( @@ -172,7 +172,7 @@ class PgSprayJsonSupportSuite extends AnyFunSuite with PostgresContainer { test("Spray json Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getJsonBeanResult = GetResult(r => JsonBean1(r.nextLong(), r.nextJson())) + implicit val getJsonBeanResult: GetResult[JsonBean1] = GetResult(r => JsonBean1(r.nextLong(), r.nextJson())) val b = JsonBean1(34L, """ { "a":101, "b":"aaa", "c":[3,4,5,9] } """.parseJson) diff --git a/addons/upickle-json/src/test/scala/com/github/tminglei/slickpg/PgUPickleJsonSupportSuite.scala b/addons/upickle-json/src/test/scala/com/github/tminglei/slickpg/PgUPickleJsonSupportSuite.scala index a1ae4126..e4ebaaf1 100644 --- a/addons/upickle-json/src/test/scala/com/github/tminglei/slickpg/PgUPickleJsonSupportSuite.scala +++ b/addons/upickle-json/src/test/scala/com/github/tminglei/slickpg/PgUPickleJsonSupportSuite.scala @@ -1,15 +1,14 @@ package com.github.tminglei.slickpg import java.util.concurrent.Executors - import org.scalatest.funsuite.AnyFunSuite import slick.jdbc.{GetResult, PostgresProfile} -import scala.concurrent.{Await, ExecutionContext} +import scala.concurrent.{Await, ExecutionContext, ExecutionContextExecutorService} import scala.concurrent.duration._ class PgUPickleJsonSupportSuite extends AnyFunSuite with PostgresContainer { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) trait MyPostgresProfile extends PostgresProfile with PgUPickleJsonSupport @@ -22,7 +21,7 @@ class PgUPickleJsonSupportSuite extends AnyFunSuite with PostgresContainer { /// trait API extends JdbcAPI with JsonImplicits { - implicit val strListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList) + implicit val strListTypeMapper: DriverJdbcType[List[String]] = new SimpleArrayJdbcType[String]("text").to(_.toList) } } object MyPostgresProfile extends MyPostgresProfile @@ -37,7 +36,7 @@ class PgUPickleJsonSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id", O.AutoInc, O.PrimaryKey) def json = column[ujson.Value]("json") - def * = (id, json) <> (JsonBean.tupled, JsonBean.unapply) + def * = (id, json) <> ((JsonBean.apply _).tupled, JsonBean.unapply) } val JsonTests = TableQuery[JsonTestTable] @@ -134,7 +133,7 @@ class PgUPickleJsonSupportSuite extends AnyFunSuite with PostgresContainer { test("UPickle json Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getJsonBeanResult = GetResult(r => JsonBean(r.nextLong(), r.nextJson())) + implicit val getJsonBeanResult: GetResult[JsonBean] = GetResult(r => JsonBean(r.nextLong(), r.nextJson())) val b = JsonBean(34L, ujson.read(""" { "a":101, "b":"aaa", "c":[3,4,5,9] } """)) diff --git a/core/src/main/scala/com/github/tminglei/slickpg/lobj/LargeObjectStreamingDBIOAction.scala b/core/src/main/scala/com/github/tminglei/slickpg/lobj/LargeObjectStreamingDBIOAction.scala index 26d6e9dd..a921b259 100644 --- a/core/src/main/scala/com/github/tminglei/slickpg/lobj/LargeObjectStreamingDBIOAction.scala +++ b/core/src/main/scala/com/github/tminglei/slickpg/lobj/LargeObjectStreamingDBIOAction.scala @@ -14,7 +14,7 @@ import slick.util.DumpInfo * @param largeObjectId The oid of the LargeObject to stream. * @param bufferSize The chunk size in bytes. Default to 8KB. */ -case class LargeObjectStreamingDBIOAction(largeObjectId: Long, bufferSize: Int = 1024 * 8) +case class LargeObjectStreamingDBIOAction(largeObjectId: Long, bufferSize: Int = 1024 * 8)(implicit proof: JdbcBackend#StreamingContext <:< JdbcBackend#Context) extends SynchronousDatabaseAction[ Array[Byte], Streaming[Array[Byte]], @@ -78,8 +78,8 @@ case class LargeObjectStreamingDBIOAction(largeObjectId: Long, bufferSize: Int = */ override def emitStream(context: JdbcBackend#StreamingContext, limit: Long, state: StreamState): StreamState = { //open the stream iff no stream state exists - val (stream, previousBytesRead) = state == null match { - case true => (openObject(context), 1) + val (stream, previousBytesRead) = (state == null) match { + case true => (openObject(proof(context)), 1) case false => state } diff --git a/core/src/test/scala/com/github/tminglei/slickpg/PgAggFuncCoreSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/PgAggFuncCoreSuite.scala index ce8d3793..69b30e4e 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/PgAggFuncCoreSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/PgAggFuncCoreSuite.scala @@ -22,7 +22,7 @@ class PgAggFuncCoreSuite extends AnyFunSuite with PostgresContainer { def x = column[Double]("x") def y = column[Double]("y") - def * = (name, count, x, y) <> (Tab.tupled, Tab.unapply) + def * = (name, count, x, y) <> ((Tab.apply _).tupled, Tab.unapply) } val tabs = TableQuery(new Tabs(_)) diff --git a/core/src/test/scala/com/github/tminglei/slickpg/PgAggFuncSupportSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/PgAggFuncSupportSuite.scala index 50e80b33..4fa97db6 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/PgAggFuncSupportSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/PgAggFuncSupportSuite.scala @@ -9,9 +9,9 @@ class PgAggFuncSupportSuite extends AnyFunSuite with PostgresContainer { import ExPostgresProfile.api._ val PgArrayJdbcTypes = new array.PgArrayJdbcTypes with ExPostgresProfile {} - implicit val simpleIntListTypeMapper = new PgArrayJdbcTypes.SimpleArrayJdbcType[Int]("int4").to(_.toList) - implicit val simpleStrListTypeMapper = new PgArrayJdbcTypes.SimpleArrayJdbcType[String]("text").to(_.toList) - implicit val simpleDoubleListTypeMapper = new PgArrayJdbcTypes.SimpleArrayJdbcType[Double]("float8").to(_.toList) + implicit val simpleIntListTypeMapper: PgArrayJdbcTypes.DriverJdbcType[List[Int]] = new PgArrayJdbcTypes.SimpleArrayJdbcType[Int]("int4").to(_.toList) + implicit val simpleStrListTypeMapper: PgArrayJdbcTypes.DriverJdbcType[List[String]] = new PgArrayJdbcTypes.SimpleArrayJdbcType[String]("text").to(_.toList) + implicit val simpleDoubleListTypeMapper: PgArrayJdbcTypes.DriverJdbcType[List[Double]] = new PgArrayJdbcTypes.SimpleArrayJdbcType[Double]("float8").to(_.toList) lazy val db = Database.forURL(url = container.jdbcUrl, driver = "org.postgresql.Driver") @@ -24,7 +24,7 @@ class PgAggFuncSupportSuite extends AnyFunSuite with PostgresContainer { def x = column[Double]("x") def y = column[Double]("y") - def * = (name, count, bool, x, y) <> (Tab.tupled, Tab.unapply) + def * = (name, count, bool, x, y) <> ((Tab.apply _).tupled, Tab.unapply) } val tabs = TableQuery(new Tabs(_)) diff --git a/core/src/test/scala/com/github/tminglei/slickpg/PgAutoIncSeqColumnSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/PgAutoIncSeqColumnSuite.scala index 8b26bd52..e50f2c8f 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/PgAutoIncSeqColumnSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/PgAutoIncSeqColumnSuite.scala @@ -16,7 +16,7 @@ class PgAutoIncSeqColumnSuite extends AnyFunSuite with PostgresContainer { def name = column[String]("name") - def * = (id, name) <> (User.tupled, User.unapply) + def * = (id, name) <> ((User.apply _).tupled, User.unapply) } val AutoIncSeqTests = TableQuery[AutoIncSeqTestTable] @@ -26,7 +26,7 @@ class PgAutoIncSeqColumnSuite extends AnyFunSuite with PostgresContainer { def name = column[String]("name") - def * = (id, name) <> (User.tupled, User.unapply) + def * = (id, name) <> ((User.apply _).tupled, User.unapply) } val AutoIncSeqNameTests = TableQuery[AutoIncSeqNameTestTable] @@ -36,7 +36,7 @@ class PgAutoIncSeqColumnSuite extends AnyFunSuite with PostgresContainer { def name = column[String]("name") - def * = (id, name) <> (User.tupled, User.unapply) + def * = (id, name) <> ((User.apply _).tupled, User.unapply) } val AutoIncSeqFnTests = TableQuery[AutoIncSeqFnTestTable] @@ -53,7 +53,7 @@ class PgAutoIncSeqColumnSuite extends AnyFunSuite with PostgresContainer { def name = column[String]("name") - def * = (id, name) <> (User.tupled, User.unapply) + def * = (id, name) <> ((User.apply _).tupled, User.unapply) } val AutoIncSeqNameWithFnTests = TableQuery[AutoIncSeqNameWithFnTestTable] diff --git a/core/src/test/scala/com/github/tminglei/slickpg/PgInheritsSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/PgInheritsSuite.scala index 1b1d6526..7eb1d7c4 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/PgInheritsSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/PgInheritsSuite.scala @@ -20,7 +20,7 @@ class PgInheritsSuite extends AnyFunSuite with PostgresContainer { case class Tab1(col1: String, col2: String, col3: String, col4: Int) class Tabs1(tag: Tag) extends BaseT[Tab1](tag, "test_tab1") { - def * = (col1, col2, col3, col4) <> (Tab1.tupled, Tab1.unapply) + def * = (col1, col2, col3, col4) <> ((Tab1.apply _).tupled, Tab1.unapply) } val tabs1 = TableQuery(new Tabs1(_)) @@ -31,7 +31,7 @@ class PgInheritsSuite extends AnyFunSuite with PostgresContainer { val inherited = tabs1.baseTableRow def col5 = column[Long]("col5") - def * = (col1, col2, col3, col4, col5) <> (Tab2.tupled, Tab2.unapply) + def * = (col1, col2, col3, col4, col5) <> ((Tab2.apply _).tupled, Tab2.unapply) } val tabs2 = TableQuery(new Tabs2(_)) diff --git a/core/src/test/scala/com/github/tminglei/slickpg/PgUpsertSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/PgUpsertSuite.scala index 02af4418..8abdc0a7 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/PgUpsertSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/PgUpsertSuite.scala @@ -28,7 +28,7 @@ class PgUpsertSuite extends AnyFunSuite with PostgresContainer { def col1 = column[String]("col1") def col2 = column[Int]("col2") - def * = (id, col1, col2) <> (Bean.tupled, Bean.unapply) + def * = (id, col1, col2) <> ((Bean.apply _).tupled, Bean.unapply) } val UpsertTests = TableQuery[UpsertTestTable] @@ -152,7 +152,7 @@ class PgUpsertSuite extends AnyFunSuite with PostgresContainer { def code = column[String]("code", O.PrimaryKey) def col2 = column[Int]("col2") - def * = (id.?, code, col2) <> (Bean1.tupled, Bean1.unapply) + def * = (id.?, code, col2) <> ((Bean1.apply _).tupled, Bean1.unapply) } val UpsertTests1 = TableQuery[UpsertTestTable1] @@ -162,7 +162,7 @@ class PgUpsertSuite extends AnyFunSuite with PostgresContainer { def col2 = column[Int]("col2") def pk = primaryKey("pk_a1", code) - def * = (id.?, code, col2) <> (Bean1.tupled, Bean1.unapply) + def * = (id.?, code, col2) <> ((Bean1.apply _).tupled, Bean1.unapply) } val UpsertTests11 = TableQuery[UpsertTestTable11] @@ -325,7 +325,7 @@ class PgUpsertSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id", O.AutoInc) def code = column[String]("code", O.PrimaryKey) - def * = (id.?, code) <> (Bean12.tupled, Bean12.unapply) + def * = (id.?, code) <> ((Bean12.apply _).tupled, Bean12.unapply) } val UpsertTests12 = TableQuery[UpsertTestTable12] @@ -412,7 +412,7 @@ class PgUpsertSuite extends AnyFunSuite with PostgresContainer { def start = column[Int]("start") def end = column[Int]("end") - def * = (id, start, end) <> (Bean2.tupled, Bean2.unapply) + def * = (id, start, end) <> ((Bean2.apply _).tupled, Bean2.unapply) } val UpsertTests2 = TableQuery[UpsertTestTable2] diff --git a/core/src/test/scala/com/github/tminglei/slickpg/PgWindowFuncCoreSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/PgWindowFuncCoreSuite.scala index b7f5220a..c5029591 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/PgWindowFuncCoreSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/PgWindowFuncCoreSuite.scala @@ -25,7 +25,7 @@ class PgWindowFuncCoreSuite extends AnyFunSuite with PostgresContainer { def col3 = column[String]("COL3") def col4 = column[Int]("COL4") - def * = (col1, col2, col3, col4) <> (Tab.tupled, Tab.unapply) + def * = (col1, col2, col3, col4) <> ((Tab.apply _).tupled, Tab.unapply) } val tabs = TableQuery[Tabs] diff --git a/core/src/test/scala/com/github/tminglei/slickpg/PgWindowFuncSupportSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/PgWindowFuncSupportSuite.scala index f3947a81..41deec20 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/PgWindowFuncSupportSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/PgWindowFuncSupportSuite.scala @@ -21,7 +21,7 @@ class PgWindowFuncSupportSuite extends AnyFunSuite with PostgresContainer { def col3 = column[String]("COL3") def col4 = column[Int]("COL4") - def * = (col1, col2, col3, col4) <> (Tab.tupled, Tab.unapply) + def * = (col1, col2, col3, col4) <> ((Tab.apply _).tupled, Tab.unapply) } val tabs = TableQuery[Tabs] diff --git a/core/src/test/scala/com/github/tminglei/slickpg/package.scala b/core/src/test/scala/com/github/tminglei/slickpg/package.scala index 29199870..2a5963aa 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/package.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/package.scala @@ -1,8 +1,8 @@ package com.github.tminglei import java.util.concurrent.Executors -import scala.concurrent.ExecutionContext +import scala.concurrent.{ExecutionContext, ExecutionContextExecutorService} package object slickpg { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) } diff --git a/core/src/test/scala/com/github/tminglei/slickpg/str/PgStringSupportSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/str/PgStringSupportSuite.scala index 4fcdca71..fe2d3d42 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/str/PgStringSupportSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/str/PgStringSupportSuite.scala @@ -34,7 +34,7 @@ class PgStringSupportSuite extends AnyFunSuite with PostgresContainer { val str = column[String]("str") val strArr = column[Array[Byte]]("str_arr") - def * = (id, str, strArr) <> (StrBean.tupled, StrBean.unapply) + def * = (id, str, strArr) <> ((StrBean.apply _).tupled, StrBean.unapply) } val stringTestTable = TableQuery[StringTestTable] diff --git a/core/src/test/scala/com/github/tminglei/slickpg/trgm/PgTrgmSupportSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/trgm/PgTrgmSupportSuite.scala index f27d639f..e54d1189 100644 --- a/core/src/test/scala/com/github/tminglei/slickpg/trgm/PgTrgmSupportSuite.scala +++ b/core/src/test/scala/com/github/tminglei/slickpg/trgm/PgTrgmSupportSuite.scala @@ -30,7 +30,7 @@ class PgTrgmSupportSuite extends AnyFunSuite with PostgresContainer { val id = column[Long]("id") val str = column[String]("str") - def * = (id, str) <> (StrBean.tupled, StrBean.unapply) + def * = (id, str) <> ((StrBean.apply _).tupled, StrBean.unapply) } val trgmTestTable = TableQuery[StringTestTable] diff --git a/src/test/scala/com/github/tminglei/slickpg/PgArraySupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgArraySupportSuite.scala index 281beeab..ebedc166 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgArraySupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgArraySupportSuite.scala @@ -2,10 +2,11 @@ package com.github.tminglei.slickpg import java.sql.{Date, Time, Timestamp} import java.util.UUID - import org.scalatest.funsuite.AnyFunSuite -import slick.jdbc.GetResult +import slick.ast.BaseTypedType +import slick.jdbc.{GetResult, JdbcType, SetParameter} +import scala.collection.mutable import scala.collection.mutable.Buffer import scala.concurrent.Await import scala.concurrent.duration._ @@ -22,27 +23,27 @@ class PgArraySupportSuite extends AnyFunSuite with PostgresContainer { /// trait MyAPI extends ExtPostgresAPI with ArrayImplicits { - implicit val simpleOptStrListListMapper = new SimpleArrayJdbcType[String]("text") + implicit val simpleOptStrListListMapper: DriverJdbcType[List[Option[String]]] = new SimpleArrayJdbcType[String]("text") .mapTo[Option[String]](Option(_), _.orNull).to(_.toList) - implicit val simpleLongBufferTypeMapper = new SimpleArrayJdbcType[Long]("int8").to(_.toBuffer[Long], (v: Buffer[Long]) => v.toSeq) - implicit val simpleStrVectorTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toVector) - implicit val institutionListTypeWrapper = new SimpleArrayJdbcType[Long]("int8") + implicit val simpleLongBufferTypeMapper: DriverJdbcType[mutable.Buffer[Long]] = new SimpleArrayJdbcType[Long]("int8").to(_.toBuffer[Long], (v: Buffer[Long]) => v.toSeq) + implicit val simpleStrVectorTypeMapper: DriverJdbcType[Vector[String]] = new SimpleArrayJdbcType[String]("text").to(_.toVector) + implicit val institutionListTypeWrapper: DriverJdbcType[List[Institution]] = new SimpleArrayJdbcType[Long]("int8") .mapTo[Institution](new Institution(_), _.value).to(_.toList) - implicit val marketFinancialProductWrapper = new SimpleArrayJdbcType[String]("text") + implicit val marketFinancialProductWrapper: DriverJdbcType[List[MarketFinancialProduct]] = new SimpleArrayJdbcType[String]("text") .mapTo[MarketFinancialProduct](new MarketFinancialProduct(_), _.value).to(_.toList) /// - implicit val bigDecimalTypeWrapper = new SimpleArrayJdbcType[java.math.BigDecimal]("numeric") + implicit val bigDecimalTypeWrapper: DriverJdbcType[List[BigDecimal]] = new SimpleArrayJdbcType[java.math.BigDecimal]("numeric") .mapTo[scala.math.BigDecimal](javaBigDecimal => scala.math.BigDecimal(javaBigDecimal), scalaBigDecimal => scalaBigDecimal.bigDecimal).to(_.toList) - implicit val advancedStringListTypeMapper = new AdvancedArrayJdbcType[String]("text", - fromString(identity)(_).orNull, mkString(identity)) + implicit val advancedStringListTypeMapper: AdvancedArrayJdbcType[String] = new AdvancedArrayJdbcType[String]("text", + fromString(identity)(_).orNull, mkString(identity[String])) /// - implicit val longlongWitness = ElemWitness.AnyWitness.asInstanceOf[ElemWitness[List[Long]]] - implicit val simpleLongLongListTypeMapper = new SimpleArrayJdbcType[List[Long]]("int8[]") + implicit val longlongWitness: ElemWitness[List[Long]] = ElemWitness.AnyWitness.asInstanceOf[ElemWitness[List[Long]]] + implicit val simpleLongLongListTypeMapper: DriverJdbcType[List[List[Long]]] = new SimpleArrayJdbcType[List[Long]]("int8[]") .to(_.asInstanceOf[Seq[Array[Any]]].toList.map(_.toList.asInstanceOf[List[Long]])) - implicit val institutionTypeWrapper = MappedJdbcType.base[Institution, Long](_.value, Institution) - implicit val marketFinancialProductTypeWrapper = MappedJdbcType.base[MarketFinancialProduct, String](_.value, MarketFinancialProduct) + implicit val institutionTypeWrapper: JdbcType[Institution] with BaseTypedType[Institution] = MappedJdbcType.base[Institution, Long](_.value, Institution) + implicit val marketFinancialProductTypeWrapper: JdbcType[MarketFinancialProduct] with BaseTypedType[MarketFinancialProduct] = MappedJdbcType.base[MarketFinancialProduct, String](_.value, MarketFinancialProduct) } } object MyPostgresProfile1 extends MyPostgresProfile1 @@ -84,7 +85,7 @@ class PgArraySupportSuite extends AnyFunSuite with PostgresContainer { def mktFinancialProducts = column[Option[List[MarketFinancialProduct]]]("mktFinancialProducts") def * = (id, str, intArr, longArr, longlongArr, shortArr, strList, optStrList, strArr, uuidArr, - bigDecimalArr, institutions, mktFinancialProducts) <> (ArrayBean.tupled, ArrayBean.unapply) + bigDecimalArr, institutions, mktFinancialProducts) <> ((ArrayBean.apply _).tupled, ArrayBean.unapply) } val ArrayTests = TableQuery[ArrayTestTable] @@ -206,12 +207,12 @@ class PgArraySupportSuite extends AnyFunSuite with PostgresContainer { addNextArrayConverter((r) => r.nextArrayOption[Long]().map(_.map(Institution(_)))) } - implicit val getInstitutionArray = mkGetResult(_.nextArray[Institution]()) - implicit val getInstitutionArrayOption = mkGetResult(_.nextArrayOption[Institution]()) - implicit val setInstitutionArray = mkArraySetParameter[Institution]("int8", v => String.valueOf(v.value)) - implicit val setInstitutionArrayOption = mkArrayOptionSetParameter[Institution]("int8", v => String.valueOf(v.value)) + implicit val getInstitutionArray: GetResult[Seq[Institution]] = mkGetResult(_.nextArray[Institution]()) + implicit val getInstitutionArrayOption: GetResult[Option[Seq[Institution]]] = mkGetResult(_.nextArrayOption[Institution]()) + implicit val setInstitutionArray: SetParameter[Seq[Institution]] = mkArraySetParameter[Institution]("int8", v => String.valueOf(v.value)) + implicit val setInstitutionArrayOption: SetParameter[Option[Seq[Institution]]] = mkArrayOptionSetParameter[Institution]("int8", v => String.valueOf(v.value)) - implicit val getArrarBean1Result = GetResult { r => + implicit val getArrarBean1Result: GetResult[ArrayBean1] = GetResult { r => ArrayBean1(r.nextLong(), r.<<[Array[Byte]], r.<<[Seq[UUID]].toList, diff --git a/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala index df08c6f8..6de40861 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala @@ -1,13 +1,10 @@ package com.github.tminglei.slickpg import java.time.LocalDateTime - import scala.concurrent.Await import scala.concurrent.duration._ import scala.jdk.CollectionConverters._ - -import slick.jdbc.{GetResult, PositionedResult, PostgresProfile} - +import slick.jdbc.{GetResult, PositionedResult, PostgresProfile, SetParameter} import com.github.tminglei.slickpg.composite.Struct import org.postgresql.util.HStoreConverter import org.scalatest.funsuite.AnyFunSuite @@ -67,16 +64,16 @@ object PgCompositeSupportSuite { utils.TypeConverters.register(mapToString) utils.TypeConverters.register(stringToMap) - implicit val composite1TypeMapper = createCompositeJdbcType[Composite1]("composite1") - implicit val composite2TypeMapper = createCompositeJdbcType[Composite2]("composite2") - implicit val composite3TypeMapper = createCompositeJdbcType[Composite3]("composite3") - implicit val composite4TypeMapper = createCompositeJdbcType[Composite4]("composite4") - implicit val c1TypeMapper = createCompositeJdbcType[C1]("c1") - implicit val c2TypeMapper = createCompositeJdbcType[C2]("c2") + implicit val composite1TypeMapper: GenericJdbcType[Composite1] = createCompositeJdbcType[Composite1]("composite1") + implicit val composite2TypeMapper: GenericJdbcType[Composite2] = createCompositeJdbcType[Composite2]("composite2") + implicit val composite3TypeMapper: GenericJdbcType[Composite3] = createCompositeJdbcType[Composite3]("composite3") + implicit val composite4TypeMapper: GenericJdbcType[Composite4] = createCompositeJdbcType[Composite4]("composite4") + implicit val c1TypeMapper: GenericJdbcType[C1] = createCompositeJdbcType[C1]("c1") + implicit val c2TypeMapper: GenericJdbcType[C2] = createCompositeJdbcType[C2]("c2") - implicit val composite1ArrayTypeMapper = createCompositeArrayJdbcType[Composite1]("composite1").to(_.toList) - implicit val composite2ArrayTypeMapper = createCompositeArrayJdbcType[Composite2]("composite2").to(_.toList) - implicit val composite3ArrayTypeMapper = createCompositeArrayJdbcType[Composite3]("composite3").to(_.toList) + implicit val composite1ArrayTypeMapper: DriverJdbcType[List[Composite1]] = createCompositeArrayJdbcType[Composite1]("composite1").to(_.toList) + implicit val composite2ArrayTypeMapper: DriverJdbcType[List[Composite2]] = createCompositeArrayJdbcType[Composite2]("composite2").to(_.toList) + implicit val composite3ArrayTypeMapper: DriverJdbcType[List[Composite3]] = createCompositeArrayJdbcType[Composite3]("composite3").to(_.toList) } override val api: API = new API {} @@ -95,20 +92,20 @@ object PgCompositeSupportSuite { def nextComposite3() = nextComposite[Composite3](r) } - implicit val composite1SetParameter = createCompositeSetParameter[Composite1]("composite1") - implicit val composite1OptSetParameter = createCompositeOptionSetParameter[Composite1]("composite1") - implicit val composite1ArraySetParameter = createCompositeArraySetParameter[Composite1]("composite1") - implicit val composite1ArrayOptSetParameter = createCompositeOptionArraySetParameter[Composite1]("composite1") + implicit val composite1SetParameter: SetParameter[Composite1] = createCompositeSetParameter[Composite1]("composite1") + implicit val composite1OptSetParameter: SetParameter[Option[Composite1]] = createCompositeOptionSetParameter[Composite1]("composite1") + implicit val composite1ArraySetParameter: SetParameter[Seq[Composite1]] = createCompositeArraySetParameter[Composite1]("composite1") + implicit val composite1ArrayOptSetParameter: SetParameter[Option[Seq[Composite1]]] = createCompositeOptionArraySetParameter[Composite1]("composite1") - implicit val composite2SetParameter = createCompositeSetParameter[Composite2]("composite2") - implicit val composite2OptSetParameter = createCompositeOptionSetParameter[Composite2]("composite2") - implicit val composite2ArraySetParameter = createCompositeArraySetParameter[Composite2]("composite2") - implicit val composite2ArrayOptSetParameter = createCompositeOptionArraySetParameter[Composite2]("composite2") + implicit val composite2SetParameter: SetParameter[Composite2] = createCompositeSetParameter[Composite2]("composite2") + implicit val composite2OptSetParameter: SetParameter[Option[Composite2]] = createCompositeOptionSetParameter[Composite2]("composite2") + implicit val composite2ArraySetParameter: SetParameter[Seq[Composite2]] = createCompositeArraySetParameter[Composite2]("composite2") + implicit val composite2ArrayOptSetParameter: SetParameter[Option[Seq[Composite2]]] = createCompositeOptionArraySetParameter[Composite2]("composite2") - implicit val composite3SetParameter = createCompositeSetParameter[Composite3]("composite3") - implicit val composite3OptSetParameter = createCompositeOptionSetParameter[Composite3]("composite3") - implicit val composite3ArraySetParameter = createCompositeArraySetParameter[Composite3]("composite3") - implicit val composite3ArrayOptSetParameter = createCompositeOptionArraySetParameter[Composite3]("composite3") + implicit val composite3SetParameter: SetParameter[Composite3] = createCompositeSetParameter[Composite3]("composite3") + implicit val composite3OptSetParameter: SetParameter[Option[Composite3]] = createCompositeOptionSetParameter[Composite3]("composite3") + implicit val composite3ArraySetParameter: SetParameter[Seq[Composite3]] = createCompositeArraySetParameter[Composite3]("composite3") + implicit val composite3ArrayOptSetParameter: SetParameter[Option[Seq[Composite3]]] = createCompositeOptionArraySetParameter[Composite3]("composite3") } } object MyPostgresProfile1 extends MyPostgresProfile1 @@ -146,7 +143,7 @@ class PgCompositeSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id") def comps = column[List[Composite2]]("comps", O.Default(Nil)) - def * = (id,comps) <> (TestBean.tupled, TestBean.unapply) + def * = (id,comps) <> ((TestBean.apply _).tupled, TestBean.unapply) } val CompositeTests = TableQuery(new TestTable(_)) @@ -154,7 +151,7 @@ class PgCompositeSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id") def comps = column[List[Composite3]]("comps") - def * = (id,comps) <> (TestBean1.tupled, TestBean1.unapply) + def * = (id,comps) <> ((TestBean1.apply _).tupled, TestBean1.unapply) } val CompositeTests1 = TableQuery(new TestTable1(_)) @@ -163,7 +160,7 @@ class PgCompositeSupportSuite extends AnyFunSuite with PostgresContainer { def comps = column[Composite1]("comp") def c2 = column[C2]("c2") - def * = (id,comps,c2) <> (TestBean2.tupled, TestBean2.unapply) + def * = (id,comps,c2) <> ((TestBean2.apply _).tupled, TestBean2.unapply) } val CompositeTests2 = TableQuery(new TestTable2(_)) @@ -171,7 +168,7 @@ class PgCompositeSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id") def comps = column[Option[Composite4]]("comp") - def * = (id, comps) <> (TestBean3.tupled, TestBean3.unapply) + def * = (id, comps) <> ((TestBean3.apply _).tupled, TestBean3.unapply) } val CompositeTests3 = TableQuery(new TestTable3(_)) @@ -284,8 +281,8 @@ class PgCompositeSupportSuite extends AnyFunSuite with PostgresContainer { test("Composite type Plain SQL support") { import MyPostgresProfile1.plainImplicits._ - implicit val getTestBeanResult = GetResult(r => TestBean(r.nextLong(), r.nextArray[Composite2]().toList)) - implicit val getTestBean1Result = GetResult(r => TestBean1(r.nextLong(), r.nextArray[Composite3]().toList)) + implicit val getTestBeanResult: GetResult[TestBean] = GetResult(r => TestBean(r.nextLong(), r.nextArray[Composite2]().toList)) + implicit val getTestBean1Result: GetResult[TestBean1] = GetResult(r => TestBean1(r.nextLong(), r.nextArray[Composite3]().toList)) Await.result(db.run(DBIO.seq( sqlu"create type composite1 as (id int8, txt text, date timestamp, ts_range tsrange)", diff --git a/src/test/scala/com/github/tminglei/slickpg/PgDate2SupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgDate2SupportSuite.scala index 63ce9df6..6be0077e 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgDate2SupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgDate2SupportSuite.scala @@ -43,7 +43,7 @@ class PgDate2SupportSuite extends AnyFunSuite with PostgresContainer { def zone = column[ZoneId]("zone") def * = (id, date, time, dateTime, dateTimeOffset, dateTimeTz, instant, duration, period, zone) <> - (DatetimeBean.tupled, DatetimeBean.unapply) + ((DatetimeBean.apply _).tupled, DatetimeBean.unapply) } val Datetimes = TableQuery[DatetimeTable] @@ -289,7 +289,7 @@ class PgDate2SupportSuite extends AnyFunSuite with PostgresContainer { def * = (id, date, time, dateTime, dateTimeOffset, dateTimeTz, instant, duration, period, zone) <> - (DatetimeOptionBean.tupled, DatetimeOptionBean.unapply) + ((DatetimeOptionBean.apply _).tupled, DatetimeOptionBean.unapply) } val DatetimesOption = TableQuery[DatetimeOptionTable] @@ -360,7 +360,7 @@ class PgDate2SupportSuite extends AnyFunSuite with PostgresContainer { test("Java8 date Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getDateBean = GetResult(r => DatetimeBean( + implicit val getDateBean: GetResult[DatetimeBean] = GetResult(r => DatetimeBean( r.nextLong(), r.nextLocalDate(), r.nextLocalTime(), r.nextLocalDateTime(), r.nextOffsetDateTime(), r.nextZonedDateTime(), r.nextInstant(), r.nextDuration(), r.nextPeriod(), r.nextZoneId())) diff --git a/src/test/scala/com/github/tminglei/slickpg/PgDateSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgDateSupportSuite.scala index 1d1f3dc6..f5d0a4df 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgDateSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgDateSupportSuite.scala @@ -51,7 +51,7 @@ class PgDateSupportSuite extends AnyFunSuite with PostgresContainer { def timestamptz = column[Calendar]("timestamptz") def interval = column[Interval]("interval") - def * = (id, date, time, timestamp, timestamptz, interval) <> (DatetimeBean.tupled, DatetimeBean.unapply) + def * = (id, date, time, timestamp, timestamptz, interval) <> ((DatetimeBean.apply _).tupled, DatetimeBean.unapply) } val Datetimes = TableQuery[DatetimeTable] diff --git a/src/test/scala/com/github/tminglei/slickpg/PgEnumSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgEnumSupportSuite.scala index e5cd1ba5..4b90fbec 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgEnumSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgEnumSupportSuite.scala @@ -4,9 +4,7 @@ import scala.collection.compat._ import scala.collection.compat.immutable.LazyList import scala.concurrent.Await import scala.concurrent.duration._ - -import slick.jdbc.PostgresProfile - +import slick.jdbc.{JdbcType, PostgresProfile} import org.scalatest.funsuite.AnyFunSuite @@ -57,30 +55,30 @@ class PgEnumSupportSuite extends AnyFunSuite with PostgresContainer { /// trait API extends JdbcAPI { - implicit val weekDayTypeMapper = createEnumJdbcType("WeekDay", WeekDays) - implicit val weekDayListTypeMapper = createEnumListJdbcType("weekDay", WeekDays) - implicit val rainbowTypeMapper = createEnumJdbcType("Rainbow", Rainbows, true) - implicit val rainbowListTypeMapper = createEnumListJdbcType("Rainbow", Rainbows, true) + implicit val weekDayTypeMapper: JdbcType[WeekDays.Value] = createEnumJdbcType[WeekDays.type]("WeekDay", WeekDays) + implicit val weekDayListTypeMapper: JdbcType[List[WeekDays.Value]] = createEnumListJdbcType[WeekDays.type]("weekDay", WeekDays) + implicit val rainbowTypeMapper: JdbcType[Rainbows.Value] = createEnumJdbcType[Rainbows.type]("Rainbow", Rainbows, true) + implicit val rainbowListTypeMapper: JdbcType[List[Rainbows.Value]] = createEnumListJdbcType[Rainbows.type]("Rainbow", Rainbows, true) - implicit val weekDayColumnExtensionMethodsBuilder = createEnumColumnExtensionMethodsBuilder(WeekDays) - implicit val weekDayOptionColumnExtensionMethodsBuilder = createEnumOptionColumnExtensionMethodsBuilder(WeekDays) - implicit val rainbowColumnExtensionMethodsBuilder = createEnumColumnExtensionMethodsBuilder(Rainbows) - implicit val rainbowOptionColumnExtensionMethodsBuilder = createEnumOptionColumnExtensionMethodsBuilder(Rainbows) + implicit val weekDayColumnExtensionMethodsBuilder: api.Rep[WeekDays.Value] => EnumColumnExtensionMethods[WeekDays.Value, WeekDays.Value] = createEnumColumnExtensionMethodsBuilder[WeekDays.type](WeekDays) + implicit val weekDayOptionColumnExtensionMethodsBuilder: api.Rep[Option[WeekDays.Value]] => EnumColumnExtensionMethods[WeekDays.Value, Option[WeekDays.Value]] = createEnumOptionColumnExtensionMethodsBuilder[WeekDays.type](WeekDays) + implicit val rainbowColumnExtensionMethodsBuilder: api.Rep[Rainbows.Value] => EnumColumnExtensionMethods[Rainbows.Value, Rainbows.Value] = createEnumColumnExtensionMethodsBuilder[Rainbows.type](Rainbows) + implicit val rainbowOptionColumnExtensionMethodsBuilder: api.Rep[Option[Rainbows.Value]] => EnumColumnExtensionMethods[Rainbows.Value, Option[Rainbows.Value]] = createEnumOptionColumnExtensionMethodsBuilder[Rainbows.type](Rainbows) /// custom types of java enums and algebraic data type (ADT) - implicit val currencyTypeMapper = createEnumJdbcType[Currency]("Currency", _.toString, Currency.values.get(_).get, quoteName = false) - implicit val currencyTypeListMapper = createEnumListJdbcType[Currency]("Currency", _.toString, Currency.values.get(_).get, quoteName = false) - implicit val languagesTypeMapper = createEnumJdbcType[Languages]("Languages", _.name(), Languages.valueOf, quoteName = true) - implicit val languagesTypeListMapper = createEnumListJdbcType[Languages]("Languages", _.name(), Languages.valueOf, quoteName = true) - implicit val genderTypeMapper = createEnumJdbcType[Gender]("Gender", _.repr, Gender.fromString, quoteName = false) - implicit val genderTypeListMapper = createEnumListJdbcType[Gender]("Gender", _.repr, Gender.fromString, quoteName = false) - - implicit val currencyColumnExtensionMethodsBuilder = createEnumColumnExtensionMethodsBuilder[Currency] - implicit val currencyOptionColumnExtensionMethodsBuilder = createEnumOptionColumnExtensionMethodsBuilder[Currency] - implicit val languagesColumnExtensionMethodsBuilder = createEnumColumnExtensionMethodsBuilder[Languages] - implicit val languagesOptionColumnExtensionMethodsBuilder = createEnumOptionColumnExtensionMethodsBuilder[Languages] - implicit val genderColumnExtensionMethodsBuilder = createEnumColumnExtensionMethodsBuilder[Gender] - implicit val genderOptionColumnExtensionMethodsBuilder = createEnumOptionColumnExtensionMethodsBuilder[Gender] + implicit val currencyTypeMapper: JdbcType[Currency] = createEnumJdbcType[Currency]("Currency", _.toString, Currency.values.get(_).get, quoteName = false) + implicit val currencyTypeListMapper: JdbcType[List[Currency]] = createEnumListJdbcType[Currency]("Currency", _.toString, Currency.values.get(_).get, quoteName = false) + implicit val languagesTypeMapper: JdbcType[Languages] = createEnumJdbcType[Languages]("Languages", _.name(), Languages.valueOf, quoteName = true) + implicit val languagesTypeListMapper: JdbcType[List[Languages]] = createEnumListJdbcType[Languages]("Languages", _.name(), Languages.valueOf, quoteName = true) + implicit val genderTypeMapper: JdbcType[Gender] = createEnumJdbcType[Gender]("Gender", _.repr, Gender.fromString, quoteName = false) + implicit val genderTypeListMapper: JdbcType[List[Gender]] = createEnumListJdbcType[Gender]("Gender", _.repr, Gender.fromString, quoteName = false) + + implicit val currencyColumnExtensionMethodsBuilder: api.Rep[Currency] => EnumColumnExtensionMethods[Currency, Currency] = createEnumColumnExtensionMethodsBuilder[Currency] + implicit val currencyOptionColumnExtensionMethodsBuilder: api.Rep[Option[Currency]] => EnumColumnExtensionMethods[Currency, Option[Currency]] = createEnumOptionColumnExtensionMethodsBuilder[Currency] + implicit val languagesColumnExtensionMethodsBuilder: api.Rep[Languages] => EnumColumnExtensionMethods[Languages, Languages] = createEnumColumnExtensionMethodsBuilder[Languages] + implicit val languagesOptionColumnExtensionMethodsBuilder: api.Rep[Option[Languages]] => EnumColumnExtensionMethods[Languages, Option[Languages]] = createEnumOptionColumnExtensionMethodsBuilder[Languages] + implicit val genderColumnExtensionMethodsBuilder: api.Rep[Gender] => EnumColumnExtensionMethods[Gender, Gender] = createEnumColumnExtensionMethodsBuilder[Gender] + implicit val genderOptionColumnExtensionMethodsBuilder: api.Rep[Option[Gender]] => EnumColumnExtensionMethods[Gender, Option[Gender]] = createEnumOptionColumnExtensionMethodsBuilder[Gender] } } object MyPostgresProfile1 extends MyPostgresProfile1 @@ -104,7 +102,7 @@ class PgEnumSupportSuite extends AnyFunSuite with PostgresContainer { def weekdays = column[List[WeekDay]]("weekdays") def rainbows = column[List[Rainbow]]("rainbows") - def * = (id, weekday, rainbow, weekdays, rainbows) <> (TestEnumBean.tupled, TestEnumBean.unapply) + def * = (id, weekday, rainbow, weekdays, rainbows) <> ((TestEnumBean.apply _).tupled, TestEnumBean.unapply) } val TestEnums = TableQuery(new TestEnumTable(_)) @@ -125,7 +123,7 @@ class PgEnumSupportSuite extends AnyFunSuite with PostgresContainer { def currencies = column[List[Currency]]("currencies") def languages = column[List[Languages]]("languages") - def * = (id, currency, language, gender, currencies, languages) <> (TestEnumBean1.tupled, TestEnumBean1.unapply) + def * = (id, currency, language, gender, currencies, languages) <> ((TestEnumBean1.apply _).tupled, TestEnumBean1.unapply) } val TestEnums1 = TableQuery(new TestEnumTable1(_)) diff --git a/src/test/scala/com/github/tminglei/slickpg/PgHStoreSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgHStoreSupportSuite.scala index c84e80b3..ab767f2e 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgHStoreSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgHStoreSupportSuite.scala @@ -17,7 +17,7 @@ class PgHStoreSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id", O.AutoInc, O.PrimaryKey) def hstore = column[Map[String, String]]("hstoreMap", O.Default(Map.empty)) - def * = (id, hstore) <> (MapBean.tupled, MapBean.unapply) + def * = (id, hstore) <> ((MapBean.apply _).tupled, MapBean.unapply) } val HStoreTests = TableQuery[HStoreTestTable] @@ -107,7 +107,7 @@ class PgHStoreSupportSuite extends AnyFunSuite with PostgresContainer { test("Hstore Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getMapBeanResult = GetResult(r => MapBean(r.nextLong(), r.nextHStore())) + implicit val getMapBeanResult: GetResult[MapBean] = GetResult(r => MapBean(r.nextLong(), r.nextHStore())) val b = MapBean(34L, Map("a"->"val1", "b"->"val3", "c"->"321")) diff --git a/src/test/scala/com/github/tminglei/slickpg/PgJsonSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgJsonSupportSuite.scala index 335a20d3..3e87bf95 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgJsonSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgJsonSupportSuite.scala @@ -18,7 +18,7 @@ class PgJsonSupportSuite extends AnyFunSuite with PostgresContainer { def id = column[Long]("id", O.AutoInc, O.PrimaryKey) def json = column[JsonString]("json", O.Default(JsonString(""" {"a":"v1","b":2} """))) - def * = (id, json) <> (JsonBean.tupled, JsonBean.unapply) + def * = (id, json) <> ((JsonBean.apply _).tupled, JsonBean.unapply) } val JsonTests = TableQuery[JsonTestTable] @@ -148,7 +148,7 @@ class PgJsonSupportSuite extends AnyFunSuite with PostgresContainer { test("Json Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getJsonBeanResult = GetResult(r => JsonBean(r.nextLong(), r.nextJson())) + implicit val getJsonBeanResult: GetResult[JsonBean] = GetResult(r => JsonBean(r.nextLong(), r.nextJson())) val b = JsonBean(34L, JsonString(""" { "a":101, "b":"aaa", "c":[3,4,5,9] } """)) diff --git a/src/test/scala/com/github/tminglei/slickpg/PgLTreeSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgLTreeSupportSuite.scala index f42f9211..ef067703 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgLTreeSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgLTreeSupportSuite.scala @@ -19,7 +19,7 @@ class PgLTreeSupportSuite extends AnyFunSuite with PostgresContainer { def path = column[LTree]("path") def treeArr = column[List[LTree]]("tree_arr") - def * = (id, path, treeArr) <> (LTreeBean.tupled, LTreeBean.unapply) + def * = (id, path, treeArr) <> ((LTreeBean.apply _).tupled, LTreeBean.unapply) } val LTreeTests = TableQuery[LTreeTestTable] @@ -166,7 +166,7 @@ class PgLTreeSupportSuite extends AnyFunSuite with PostgresContainer { test("Ltree Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getLTreeBeanResult = GetResult(r => LTreeBean(r.nextLong(), r.nextLTree(), r.nextArray[LTree]().toList)) + implicit val getLTreeBeanResult: GetResult[LTreeBean] = GetResult(r => LTreeBean(r.nextLong(), r.nextLTree(), r.nextArray[LTree]().toList)) val b = LTreeBean(100L, LTree("Top"), List(LTree("Top.Science"), LTree("Top.Collections"))) diff --git a/src/test/scala/com/github/tminglei/slickpg/PgNetSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgNetSupportSuite.scala index fd262d86..10084ac2 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgNetSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgNetSupportSuite.scala @@ -19,7 +19,7 @@ class PgNetSupportSuite extends AnyFunSuite with PostgresContainer { def inet = column[InetString]("inet") def mac = column[Option[MacAddrString]]("mac") - def * = (id, inet, mac) <> (NetBean.tupled, NetBean.unapply) + def * = (id, inet, mac) <> ((NetBean.apply _).tupled, NetBean.unapply) } val NetTests = TableQuery[NetTestTable] @@ -180,7 +180,7 @@ class PgNetSupportSuite extends AnyFunSuite with PostgresContainer { test("net Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getNetBeanResult = GetResult(r => NetBean(r.nextLong(), r.nextIPAddr(), r.nextMacAddrOption())) + implicit val getNetBeanResult: GetResult[NetBean] = GetResult(r => NetBean(r.nextLong(), r.nextIPAddr(), r.nextMacAddrOption())) val b = NetBean(34L, InetString("10.1.0.0/16"), Some(MacAddrString("12:34:56:78:90:ab"))) diff --git a/src/test/scala/com/github/tminglei/slickpg/PgRangeSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgRangeSupportSuite.scala index 57488c43..68e35cbf 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgRangeSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgRangeSupportSuite.scala @@ -39,7 +39,7 @@ class PgRangeSupportSuite extends AnyFunSuite with PostgresContainer { def odtRange = column[Option[Range[OffsetDateTime]]]("odt_range") def ldRange = column[Option[Range[LocalDate]]]("ld_range") - def * = (id, intRange, floatRange, tsRange, ldtRange, odtRange, ldRange) <> (RangeBean.tupled, RangeBean.unapply) + def * = (id, intRange, floatRange, tsRange, ldtRange, odtRange, ldRange) <> ((RangeBean.apply _).tupled, RangeBean.unapply) } val RangeTests = TableQuery[RangeTestTable] @@ -159,7 +159,7 @@ class PgRangeSupportSuite extends AnyFunSuite with PostgresContainer { test("Range Plain SQL support") { import MyPostgresProfile.plainAPI._ - implicit val getRangeBeanResult = GetResult(r => + implicit val getRangeBeanResult: GetResult[RangeBean] = GetResult(r => RangeBean(r.nextLong(), r.nextIntRange(), r.nextFloatRange(), r.nextTimestampRangeOption(), r.nextLocalDateTimeRangeOption(), r.nextOffsetDateTimeRangeOption(), r.nextLocalDateRangeOption())) diff --git a/src/test/scala/com/github/tminglei/slickpg/PgSearchSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgSearchSupportSuite.scala index 6945d802..410c8102 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgSearchSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgSearchSupportSuite.scala @@ -23,7 +23,7 @@ class PgSearchSupportSuite extends AnyFunSuite with PostgresContainer { def search = column[TsVector]("search") def comment = column[String]("comment") - def * = (id, text, search, comment) <> (TestBean.tupled, TestBean.unapply) + def * = (id, text, search, comment) <> ((TestBean.apply _).tupled, TestBean.unapply) } val Tests = TableQuery[TestTable] @@ -160,7 +160,7 @@ class PgSearchSupportSuite extends AnyFunSuite with PostgresContainer { case class SearchBean(id: Long, tVec: TsVector, tQ: TsQuery) - implicit val getSearchBeanResult = GetResult(r => SearchBean(r.nextLong(), r.nextTsVector(), r.nextTsQuery())) + implicit val getSearchBeanResult: GetResult[SearchBean] = GetResult(r => SearchBean(r.nextLong(), r.nextTsVector(), r.nextTsQuery())) val b = SearchBean(101L, TsVector("'ate' 'cat' 'fat' 'rat'"), TsQuery("'rat'")) diff --git a/src/test/scala/com/github/tminglei/slickpg/package.scala b/src/test/scala/com/github/tminglei/slickpg/package.scala index 29199870..2a5963aa 100644 --- a/src/test/scala/com/github/tminglei/slickpg/package.scala +++ b/src/test/scala/com/github/tminglei/slickpg/package.scala @@ -1,8 +1,8 @@ package com.github.tminglei import java.util.concurrent.Executors -import scala.concurrent.ExecutionContext +import scala.concurrent.{ExecutionContext, ExecutionContextExecutorService} package object slickpg { - implicit val testExecContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) + implicit val testExecContext: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4)) } From f14654d24b893a5033ffb724bb3c86373d819ef3 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Tue, 28 Nov 2023 13:58:55 +0000 Subject: [PATCH 02/14] fix more scala 3 compile errors --- README.md | 4 ++-- .../tminglei/slickpg/PgDateSupportJoda.scala | 3 --- .../slickpg/PgDateSupportJodaSuite.scala | 2 +- .../slickpg/PgPlayJsonSupportSuite.scala | 8 ++++++- .../slickpg/geom/PgPostGISExtensions.scala | 12 +++++----- .../slickpg/str/PgStringExtensions.scala | 4 ++-- .../main/scala/demo/MyPostgresDriver.scala | 2 +- .../app/util/MyPostgresDriver.scala | 2 +- .../tminglei/slickpg/PgDate2Support.scala | 1 - .../tminglei/slickpg/PgDateSupport.scala | 3 --- .../tminglei/slickpg/MyPostgresProfile.scala | 2 +- .../slickpg/PgArraySupportSuite.scala | 4 ++-- .../slickpg/PgCompositeSupportSuite.scala | 2 +- .../tminglei/slickpg/PgEnumSupportSuite.scala | 22 +++++++++---------- 14 files changed, 35 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 10c25464..eab4dc45 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ trait MyPostgresProfile extends ExPostgresProfile override val api = MyAPI object MyAPI extends ExtPostgresAPI with ArrayImplicits - with DateTimeImplicits + with Date2DateTimeImplicitsDuration with JsonImplicits with NetImplicits with LTreeImplicits @@ -91,7 +91,7 @@ class TestTable(tag: Tag) extends Table[Test](tag, Some("xxx"), "Test") { def props = column[Map[String,String]]("props_hstore") def tags = column[List[String]]("tags_arr") - def * = (id, during, location, text, props, tags) <> (Test.tupled, Test.unapply) + def * = (id, during, location, text, props, tags) <> ((Test.apply _).tupled, Test.unapply) } object tests extends TableQuery(new TestTable(_)) { diff --git a/addons/joda-time/src/main/scala/com/github/tminglei/slickpg/PgDateSupportJoda.scala b/addons/joda-time/src/main/scala/com/github/tminglei/slickpg/PgDateSupportJoda.scala index d15c8277..d4dc0dbe 100644 --- a/addons/joda-time/src/main/scala/com/github/tminglei/slickpg/PgDateSupportJoda.scala +++ b/addons/joda-time/src/main/scala/com/github/tminglei/slickpg/PgDateSupportJoda.scala @@ -22,9 +22,6 @@ trait PgDateSupportJoda extends date.PgDateExtensions with utils.PgCommonJdbcTyp } } - /// alias - trait DateTimeImplicits extends JodaDateTimeImplicits - trait JodaDateTimeFormatters { val jodaDateFormatter = ISODateTimeFormat.date() val jodaTimeFormatter = DateTimeFormat.forPattern("HH:mm:ss.SSSSSS") diff --git a/addons/joda-time/src/test/scala/com/github/tminglei/slickpg/PgDateSupportJodaSuite.scala b/addons/joda-time/src/test/scala/com/github/tminglei/slickpg/PgDateSupportJodaSuite.scala index 7c27f9ec..ed2c6ccc 100644 --- a/addons/joda-time/src/test/scala/com/github/tminglei/slickpg/PgDateSupportJodaSuite.scala +++ b/addons/joda-time/src/test/scala/com/github/tminglei/slickpg/PgDateSupportJodaSuite.scala @@ -18,7 +18,7 @@ class PgDateSupportJodaSuite extends AnyFunSuite with PostgresContainer { val plainAPI = new API with JodaDateTimePlainImplicits /// - trait API extends JdbcAPI with DateTimeImplicits + trait API extends JdbcAPI with JodaDateTimeImplicits } object MyPostgresProfile extends MyPostgresProfile diff --git a/addons/play-json/src/test/scala/com/github/tminglei/slickpg/PgPlayJsonSupportSuite.scala b/addons/play-json/src/test/scala/com/github/tminglei/slickpg/PgPlayJsonSupportSuite.scala index f9c81fa7..64384ccb 100644 --- a/addons/play-json/src/test/scala/com/github/tminglei/slickpg/PgPlayJsonSupportSuite.scala +++ b/addons/play-json/src/test/scala/com/github/tminglei/slickpg/PgPlayJsonSupportSuite.scala @@ -7,6 +7,7 @@ import play.api.libs.json._ import slick.jdbc.{GetResult, JdbcType, PostgresProfile} import com.github.tminglei.slickpg.utils.JsonUtils import org.scalatest.funsuite.AnyFunSuite +import play.api.libs.functional.syntax.toFunctionalBuilderOps import slick.ast.BaseTypedType @@ -15,7 +16,12 @@ class PgPlayJsonSupportSuite extends AnyFunSuite with PostgresContainer { case class JBean(name: String, count: Int) object JBean { - implicit val jbeanFmt: OFormat[JBean] = Json.format[JBean] + // jbeanFmt should just be this, but there's a bug in play-json for scala 3 that causes it to throw a java.lang.ClassCastException -- and we're not testing that here +// implicit val jbeanFmt: OFormat[JBean] = Json.format[JBean] + implicit val jbeanFmt: OFormat[JBean] = ( + (__ \ implicitly[JsonConfiguration].naming("name")).format[String] and + (__ \ implicitly[JsonConfiguration].naming("count")).format[Int] + )(JBean.apply _, x => (x.name, x.count)) implicit val jbeanWrt: OWrites[JBean] = Json.writes[JBean] } diff --git a/core/src/main/scala/com/github/tminglei/slickpg/geom/PgPostGISExtensions.scala b/core/src/main/scala/com/github/tminglei/slickpg/geom/PgPostGISExtensions.scala index 2c04914a..f3d95e4e 100644 --- a/core/src/main/scala/com/github/tminglei/slickpg/geom/PgPostGISExtensions.scala +++ b/core/src/main/scala/com/github/tminglei/slickpg/geom/PgPostGISExtensions.scala @@ -53,12 +53,12 @@ trait PgPostGISExtensions extends JdbcTypesComponent { driver: PostgresProfile = case Some(p) => om.column(GeomLibrary.LineFromEncodedPolyline, encodedPolyline.toNode, LiteralNode(p)) case None => om.column(GeomLibrary.LineFromEncodedPolyline, encodedPolyline.toNode) } - def makeBox[G1 <: GEOMETRY, P1, G2 <: GEOMETRY, P2, R](lowLeftPoint: Rep[P1], upRightPoint: Rep[P2])( - implicit tm: JdbcType[GEOMETRY], om: OptionMapperDSL.arg[G1, P1]#arg[G2, P2]#to[GEOMETRY, R]) = { + def makeBox[G <: GEOMETRY, P1, P2, R](lowLeftPoint: Rep[P1], upRightPoint: Rep[P2])( + implicit tm: JdbcType[GEOMETRY], om: OptionMapperDSL.arg[G, P1]#arg[G, P1]#to[GEOMETRY, R]) = { om.column(GeomLibrary.MakeBox, lowLeftPoint.toNode, upRightPoint.toNode) } - def makeBox3d[G1 <: GEOMETRY, P1, G2 <: GEOMETRY, P2, R](lowLeftPoint: Rep[P1], upRightPoint: Rep[P2])( - implicit tm: JdbcType[GEOMETRY], om: OptionMapperDSL.arg[G1, P1]#arg[G2, P2]#to[GEOMETRY, R]) = { + def makeBox3d[G <: GEOMETRY, P1, P2, R](lowLeftPoint: Rep[P1], upRightPoint: Rep[P2])( + implicit tm: JdbcType[GEOMETRY], om: OptionMapperDSL.arg[G, P1]#arg[G, P2]#to[GEOMETRY, R]) = { om.column(GeomLibrary.MakeBox3D, lowLeftPoint.toNode, upRightPoint.toNode) } def makeEnvelope(xmin: Rep[Double], ymin: Rep[Double], xmax: Rep[Double], ymax: Rep[Double], srid: Option[Int] = None)( @@ -75,8 +75,8 @@ trait PgPostGISExtensions extends JdbcTypesComponent { driver: PostgresProfile = case (None, Some(m)) => om.column(GeomLibrary.MakePointM, x.toNode, y.toNode, LiteralNode(m)) case (None, None) => om.column(GeomLibrary.MakePoint, x.toNode, y.toNode) } - def makeLine[G1 <: GEOMETRY, P1, G2 <: GEOMETRY, P2, R](point1: Rep[P1], point2: Rep[P2])( - implicit tm: JdbcType[GEOMETRY], om: OptionMapperDSL.arg[G1, P1]#arg[G2, P2]#to[GEOMETRY, R]) = { + def makeLine[G <: GEOMETRY, P1, P2, R](point1: Rep[P1], point2: Rep[P2])( + implicit tm: JdbcType[GEOMETRY], om: OptionMapperDSL.arg[G, P1]#arg[G, P2]#to[GEOMETRY, R]) = { om.column(GeomLibrary.MakeLine, point1.toNode, point2.toNode) } def makePolygon[G <: GEOMETRY, P, R](linestring: Rep[P])( diff --git a/core/src/main/scala/com/github/tminglei/slickpg/str/PgStringExtensions.scala b/core/src/main/scala/com/github/tminglei/slickpg/str/PgStringExtensions.scala index a3e28cd5..77f1db0c 100644 --- a/core/src/main/scala/com/github/tminglei/slickpg/str/PgStringExtensions.scala +++ b/core/src/main/scala/com/github/tminglei/slickpg/str/PgStringExtensions.scala @@ -27,7 +27,7 @@ trait PgStringExtensions extends JdbcTypesComponent { driver: PostgresProfile => } class PgStringColumnExtensionMethods[P1](val c: Rep[P1]) extends ExtensionMethods[String, P1] { - protected implicit def b1Type = implicitly[TypedType[String]] + protected def b1Type = implicitly[TypedType[String]] def ilike[P2, R](e: Rep[P2])(implicit om: o#arg[String, P2]#to[Boolean, R]) = { om.column(StringLibrary.ILike, n, e.toNode) @@ -58,7 +58,7 @@ trait PgStringExtensions extends JdbcTypesComponent { driver: PostgresProfile => } class PgStringByteaColumnExtensionMethods[P1](val c: Rep[P1]) extends ExtensionMethods[Array[Byte], P1] { - protected implicit def b1Type = implicitly[TypedType[Array[Byte]]] + protected def b1Type = implicitly[TypedType[Array[Byte]]] def convert[R](srcEncoding: Rep[String], destEncoding: Rep[String])(implicit om: o#to[Array[Byte], R]) = { om.column(StringLibrary.Convert, n, srcEncoding.toNode, destEncoding.toNode) diff --git a/examples/codegen-customization/codegen/src/main/scala/demo/MyPostgresDriver.scala b/examples/codegen-customization/codegen/src/main/scala/demo/MyPostgresDriver.scala index 4d4e2c64..82493b33 100644 --- a/examples/codegen-customization/codegen/src/main/scala/demo/MyPostgresDriver.scala +++ b/examples/codegen-customization/codegen/src/main/scala/demo/MyPostgresDriver.scala @@ -16,7 +16,7 @@ trait MyPostgresDriver extends ExPostgresProfile ////// trait MyAPI extends ExtPostgresAPI with ArrayImplicits - with DateTimeImplicits + with Date2DateTimeImplicitsDuration with RangeImplicits with HStoreImplicits with SearchImplicits diff --git a/examples/play-slick-example/app/util/MyPostgresDriver.scala b/examples/play-slick-example/app/util/MyPostgresDriver.scala index c0dc8bb3..f9893229 100644 --- a/examples/play-slick-example/app/util/MyPostgresDriver.scala +++ b/examples/play-slick-example/app/util/MyPostgresDriver.scala @@ -15,7 +15,7 @@ trait MyPostgresDriver extends ExPostgresDriver override val pgjson = "jsonb" /// override val api = new ExtPostgresAPI with ArrayImplicits - with DateTimeImplicits + with Date2DateTimeImplicitsDuration with PlayJsonImplicits with NetImplicits with LTreeImplicits diff --git a/src/main/scala/com/github/tminglei/slickpg/PgDate2Support.scala b/src/main/scala/com/github/tminglei/slickpg/PgDate2Support.scala index 271a7965..a480fa8a 100644 --- a/src/main/scala/com/github/tminglei/slickpg/PgDate2Support.scala +++ b/src/main/scala/com/github/tminglei/slickpg/PgDate2Support.scala @@ -29,7 +29,6 @@ trait PgDate2Support extends date.PgDateExtensions with utils.PgCommonJdbcTypes } /// alias - trait DateTimeImplicits extends Date2DateTimeImplicitsDuration trait DateTimeImplicitsPeriod extends Date2DateTimeImplicitsPeriod trait Date2DateTimeImplicitsDuration extends Date2DateTimeImplicits[Duration] diff --git a/src/main/scala/com/github/tminglei/slickpg/PgDateSupport.scala b/src/main/scala/com/github/tminglei/slickpg/PgDateSupport.scala index e8d57e9e..2900a60d 100644 --- a/src/main/scala/com/github/tminglei/slickpg/PgDateSupport.scala +++ b/src/main/scala/com/github/tminglei/slickpg/PgDateSupport.scala @@ -8,9 +8,6 @@ import slick.jdbc.{JdbcType, PostgresProfile} trait PgDateSupport extends date.PgDateExtensions with utils.PgCommonJdbcTypes with date.PgDateJdbcTypes { driver: PostgresProfile => import driver.api._ - /// alias - trait DateTimeImplicits extends SimpleDateTimeImplicits - trait SimpleDateTimeImplicits { implicit val simpleIntervalTypeMapper: JdbcType[Interval] = new GenericJdbcType[Interval]("interval", Interval.apply, hasLiteralForm=false) implicit val simpleTimestampTZTypeMapper: JdbcType[Calendar] = new GenericDateJdbcType[Calendar]("timestamptz", java.sql.Types.TIMESTAMP_WITH_TIMEZONE) diff --git a/src/test/scala/com/github/tminglei/slickpg/MyPostgresProfile.scala b/src/test/scala/com/github/tminglei/slickpg/MyPostgresProfile.scala index aaa4ad6a..262ce7ee 100644 --- a/src/test/scala/com/github/tminglei/slickpg/MyPostgresProfile.scala +++ b/src/test/scala/com/github/tminglei/slickpg/MyPostgresProfile.scala @@ -17,7 +17,7 @@ trait MyPostgresProfile extends ExPostgresProfile trait MyAPI extends ExtPostgresAPI with ArrayImplicits with SimpleDateTimeImplicits - with DateTimeImplicits + with Date2DateTimeImplicitsDuration with SimpleJsonImplicits with NetImplicits with LTreeImplicits diff --git a/src/test/scala/com/github/tminglei/slickpg/PgArraySupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgArraySupportSuite.scala index ebedc166..3eab1890 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgArraySupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgArraySupportSuite.scala @@ -126,7 +126,7 @@ class PgArraySupportSuite extends AnyFunSuite with PostgresContainer { r => assert(List(testRec2) === r) ), // @> - ArrayTests.filter(_.strArr @> Vector("str3")).sortBy(_.id).to[List].result.map( + ArrayTests.filter(_.strArr @> (Vector("str3"): Rep[Vector[String]])).sortBy(_.id).to[List].result.map( r => assert(List(testRec1, testRec2, testRec3) === r) ), ArrayTests.filter(_.mktFinancialProducts @> List(MarketFinancialProduct("product1"))).sortBy(_.id).to[List].result.map( @@ -255,7 +255,7 @@ class PgArraySupportSuite extends AnyFunSuite with PostgresContainer { sqlu"insert into ArrayTest1 values(${b.id}, ${b.bytea}, ${b.uuidArr}, ${b.strArr}, ${b.longArr}, ${b.intArr}, ${b.shortArr}, ${b.floatArr}, ${b.doubleArr}, ${b.boolArr}, ${b.dateArr}, ${b.timeArr}, ${b.tsArr}, ${b.institutionArr})", sql"select * from ArrayTest1 where id = ${b.id}".as[ArrayBean1].head.map( f => { - b.bytea.zip(f.bytea).map(r => assert(r._1 === r._2)) + b.bytea.toSeq.zip(f.bytea.toSeq).map(r => assert(r._1 === r._2)) b.uuidArr.zip(f.uuidArr).map(r => assert(r._1 === r._2)) b.strArr.getOrElse(Nil).zip(f.strArr.getOrElse(Nil)).map(r => assert(r._1 === r._2)) b.longArr.zip(f.longArr).map(r => assert(r._1 === r._2)) diff --git a/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala index 6de40861..2bbbbcd5 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala @@ -77,7 +77,7 @@ object PgCompositeSupportSuite { } override val api: API = new API {} - val plainImplicits = new API with SimpleArrayPlainImplicits { + object plainImplicits extends API with SimpleArrayPlainImplicits { import utils.PlainSQLUtils._ // to support 'nextArray[T]/nextArrayOption[T]' in PgArraySupport { diff --git a/src/test/scala/com/github/tminglei/slickpg/PgEnumSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgEnumSupportSuite.scala index 4b90fbec..987f3ecf 100644 --- a/src/test/scala/com/github/tminglei/slickpg/PgEnumSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgEnumSupportSuite.scala @@ -27,8 +27,8 @@ class PgEnumSupportSuite extends AnyFunSuite with PostgresContainer { def values = _values map (v => (v.toString, v)) toMap } - object Currency extends Enum[Currency] sealed trait Currency extends Currency.Value + object Currency extends Enum[Currency] case object EUR extends Currency case object GBP extends Currency case object USD extends Currency @@ -60,10 +60,10 @@ class PgEnumSupportSuite extends AnyFunSuite with PostgresContainer { implicit val rainbowTypeMapper: JdbcType[Rainbows.Value] = createEnumJdbcType[Rainbows.type]("Rainbow", Rainbows, true) implicit val rainbowListTypeMapper: JdbcType[List[Rainbows.Value]] = createEnumListJdbcType[Rainbows.type]("Rainbow", Rainbows, true) - implicit val weekDayColumnExtensionMethodsBuilder: api.Rep[WeekDays.Value] => EnumColumnExtensionMethods[WeekDays.Value, WeekDays.Value] = createEnumColumnExtensionMethodsBuilder[WeekDays.type](WeekDays) - implicit val weekDayOptionColumnExtensionMethodsBuilder: api.Rep[Option[WeekDays.Value]] => EnumColumnExtensionMethods[WeekDays.Value, Option[WeekDays.Value]] = createEnumOptionColumnExtensionMethodsBuilder[WeekDays.type](WeekDays) - implicit val rainbowColumnExtensionMethodsBuilder: api.Rep[Rainbows.Value] => EnumColumnExtensionMethods[Rainbows.Value, Rainbows.Value] = createEnumColumnExtensionMethodsBuilder[Rainbows.type](Rainbows) - implicit val rainbowOptionColumnExtensionMethodsBuilder: api.Rep[Option[Rainbows.Value]] => EnumColumnExtensionMethods[Rainbows.Value, Option[Rainbows.Value]] = createEnumOptionColumnExtensionMethodsBuilder[Rainbows.type](Rainbows) + implicit def weekDayColumnExtensionMethodsBuilder(rep: Rep[WeekDays.Value]): EnumColumnExtensionMethods[WeekDays.Value, WeekDays.Value] = createEnumColumnExtensionMethodsBuilder[WeekDays.type](WeekDays).apply(rep) + implicit def weekDayOptionColumnExtensionMethodsBuilder(rep: Rep[Option[WeekDays.Value]]): EnumColumnExtensionMethods[WeekDays.Value, Option[WeekDays.Value]] = createEnumOptionColumnExtensionMethodsBuilder[WeekDays.type](WeekDays).apply(rep) + implicit def rainbowColumnExtensionMethodsBuilder(rep: Rep[Rainbows.Value]): EnumColumnExtensionMethods[Rainbows.Value, Rainbows.Value] = createEnumColumnExtensionMethodsBuilder[Rainbows.type](Rainbows).apply(rep) + implicit def rainbowOptionColumnExtensionMethodsBuilder(rep: Rep[Option[Rainbows.Value]]): EnumColumnExtensionMethods[Rainbows.Value, Option[Rainbows.Value]] = createEnumOptionColumnExtensionMethodsBuilder[Rainbows.type](Rainbows).apply(rep) /// custom types of java enums and algebraic data type (ADT) implicit val currencyTypeMapper: JdbcType[Currency] = createEnumJdbcType[Currency]("Currency", _.toString, Currency.values.get(_).get, quoteName = false) @@ -73,12 +73,12 @@ class PgEnumSupportSuite extends AnyFunSuite with PostgresContainer { implicit val genderTypeMapper: JdbcType[Gender] = createEnumJdbcType[Gender]("Gender", _.repr, Gender.fromString, quoteName = false) implicit val genderTypeListMapper: JdbcType[List[Gender]] = createEnumListJdbcType[Gender]("Gender", _.repr, Gender.fromString, quoteName = false) - implicit val currencyColumnExtensionMethodsBuilder: api.Rep[Currency] => EnumColumnExtensionMethods[Currency, Currency] = createEnumColumnExtensionMethodsBuilder[Currency] - implicit val currencyOptionColumnExtensionMethodsBuilder: api.Rep[Option[Currency]] => EnumColumnExtensionMethods[Currency, Option[Currency]] = createEnumOptionColumnExtensionMethodsBuilder[Currency] - implicit val languagesColumnExtensionMethodsBuilder: api.Rep[Languages] => EnumColumnExtensionMethods[Languages, Languages] = createEnumColumnExtensionMethodsBuilder[Languages] - implicit val languagesOptionColumnExtensionMethodsBuilder: api.Rep[Option[Languages]] => EnumColumnExtensionMethods[Languages, Option[Languages]] = createEnumOptionColumnExtensionMethodsBuilder[Languages] - implicit val genderColumnExtensionMethodsBuilder: api.Rep[Gender] => EnumColumnExtensionMethods[Gender, Gender] = createEnumColumnExtensionMethodsBuilder[Gender] - implicit val genderOptionColumnExtensionMethodsBuilder: api.Rep[Option[Gender]] => EnumColumnExtensionMethods[Gender, Option[Gender]] = createEnumOptionColumnExtensionMethodsBuilder[Gender] + implicit def currencyColumnExtensionMethodsBuilder(rep: Rep[Currency]): EnumColumnExtensionMethods[Currency, Currency] = createEnumColumnExtensionMethodsBuilder[Currency].apply(rep) + implicit def currencyOptionColumnExtensionMethodsBuilder(rep: Rep[Option[Currency]]): EnumColumnExtensionMethods[Currency, Option[Currency]] = createEnumOptionColumnExtensionMethodsBuilder[Currency].apply(rep) + implicit def languagesColumnExtensionMethodsBuilder(rep: Rep[Languages]): EnumColumnExtensionMethods[Languages, Languages] = createEnumColumnExtensionMethodsBuilder[Languages].apply(rep) + implicit def languagesOptionColumnExtensionMethodsBuilder(rep: Rep[Option[Languages]]): EnumColumnExtensionMethods[Languages, Option[Languages]] = createEnumOptionColumnExtensionMethodsBuilder[Languages].apply(rep) + implicit def genderColumnExtensionMethodsBuilder(rep: Rep[Gender]): EnumColumnExtensionMethods[Gender, Gender] = createEnumColumnExtensionMethodsBuilder[Gender].apply(rep) + implicit def genderOptionColumnExtensionMethodsBuilder(rep: Rep[Option[Gender]]): EnumColumnExtensionMethods[Gender, Option[Gender]] = createEnumOptionColumnExtensionMethodsBuilder[Gender].apply(rep) } } object MyPostgresProfile1 extends MyPostgresProfile1 From 6fd4690849a91d2d86de4ebd4d8f0af24d0ebd96 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Tue, 28 Nov 2023 17:19:32 +0000 Subject: [PATCH 03/14] exclude CompositeSupport for scala 3 --- build.sbt | 7 +- .../composite/PgCompositeExtensions.scala | 3 +- .../tminglei/slickpg/composite/README.md | 0 .../slickpg/utils/TypeConverters.scala | 0 .../composite/PgCompositeExtensions.scala | 14 ++++ .../tminglei/slickpg/composite/README.md | 4 ++ .../slickpg/utils/TypeConverters.scala | 68 +++++++++++++++++++ .../slickpg/utils/PlainSQLUtils.scala | 13 ++-- .../tminglei/slickpg/PgCompositeSupport.scala | 0 .../tminglei/slickpg/PgCompositeSupport.scala | 41 +++++++++++ .../tminglei/slickpg/PgArraySupport.scala | 8 +-- .../slickpg/PgCompositeSupportSuite.scala | 0 12 files changed, 141 insertions(+), 17 deletions(-) rename core/src/main/{scala => scala-2}/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala (79%) rename core/src/main/{scala => scala-2}/com/github/tminglei/slickpg/composite/README.md (100%) rename core/src/main/{scala => scala-2}/com/github/tminglei/slickpg/utils/TypeConverters.scala (100%) create mode 100644 core/src/main/scala-3/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala create mode 100644 core/src/main/scala-3/com/github/tminglei/slickpg/composite/README.md create mode 100644 core/src/main/scala-3/com/github/tminglei/slickpg/utils/TypeConverters.scala rename src/main/{scala => scala-2}/com/github/tminglei/slickpg/PgCompositeSupport.scala (100%) create mode 100644 src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala rename src/test/{scala => scala-2}/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala (100%) diff --git a/build.sbt b/build.sbt index b167c36d..7afc1ab6 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,6 @@ val scala212 = "2.12.18" val scala213 = "2.13.12" +val scala3 = "3.3.1" lazy val commonSettings = Seq( organizationName := "slick-pg", @@ -8,7 +9,7 @@ lazy val commonSettings = Seq( version := "0.22.0-M4", scalaVersion := scala213, - crossScalaVersions := Seq(scala212, scala213), + crossScalaVersions := Seq(scala212, scala213, scala3), scalacOptions ++= Seq("-deprecation", "-feature", "-language:implicitConversions", "-language:reflectiveCalls", @@ -64,7 +65,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", @@ -145,7 +146,7 @@ lazy val slickPgPlayJson = (project in file("./addons/play-json")) name := "slick-pg_play-json", description := "Slick extensions for PostgreSQL - play-json module", libraryDependencies := mainDependencies(scalaVersion.value) ++ - Seq("com.typesafe.play" %% "play-json" % "2.9.4") + Seq("org.playframework" %% "play-json" % "3.0.1") ) .dependsOn (slickPgCore % "test->test;compile->compile") diff --git a/core/src/main/scala/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala b/core/src/main/scala-2/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala similarity index 79% rename from core/src/main/scala/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala rename to core/src/main/scala-2/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala index c4f71751..7a9f4bf7 100644 --- a/core/src/main/scala/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala +++ b/core/src/main/scala-2/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala @@ -1,5 +1,4 @@ -package com.github.tminglei.slickpg -package composite +package com.github.tminglei.slickpg.composite import slick.jdbc.{JdbcTypesComponent, PostgresProfile} diff --git a/core/src/main/scala/com/github/tminglei/slickpg/composite/README.md b/core/src/main/scala-2/com/github/tminglei/slickpg/composite/README.md similarity index 100% rename from core/src/main/scala/com/github/tminglei/slickpg/composite/README.md rename to core/src/main/scala-2/com/github/tminglei/slickpg/composite/README.md diff --git a/core/src/main/scala/com/github/tminglei/slickpg/utils/TypeConverters.scala b/core/src/main/scala-2/com/github/tminglei/slickpg/utils/TypeConverters.scala similarity index 100% rename from core/src/main/scala/com/github/tminglei/slickpg/utils/TypeConverters.scala rename to core/src/main/scala-2/com/github/tminglei/slickpg/utils/TypeConverters.scala diff --git a/core/src/main/scala-3/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala b/core/src/main/scala-3/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala new file mode 100644 index 00000000..04e52248 --- /dev/null +++ b/core/src/main/scala-3/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala @@ -0,0 +1,14 @@ +package com.github.tminglei.slickpg.composite + +import izumi.reflect.macrortti.LightTypeTag +import izumi.reflect.Tag +import slick.jdbc.{JdbcTypesComponent, PostgresProfile} +import scala.annotation.static +import scala.collection.concurrent.TrieMap +import scala.reflect.{classTag, ClassTag} + +trait Struct extends AnyRef + +trait PgCompositeExtensions extends JdbcTypesComponent { driver: PostgresProfile => + //TODO not implemented by now +} diff --git a/core/src/main/scala-3/com/github/tminglei/slickpg/composite/README.md b/core/src/main/scala-3/com/github/tminglei/slickpg/composite/README.md new file mode 100644 index 00000000..7dda284d --- /dev/null +++ b/core/src/main/scala-3/com/github/tminglei/slickpg/composite/README.md @@ -0,0 +1,4 @@ +Supported Composite type Oper/Functions +--------------------------------------- + +_ps: only type mapper supported currently_ diff --git a/core/src/main/scala-3/com/github/tminglei/slickpg/utils/TypeConverters.scala b/core/src/main/scala-3/com/github/tminglei/slickpg/utils/TypeConverters.scala new file mode 100644 index 00000000..9226bfec --- /dev/null +++ b/core/src/main/scala-3/com/github/tminglei/slickpg/utils/TypeConverters.scala @@ -0,0 +1,68 @@ +package com.github.tminglei.slickpg +package utils + +import izumi.reflect.{Tag => TTag} +import izumi.reflect.macrortti.LightTypeTag +import slick.util.Logging +import java.sql.{Date, Time, Timestamp} +import java.time.{LocalDate, LocalDateTime, LocalTime} +import java.util.UUID + +object TypeConverters extends Logging { + case class ConvConfig(from: LightTypeTag, to: LightTypeTag, var conv: (_ => _)) + + private var convConfigList = List[ConvConfig]() + + // register basic converters + register((v: String) => v.toInt) + register((v: String) => v.toLong) + register((v: String) => v.toShort) + register((v: String) => v.toFloat) + register((v: String) => v.toDouble) + register((v: String) => pgBoolAdjust(v).toBoolean) + register((v: String) => v.toByte) + register((v: String) => UUID.fromString(v)) + // register date/time converters + register((v: String) => Date.valueOf(v)) + register((v: String) => Time.valueOf(v)) + register((v: String) => Timestamp.valueOf(v)) + register((v: Date) => v.toString) + register((v: Time) => v.toString) + register((v: Timestamp) => v.toString) + register((v: String) => LocalDate.parse(v)) + register((v: String) => LocalTime.parse(v)) + register((v: String) => LocalDateTime.parse(v.replace(' ', 'T'))) + register((v: LocalDate) => v.toString) + register((v: LocalTime) => v.toString) + register((v: LocalDateTime) => v.toString) + + def register[FROM, TO](convert: (FROM => TO))(implicit from: TTag[FROM], to: TTag[TO]) = { + logger.info(s"register converter for ${from.tag.repr} => ${to.tag.repr}") + find(from.tag, to.tag).map(_.conv = convert).orElse({ + convConfigList :+= ConvConfig(from.tag, to.tag, convert) + None + }) + } + + 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}")) + } + + /// + private def pgBoolAdjust(s: String): String = + Option(s).map(_.toLowerCase) match { + case Some("t") => "true" + case Some("f") => "false" + case _ => s + } + + def find(from: LightTypeTag, to: LightTypeTag): Option[ConvConfig] = { + logger.debug(s"get converter for ${from.repr} => ${to.repr}") + convConfigList.find(e => (e.from =:= from && e.to =:= to)).orElse({ + if (from <:< to) { + Some(ConvConfig(from, to, (v: Any) => v)) + } else None + }) + } +} diff --git a/core/src/main/scala/com/github/tminglei/slickpg/utils/PlainSQLUtils.scala b/core/src/main/scala/com/github/tminglei/slickpg/utils/PlainSQLUtils.scala index f11c25bf..8928afbc 100644 --- a/core/src/main/scala/com/github/tminglei/slickpg/utils/PlainSQLUtils.scala +++ b/core/src/main/scala/com/github/tminglei/slickpg/utils/PlainSQLUtils.scala @@ -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.repr} \u001B[0m") + val convKey = ttag.tag.repr 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.repr}!!! \u001B[36m If it's expected, pls ignore it.\u001B[0m" ) nextArrayConverters += (convKey -> conv) - } } /// diff --git a/src/main/scala/com/github/tminglei/slickpg/PgCompositeSupport.scala b/src/main/scala-2/com/github/tminglei/slickpg/PgCompositeSupport.scala similarity index 100% rename from src/main/scala/com/github/tminglei/slickpg/PgCompositeSupport.scala rename to src/main/scala-2/com/github/tminglei/slickpg/PgCompositeSupport.scala diff --git a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala new file mode 100644 index 00000000..fef8c99e --- /dev/null +++ b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala @@ -0,0 +1,41 @@ +package com.github.tminglei.slickpg + +import izumi.reflect.macrortti.LightTypeTag +import izumi.reflect.{Tag => TTag} + +import scala.reflect.{ClassTag, classTag} +import composite.Struct +import slick.jdbc.{PositionedResult, PostgresProfile} +import slick.jdbc.SetParameter + +import scala.deriving.* +import scala.compiletime.{error, erasedValue, summonInline} + +trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcTypes { driver: PostgresProfile => + + protected lazy val emptyMembersAsNull = true + + //--- + def createCompositeJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]): GenericJdbcType[T] = + throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") + + def createCompositeArrayJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]): AdvancedArrayJdbcType[T] = + throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") + + /// Plain SQL support + def nextComposite[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = + throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") + def nextCompositeArray[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = + throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") + + def createCompositeSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = + throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") + + def createCompositeOptionSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = + throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") + def createCompositeArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = { + throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") + } + def createCompositeOptionArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = + throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +} diff --git a/src/main/scala/com/github/tminglei/slickpg/PgArraySupport.scala b/src/main/scala/com/github/tminglei/slickpg/PgArraySupport.scala index 35f6b47c..04772df4 100644 --- a/src/main/scala/com/github/tminglei/slickpg/PgArraySupport.scala +++ b/src/main/scala/com/github/tminglei/slickpg/PgArraySupport.scala @@ -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 => @@ -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.repr).map(_.apply(r)) .getOrElse(simpleNextArray[T](r)).asInstanceOf[Option[Seq[T]]] } } diff --git a/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala b/src/test/scala-2/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala similarity index 100% rename from src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala rename to src/test/scala-2/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala From ab26dfdcb76493d45374a4bba860884170dba7c0 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Tue, 28 Nov 2023 17:26:46 +0000 Subject: [PATCH 04/14] add scala 3.3.1 to build matric --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3de36825..3f5ce4f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: java: [8, 11] - scala: [2.12.18, 2.13.12] + scala: [2.12.18, 2.13.12, 3.3.1] postgres: [11, 12, 13, 14] name: Test (Postgres ${{ matrix.postgres }} Scala ${{ matrix.scala }} Java ${{ matrix.java }}) runs-on: ubuntu-latest From 6ffb7b29824aa37398ee14f1dd189ca4b1927ad5 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Tue, 28 Nov 2023 17:28:19 +0000 Subject: [PATCH 05/14] whoops, build --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 7afc1ab6..5b280a27 100644 --- a/build.sbt +++ b/build.sbt @@ -73,7 +73,7 @@ def mainDependencies(scalaVersion: String) = { "org.scalatest" %% "scalatest" % "3.2.17" % "test", "com.dimafeng" %% "testcontainers-scala-scalatest" % "0.40.17" % "test", "com.dimafeng" %% "testcontainers-scala-postgresql" % "0.40.17" % "test" - ) + ) ++ (if (scalaVersion.startsWith("3")) Nil else Seq("org.scala-lang" % "scala-reflect" % scalaVersion)) } lazy val slickPgCore = (project in file("./core")) From d924a60f14520f2068ef308949986a4c439a9dd0 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Tue, 28 Nov 2023 18:04:29 +0000 Subject: [PATCH 06/14] bump M --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 5b280a27..a99d0189 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ lazy val commonSettings = Seq( organizationName := "slick-pg", organization := "com.github.tminglei", name := "slick-pg", - version := "0.22.0-M4", + version := "0.22.0-M5", scalaVersion := scala213, crossScalaVersions := Seq(scala212, scala213, scala3), @@ -66,7 +66,7 @@ def mainDependencies(scalaVersion: String) = { Seq ( "org.scala-lang.modules" %% "scala-parser-combinators" % "2.3.0", "dev.zio" %% "izumi-reflect" % "2.3.8", - "com.typesafe.slick" %% "slick" % "3.5.0-M4", + "com.typesafe.slick" %% "slick" % "3.5.0-M5", "org.postgresql" % "postgresql" % "42.6.0", "org.scala-lang.modules" %% "scala-collection-compat" % "2.11.0", "org.slf4j" % "slf4j-simple" % "2.0.9" % "provided", From 3d9d4b9be97169dbebf1cb1416a7d01e0c6905b1 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Wed, 6 Dec 2023 23:39:47 +0000 Subject: [PATCH 07/14] comment out methods so as not to lead to misuse --- .../tminglei/slickpg/PgCompositeSupport.scala | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala index fef8c99e..7c059027 100644 --- a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala +++ b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala @@ -14,28 +14,28 @@ import scala.compiletime.{error, erasedValue, summonInline} trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcTypes { driver: PostgresProfile => protected lazy val emptyMembersAsNull = true - - //--- - def createCompositeJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]): GenericJdbcType[T] = - throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") - - def createCompositeArrayJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]): AdvancedArrayJdbcType[T] = - throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") - - /// Plain SQL support - def nextComposite[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = - throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") - def nextCompositeArray[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = - throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") - - def createCompositeSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = - throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") - - def createCompositeOptionSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = - throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") - def createCompositeArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = { - throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") - } - def createCompositeOptionArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = - throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +// +// //--- +// def createCompositeJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]): GenericJdbcType[T] = +// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +// +// def createCompositeArrayJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]): AdvancedArrayJdbcType[T] = +// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +// +// /// Plain SQL support +// def nextComposite[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = +// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +// def nextCompositeArray[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = +// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +// +// def createCompositeSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = +// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +// +// def createCompositeOptionSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = +// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +// def createCompositeArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = { +// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") +// } +// def createCompositeOptionArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = +// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") } From 7318a7f28fe175590a3d7550fb9c9dd1c01eacbe Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Thu, 7 Dec 2023 13:53:04 +0000 Subject: [PATCH 08/14] Implement struct support for scala 3 --- .../composite/PgCompositeExtensions.scala | 2 +- .../slickpg/utils/TypeConverters.scala | 76 ++--- .../slickpg/TypeTagSupportSuite.scala | 23 ++ .../tminglei/slickpg/PgCompositeSupport.scala | 16 +- .../tminglei/slickpg/PgCompositeSupport.scala | 243 ++++++++++++-- .../slickpg/PgCompositeSupportSuite.scala | 317 ++++++++++++++++++ 6 files changed, 603 insertions(+), 74 deletions(-) create mode 100644 core/src/test/scala/com/github/tminglei/slickpg/TypeTagSupportSuite.scala create mode 100644 src/test/scala-3/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala diff --git a/core/src/main/scala-2/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala b/core/src/main/scala-2/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala index 7a9f4bf7..31869062 100644 --- a/core/src/main/scala-2/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala +++ b/core/src/main/scala-2/com/github/tminglei/slickpg/composite/PgCompositeExtensions.scala @@ -2,7 +2,7 @@ package com.github.tminglei.slickpg.composite import slick.jdbc.{JdbcTypesComponent, PostgresProfile} -trait Struct extends AnyRef +trait Struct extends Product trait PgCompositeExtensions extends JdbcTypesComponent { driver: PostgresProfile => //TODO not implemented by now diff --git a/core/src/main/scala-3/com/github/tminglei/slickpg/utils/TypeConverters.scala b/core/src/main/scala-3/com/github/tminglei/slickpg/utils/TypeConverters.scala index 9226bfec..7fb8f191 100644 --- a/core/src/main/scala-3/com/github/tminglei/slickpg/utils/TypeConverters.scala +++ b/core/src/main/scala-3/com/github/tminglei/slickpg/utils/TypeConverters.scala @@ -8,46 +8,51 @@ import java.sql.{Date, Time, Timestamp} import java.time.{LocalDate, LocalDateTime, LocalTime} import java.util.UUID +case class RegisteredTypeConverter[From, To](convert: From => To) + object TypeConverters extends Logging { case class ConvConfig(from: LightTypeTag, to: LightTypeTag, var conv: (_ => _)) private var convConfigList = List[ConvConfig]() // register basic converters - register((v: String) => v.toInt) - register((v: String) => v.toLong) - register((v: String) => v.toShort) - register((v: String) => v.toFloat) - register((v: String) => v.toDouble) - register((v: String) => pgBoolAdjust(v).toBoolean) - register((v: String) => v.toByte) - register((v: String) => UUID.fromString(v)) + implicit val StringToInt: RegisteredTypeConverter[String, Int] = RegisteredTypeConverter[String, Int](_.toInt) + implicit val StringToLong: RegisteredTypeConverter[String, Long] = RegisteredTypeConverter(_.toLong) + implicit val StringToShort: RegisteredTypeConverter[String, Short] = RegisteredTypeConverter(_.toShort) + implicit val StringToFloat: RegisteredTypeConverter[String, Float] = RegisteredTypeConverter(_.toFloat) + implicit val StringToDouble: RegisteredTypeConverter[String, Double] = RegisteredTypeConverter(_.toDouble) + implicit val StringToBoolean: RegisteredTypeConverter[String, Boolean] = RegisteredTypeConverter(pgBoolAdjust(_).toBoolean) + implicit val StringToByte: RegisteredTypeConverter[String, Byte] = RegisteredTypeConverter(_.toByte) + implicit val StringToUUID: RegisteredTypeConverter[String, UUID] = RegisteredTypeConverter(UUID.fromString) + implicit val IntToString: RegisteredTypeConverter[Int, String] = RegisteredTypeConverter(_.toString) + implicit val LongToString: RegisteredTypeConverter[Long, String] = RegisteredTypeConverter(_.toString) + implicit val ShortToString: RegisteredTypeConverter[Short, String] = RegisteredTypeConverter(_.toString) + implicit val FloatToString: RegisteredTypeConverter[Float, String] = RegisteredTypeConverter(_.toString) + implicit val DoubleToString: RegisteredTypeConverter[Double, String] = RegisteredTypeConverter(_.toString) + implicit val BooleanToString: RegisteredTypeConverter[Boolean, String] = RegisteredTypeConverter(_.toString.take(1)) + implicit val ByteToString: RegisteredTypeConverter[Byte, String] = RegisteredTypeConverter(_.toString) + implicit val UUIDToString: RegisteredTypeConverter[UUID, String] = RegisteredTypeConverter(_.toString) + implicit val StringToString: RegisteredTypeConverter[String, String] = RegisteredTypeConverter(identity) // register date/time converters - register((v: String) => Date.valueOf(v)) - register((v: String) => Time.valueOf(v)) - register((v: String) => Timestamp.valueOf(v)) - register((v: Date) => v.toString) - register((v: Time) => v.toString) - register((v: Timestamp) => v.toString) - register((v: String) => LocalDate.parse(v)) - register((v: String) => LocalTime.parse(v)) - register((v: String) => LocalDateTime.parse(v.replace(' ', 'T'))) - register((v: LocalDate) => v.toString) - register((v: LocalTime) => v.toString) - register((v: LocalDateTime) => v.toString) + implicit val StringToDate: RegisteredTypeConverter[String, Date] = RegisteredTypeConverter(Date.valueOf) + implicit val StringToTime: RegisteredTypeConverter[String, Time] = RegisteredTypeConverter(Time.valueOf) + implicit val StringToTimestamp: RegisteredTypeConverter[String, Timestamp] = RegisteredTypeConverter(Timestamp.valueOf) + implicit val DateToString: RegisteredTypeConverter[Date, String] = RegisteredTypeConverter(_.toString) + implicit val TimeToString: RegisteredTypeConverter[Time, String] = RegisteredTypeConverter(_.toString) + implicit val TimestampToString: RegisteredTypeConverter[Timestamp, String] = RegisteredTypeConverter(_.toString) + + implicit val StringToLocalDate: RegisteredTypeConverter[String, LocalDate] = RegisteredTypeConverter(LocalDate.parse) + implicit val StringToLocalTime: RegisteredTypeConverter[String, LocalTime] = RegisteredTypeConverter(LocalTime.parse) + + implicit val StringToLocalDateTime: RegisteredTypeConverter[String, LocalDateTime] = + RegisteredTypeConverter(v => LocalDateTime.parse(v.replace(' ', 'T'))) - def register[FROM, TO](convert: (FROM => TO))(implicit from: TTag[FROM], to: TTag[TO]) = { - logger.info(s"register converter for ${from.tag.repr} => ${to.tag.repr}") - find(from.tag, to.tag).map(_.conv = convert).orElse({ - convConfigList :+= ConvConfig(from.tag, to.tag, convert) - None - }) - } + implicit val LocalDateToString: RegisteredTypeConverter[LocalDate, String] = RegisteredTypeConverter(_.toString) + implicit val LocalTimeToString: RegisteredTypeConverter[LocalTime, String] = RegisteredTypeConverter(_.toString) + implicit val LocalDateTimeToString: RegisteredTypeConverter[LocalDateTime, String] = RegisteredTypeConverter(_.toString) - 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}")) - } + + def converter[FROM, TO](implicit converter: RegisteredTypeConverter[FROM, TO]): (FROM => TO) = converter.convert /// private def pgBoolAdjust(s: String): String = @@ -56,13 +61,4 @@ object TypeConverters extends Logging { case Some("f") => "false" case _ => s } - - def find(from: LightTypeTag, to: LightTypeTag): Option[ConvConfig] = { - logger.debug(s"get converter for ${from.repr} => ${to.repr}") - convConfigList.find(e => (e.from =:= from && e.to =:= to)).orElse({ - if (from <:< to) { - Some(ConvConfig(from, to, (v: Any) => v)) - } else None - }) - } } diff --git a/core/src/test/scala/com/github/tminglei/slickpg/TypeTagSupportSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/TypeTagSupportSuite.scala new file mode 100644 index 00000000..23dd125a --- /dev/null +++ b/core/src/test/scala/com/github/tminglei/slickpg/TypeTagSupportSuite.scala @@ -0,0 +1,23 @@ +package com.github.tminglei.slickpg + +import izumi.reflect.Tag +import izumi.reflect.macrortti.LightTypeTag +import org.scalatest.funsuite.AnyFunSuite + +class TypeTagSupportSuite extends AnyFunSuite { + case class Foo(x: Int) + class Around { + case class Inner(y: String) + } + type AroundInner = Around#Inner + def classFromTypeTag(tag: LightTypeTag): Class[_] = { + val mungedRef = tag.ref.repr.replace("::", "$") + Class.forName(mungedRef) + } + test("class from type tag") { + classFromTypeTag(Tag[String].tag) === classOf[String] + classFromTypeTag(Tag[Foo].tag) === classOf[Foo] + classFromTypeTag(Tag[Around#Inner].tag) === classOf[Around#Inner] + classFromTypeTag(Tag[AroundInner].tag) === classOf[Around#Inner] + } +} diff --git a/src/main/scala-2/com/github/tminglei/slickpg/PgCompositeSupport.scala b/src/main/scala-2/com/github/tminglei/slickpg/PgCompositeSupport.scala index f7dfa5e0..2cc04268 100644 --- a/src/main/scala-2/com/github/tminglei/slickpg/PgCompositeSupport.scala +++ b/src/main/scala-2/com/github/tminglei/slickpg/PgCompositeSupport.scala @@ -11,39 +11,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: u.TypeTag[T], tag: ClassTag[T]): GenericJdbcType[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: u.TypeTag[T], tag: ClassTag[T]): AdvancedArrayJdbcType[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: u.TypeTag[T], tag: ClassTag[T]): Option[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: u.TypeTag[T], tag: ClassTag[T]): Option[Seq[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: u.TypeTag[T], tag: ClassTag[T]): SetParameter[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: u.TypeTag[T], tag: ClassTag[T]): SetParameter[Option[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: u.TypeTag[T], tag: ClassTag[T]): SetParameter[Seq[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: u.TypeTag[T], tag: ClassTag[T]): SetParameter[Option[Seq[T]]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) utils.PlainSQLUtils.mkArrayOptionSetParameter[T](sqlTypeName, seqToStr = Some(util.mkStringFromCompositeSeq[T])) } diff --git a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala index 7c059027..c13894fb 100644 --- a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala +++ b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala @@ -8,34 +8,227 @@ import composite.Struct import slick.jdbc.{PositionedResult, PostgresProfile} import slick.jdbc.SetParameter +import scala.annotation.unchecked.uncheckedVariance import scala.deriving.* -import scala.compiletime.{error, erasedValue, summonInline} +import scala.compiletime.{error, erasedValue, summonInline, summonFrom} +import utils.PgTokenHelper._ +import utils.TypeConverters._ +import utils.RegisteredTypeConverter + +sealed abstract class BaseLevel[D <: BaseLevel[?, ?] , I <: BaseLevel[?, ?]] { + def i: Int + final type Dec = D + final type Inc = I + def -- : Dec + def ++ : Inc +} +sealed abstract class Level[D <: BaseLevel[?, ?] , I <: BaseLevel[?, ?]](val -- : D, val ++ : I, val i: Int) extends BaseLevel[D, I] +case object Level_1 extends BaseLevel[Level_1.type, Level0.type]{ + def i: Int = -1 + override def -- = this + override def ++ = Level0 +} +case object Level0 extends Level[Level_1.type, Level1.type](Level_1, Level1, 0) +case object Level1 extends Level[Level0.type, Level2.type](Level0, Level2, 1) +case object Level2 extends Level[Level1.type, Level3.type](Level1, Level3, 2) +case object Level3 extends Level[Level2.type, Level4.type](Level2, Level4, 3) +case object Level4 extends Level[Level3.type, Level5.type](Level3, Level5, 4) +case object Level5 extends Level[Level4.type, Level6.type](Level4, Level6, 5) +case object Level6 extends BaseLevel[Level5.type, Level6.type]{ + def i: Int = 6 + override def -- = Level5 + override def ++ = this +} + + +case class Args(args: Any*) + +sealed trait TokenConverter[T, L <: BaseLevel[?, ?]](val l: L) { + type Type + type Level = L + type LevelInc = l.Inc + def levelInc: LevelInc = l.++ + type LevelDec = l.Dec + def levelDec: LevelDec = l.-- + def fromToken(token: Token): T + + def toToken(value: T): Token +} + trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcTypes { driver: PostgresProfile => protected lazy val emptyMembersAsNull = true -// -// //--- -// def createCompositeJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]): GenericJdbcType[T] = -// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") -// -// def createCompositeArrayJdbcType[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]): AdvancedArrayJdbcType[T] = -// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") -// -// /// Plain SQL support -// def nextComposite[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = -// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") -// def nextCompositeArray[T <: Struct](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = -// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") -// -// def createCompositeSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = -// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") -// -// def createCompositeOptionSetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = -// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") -// def createCompositeArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = { -// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") -// } -// def createCompositeOptionArraySetParameter[T <: Struct](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader)(implicit ev: TTag[T], tag: ClassTag[T]) = -// throw new UnsupportedOperationException("Composite support is unimplemented for scala 3") + + inline implicit def baseConverter[T, L <: BaseLevel[?, ?]: ValueOf](using fromString: RegisteredTypeConverter[String, T], toStringFn: RegisteredTypeConverter[T, String]): TokenConverter[T, L] = new TokenConverter[T, L](valueOf[L]) { + def fromToken(token: Token): T = if (token == Null) null.asInstanceOf[T] else fromString.convert(getString(token, valueOf[L].i)) + + def toToken(value: T): Token = if (value == null) Null else Chunk(toStringFn.convert(value)) + } + + //--- + inline def createCompositeJdbcType[T <: Struct : Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): GenericJdbcType[T] = { + lazy val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) + val c = util.derived[T, Level_1.type ] + new GenericJdbcType[T](sqlTypeName, { input => + val root = grouping(Tokenizer.tokenize(input)) + c.fromToken(root) + }, value => createString(c.toToken(value))) + } + + inline def createCompositeArrayJdbcType[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): AdvancedArrayJdbcType[T] = { + lazy val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) + implicit val bar: TokenConverter[T, Level0.type ] = util.derived[T, Level0.type ] + val c: TokenConverter[Seq[T], Level_1.type] = util.seqConverter[T, Level0.type](bar) + new AdvancedArrayJdbcType[T](sqlTypeName, { input => + val root = grouping(Tokenizer.tokenize(input)) + c.fromToken(root) + }, value => createString(c.toToken(value))) + } + + /// Plain SQL support + inline def nextComposite[T <: Struct: Mirror.Of: ClassTag](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader): Option[T] = { + val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) + val c = util.derived[T, Level_1.type] + r.nextStringOption().map { input => + val root = grouping(Tokenizer.tokenize(input)) + c.fromToken(root) + } + } + + inline def nextCompositeArray[T <: Struct: Mirror.Of: ClassTag](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader): Option[Seq[T]] = { + val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) + implicit val bar: TokenConverter[T, Level0.type] = util.derived[T, Level0.type] + val c: TokenConverter[Seq[T], Level_1.type] = util.seqConverter[T, Level0.type](bar) + r.nextStringOption().map { input => + val root = grouping(Tokenizer.tokenize(input)) + c.fromToken(root) + } + } + + inline def createCompositeSetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[T] = { + val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) + val c = util.derived[T, Level_1.type] + utils.PlainSQLUtils.mkSetParameter[T](sqlTypeName, value => createString(c.toToken(value))) + } + + inline def createCompositeOptionSetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Option[T]] = { + val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) + val c = util.derived[T, Level_1.type] + utils.PlainSQLUtils.mkOptionSetParameter[T](sqlTypeName, value => createString(c.toToken(value))) + } + + inline def createCompositeArraySetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Seq[T]] = { + val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) + implicit val bar: TokenConverter[T, Level0.type] = util.derived[T, Level0.type] + val c: TokenConverter[Seq[T], Level_1.type] = util.seqConverter[T, Level0.type](bar) + utils.PlainSQLUtils.mkArraySetParameter[T](sqlTypeName, seqToStr = Some(value => createString(c.toToken(value)))) + } + + inline def createCompositeOptionArraySetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Option[Seq[T]]] = { + val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) + implicit val bar: TokenConverter[T, Level0.type] = util.derived[T, Level0.type] + val c: TokenConverter[Seq[T], Level_1.type] = util.seqConverter[T, Level0.type](bar) + utils.PlainSQLUtils.mkArrayOptionSetParameter[T](sqlTypeName, seqToStr = Some(value => createString(c.toToken(value)))) + } +} + +class PgCompositeSupportUtils(cl: ClassLoader, emptyMembersAsNull: Boolean) { + import scala.deriving.* + import scala.compiletime.{error, erasedValue, summonInline} + + def seqConverter[T, L <: BaseLevel[?, ?]](delegate: TokenConverter[T, L]): TokenConverter[Seq[T], delegate.LevelDec] = new TokenConverter[Seq[T], delegate.LevelDec](delegate.levelDec) { + def fromToken(token: Token): Seq[T] = + if (token == Null) null else getChildren(token).map(delegate.fromToken) + + def toToken(value: Seq[T]): Token = value match { + case vList: Seq[Any] => { + val members = Open("{") +: vList.map(delegate.toToken) :+ Close("}") + GroupToken(members) + } + case null => Null + case _ => throw new IllegalArgumentException("WRONG type value: " + value) + } + } + def optConverter[T, L <: BaseLevel[?, ?]](delegate: TokenConverter[T, L]): TokenConverter[Option[T], L] = new TokenConverter[Option[T], L](delegate.l) { + private def isNull(token: Token): Boolean = token match { + case g@GroupToken(_) if emptyMembersAsNull => getChildren(g).forall(isNull) + case Null => true + case _ => false + } + + def fromToken(token: Token): Option[T] = + if (isNull(token)) None else Some(delegate.fromToken(token)) + + def toToken(value: Option[T]): Token = value match { + case Some(v: T) => delegate.toToken(v) + case None => Null + case _ => throw new IllegalArgumentException("WRONG type value: " + value) + } + } + + inline def summonInstances[Elems <: Tuple, L <: BaseLevel[?, ?]: ValueOf]: List[TokenConverter[?, ?]] = { + val v = valueOf[L] + type Inc = v.Inc + implicit val vo: ValueOf[Inc] = ValueOf[Inc](v.++) + inline erasedValue[Elems] match { + case _: (elem *: elems) => deriveOrSummon[elem, Inc] :: summonInstances[elems, L] + case _: EmptyTuple => Nil + } + } + + inline def deriveOrSummon[ Elem, L <: BaseLevel[?, ?]: ValueOf]: TokenConverter[Elem, L] = summonFrom { + case m: Mirror.Of[Elem & Struct] => + summonFrom { case ct: ClassTag[Elem & Struct] => derived[Elem & Struct, L].asInstanceOf[TokenConverter[Elem, L]] } + case _: (Elem <:< Option[Any]) => + inline erasedValue[Elem] match { + case _: Option[t] => + val elemConverter: TokenConverter[t, L] = deriveOrSummon[t, L] + optConverter(elemConverter).asInstanceOf[TokenConverter[Elem, L]] + } + case _: (Elem <:< Seq[Any]) => + inline erasedValue[Elem] match { + case _: Seq[t] => + val v = valueOf[L] + type Inc = v.Inc + implicit val vo: ValueOf[Inc] = ValueOf[Inc](v ++) + val elemConverter: TokenConverter[t, Inc] = deriveOrSummon[t, Inc] + seqConverter(elemConverter).asInstanceOf[TokenConverter[Elem, L]] + } + case _ => summonInline[TokenConverter[Elem, L]] + } + + def convertProduct[T <: Struct: ClassTag, L <: BaseLevel[?, ?]: ValueOf](p: Mirror.ProductOf[T], elems: => List[TokenConverter[?, ?]]): TokenConverter[T, L] = + new TokenConverter[T, L](valueOf[L]) { + def fromToken(token: Token): T = + if (token == Null) null.asInstanceOf[T] + else { + val args = + getChildren(token) + .zip(elems) + .map { case (token, converter) => converter.fromToken(token) } + + classTag.runtimeClass.getConstructors.head.newInstance(args:_*).asInstanceOf[T] + } + + def toToken(value: T): Token = + if (value == null) Null + else { + val v = valueOf[L] + type Inc = v.Inc + implicit val vo: ValueOf[Inc] = ValueOf(v.++) + val tokens = value.asInstanceOf[Product].productIterator.zip(elems).toSeq.map({ + case (v, converter) => converter.asInstanceOf[TokenConverter[Any, Inc]].toToken(v) + }) + val members = Open("(") +: tokens :+ Close(")") + GroupToken(members) + } + } + + inline def derived[T <: Struct: ClassTag, L <: BaseLevel[?, ?]: ValueOf](using m: Mirror.Of[T]): TokenConverter[T, L] = { + lazy val elemInstances = summonInstances[m.MirroredElemTypes, L] + inline m match + case p: Mirror.ProductOf[T] => convertProduct(p, elemInstances) + } + } diff --git a/src/test/scala-3/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala b/src/test/scala-3/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala new file mode 100644 index 00000000..5cc77c1c --- /dev/null +++ b/src/test/scala-3/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala @@ -0,0 +1,317 @@ +package com.github.tminglei.slickpg + +import java.time.LocalDateTime +import scala.concurrent.Await +import scala.concurrent.duration._ +import scala.collection.immutable.{Range => ScalaRange} +import scala.jdk.CollectionConverters._ +import slick.jdbc.{GetResult, PositionedResult, PostgresProfile, SetParameter} +import com.github.tminglei.slickpg.composite.Struct +import org.postgresql.util.HStoreConverter +import org.scalatest.funsuite.AnyFunSuite + +import com.github.tminglei.slickpg.utils.{RegisteredTypeConverter,TypeConverters} + + +object PgCompositeSupportSuite { + + import TypeConverters.* + def ts(str: String) = LocalDateTime.parse(str.replace(' ', 'T')) + + case class Composite1( + id: Long, + txt: String, + date: LocalDateTime, + tsRange: Option[Range[LocalDateTime]] + ) extends Struct + + case class Composite2( + id: Long, + comp1: Composite1, + confirm: Boolean, + map: Map[String, String] + ) extends Struct + + case class Composite3( + name: Option[String] = None, + code: Option[Int] = None, + num: Option[Int] = None, + bool: Option[Boolean] = None + ) extends Struct + + case class Composite4( + id: Int, + name: String, + variable: List[String], + optVars: Option[List[String]], + script1: String, + script2: String + ) extends Struct + + case class C1 ( + name: String + ) extends Struct + + case class C2 ( + c1: List[C1] + ) extends Struct + + //------------------------------------------------------------- + trait MyPostgresProfile1 extends PostgresProfile with PgCompositeSupport with PgArraySupport with utils.PgCommonJdbcTypes { + def mapToString(m: Map[String, String]): String = HStoreConverter.toString((m).asJava) + def stringToMap(s: String): Map[String, String] = (HStoreConverter.fromString(s) + .asInstanceOf[java.util.Map[String, String]]).asScala.toMap + + /// + trait API extends JdbcAPI with ArrayImplicits { + implicit val StringToRange: RegisteredTypeConverter[String, Range[LocalDateTime]] = + RegisteredTypeConverter(PgRangeSupportUtils.mkRangeFn(ts)) + implicit val RangeToString: RegisteredTypeConverter[Range[LocalDateTime], String] = + RegisteredTypeConverter(PgRangeSupportUtils.toStringFn[LocalDateTime](_.toString)) + implicit val MapToString: RegisteredTypeConverter[Map[String, String], String] = RegisteredTypeConverter(mapToString) + implicit val StringToMap: RegisteredTypeConverter[String, Map[String, String]] = RegisteredTypeConverter(stringToMap) + + implicit val composite1TypeMapper: GenericJdbcType[Composite1] = createCompositeJdbcType[Composite1]("composite1") + implicit val composite2TypeMapper: GenericJdbcType[Composite2] = createCompositeJdbcType[Composite2]("composite2") + implicit val composite3TypeMapper: GenericJdbcType[Composite3] = createCompositeJdbcType[Composite3]("composite3") + implicit val composite4TypeMapper: GenericJdbcType[Composite4] = createCompositeJdbcType[Composite4]("composite4") + implicit val c1TypeMapper: GenericJdbcType[C1] = createCompositeJdbcType[C1]("c1") + implicit val c2TypeMapper: GenericJdbcType[C2] = createCompositeJdbcType[C2]("c2") + + implicit val composite1ArrayTypeMapper: DriverJdbcType[List[Composite1]] = createCompositeArrayJdbcType[Composite1]("composite1").to(_.toList) + implicit val composite2ArrayTypeMapper: DriverJdbcType[List[Composite2]] = createCompositeArrayJdbcType[Composite2]("composite2").to(_.toList) + implicit val composite3ArrayTypeMapper: DriverJdbcType[List[Composite3]] = createCompositeArrayJdbcType[Composite3]("composite3").to(_.toList) + } + override val api: API = new API {} + + object plainImplicits extends API with SimpleArrayPlainImplicits { + import utils.PlainSQLUtils._ + // to support 'nextArray[T]/nextArrayOption[T]' in PgArraySupport + { + addNextArrayConverter((r) => nextCompositeArray[Composite1](r)) + addNextArrayConverter((r) => nextCompositeArray[Composite2](r)) + addNextArrayConverter((r) => nextCompositeArray[Composite3](r)) + } + + implicit class MyCompositePositionedResult(r: PositionedResult) { + def nextComposite1() = nextComposite[Composite1](r) + def nextComposite2() = nextComposite[Composite2](r) + def nextComposite3() = nextComposite[Composite3](r) + } + + implicit val composite1SetParameter: SetParameter[Composite1] = createCompositeSetParameter[Composite1]("composite1") + implicit val composite1OptSetParameter: SetParameter[Option[Composite1]] = createCompositeOptionSetParameter[Composite1]("composite1") + implicit val composite1ArraySetParameter: SetParameter[Seq[Composite1]] = createCompositeArraySetParameter[Composite1]("composite1") + implicit val composite1ArrayOptSetParameter: SetParameter[Option[Seq[Composite1]]] = createCompositeOptionArraySetParameter[Composite1]("composite1") + + implicit val composite2SetParameter: SetParameter[Composite2] = createCompositeSetParameter[Composite2]("composite2") + implicit val composite2OptSetParameter: SetParameter[Option[Composite2]] = createCompositeOptionSetParameter[Composite2]("composite2") + implicit val composite2ArraySetParameter: SetParameter[Seq[Composite2]] = createCompositeArraySetParameter[Composite2]("composite2") + implicit val composite2ArrayOptSetParameter: SetParameter[Option[Seq[Composite2]]] = createCompositeOptionArraySetParameter[Composite2]("composite2") + + implicit val composite3SetParameter: SetParameter[Composite3] = createCompositeSetParameter[Composite3]("composite3") + implicit val composite3OptSetParameter: SetParameter[Option[Composite3]] = createCompositeOptionSetParameter[Composite3]("composite3") + implicit val composite3ArraySetParameter: SetParameter[Seq[Composite3]] = createCompositeArraySetParameter[Composite3]("composite3") + implicit val composite3ArrayOptSetParameter: SetParameter[Option[Seq[Composite3]]] = createCompositeOptionArraySetParameter[Composite3]("composite3") + } + } + object MyPostgresProfile1 extends MyPostgresProfile1 +} + +/// +class PgCompositeSupportSuite extends AnyFunSuite with PostgresContainer { + import PgCompositeSupportSuite._ + import MyPostgresProfile1.api._ + + lazy val db = Database.forURL(url = container.jdbcUrl, driver = "org.postgresql.Driver") + + case class TestBean( + id: Long, + comps: List[Composite2] + ) + + case class TestBean1( + id: Long, + comps: List[Composite3] + ) + + case class TestBean2( + id: Long, + comps: Composite1, + c2: C2 + ) + + case class TestBean3( + id: Long, + comps: Option[Composite4] + ) + + class TestTable(tag: Tag) extends Table[TestBean](tag, "CompositeTest") { + def id = column[Long]("id") + def comps = column[List[Composite2]]("comps", O.Default(Nil)) + + def * = (id,comps) <> ((TestBean.apply _).tupled, TestBean.unapply) + } + val CompositeTests = TableQuery(new TestTable(_)) + + class TestTable1(tag: Tag) extends Table[TestBean1](tag, "CompositeTest1") { + def id = column[Long]("id") + def comps = column[List[Composite3]]("comps") + + def * = (id,comps) <> ((TestBean1.apply _).tupled, TestBean1.unapply) + } + val CompositeTests1 = TableQuery(new TestTable1(_)) + + class TestTable2(tag: Tag) extends Table[TestBean2](tag, "CompositeTest2") { + def id = column[Long]("id") + def comps = column[Composite1]("comp") + def c2 = column[C2]("c2") + + def * = (id,comps,c2) <> ((TestBean2.apply _).tupled, TestBean2.unapply) + } + val CompositeTests2 = TableQuery(new TestTable2(_)) + + class TestTable3(tag: Tag) extends Table[TestBean3](tag, "CompositeTest3") { + def id = column[Long]("id") + def comps = column[Option[Composite4]]("comp") + + def * = (id, comps) <> ((TestBean3.apply _).tupled, TestBean3.unapply) + } + val CompositeTests3 = TableQuery(new TestTable3(_)) + + //------------------------------------------------------------------- + + val rec1 = TestBean(333, List(Composite2(201, Composite1(101, "(test1'", ts("2001-01-03T13:21:00"), + Some(Range(ts("2010-01-01T14:30:00"), ts("2010-01-03T15:30:00")))), true, Map("t" -> "haha", "t2" -> "133")))) + val rec2 = TestBean(335, List(Composite2(202, Composite1(102, "test2\\", ts("2012-05-08T11:31:06"), + Some(Range(ts("2011-01-01T14:30:00"), ts("2011-11-01T15:30:00")))), false, Map("t't" -> "1,363")))) + val rec3 = TestBean(337, List(Composite2(203, Composite1(103, "getRate(\"x\") + 5;", ts("2015-03-08T17:17:03"), + None), false, Map("t,t" -> "getRate(\"x\") + 5;")))) + val rec4 = TestBean(339, List(Composite2(204, Composite1(104, "x=1&y=2&[INSERT_DEVICE_ID_HERE]&z=3", ts("2001-01-03T13:21:00"), + Some(Range(ts("2010-01-01T14:30:00"), ts("2010-01-03T15:30:00")))), true, Map("t" -> "haha", "t2" -> "133")))) + + val rec11 = TestBean1(111, List(Composite3(Some("(test1'")))) + val rec12 = TestBean1(112, List(Composite3(code = Some(102)))) + val rec13 = TestBean1(113, List(Composite3())) + val rec14 = TestBean1(114, List(Composite3(Some("Word1 (Word2)")))) + val rec15 = TestBean1(115, List(Composite3(Some("")))) + + val rec21 = TestBean2(211, Composite1(201, "test3", ts("2015-01-03T13:21:00"), + Some(Range(ts("2015-01-01T14:30:00"), ts("2016-01-03T15:30:00")))), C2(List(C1("1s")))) + val rec22 = TestBean2(212, Composite1(202, "", ts("2015-01-03T13:21:00"), + Some(Range(ts("2015-01-01T14:30:00"), ts("2016-01-03T15:30:00")))), C2(List(C1("test1")))) + + val rec31 = TestBean3(1, None) + val rec32 = TestBean3(2, Some(Composite4(1, "x1", Nil, Some(List.empty), "get(\"x1\").ok", "(4).ok"))) + val rec32_al = TestBean3(2, Some(Composite4(1, "x1", Nil, None, "get(\"x1\").ok", "(4).ok"))) + val rec33 = TestBean3(3, Some(Composite4(2, "x2", List("xxx(yyy)zz,z", "u(vv)(w)x(y)", "x=1&y=2&[INSERT_DEVICE_ID_HERE]&z=3"), Some(List("\"t")), "(get(\"A\") + get(\"A\")).ok", "call(A, B).ok"))) + + test("Composite type Lifted support") { + Await.result(db.run( + DBIO.seq( + sqlu"create type composite1 as (id int8, txt text, date timestamp, ts_range tsrange)", + sqlu"create type composite2 as (id int8, comp1 composite1, confirm boolean, map hstore)", + sqlu"create type composite3 as (txt text, id int4, code int4, bool boolean)", + sqlu"create type composite4 as (id int4, name text, variable text[], optVars text[], script1 text, script2 text)", + sqlu"create type c1 as (name text)", + sqlu"create type c2 as (c1 c1[])", + (CompositeTests.schema ++ CompositeTests1.schema ++ CompositeTests2.schema ++ CompositeTests3.schema) create, + CompositeTests forceInsertAll List(rec1, rec2, rec3, rec4), + CompositeTests1 forceInsertAll List(rec11, rec12, rec13, rec14, rec15), + CompositeTests2 forceInsertAll List(rec21, rec22), + CompositeTests3 forceInsertAll List(rec31, rec32, rec33) + ).andThen( + DBIO.seq( + CompositeTests.filter(_.id === 333L.bind).result.head.map( + r => assert(rec1 === r) + ), + CompositeTests.filter(_.id === 335L.bind).result.head.map( + r => assert(rec2 === r) + ), + CompositeTests.filter(_.id === 337L.bind).result.head.map( + r => assert(rec3 === r) + ), + CompositeTests.filter(_.id === 339L.bind).result.head.map( + r => assert(rec4 === r) + ) + ) + ).andThen( + DBIO.seq( + CompositeTests1.filter(_.id === 111L.bind).result.head.map( + r => assert(rec11 === r) + ), + CompositeTests1.filter(_.id === 112L.bind).result.head.map( + r => assert(rec12 === r) + ), + CompositeTests1.filter(_.id === 113L.bind).result.head.map( + r => assert(rec13 === r) + ), + CompositeTests1.filter(_.id === 114L.bind).result.head.map( + r => assert(rec14 === r) + ), + CompositeTests1.filter(_.id === 115L.bind).result.head.map( + r => assert(rec15 === r) + ), + CompositeTests2.filter(_.comps === rec21.comps.asColumnOf[Composite1]).result.head.map( + r => assert(rec21 === r) + ) + ) + ).andThen( + DBIO.seq( + CompositeTests2.filter(_.id === 211L.bind).result.head.map( + r => assert(rec21 === r) + ), + CompositeTests2.filter(_.id === 212L.bind).result.head.map( + r => assert(rec22 === r) + ) + ) + ).andThen( + DBIO.seq( + CompositeTests3.filter(_.id === 1L.bind).result.head.map(r => assert(rec31 === r)), + CompositeTests3.filter(_.id === 2L.bind).result.head.map(r => assert(rec32_al === r)), + CompositeTests3.filter(_.id === 3L.bind).result.head.map(r => assert(rec33 === r)) + ) + ).andFinally( + DBIO.seq( + (CompositeTests.schema ++ CompositeTests1.schema ++ CompositeTests2.schema ++ CompositeTests3.schema) drop, + sqlu"drop type c2", + sqlu"drop type c1", + sqlu"drop type composite4", + sqlu"drop type composite3", + sqlu"drop type composite2", + sqlu"drop type composite1" + ) + ).transactionally + ), Duration.Inf) + } + + test("Composite type Plain SQL support") { + import MyPostgresProfile1.plainImplicits._ + + implicit val getTestBeanResult: GetResult[TestBean] = GetResult(r => TestBean(r.nextLong(), r.nextArray[Composite2]().toList)) + implicit val getTestBean1Result: GetResult[TestBean1] = GetResult(r => TestBean1(r.nextLong(), r.nextArray[Composite3]().toList)) + + Await.result(db.run(DBIO.seq( + sqlu"create type composite1 as (id int8, txt text, date timestamp, ts_range tsrange)", + sqlu"create type composite2 as (id int8, comp1 composite1, confirm boolean, map hstore)", + sqlu"create type composite3 as (txt text, id int4, code int4, bool boolean)", + sqlu"create table CompositeTest (id BIGINT NOT NULL, comps composite2[] DEFAULT '{}' NOT NULL)", + sqlu"create table CompositeTest1 (id BIGINT NOT NULL, comps composite3[] NOT NULL)", + /// + sqlu"insert into CompositeTest values(${rec1.id}, ${rec1.comps})", + sql"select * from CompositeTest where id = ${rec1.id}".as[TestBean].head.map( + r => assert(rec1 === r) + ), + sqlu"insert into CompositeTest1 values(${rec11.id}, ${rec11.comps})", + sql"select * from CompositeTest1 where id = ${rec11.id}".as[TestBean1].head.map( + r => assert(rec11 === r) + ), + /// + sqlu"drop table CompositeTest1", + sqlu"drop table CompositeTest", + sqlu"drop type composite3", + sqlu"drop type composite2", + sqlu"drop type composite1" + ).transactionally), Duration.Inf) + } +} From b0e75074405adc786e495f7d16c57ca0cecbe91c Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Thu, 7 Dec 2023 13:55:53 +0000 Subject: [PATCH 09/14] rm dead file --- .../slickpg/TypeTagSupportSuite.scala | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 core/src/test/scala/com/github/tminglei/slickpg/TypeTagSupportSuite.scala diff --git a/core/src/test/scala/com/github/tminglei/slickpg/TypeTagSupportSuite.scala b/core/src/test/scala/com/github/tminglei/slickpg/TypeTagSupportSuite.scala deleted file mode 100644 index 23dd125a..00000000 --- a/core/src/test/scala/com/github/tminglei/slickpg/TypeTagSupportSuite.scala +++ /dev/null @@ -1,23 +0,0 @@ -package com.github.tminglei.slickpg - -import izumi.reflect.Tag -import izumi.reflect.macrortti.LightTypeTag -import org.scalatest.funsuite.AnyFunSuite - -class TypeTagSupportSuite extends AnyFunSuite { - case class Foo(x: Int) - class Around { - case class Inner(y: String) - } - type AroundInner = Around#Inner - def classFromTypeTag(tag: LightTypeTag): Class[_] = { - val mungedRef = tag.ref.repr.replace("::", "$") - Class.forName(mungedRef) - } - test("class from type tag") { - classFromTypeTag(Tag[String].tag) === classOf[String] - classFromTypeTag(Tag[Foo].tag) === classOf[Foo] - classFromTypeTag(Tag[Around#Inner].tag) === classOf[Around#Inner] - classFromTypeTag(Tag[AroundInner].tag) === classOf[Around#Inner] - } -} From 168c3963e602bde9f8bf8821bcd0d9f3fce1df90 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Thu, 7 Dec 2023 15:54:51 +0000 Subject: [PATCH 10/14] rm things --- .../com/github/tminglei/slickpg/PgCompositeSupport.scala | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala index c13894fb..10485b45 100644 --- a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala +++ b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala @@ -44,10 +44,6 @@ case object Level6 extends BaseLevel[Level5.type, Level6.type]{ case class Args(args: Any*) sealed trait TokenConverter[T, L <: BaseLevel[?, ?]](val l: L) { - type Type - type Level = L - type LevelInc = l.Inc - def levelInc: LevelInc = l.++ type LevelDec = l.Dec def levelDec: LevelDec = l.-- def fromToken(token: Token): T From a0a1b65c9b77cb9eeb90cd93be9826c6d6bb95c3 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Fri, 8 Dec 2023 09:09:23 +0000 Subject: [PATCH 11/14] make level handling simpler, remove artificial '6 layers of nesting' retriction --- .../tminglei/slickpg/PgCompositeSupport.scala | 151 ++++++------------ 1 file changed, 50 insertions(+), 101 deletions(-) diff --git a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala index 10485b45..42d4450d 100644 --- a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala +++ b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala @@ -15,40 +15,9 @@ import utils.PgTokenHelper._ import utils.TypeConverters._ import utils.RegisteredTypeConverter -sealed abstract class BaseLevel[D <: BaseLevel[?, ?] , I <: BaseLevel[?, ?]] { - def i: Int - final type Dec = D - final type Inc = I - def -- : Dec - def ++ : Inc -} -sealed abstract class Level[D <: BaseLevel[?, ?] , I <: BaseLevel[?, ?]](val -- : D, val ++ : I, val i: Int) extends BaseLevel[D, I] -case object Level_1 extends BaseLevel[Level_1.type, Level0.type]{ - def i: Int = -1 - override def -- = this - override def ++ = Level0 -} -case object Level0 extends Level[Level_1.type, Level1.type](Level_1, Level1, 0) -case object Level1 extends Level[Level0.type, Level2.type](Level0, Level2, 1) -case object Level2 extends Level[Level1.type, Level3.type](Level1, Level3, 2) -case object Level3 extends Level[Level2.type, Level4.type](Level2, Level4, 3) -case object Level4 extends Level[Level3.type, Level5.type](Level3, Level5, 4) -case object Level5 extends Level[Level4.type, Level6.type](Level4, Level6, 5) -case object Level6 extends BaseLevel[Level5.type, Level6.type]{ - def i: Int = 6 - override def -- = Level5 - override def ++ = this -} - - -case class Args(args: Any*) - -sealed trait TokenConverter[T, L <: BaseLevel[?, ?]](val l: L) { - type LevelDec = l.Dec - def levelDec: LevelDec = l.-- - def fromToken(token: Token): T - - def toToken(value: T): Token +case class TokenConverter[T](level: Int, fromTokenAndLevel: Int => Token => T, toToken: T => Token) { + def fromToken(t: Token): T = fromTokenAndLevel(level)(t) + def withLevel(l: Int): TokenConverter[T] = copy(level = l) } @@ -56,16 +25,14 @@ trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcT protected lazy val emptyMembersAsNull = true - inline implicit def baseConverter[T, L <: BaseLevel[?, ?]: ValueOf](using fromString: RegisteredTypeConverter[String, T], toStringFn: RegisteredTypeConverter[T, String]): TokenConverter[T, L] = new TokenConverter[T, L](valueOf[L]) { - def fromToken(token: Token): T = if (token == Null) null.asInstanceOf[T] else fromString.convert(getString(token, valueOf[L].i)) - - def toToken(value: T): Token = if (value == null) Null else Chunk(toStringFn.convert(value)) - } + inline implicit def baseConverter[T](using fromString: RegisteredTypeConverter[String, T], toStringFn: RegisteredTypeConverter[T, String]): TokenConverter[T] = new TokenConverter[T](0, + level => token => if (token == Null) null.asInstanceOf[T] else fromString.convert(getString(token, level)), + value => if (value == null) Null else Chunk(toStringFn.convert(value))) //--- inline def createCompositeJdbcType[T <: Struct : Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): GenericJdbcType[T] = { lazy val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - val c = util.derived[T, Level_1.type ] + val c = util.derived[T](-1) new GenericJdbcType[T](sqlTypeName, { input => val root = grouping(Tokenizer.tokenize(input)) c.fromToken(root) @@ -74,8 +41,8 @@ trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcT inline def createCompositeArrayJdbcType[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): AdvancedArrayJdbcType[T] = { lazy val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - implicit val bar: TokenConverter[T, Level0.type ] = util.derived[T, Level0.type ] - val c: TokenConverter[Seq[T], Level_1.type] = util.seqConverter[T, Level0.type](bar) + implicit val bar: TokenConverter[T] = util.derived[T](0) + val c: TokenConverter[Seq[T]] = util.seqConverter[T](bar) new AdvancedArrayJdbcType[T](sqlTypeName, { input => val root = grouping(Tokenizer.tokenize(input)) c.fromToken(root) @@ -85,7 +52,7 @@ trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcT /// Plain SQL support inline def nextComposite[T <: Struct: Mirror.Of: ClassTag](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader): Option[T] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - val c = util.derived[T, Level_1.type] + val c = util.derived[T](-1) r.nextStringOption().map { input => val root = grouping(Tokenizer.tokenize(input)) c.fromToken(root) @@ -94,8 +61,8 @@ trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcT inline def nextCompositeArray[T <: Struct: Mirror.Of: ClassTag](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader): Option[Seq[T]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - implicit val bar: TokenConverter[T, Level0.type] = util.derived[T, Level0.type] - val c: TokenConverter[Seq[T], Level_1.type] = util.seqConverter[T, Level0.type](bar) + implicit val bar: TokenConverter[T] = util.derived[T](0) + val c: TokenConverter[Seq[T]] = util.seqConverter[T](bar) r.nextStringOption().map { input => val root = grouping(Tokenizer.tokenize(input)) c.fromToken(root) @@ -104,27 +71,27 @@ trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcT inline def createCompositeSetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[T] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - val c = util.derived[T, Level_1.type] + val c = util.derived[T](-1) utils.PlainSQLUtils.mkSetParameter[T](sqlTypeName, value => createString(c.toToken(value))) } inline def createCompositeOptionSetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Option[T]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - val c = util.derived[T, Level_1.type] + val c = util.derived[T](-1) utils.PlainSQLUtils.mkOptionSetParameter[T](sqlTypeName, value => createString(c.toToken(value))) } inline def createCompositeArraySetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Seq[T]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - implicit val bar: TokenConverter[T, Level0.type] = util.derived[T, Level0.type] - val c: TokenConverter[Seq[T], Level_1.type] = util.seqConverter[T, Level0.type](bar) + implicit val bar: TokenConverter[T] = util.derived[T](0) + val c: TokenConverter[Seq[T]] = util.seqConverter[T](bar) utils.PlainSQLUtils.mkArraySetParameter[T](sqlTypeName, seqToStr = Some(value => createString(c.toToken(value)))) } inline def createCompositeOptionArraySetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Option[Seq[T]]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - implicit val bar: TokenConverter[T, Level0.type] = util.derived[T, Level0.type] - val c: TokenConverter[Seq[T], Level_1.type] = util.seqConverter[T, Level0.type](bar) + implicit val bar: TokenConverter[T] = util.derived[T](0) + val c: TokenConverter[Seq[T]] = util.seqConverter[T](bar) utils.PlainSQLUtils.mkArrayOptionSetParameter[T](sqlTypeName, seqToStr = Some(value => createString(c.toToken(value)))) } } @@ -133,70 +100,58 @@ class PgCompositeSupportUtils(cl: ClassLoader, emptyMembersAsNull: Boolean) { import scala.deriving.* import scala.compiletime.{error, erasedValue, summonInline} - def seqConverter[T, L <: BaseLevel[?, ?]](delegate: TokenConverter[T, L]): TokenConverter[Seq[T], delegate.LevelDec] = new TokenConverter[Seq[T], delegate.LevelDec](delegate.levelDec) { - def fromToken(token: Token): Seq[T] = - if (token == Null) null else getChildren(token).map(delegate.fromToken) - - def toToken(value: Seq[T]): Token = value match { + def seqConverter[T](delegate: TokenConverter[T]): TokenConverter[Seq[T]] = TokenConverter[Seq[T]](delegate.level - 1, + level => token => if (token == Null) null else getChildren(token).map(delegate.fromToken), + { case vList: Seq[Any] => { val members = Open("{") +: vList.map(delegate.toToken) :+ Close("}") GroupToken(members) } case null => Null - case _ => throw new IllegalArgumentException("WRONG type value: " + value) - } - } - def optConverter[T, L <: BaseLevel[?, ?]](delegate: TokenConverter[T, L]): TokenConverter[Option[T], L] = new TokenConverter[Option[T], L](delegate.l) { - private def isNull(token: Token): Boolean = token match { - case g@GroupToken(_) if emptyMembersAsNull => getChildren(g).forall(isNull) - case Null => true - case _ => false - } + case value => throw new IllegalArgumentException("WRONG type value: " + value) + }) - def fromToken(token: Token): Option[T] = - if (isNull(token)) None else Some(delegate.fromToken(token)) + private def isNull(token: Token): Boolean = token match { + case g@GroupToken(_) if emptyMembersAsNull => getChildren(g).forall(isNull) + case Null => true + case _ => false + } - def toToken(value: Option[T]): Token = value match { + def optConverter[T](delegate: TokenConverter[T]): TokenConverter[Option[T]] = new TokenConverter[Option[T]](delegate.level, + level => token => if (isNull(token)) None else Some(delegate.fromToken(token)), + { case Some(v: T) => delegate.toToken(v) case None => Null - case _ => throw new IllegalArgumentException("WRONG type value: " + value) - } - } + case value => throw new IllegalArgumentException("WRONG type value: " + value) + }) - inline def summonInstances[Elems <: Tuple, L <: BaseLevel[?, ?]: ValueOf]: List[TokenConverter[?, ?]] = { - val v = valueOf[L] - type Inc = v.Inc - implicit val vo: ValueOf[Inc] = ValueOf[Inc](v.++) + inline def summonInstances[Elems <: Tuple](i: Int): List[TokenConverter[?]] = { inline erasedValue[Elems] match { - case _: (elem *: elems) => deriveOrSummon[elem, Inc] :: summonInstances[elems, L] + case _: (elem *: elems) => deriveOrSummon[elem](i + 1) :: summonInstances[elems](i) case _: EmptyTuple => Nil } } - inline def deriveOrSummon[ Elem, L <: BaseLevel[?, ?]: ValueOf]: TokenConverter[Elem, L] = summonFrom { + inline def deriveOrSummon[Elem](i: Int): TokenConverter[Elem] = summonFrom { case m: Mirror.Of[Elem & Struct] => - summonFrom { case ct: ClassTag[Elem & Struct] => derived[Elem & Struct, L].asInstanceOf[TokenConverter[Elem, L]] } + summonFrom { case ct: ClassTag[Elem & Struct] => derived[Elem & Struct](i).asInstanceOf[TokenConverter[Elem]] } case _: (Elem <:< Option[Any]) => inline erasedValue[Elem] match { case _: Option[t] => - val elemConverter: TokenConverter[t, L] = deriveOrSummon[t, L] - optConverter(elemConverter).asInstanceOf[TokenConverter[Elem, L]] + val elemConverter: TokenConverter[t] = deriveOrSummon[t](i) + optConverter(elemConverter).asInstanceOf[TokenConverter[Elem]] } case _: (Elem <:< Seq[Any]) => inline erasedValue[Elem] match { case _: Seq[t] => - val v = valueOf[L] - type Inc = v.Inc - implicit val vo: ValueOf[Inc] = ValueOf[Inc](v ++) - val elemConverter: TokenConverter[t, Inc] = deriveOrSummon[t, Inc] - seqConverter(elemConverter).asInstanceOf[TokenConverter[Elem, L]] + val elemConverter: TokenConverter[t] = deriveOrSummon[t](i + 1) + seqConverter(elemConverter).asInstanceOf[TokenConverter[Elem]] } - case _ => summonInline[TokenConverter[Elem, L]] + case _ => summonInline[TokenConverter[Elem]].withLevel(i) } - def convertProduct[T <: Struct: ClassTag, L <: BaseLevel[?, ?]: ValueOf](p: Mirror.ProductOf[T], elems: => List[TokenConverter[?, ?]]): TokenConverter[T, L] = - new TokenConverter[T, L](valueOf[L]) { - def fromToken(token: Token): T = + def convertProduct[T <: Struct: ClassTag](i: Int)(p: Mirror.ProductOf[T], elems: => List[TokenConverter[?]]): TokenConverter[T] = + new TokenConverter[T](i, level => token => if (token == Null) null.asInstanceOf[T] else { val args = @@ -205,26 +160,20 @@ class PgCompositeSupportUtils(cl: ClassLoader, emptyMembersAsNull: Boolean) { .map { case (token, converter) => converter.fromToken(token) } classTag.runtimeClass.getConstructors.head.newInstance(args:_*).asInstanceOf[T] - } - - def toToken(value: T): Token = + }, value => if (value == null) Null else { - val v = valueOf[L] - type Inc = v.Inc - implicit val vo: ValueOf[Inc] = ValueOf(v.++) val tokens = value.asInstanceOf[Product].productIterator.zip(elems).toSeq.map({ - case (v, converter) => converter.asInstanceOf[TokenConverter[Any, Inc]].toToken(v) + case (v, converter) => converter.asInstanceOf[TokenConverter[Any]].toToken(v) }) val members = Open("(") +: tokens :+ Close(")") GroupToken(members) - } - } + }) - inline def derived[T <: Struct: ClassTag, L <: BaseLevel[?, ?]: ValueOf](using m: Mirror.Of[T]): TokenConverter[T, L] = { - lazy val elemInstances = summonInstances[m.MirroredElemTypes, L] + inline def derived[T <: Struct: ClassTag](i: Int)(using m: Mirror.Of[T]): TokenConverter[T] = { + lazy val elemInstances = summonInstances[m.MirroredElemTypes](i) inline m match - case p: Mirror.ProductOf[T] => convertProduct(p, elemInstances) + case p: Mirror.ProductOf[T] => convertProduct[T](i)(p, elemInstances) } } From 67fa72f2377bb23f4f9643e5dda0b2ccf0e16799 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Sun, 10 Dec 2023 14:17:11 +0000 Subject: [PATCH 12/14] tidy up --- .../tminglei/slickpg/PgCompositeSupport.scala | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala index 42d4450d..da1570cc 100644 --- a/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala +++ b/src/main/scala-3/com/github/tminglei/slickpg/PgCompositeSupport.scala @@ -30,69 +30,45 @@ trait PgCompositeSupport extends utils.PgCommonJdbcTypes with array.PgArrayJdbcT value => if (value == null) Null else Chunk(toStringFn.convert(value))) //--- - inline def createCompositeJdbcType[T <: Struct : Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): GenericJdbcType[T] = { + inline def createCompositeJdbcType[T <: Struct: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): GenericJdbcType[T] = { lazy val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - val c = util.derived[T](-1) - new GenericJdbcType[T](sqlTypeName, { input => - val root = grouping(Tokenizer.tokenize(input)) - c.fromToken(root) - }, value => createString(c.toToken(value))) + new GenericJdbcType[T](sqlTypeName, util.mkCompositeFromString[T], util.mkStringFromComposite[T]) } - inline def createCompositeArrayJdbcType[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): AdvancedArrayJdbcType[T] = { + inline def createCompositeArrayJdbcType[T <: Struct: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): AdvancedArrayJdbcType[T] = { lazy val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - implicit val bar: TokenConverter[T] = util.derived[T](0) - val c: TokenConverter[Seq[T]] = util.seqConverter[T](bar) - new AdvancedArrayJdbcType[T](sqlTypeName, { input => - val root = grouping(Tokenizer.tokenize(input)) - c.fromToken(root) - }, value => createString(c.toToken(value))) + new AdvancedArrayJdbcType[T](sqlTypeName, util.mkCompositeSeqFromString[T], util.mkStringFromCompositeSeq[T]) } /// Plain SQL support - inline def nextComposite[T <: Struct: Mirror.Of: ClassTag](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader): Option[T] = { + inline def nextComposite[T <: Struct: ClassTag](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader): Option[T] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - val c = util.derived[T](-1) - r.nextStringOption().map { input => - val root = grouping(Tokenizer.tokenize(input)) - c.fromToken(root) - } + r.nextStringOption().map(util.mkCompositeFromString[T]) } - inline def nextCompositeArray[T <: Struct: Mirror.Of: ClassTag](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader): Option[Seq[T]] = { + inline def nextCompositeArray[T <: Struct: ClassTag](r: PositionedResult, cl: ClassLoader = getClass.getClassLoader): Option[Seq[T]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - implicit val bar: TokenConverter[T] = util.derived[T](0) - val c: TokenConverter[Seq[T]] = util.seqConverter[T](bar) - r.nextStringOption().map { input => - val root = grouping(Tokenizer.tokenize(input)) - c.fromToken(root) - } + r.nextStringOption().map(util.mkCompositeSeqFromString[T]) } - inline def createCompositeSetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[T] = { + inline def createCompositeSetParameter[T <: Struct: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[T] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - val c = util.derived[T](-1) - utils.PlainSQLUtils.mkSetParameter[T](sqlTypeName, value => createString(c.toToken(value))) + utils.PlainSQLUtils.mkSetParameter[T](sqlTypeName, util.mkStringFromComposite[T]) } - inline def createCompositeOptionSetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Option[T]] = { + inline def createCompositeOptionSetParameter[T <: Struct: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Option[T]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - val c = util.derived[T](-1) - utils.PlainSQLUtils.mkOptionSetParameter[T](sqlTypeName, value => createString(c.toToken(value))) + utils.PlainSQLUtils.mkOptionSetParameter[T](sqlTypeName, util.mkStringFromComposite[T]) } - inline def createCompositeArraySetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Seq[T]] = { + inline def createCompositeArraySetParameter[T <: Struct: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Seq[T]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - implicit val bar: TokenConverter[T] = util.derived[T](0) - val c: TokenConverter[Seq[T]] = util.seqConverter[T](bar) - utils.PlainSQLUtils.mkArraySetParameter[T](sqlTypeName, seqToStr = Some(value => createString(c.toToken(value)))) + utils.PlainSQLUtils.mkArraySetParameter[T](sqlTypeName, seqToStr = Some(util.mkStringFromCompositeSeq[T])) } - inline def createCompositeOptionArraySetParameter[T <: Struct: Mirror.Of: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Option[Seq[T]]] = { + inline def createCompositeOptionArraySetParameter[T <: Struct: ClassTag](sqlTypeName: String, cl: ClassLoader = getClass.getClassLoader): SetParameter[Option[Seq[T]]] = { val util = new PgCompositeSupportUtils(cl, emptyMembersAsNull) - implicit val bar: TokenConverter[T] = util.derived[T](0) - val c: TokenConverter[Seq[T]] = util.seqConverter[T](bar) - utils.PlainSQLUtils.mkArrayOptionSetParameter[T](sqlTypeName, seqToStr = Some(value => createString(c.toToken(value)))) + utils.PlainSQLUtils.mkArrayOptionSetParameter[T](sqlTypeName, seqToStr = Some(util.mkStringFromCompositeSeq[T])) } } @@ -100,8 +76,32 @@ class PgCompositeSupportUtils(cl: ClassLoader, emptyMembersAsNull: Boolean) { import scala.deriving.* import scala.compiletime.{error, erasedValue, summonInline} + inline def mkCompositeFromString[T] = { + val c = deriveOrSummon[T](-1) + (input: String) => + val root = grouping(Tokenizer.tokenize(input)) + c.fromToken(root) + } + + inline def mkStringFromComposite[T] = { + val c = deriveOrSummon[T](-1) + (value: T) => createString(c.toToken(value)) + } + + inline def mkCompositeSeqFromString[T] = { + val c: TokenConverter[Seq[T]] = deriveOrSummon[Seq[T]](-1) + (input: String) => + val root = grouping(Tokenizer.tokenize(input)) + c.fromToken(root) + } + + inline def mkStringFromCompositeSeq[T] = { + val c: TokenConverter[Seq[T]] = deriveOrSummon[Seq[T]](-1) + (value: Seq[T]) => createString(c.toToken(value)) + } + def seqConverter[T](delegate: TokenConverter[T]): TokenConverter[Seq[T]] = TokenConverter[Seq[T]](delegate.level - 1, - level => token => if (token == Null) null else getChildren(token).map(delegate.fromToken), + _ => token => if (token == Null) null else getChildren(token).map(delegate.fromToken), { case vList: Seq[Any] => { val members = Open("{") +: vList.map(delegate.toToken) :+ Close("}") @@ -118,7 +118,7 @@ class PgCompositeSupportUtils(cl: ClassLoader, emptyMembersAsNull: Boolean) { } def optConverter[T](delegate: TokenConverter[T]): TokenConverter[Option[T]] = new TokenConverter[Option[T]](delegate.level, - level => token => if (isNull(token)) None else Some(delegate.fromToken(token)), + _ => token => if (isNull(token)) None else Some(delegate.fromToken(token)), { case Some(v: T) => delegate.toToken(v) case None => Null @@ -151,7 +151,7 @@ class PgCompositeSupportUtils(cl: ClassLoader, emptyMembersAsNull: Boolean) { } def convertProduct[T <: Struct: ClassTag](i: Int)(p: Mirror.ProductOf[T], elems: => List[TokenConverter[?]]): TokenConverter[T] = - new TokenConverter[T](i, level => token => + new TokenConverter[T](i, _ => token => if (token == Null) null.asInstanceOf[T] else { val args = From b35cc1ff5f4f44b759931748fe0e061816866b40 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Thu, 14 Dec 2023 00:52:29 +0000 Subject: [PATCH 13/14] dedup test --- .../tminglei/slickpg/ScalaVersionShim.scala | 25 ++ .../slickpg/PgCompositeSupportSuite.scala | 317 ------------------ .../tminglei/slickpg/ScalaVersionShim.scala | 24 ++ .../slickpg/PgCompositeSupportSuite.scala | 18 +- 4 files changed, 59 insertions(+), 325 deletions(-) create mode 100644 src/test/scala-2/com/github/tminglei/slickpg/ScalaVersionShim.scala delete mode 100644 src/test/scala-3/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala create mode 100644 src/test/scala-3/com/github/tminglei/slickpg/ScalaVersionShim.scala rename src/test/{scala-2 => scala}/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala (98%) diff --git a/src/test/scala-2/com/github/tminglei/slickpg/ScalaVersionShim.scala b/src/test/scala-2/com/github/tminglei/slickpg/ScalaVersionShim.scala new file mode 100644 index 00000000..36c7f7e8 --- /dev/null +++ b/src/test/scala-2/com/github/tminglei/slickpg/ScalaVersionShim.scala @@ -0,0 +1,25 @@ +package com.github.tminglei.slickpg + +import com.github.tminglei.slickpg.PgCompositeSupportSuite.ts +import org.postgresql.util.HStoreConverter + +import java.time.LocalDateTime +import scala.jdk.CollectionConverters._ + +object ScalaVersionShim { + def mapToString(m: Map[String, String]): String = HStoreConverter.toString((m).asJava) + def stringToMap(s: String): Map[String, String] = (HStoreConverter.fromString(s) + .asInstanceOf[java.util.Map[String, String]]).asScala.toMap + + def registerTypeConverters(): Unit = { + + utils.TypeConverters.register(PgRangeSupportUtils.mkRangeFn(ts)) + utils.TypeConverters.register(PgRangeSupportUtils.toStringFn[LocalDateTime](_.toString)) + utils.TypeConverters.register(mapToString) + utils.TypeConverters.register(stringToMap) + } + + object maybeTypeConverters {} +} + +object TypeConverters {} diff --git a/src/test/scala-3/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala b/src/test/scala-3/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala deleted file mode 100644 index 5cc77c1c..00000000 --- a/src/test/scala-3/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala +++ /dev/null @@ -1,317 +0,0 @@ -package com.github.tminglei.slickpg - -import java.time.LocalDateTime -import scala.concurrent.Await -import scala.concurrent.duration._ -import scala.collection.immutable.{Range => ScalaRange} -import scala.jdk.CollectionConverters._ -import slick.jdbc.{GetResult, PositionedResult, PostgresProfile, SetParameter} -import com.github.tminglei.slickpg.composite.Struct -import org.postgresql.util.HStoreConverter -import org.scalatest.funsuite.AnyFunSuite - -import com.github.tminglei.slickpg.utils.{RegisteredTypeConverter,TypeConverters} - - -object PgCompositeSupportSuite { - - import TypeConverters.* - def ts(str: String) = LocalDateTime.parse(str.replace(' ', 'T')) - - case class Composite1( - id: Long, - txt: String, - date: LocalDateTime, - tsRange: Option[Range[LocalDateTime]] - ) extends Struct - - case class Composite2( - id: Long, - comp1: Composite1, - confirm: Boolean, - map: Map[String, String] - ) extends Struct - - case class Composite3( - name: Option[String] = None, - code: Option[Int] = None, - num: Option[Int] = None, - bool: Option[Boolean] = None - ) extends Struct - - case class Composite4( - id: Int, - name: String, - variable: List[String], - optVars: Option[List[String]], - script1: String, - script2: String - ) extends Struct - - case class C1 ( - name: String - ) extends Struct - - case class C2 ( - c1: List[C1] - ) extends Struct - - //------------------------------------------------------------- - trait MyPostgresProfile1 extends PostgresProfile with PgCompositeSupport with PgArraySupport with utils.PgCommonJdbcTypes { - def mapToString(m: Map[String, String]): String = HStoreConverter.toString((m).asJava) - def stringToMap(s: String): Map[String, String] = (HStoreConverter.fromString(s) - .asInstanceOf[java.util.Map[String, String]]).asScala.toMap - - /// - trait API extends JdbcAPI with ArrayImplicits { - implicit val StringToRange: RegisteredTypeConverter[String, Range[LocalDateTime]] = - RegisteredTypeConverter(PgRangeSupportUtils.mkRangeFn(ts)) - implicit val RangeToString: RegisteredTypeConverter[Range[LocalDateTime], String] = - RegisteredTypeConverter(PgRangeSupportUtils.toStringFn[LocalDateTime](_.toString)) - implicit val MapToString: RegisteredTypeConverter[Map[String, String], String] = RegisteredTypeConverter(mapToString) - implicit val StringToMap: RegisteredTypeConverter[String, Map[String, String]] = RegisteredTypeConverter(stringToMap) - - implicit val composite1TypeMapper: GenericJdbcType[Composite1] = createCompositeJdbcType[Composite1]("composite1") - implicit val composite2TypeMapper: GenericJdbcType[Composite2] = createCompositeJdbcType[Composite2]("composite2") - implicit val composite3TypeMapper: GenericJdbcType[Composite3] = createCompositeJdbcType[Composite3]("composite3") - implicit val composite4TypeMapper: GenericJdbcType[Composite4] = createCompositeJdbcType[Composite4]("composite4") - implicit val c1TypeMapper: GenericJdbcType[C1] = createCompositeJdbcType[C1]("c1") - implicit val c2TypeMapper: GenericJdbcType[C2] = createCompositeJdbcType[C2]("c2") - - implicit val composite1ArrayTypeMapper: DriverJdbcType[List[Composite1]] = createCompositeArrayJdbcType[Composite1]("composite1").to(_.toList) - implicit val composite2ArrayTypeMapper: DriverJdbcType[List[Composite2]] = createCompositeArrayJdbcType[Composite2]("composite2").to(_.toList) - implicit val composite3ArrayTypeMapper: DriverJdbcType[List[Composite3]] = createCompositeArrayJdbcType[Composite3]("composite3").to(_.toList) - } - override val api: API = new API {} - - object plainImplicits extends API with SimpleArrayPlainImplicits { - import utils.PlainSQLUtils._ - // to support 'nextArray[T]/nextArrayOption[T]' in PgArraySupport - { - addNextArrayConverter((r) => nextCompositeArray[Composite1](r)) - addNextArrayConverter((r) => nextCompositeArray[Composite2](r)) - addNextArrayConverter((r) => nextCompositeArray[Composite3](r)) - } - - implicit class MyCompositePositionedResult(r: PositionedResult) { - def nextComposite1() = nextComposite[Composite1](r) - def nextComposite2() = nextComposite[Composite2](r) - def nextComposite3() = nextComposite[Composite3](r) - } - - implicit val composite1SetParameter: SetParameter[Composite1] = createCompositeSetParameter[Composite1]("composite1") - implicit val composite1OptSetParameter: SetParameter[Option[Composite1]] = createCompositeOptionSetParameter[Composite1]("composite1") - implicit val composite1ArraySetParameter: SetParameter[Seq[Composite1]] = createCompositeArraySetParameter[Composite1]("composite1") - implicit val composite1ArrayOptSetParameter: SetParameter[Option[Seq[Composite1]]] = createCompositeOptionArraySetParameter[Composite1]("composite1") - - implicit val composite2SetParameter: SetParameter[Composite2] = createCompositeSetParameter[Composite2]("composite2") - implicit val composite2OptSetParameter: SetParameter[Option[Composite2]] = createCompositeOptionSetParameter[Composite2]("composite2") - implicit val composite2ArraySetParameter: SetParameter[Seq[Composite2]] = createCompositeArraySetParameter[Composite2]("composite2") - implicit val composite2ArrayOptSetParameter: SetParameter[Option[Seq[Composite2]]] = createCompositeOptionArraySetParameter[Composite2]("composite2") - - implicit val composite3SetParameter: SetParameter[Composite3] = createCompositeSetParameter[Composite3]("composite3") - implicit val composite3OptSetParameter: SetParameter[Option[Composite3]] = createCompositeOptionSetParameter[Composite3]("composite3") - implicit val composite3ArraySetParameter: SetParameter[Seq[Composite3]] = createCompositeArraySetParameter[Composite3]("composite3") - implicit val composite3ArrayOptSetParameter: SetParameter[Option[Seq[Composite3]]] = createCompositeOptionArraySetParameter[Composite3]("composite3") - } - } - object MyPostgresProfile1 extends MyPostgresProfile1 -} - -/// -class PgCompositeSupportSuite extends AnyFunSuite with PostgresContainer { - import PgCompositeSupportSuite._ - import MyPostgresProfile1.api._ - - lazy val db = Database.forURL(url = container.jdbcUrl, driver = "org.postgresql.Driver") - - case class TestBean( - id: Long, - comps: List[Composite2] - ) - - case class TestBean1( - id: Long, - comps: List[Composite3] - ) - - case class TestBean2( - id: Long, - comps: Composite1, - c2: C2 - ) - - case class TestBean3( - id: Long, - comps: Option[Composite4] - ) - - class TestTable(tag: Tag) extends Table[TestBean](tag, "CompositeTest") { - def id = column[Long]("id") - def comps = column[List[Composite2]]("comps", O.Default(Nil)) - - def * = (id,comps) <> ((TestBean.apply _).tupled, TestBean.unapply) - } - val CompositeTests = TableQuery(new TestTable(_)) - - class TestTable1(tag: Tag) extends Table[TestBean1](tag, "CompositeTest1") { - def id = column[Long]("id") - def comps = column[List[Composite3]]("comps") - - def * = (id,comps) <> ((TestBean1.apply _).tupled, TestBean1.unapply) - } - val CompositeTests1 = TableQuery(new TestTable1(_)) - - class TestTable2(tag: Tag) extends Table[TestBean2](tag, "CompositeTest2") { - def id = column[Long]("id") - def comps = column[Composite1]("comp") - def c2 = column[C2]("c2") - - def * = (id,comps,c2) <> ((TestBean2.apply _).tupled, TestBean2.unapply) - } - val CompositeTests2 = TableQuery(new TestTable2(_)) - - class TestTable3(tag: Tag) extends Table[TestBean3](tag, "CompositeTest3") { - def id = column[Long]("id") - def comps = column[Option[Composite4]]("comp") - - def * = (id, comps) <> ((TestBean3.apply _).tupled, TestBean3.unapply) - } - val CompositeTests3 = TableQuery(new TestTable3(_)) - - //------------------------------------------------------------------- - - val rec1 = TestBean(333, List(Composite2(201, Composite1(101, "(test1'", ts("2001-01-03T13:21:00"), - Some(Range(ts("2010-01-01T14:30:00"), ts("2010-01-03T15:30:00")))), true, Map("t" -> "haha", "t2" -> "133")))) - val rec2 = TestBean(335, List(Composite2(202, Composite1(102, "test2\\", ts("2012-05-08T11:31:06"), - Some(Range(ts("2011-01-01T14:30:00"), ts("2011-11-01T15:30:00")))), false, Map("t't" -> "1,363")))) - val rec3 = TestBean(337, List(Composite2(203, Composite1(103, "getRate(\"x\") + 5;", ts("2015-03-08T17:17:03"), - None), false, Map("t,t" -> "getRate(\"x\") + 5;")))) - val rec4 = TestBean(339, List(Composite2(204, Composite1(104, "x=1&y=2&[INSERT_DEVICE_ID_HERE]&z=3", ts("2001-01-03T13:21:00"), - Some(Range(ts("2010-01-01T14:30:00"), ts("2010-01-03T15:30:00")))), true, Map("t" -> "haha", "t2" -> "133")))) - - val rec11 = TestBean1(111, List(Composite3(Some("(test1'")))) - val rec12 = TestBean1(112, List(Composite3(code = Some(102)))) - val rec13 = TestBean1(113, List(Composite3())) - val rec14 = TestBean1(114, List(Composite3(Some("Word1 (Word2)")))) - val rec15 = TestBean1(115, List(Composite3(Some("")))) - - val rec21 = TestBean2(211, Composite1(201, "test3", ts("2015-01-03T13:21:00"), - Some(Range(ts("2015-01-01T14:30:00"), ts("2016-01-03T15:30:00")))), C2(List(C1("1s")))) - val rec22 = TestBean2(212, Composite1(202, "", ts("2015-01-03T13:21:00"), - Some(Range(ts("2015-01-01T14:30:00"), ts("2016-01-03T15:30:00")))), C2(List(C1("test1")))) - - val rec31 = TestBean3(1, None) - val rec32 = TestBean3(2, Some(Composite4(1, "x1", Nil, Some(List.empty), "get(\"x1\").ok", "(4).ok"))) - val rec32_al = TestBean3(2, Some(Composite4(1, "x1", Nil, None, "get(\"x1\").ok", "(4).ok"))) - val rec33 = TestBean3(3, Some(Composite4(2, "x2", List("xxx(yyy)zz,z", "u(vv)(w)x(y)", "x=1&y=2&[INSERT_DEVICE_ID_HERE]&z=3"), Some(List("\"t")), "(get(\"A\") + get(\"A\")).ok", "call(A, B).ok"))) - - test("Composite type Lifted support") { - Await.result(db.run( - DBIO.seq( - sqlu"create type composite1 as (id int8, txt text, date timestamp, ts_range tsrange)", - sqlu"create type composite2 as (id int8, comp1 composite1, confirm boolean, map hstore)", - sqlu"create type composite3 as (txt text, id int4, code int4, bool boolean)", - sqlu"create type composite4 as (id int4, name text, variable text[], optVars text[], script1 text, script2 text)", - sqlu"create type c1 as (name text)", - sqlu"create type c2 as (c1 c1[])", - (CompositeTests.schema ++ CompositeTests1.schema ++ CompositeTests2.schema ++ CompositeTests3.schema) create, - CompositeTests forceInsertAll List(rec1, rec2, rec3, rec4), - CompositeTests1 forceInsertAll List(rec11, rec12, rec13, rec14, rec15), - CompositeTests2 forceInsertAll List(rec21, rec22), - CompositeTests3 forceInsertAll List(rec31, rec32, rec33) - ).andThen( - DBIO.seq( - CompositeTests.filter(_.id === 333L.bind).result.head.map( - r => assert(rec1 === r) - ), - CompositeTests.filter(_.id === 335L.bind).result.head.map( - r => assert(rec2 === r) - ), - CompositeTests.filter(_.id === 337L.bind).result.head.map( - r => assert(rec3 === r) - ), - CompositeTests.filter(_.id === 339L.bind).result.head.map( - r => assert(rec4 === r) - ) - ) - ).andThen( - DBIO.seq( - CompositeTests1.filter(_.id === 111L.bind).result.head.map( - r => assert(rec11 === r) - ), - CompositeTests1.filter(_.id === 112L.bind).result.head.map( - r => assert(rec12 === r) - ), - CompositeTests1.filter(_.id === 113L.bind).result.head.map( - r => assert(rec13 === r) - ), - CompositeTests1.filter(_.id === 114L.bind).result.head.map( - r => assert(rec14 === r) - ), - CompositeTests1.filter(_.id === 115L.bind).result.head.map( - r => assert(rec15 === r) - ), - CompositeTests2.filter(_.comps === rec21.comps.asColumnOf[Composite1]).result.head.map( - r => assert(rec21 === r) - ) - ) - ).andThen( - DBIO.seq( - CompositeTests2.filter(_.id === 211L.bind).result.head.map( - r => assert(rec21 === r) - ), - CompositeTests2.filter(_.id === 212L.bind).result.head.map( - r => assert(rec22 === r) - ) - ) - ).andThen( - DBIO.seq( - CompositeTests3.filter(_.id === 1L.bind).result.head.map(r => assert(rec31 === r)), - CompositeTests3.filter(_.id === 2L.bind).result.head.map(r => assert(rec32_al === r)), - CompositeTests3.filter(_.id === 3L.bind).result.head.map(r => assert(rec33 === r)) - ) - ).andFinally( - DBIO.seq( - (CompositeTests.schema ++ CompositeTests1.schema ++ CompositeTests2.schema ++ CompositeTests3.schema) drop, - sqlu"drop type c2", - sqlu"drop type c1", - sqlu"drop type composite4", - sqlu"drop type composite3", - sqlu"drop type composite2", - sqlu"drop type composite1" - ) - ).transactionally - ), Duration.Inf) - } - - test("Composite type Plain SQL support") { - import MyPostgresProfile1.plainImplicits._ - - implicit val getTestBeanResult: GetResult[TestBean] = GetResult(r => TestBean(r.nextLong(), r.nextArray[Composite2]().toList)) - implicit val getTestBean1Result: GetResult[TestBean1] = GetResult(r => TestBean1(r.nextLong(), r.nextArray[Composite3]().toList)) - - Await.result(db.run(DBIO.seq( - sqlu"create type composite1 as (id int8, txt text, date timestamp, ts_range tsrange)", - sqlu"create type composite2 as (id int8, comp1 composite1, confirm boolean, map hstore)", - sqlu"create type composite3 as (txt text, id int4, code int4, bool boolean)", - sqlu"create table CompositeTest (id BIGINT NOT NULL, comps composite2[] DEFAULT '{}' NOT NULL)", - sqlu"create table CompositeTest1 (id BIGINT NOT NULL, comps composite3[] NOT NULL)", - /// - sqlu"insert into CompositeTest values(${rec1.id}, ${rec1.comps})", - sql"select * from CompositeTest where id = ${rec1.id}".as[TestBean].head.map( - r => assert(rec1 === r) - ), - sqlu"insert into CompositeTest1 values(${rec11.id}, ${rec11.comps})", - sql"select * from CompositeTest1 where id = ${rec11.id}".as[TestBean1].head.map( - r => assert(rec11 === r) - ), - /// - sqlu"drop table CompositeTest1", - sqlu"drop table CompositeTest", - sqlu"drop type composite3", - sqlu"drop type composite2", - sqlu"drop type composite1" - ).transactionally), Duration.Inf) - } -} diff --git a/src/test/scala-3/com/github/tminglei/slickpg/ScalaVersionShim.scala b/src/test/scala-3/com/github/tminglei/slickpg/ScalaVersionShim.scala new file mode 100644 index 00000000..9d2f16dd --- /dev/null +++ b/src/test/scala-3/com/github/tminglei/slickpg/ScalaVersionShim.scala @@ -0,0 +1,24 @@ +package com.github.tminglei.slickpg + +import com.github.tminglei.slickpg.utils.{RegisteredTypeConverter,TypeConverters} + +import org.postgresql.util.HStoreConverter + +import java.time.LocalDateTime +import scala.jdk.CollectionConverters._ + +object ScalaVersionShim { + def ts(str: String) = LocalDateTime.parse(str.replace(' ', 'T')) + def mapToString(m: Map[String, String]): String = HStoreConverter.toString((m).asJava) + def stringToMap(s: String): Map[String, String] = (HStoreConverter.fromString(s) + .asInstanceOf[java.util.Map[String, String]]).asScala.toMap + implicit val StringToRange: RegisteredTypeConverter[String, Range[LocalDateTime]] = + RegisteredTypeConverter(PgRangeSupportUtils.mkRangeFn(ts)) + implicit val RangeToString: RegisteredTypeConverter[Range[LocalDateTime], String] = + RegisteredTypeConverter(PgRangeSupportUtils.toStringFn[LocalDateTime](_.toString)) + implicit val MapToString: RegisteredTypeConverter[Map[String, String], String] = RegisteredTypeConverter(mapToString) + implicit val StringToMap: RegisteredTypeConverter[String, Map[String, String]] = RegisteredTypeConverter(stringToMap) + + def registerTypeConverters(): Unit = () + val maybeTypeConverters: RegisteredTypeConverter.type = RegisteredTypeConverter +} diff --git a/src/test/scala-2/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala b/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala similarity index 98% rename from src/test/scala-2/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala rename to src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala index 2bbbbcd5..b1ab9b2d 100644 --- a/src/test/scala-2/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala +++ b/src/test/scala/com/github/tminglei/slickpg/PgCompositeSupportSuite.scala @@ -1,16 +1,21 @@ package com.github.tminglei.slickpg +import com.github.tminglei.slickpg.composite.Struct +import org.postgresql.util.HStoreConverter +import org.scalatest.funsuite.AnyFunSuite +import slick.jdbc.{GetResult, PositionedResult, PostgresProfile, SetParameter} +import com.github.tminglei.slickpg.utils.TypeConverters + import java.time.LocalDateTime import scala.concurrent.Await import scala.concurrent.duration._ import scala.jdk.CollectionConverters._ -import slick.jdbc.{GetResult, PositionedResult, PostgresProfile, SetParameter} -import com.github.tminglei.slickpg.composite.Struct -import org.postgresql.util.HStoreConverter -import org.scalatest.funsuite.AnyFunSuite object PgCompositeSupportSuite { + import TypeConverters._ + import ScalaVersionShim._ + import ScalaVersionShim.maybeTypeConverters._ def ts(str: String) = LocalDateTime.parse(str.replace(' ', 'T')) case class Composite1( @@ -59,10 +64,7 @@ object PgCompositeSupportSuite { /// trait API extends JdbcAPI with ArrayImplicits { - utils.TypeConverters.register(PgRangeSupportUtils.mkRangeFn(ts)) - utils.TypeConverters.register(PgRangeSupportUtils.toStringFn[LocalDateTime](_.toString)) - utils.TypeConverters.register(mapToString) - utils.TypeConverters.register(stringToMap) + registerTypeConverters() implicit val composite1TypeMapper: GenericJdbcType[Composite1] = createCompositeJdbcType[Composite1]("composite1") implicit val composite2TypeMapper: GenericJdbcType[Composite2] = createCompositeJdbcType[Composite2]("composite2") From 5f0d9cc20c6734449d70b3768f4694a98dbc7bd5 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Sat, 16 Dec 2023 21:10:06 +0000 Subject: [PATCH 14/14] revert play bump, didn't need it --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 53ba7ea9..2ff960fa 100644 --- a/build.sbt +++ b/build.sbt @@ -146,7 +146,7 @@ lazy val slickPgPlayJson = (project in file("./addons/play-json")) name := "slick-pg_play-json", description := "Slick extensions for PostgreSQL - play-json module", libraryDependencies := mainDependencies(scalaVersion.value) ++ - Seq("org.playframework" %% "play-json" % "3.0.1") + Seq("com.typesafe.play" %% "play-json" % "2.10.3") ) .dependsOn (slickPgCore % "test->test;compile->compile")