From 2f151dbd8b86dc014af7ee70317cedbe2da74e66 Mon Sep 17 00:00:00 2001 From: Sam Guymer Date: Sat, 28 Dec 2024 12:31:48 +1000 Subject: [PATCH] Remove auto derivation --- README.md | 2 +- .../scala-2/doobie/util/ReadPlatform.scala | 5 --- .../scala-2/doobie/util/WritePlatform.scala | 5 --- .../scala-3/doobie/util/ReadPlatform.scala | 5 --- .../scala-3/doobie/util/WritePlatform.scala | 5 --- .../src/main/scala/doobie/util/read.scala | 3 -- .../src/main/scala/doobie/util/write.scala | 2 - .../doobie/util/ReadSuitePlatform.scala | 3 +- .../doobie/util/WriteSuitePlatform.scala | 3 +- .../scala/doobie/util/FragmentSuite.scala | 1 - .../scala/doobie/util/FragmentsSuite.scala | 3 +- .../test/scala/doobie/util/QuerySuite.scala | 1 - .../test/scala/doobie/util/ReadSuite.scala | 16 +++----- .../test/scala/doobie/util/UpdateSuite.scala | 7 ++-- .../test/scala/doobie/util/WriteSuite.scala | 37 ++++--------------- .../docs/src/main/mdoc/docs/04-Selecting.md | 11 +++++- .../src/main/mdoc/docs/05-Parameterized.md | 7 +++- .../docs/src/main/mdoc/docs/06-Checking.md | 11 +++++- .../docs/src/main/mdoc/docs/07-Updating.md | 8 +++- .../docs/src/main/mdoc/docs/08-Fragments.md | 7 +++- .../src/main/mdoc/docs/09-Error-Handling.md | 7 +++- modules/docs/src/main/mdoc/docs/11-Arrays.md | 7 +++- .../src/main/mdoc/docs/12-Custom-Mappings.md | 2 - .../src/main/mdoc/docs/13-Unit-Testing.md | 7 +++- modules/docs/src/main/mdoc/docs/17-FAQ.md | 17 ++++++++- modules/docs/src/main/mdoc/index.md | 5 ++- .../src/main/scala/example/AnalysisTest.scala | 8 +++- .../main/scala/example/CustomReadWrite.scala | 8 +++- .../src/main/scala/example/FirstExample.scala | 11 +++++- .../src/main/scala/example/HiUsage.scala | 4 +- .../example/src/main/scala/example/Join.scala | 8 +++- .../src/main/scala/example/StreamToFile.scala | 1 - .../scala/doobie/munit/CheckerTests.scala | 33 +++-------------- .../scala/doobie/weaver/CheckerTests.scala | 32 +++------------- 34 files changed, 137 insertions(+), 155 deletions(-) diff --git a/README.md b/README.md index 660f2a2bb..df4bf5093 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **foobie** is a fork of [doobie](https://github.com/tpolecat/doobie) that aims to try and keep source compatability. Currently contains the following changes: -- `Read` and `Write` derivation is now opt-in via `import doobie.util.Read.Auto.*` and `import doobie.util.Write.Auto.*` +- There is no `Read` or `Write` auto derivation - Java time instances are available without an explicit import - removed Scala 2.12 support along with *IO implicits in `doobie.implicit.*` import - PostGIS instances have been moved to the new `postgis` module and are available under `doobie.postgis.instances.{geography,geometry}` diff --git a/modules/core/src/main/scala-2/doobie/util/ReadPlatform.scala b/modules/core/src/main/scala-2/doobie/util/ReadPlatform.scala index b3946cd84..60b9eb2cc 100644 --- a/modules/core/src/main/scala-2/doobie/util/ReadPlatform.scala +++ b/modules/core/src/main/scala-2/doobie/util/ReadPlatform.scala @@ -29,8 +29,3 @@ trait ReadPlatform { def derived[A]: Read[A] = macro Magnolia.gen[A] } - -trait ReadAutoPlatform extends ReadPlatform { - - implicit def genRead[A]: Read[A] = macro Magnolia.gen[A] -} diff --git a/modules/core/src/main/scala-2/doobie/util/WritePlatform.scala b/modules/core/src/main/scala-2/doobie/util/WritePlatform.scala index 987dee9f2..6f8264756 100644 --- a/modules/core/src/main/scala-2/doobie/util/WritePlatform.scala +++ b/modules/core/src/main/scala-2/doobie/util/WritePlatform.scala @@ -49,8 +49,3 @@ trait WritePlatform { def derived[A]: Write[A] = macro Magnolia.gen[A] } - -trait WriteAutoPlatform extends WritePlatform { - - implicit def genWrite[A]: Write[A] = macro Magnolia.gen[A] -} diff --git a/modules/core/src/main/scala-3/doobie/util/ReadPlatform.scala b/modules/core/src/main/scala-3/doobie/util/ReadPlatform.scala index 22ffdd2a2..f4cdf0f63 100644 --- a/modules/core/src/main/scala-3/doobie/util/ReadPlatform.scala +++ b/modules/core/src/main/scala-3/doobie/util/ReadPlatform.scala @@ -31,8 +31,3 @@ class ReadPlatformInstance[A](m: Mirror.ProductOf[A], typeclasses: => List[Read[ m.fromProduct(Tuple.fromArray(values)) } } - -trait ReadAutoPlatform extends ReadPlatform { - - inline implicit def genRead[A](using m: Mirror.ProductOf[A]): Read[A] = derived[A] -} diff --git a/modules/core/src/main/scala-3/doobie/util/WritePlatform.scala b/modules/core/src/main/scala-3/doobie/util/WritePlatform.scala index 96b95499a..ffca22321 100644 --- a/modules/core/src/main/scala-3/doobie/util/WritePlatform.scala +++ b/modules/core/src/main/scala-3/doobie/util/WritePlatform.scala @@ -56,8 +56,3 @@ class WritePlatformInstance[A](typeclasses: => List[Write[?]]) extends Write[A] } } } - -trait WriteAutoPlatform extends WritePlatform { - - inline implicit def genWrite[A](using m: Mirror.ProductOf[A]): Write[A] = derived[A] -} diff --git a/modules/core/src/main/scala/doobie/util/read.scala b/modules/core/src/main/scala/doobie/util/read.scala index d4c79e2fd..740360d89 100644 --- a/modules/core/src/main/scala/doobie/util/read.scala +++ b/modules/core/src/main/scala/doobie/util/read.scala @@ -25,7 +25,6 @@ This can happen for a few reasons, but the most common case is that a data member somewhere within this type doesn't have a Get instance in scope. Here are some debugging hints: -- For auto derivation ensure `doobie.util.Read.Auto.*` is being imported - For Option types, ensure that a Read instance is in scope for the non-Option version. - For types you expect to map to a single column ensure that a Get instance is in scope. - For case classes and tuples ensure that each element has a Read instance in scope. @@ -92,8 +91,6 @@ object Read extends Read1 { F: Read[F], ): Read[(A, B, C, D, E, F)] = (A, B, C, D, E, F).tupled - object Auto extends ReadAutoPlatform - implicit val ReadApply: Apply[Read] = new Apply[Read] { override def map[A, B](fa: Read[A])(f: A => B) = fa.map(f) override def ap[A, B](ff: Read[A => B])(fa: Read[A]) = fa.ap(ff) diff --git a/modules/core/src/main/scala/doobie/util/write.scala b/modules/core/src/main/scala/doobie/util/write.scala index 306b0789e..80fec2eb8 100644 --- a/modules/core/src/main/scala/doobie/util/write.scala +++ b/modules/core/src/main/scala/doobie/util/write.scala @@ -90,8 +90,6 @@ object Write extends Write1 { F: Write[F], ): Write[(A, B, C, D, E, F)] = (A, B, C, D, E, F).tupled - object Auto extends WriteAutoPlatform - implicit val WriteContravariantSemigroupal: ContravariantSemigroupal[Write] = new ContravariantSemigroupal[Write] { override def contramap[A, B](fa: Write[A])(f: B => A) = fa.contramap(f) override def product[A, B](fa: Write[A], fb: Write[B]) = fa.product(fb) diff --git a/modules/core/src/test/scala-2/doobie/util/ReadSuitePlatform.scala b/modules/core/src/test/scala-2/doobie/util/ReadSuitePlatform.scala index e0bc635d9..d9ca636f6 100644 --- a/modules/core/src/test/scala-2/doobie/util/ReadSuitePlatform.scala +++ b/modules/core/src/test/scala-2/doobie/util/ReadSuitePlatform.scala @@ -10,8 +10,7 @@ trait ReadSuitePlatform { self: ReadSuite.type => protected def platformTests = List( test("Read should exist for AnyVal") { - import doobie.util.Read.Auto.* - + implicit val read: Read[X] = Read.derived assertTrue(Read[X].length == 1) }, ) diff --git a/modules/core/src/test/scala-2/doobie/util/WriteSuitePlatform.scala b/modules/core/src/test/scala-2/doobie/util/WriteSuitePlatform.scala index ca901e77f..b9bd1df51 100644 --- a/modules/core/src/test/scala-2/doobie/util/WriteSuitePlatform.scala +++ b/modules/core/src/test/scala-2/doobie/util/WriteSuitePlatform.scala @@ -10,8 +10,7 @@ trait WriteSuitePlatform { self: WriteSuite.type => protected def platformTests = List( test("exist for AnyVal") { - import doobie.util.Write.Auto.* - + implicit val write: Write[X] = Write.derived assertTrue(Write[X].length == 1) }, ) diff --git a/modules/core/src/test/scala/doobie/util/FragmentSuite.scala b/modules/core/src/test/scala/doobie/util/FragmentSuite.scala index 950a16d0e..d11bde223 100644 --- a/modules/core/src/test/scala/doobie/util/FragmentSuite.scala +++ b/modules/core/src/test/scala/doobie/util/FragmentSuite.scala @@ -12,7 +12,6 @@ import zio.test.assertCompletes import zio.test.assertTrue object FragmentSuite extends H2DatabaseSpec { - import doobie.util.Read.Auto.* private val a = 1 private val b = "two" diff --git a/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala b/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala index c6e84f991..79a161a14 100644 --- a/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala +++ b/modules/core/src/test/scala/doobie/util/FragmentsSuite.scala @@ -11,7 +11,6 @@ import doobie.util.meta.Meta import zio.test.assertTrue object FragmentsSuite extends H2DatabaseSpec { - import doobie.util.Write.Auto.* import doobie.util.fragments.* private val nel = NonEmptyList.of(1, 2, 3) @@ -126,11 +125,13 @@ object FragmentsSuite extends H2DatabaseSpec { case class Person(name: String, age: Int) object Person { implicit val read: Read[Person] = Read.derived + implicit val write: Write[Person] = Write.derived } case class Contact(person: Person, address: Option[String]) object Contact { implicit val read: Read[Contact] = Read.derived + implicit val write: Write[Contact] = Write.derived } } diff --git a/modules/core/src/test/scala/doobie/util/QuerySuite.scala b/modules/core/src/test/scala/doobie/util/QuerySuite.scala index bbf805e12..2ac016fa2 100644 --- a/modules/core/src/test/scala/doobie/util/QuerySuite.scala +++ b/modules/core/src/test/scala/doobie/util/QuerySuite.scala @@ -11,7 +11,6 @@ import doobie.util.query.Query0 import zio.test.assertTrue object QuerySuite extends H2DatabaseSpec { - import doobie.util.Read.Auto.* private val q = Query[String, Int]("select 123 where ? = 'foo'", None) private val pairQuery = Query[String, (String, Int)]("select 'xxx', 123 where ? = 'foo'", None) diff --git a/modules/core/src/test/scala/doobie/util/ReadSuite.scala b/modules/core/src/test/scala/doobie/util/ReadSuite.scala index 2c3024936..9a58d902d 100644 --- a/modules/core/src/test/scala/doobie/util/ReadSuite.scala +++ b/modules/core/src/test/scala/doobie/util/ReadSuite.scala @@ -17,6 +17,9 @@ object ReadSuite extends H2DatabaseSpec with ReadSuitePlatform { case class X(x: Int) extends AnyVal case class LenStr1(n: Int, s: String) + object LenStr1 { + implicit val read: Read[LenStr1] = Read.derived + } case class LenStr2(n: Int, s: String) object LenStr2 { @@ -44,6 +47,9 @@ object ReadSuite extends H2DatabaseSpec with ReadSuitePlatform { } case class Woozle(a: (String, Int), b: (Int, String), c: Boolean) + object Woozle { + implicit val read: Read[Woozle] = Read.derived + } override val spec = suite("Read")( test("tuples derive") { @@ -61,8 +67,6 @@ object ReadSuite extends H2DatabaseSpec with ReadSuitePlatform { assertTrue(Read.derived[LenStr1].length == 2) }, test("exist for Unit") { - import doobie.util.Read.Auto.* - assertTrue(Read[Unit].length == 0) && assertTrue(Read[(Int, Unit)].length == 1) }, @@ -75,30 +79,22 @@ object ReadSuite extends H2DatabaseSpec with ReadSuitePlatform { assertCompletes }, test("exist for option of Unit") { - import doobie.util.Read.Auto.* - assertTrue(Read[Option[Unit]].length == 0) && assertTrue(Read[Option[(Int, Unit)]].length == 1) }, test("select multi-column instance by default") { - import doobie.util.Read.Auto.* - assertTrue(Read[LenStr1].length == 2) }, test("select 1-column instance when available") { assertTrue(Read[LenStr2].length == 1) }, test("exist for some fancy types") { - import doobie.util.Read.Auto.* - val _ = Read[Woozle] val _ = Read[(Woozle, String)] val _ = Read[(Int, (Woozle, Woozle, String))] assertCompletes }, test("exist for option of some fancy types") { - import doobie.util.Read.Auto.* - val _ = Read[Option[Woozle]] val _ = Read[Option[(Woozle, String)]] val _ = Read[Option[(Int, (Woozle, Woozle, String))]] diff --git a/modules/core/src/test/scala/doobie/util/UpdateSuite.scala b/modules/core/src/test/scala/doobie/util/UpdateSuite.scala index eb8089e98..546679673 100644 --- a/modules/core/src/test/scala/doobie/util/UpdateSuite.scala +++ b/modules/core/src/test/scala/doobie/util/UpdateSuite.scala @@ -30,10 +30,11 @@ object UpdateSuite extends H2DatabaseSpec { conn.transact }, test("write") { - import doobie.util.Read.Auto.* - import doobie.util.Write.Auto.* - case class Id(v: Int) + object Id { + implicit val get: Get[Id] = Get[Int].map(apply(_)) + implicit val put: Put[Id] = Put[Int].contramap(_.v) + } val someId: Option[Id] = Some(Id(2)) val noneId: Option[Id] = None diff --git a/modules/core/src/test/scala/doobie/util/WriteSuite.scala b/modules/core/src/test/scala/doobie/util/WriteSuite.scala index 620411f72..acff8318d 100644 --- a/modules/core/src/test/scala/doobie/util/WriteSuite.scala +++ b/modules/core/src/test/scala/doobie/util/WriteSuite.scala @@ -22,6 +22,9 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { case class X(x: Int) extends AnyVal case class LenStr1(n: Int, s: String) + object LenStr1 { + implicit val write: Write[LenStr1] = Write.derived + } case class LenStr2(n: Int, s: String) object LenStr2 { @@ -34,6 +37,9 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { } case class Woozle(a: (String, Int), b: (Int, String), c: Boolean) + object Woozle { + implicit val write: Write[Woozle] = Write.derived + } override val spec = suite("Write")( test("tuples derive") { @@ -47,8 +53,6 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { assertTrue(Write.derived[LenStr1].length == 2) }, test("deriving instances should work correctly from class scope") { - import doobie.util.Write.Auto.* - class Foo[A: Write, B: Write] { locally { val _ = Write[(A, B)] @@ -57,8 +61,6 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { assertCompletes }, test("exist for Unit") { - import doobie.util.Write.Auto.* - val _ = Write[Unit] assertTrue(Write[(Int, Unit)].length == 1) }, @@ -70,40 +72,27 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { val _ = Write[Option[(Int, Option[(Int, String)])]] assertCompletes }, - test("auto derives nested types") { - import doobie.util.Write.Auto.* - - assertTrue(Write[Widget].length == 3) - }, - test("does not auto derive nested types without an import") { + test("does not auto derive") { val _ = illTyped("Write.derived[Widget]") assertCompletes }, test("exist for option of Unit") { - import doobie.util.Write.Auto.* - assertTrue(Write[Option[Unit]].length == 0) && assertTrue(Write[Option[(Int, Unit)]].length == 1) }, test("select multi-column instance by default") { - import doobie.util.Write.Auto.* - assertTrue(Write[LenStr1].length == 2) }, test("select 1-column instance when available") { assertTrue(Write[LenStr2].length == 1) }, test("exist for some fancy types") { - import doobie.util.Write.Auto.* - val _ = Write[Woozle] val _ = Write[(Woozle, String)] val _ = Write[(Int, (Woozle, Woozle, String))] assertCompletes }, test("exist for option of some fancy types") { - import doobie.util.Write.Auto.* - val _ = Write[Option[Woozle]] val _ = Write[Option[(Woozle, String)]] val _ = Write[Option[(Int, (Woozle, Woozle, String))]] @@ -124,11 +113,6 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { t2 <- insert(Test(None, Some("str")))(Test.write) t3 <- insert(Test(Some(3), Some("str")))(Test.write) - tAuto <- { - import doobie.util.Write.Auto.* - insert(Test(Some(3), Some("str"))) - } - tup1 <- insert[(Option[Int], Option[String])]((None, None))(Test.writeTuple) tup2 <- insert[(Option[Int], Option[String])]((None, Some("str")))(Test.writeTuple) tup3 <- insert[(Option[Int], Option[String])]((Some(3), Some("str")))(Test.writeTuple) @@ -136,7 +120,6 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { assertTrue(t1 == Test(None, None)) && assertTrue(t2 == Test(None, Some("str"))) && assertTrue(t3 == Test(Some(3), Some("str"))) && - assertTrue(tAuto == Test(Some(3), Some("str"))) && assertTrue(tup1 == Test(None, None)) && assertTrue(tup2 == Test(None, Some("str"))) && assertTrue(tup3 == Test(Some(3), Some("str"))) @@ -159,11 +142,6 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { t2 <- insert(Test(None, Some("str")))(Test.write) t3 <- insert(Test(Some(3), Some("str")))(Test.write) - tAuto <- { - import doobie.util.Write.Auto.* - insert(Test(Some(3), Some("str"))) - } - tup1 <- insert[(Option[Int], Option[String])]((None, None))(Test.writeTuple) tup2 <- insert[(Option[Int], Option[String])]((None, Some("str")))(Test.writeTuple) tup3 <- insert[(Option[Int], Option[String])]((Some(3), Some("str")))(Test.writeTuple) @@ -171,7 +149,6 @@ object WriteSuite extends H2DatabaseSpec with WriteSuitePlatform { assertTrue(t1 == Test(None, None)) && assertTrue(t2 == Test(None, Some("str"))) && assertTrue(t3 == Test(Some(3), Some("str"))) && - assertTrue(tAuto == Test(Some(3), Some("str"))) && assertTrue(tup1 == Test(None, None)) && assertTrue(tup2 == Test(None, Some("str"))) && assertTrue(tup3 == Test(Some(3), Some("str"))) diff --git a/modules/docs/src/main/mdoc/docs/04-Selecting.md b/modules/docs/src/main/mdoc/docs/04-Selecting.md index 1bc82080f..e099cdc8e 100644 --- a/modules/docs/src/main/mdoc/docs/04-Selecting.md +++ b/modules/docs/src/main/mdoc/docs/04-Selecting.md @@ -13,7 +13,7 @@ import doobie.syntax.connectionio.* import doobie.syntax.stream.* import doobie.syntax.string.* import doobie.util.ExecutionContexts -import doobie.util.Read.Auto.* +import doobie.util.Read import doobie.util.transactor.Transactor import cats.* import cats.data.* @@ -139,6 +139,9 @@ Mapping rows to a case class. ```scala mdoc:silent case class Country(code: String, name: String, pop: Int, gnp: Option[Double]) +object Country { + implicit val read: Read[Country] = Read.derived +} ``` ```scala mdoc @@ -154,7 +157,13 @@ You can also nest case classes, and/or tuples arbitrarily as long as the eventua ```scala mdoc:silent case class Code(code: String) +object Code { + implicit val read: Read[Code] = Read.derived +} case class Country2(name: String, pop: Int, gnp: Option[Double]) +object Country2 { + implicit val read: Read[Country2] = Read.derived +} ``` ```scala mdoc diff --git a/modules/docs/src/main/mdoc/docs/05-Parameterized.md b/modules/docs/src/main/mdoc/docs/05-Parameterized.md index 3487d0aa0..65abafb62 100644 --- a/modules/docs/src/main/mdoc/docs/05-Parameterized.md +++ b/modules/docs/src/main/mdoc/docs/05-Parameterized.md @@ -14,9 +14,8 @@ import doobie.HPS import doobie.free.connection.ConnectionIO import doobie.syntax.string.* import doobie.util.ExecutionContexts -import doobie.util.Read.Auto.* +import doobie.util.Read import doobie.util.Write -import doobie.util.Write.Auto.* import doobie.util.transactor.Transactor import cats.* import cats.data.* @@ -62,6 +61,10 @@ Let's set up our Country class and re-run last chapter's query just to review. ```scala mdoc:silent case class Country(code: String, name: String, pop: Int, gnp: Option[Double]) +object Country { + implicit val read: Read[Country] = Read.derived + implicit val write: Write[Country] = Write.derived +} ``` ```scala mdoc diff --git a/modules/docs/src/main/mdoc/docs/06-Checking.md b/modules/docs/src/main/mdoc/docs/06-Checking.md index a6bf67496..792ee11a4 100644 --- a/modules/docs/src/main/mdoc/docs/06-Checking.md +++ b/modules/docs/src/main/mdoc/docs/06-Checking.md @@ -9,7 +9,8 @@ Our setup here is the same as last chapter, so if you're still running from last ```scala mdoc:silent import doobie.syntax.string.* import doobie.util.ExecutionContexts -import doobie.util.Read.Auto.* +import doobie.util.Read +import doobie.util.Write import doobie.util.transactor.Transactor import cats.* import cats.data.* @@ -56,6 +57,10 @@ In order to create a query that's not quite right, let's redefine our `Country` ```scala mdoc:silent case class Country(code: Int, name: String, pop: Int, gnp: Double) +object Country { + implicit val read: Read[Country] = Read.derived + implicit val write: Write[Country] = Write.derived +} ``` Here's our parameterized query from last chapter, but with the new `Country` definition and the `minPop` parameter changed to a `Short`. @@ -86,6 +91,10 @@ If we fix all of these problems and try again, we get a clean bill of health. ```scala mdoc:silent case class Country2(code: String, name: String, pop: Int, gnp: Option[BigDecimal]) +object Country2 { + implicit val read: Read[Country2] = Read.derived + implicit val write: Write[Country2] = Write.derived +} def biggerThan2(minPop: Int) = sql""" diff --git a/modules/docs/src/main/mdoc/docs/07-Updating.md b/modules/docs/src/main/mdoc/docs/07-Updating.md index 4cda07b91..9e2263cda 100644 --- a/modules/docs/src/main/mdoc/docs/07-Updating.md +++ b/modules/docs/src/main/mdoc/docs/07-Updating.md @@ -11,8 +11,8 @@ import doobie.free.connection.ConnectionIO import doobie.syntax.connectionio.* import doobie.syntax.string.* import doobie.util.ExecutionContexts -import doobie.util.Read.Auto.* -import doobie.util.Write.Auto.* +import doobie.util.Read +import doobie.util.Write import doobie.util.transactor.Transactor import doobie.util.update.Update import doobie.util.update.Update0 @@ -92,6 +92,10 @@ And read them back. ```scala mdoc:silent case class Person(id: Long, name: String, age: Option[Short]) +object Person { + implicit val read: Read[Person] = Read.derived + implicit val write: Write[Person] = Write.derived +} ``` ```scala mdoc diff --git a/modules/docs/src/main/mdoc/docs/08-Fragments.md b/modules/docs/src/main/mdoc/docs/08-Fragments.md index 3656d9a0f..1821d6c93 100644 --- a/modules/docs/src/main/mdoc/docs/08-Fragments.md +++ b/modules/docs/src/main/mdoc/docs/08-Fragments.md @@ -10,7 +10,8 @@ Same as last chapter, so if you're still set up you can skip this section. Other import doobie.Fragments import doobie.syntax.string.* import doobie.util.ExecutionContexts -import doobie.util.Read.Auto.* +import doobie.util.Read +import doobie.util.Write import doobie.util.fragment.Fragment import doobie.util.transactor.Transactor import cats.* @@ -117,6 +118,10 @@ Here we define a query with a three optional filter conditions. // Country Info case class Info(name: String, code: String, population: Int) +object Info { + implicit val read: Read[Info] = Read.derived + implicit val write: Write[Info] = Write.derived +} // Construct a Query0 with some optional filter conditions and a configurable LIMIT. def select(name: Option[String], pop: Option[Int], codes: List[String], limit: Long) = { diff --git a/modules/docs/src/main/mdoc/docs/09-Error-Handling.md b/modules/docs/src/main/mdoc/docs/09-Error-Handling.md index 37fa7db3e..965ae1489 100644 --- a/modules/docs/src/main/mdoc/docs/09-Error-Handling.md +++ b/modules/docs/src/main/mdoc/docs/09-Error-Handling.md @@ -9,7 +9,8 @@ import doobie.free.connection.ConnectionIO import doobie.syntax.applicativeerror.* import doobie.syntax.string.* import doobie.util.ExecutionContexts -import doobie.util.Read.Auto.* +import doobie.util.Read +import doobie.util.Write import doobie.util.transactor.Transactor import cats.* import cats.data.* @@ -95,6 +96,10 @@ Alright, let's define a `Person` data type and a way to insert instances. ```scala mdoc:silent case class Person(id: Int, name: String) +object Person { + implicit val read: Read[Person] = Read.derived + implicit val write: Write[Person] = Write.derived +} def insert(s: String): ConnectionIO[Person] = { sql"insert into person (name) values ($s)" diff --git a/modules/docs/src/main/mdoc/docs/11-Arrays.md b/modules/docs/src/main/mdoc/docs/11-Arrays.md index b865779dd..679f16c32 100644 --- a/modules/docs/src/main/mdoc/docs/11-Arrays.md +++ b/modules/docs/src/main/mdoc/docs/11-Arrays.md @@ -11,7 +11,8 @@ import doobie.free.connection.ConnectionIO import doobie.postgres.instances.array.* import doobie.syntax.string.* import doobie.util.ExecutionContexts -import doobie.util.Read.Auto.* +import doobie.util.Read +import doobie.util.Write import doobie.util.transactor.Transactor import cats.* import cats.data.* @@ -64,6 +65,10 @@ val create = ```scala mdoc:silent case class Person(id: Long, name: String, pets: List[String]) +object Person { + implicit val read: Read[Person] = Read.derived + implicit val write: Write[Person] = Write.derived +} def insert(name: String, pets: List[String]): ConnectionIO[Person] = { sql"insert into person (name, pets) values ($name, $pets)" diff --git a/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md b/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md index 34e5cd73c..72086fa03 100644 --- a/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md +++ b/modules/docs/src/main/mdoc/docs/12-Custom-Mappings.md @@ -12,9 +12,7 @@ In this chapter we're importing the essentials from Cats and **doobie**, as well import doobie.util.Get import doobie.util.Put import doobie.util.Read -import doobie.util.Read.Auto.* import doobie.util.Write -import doobie.util.Write.Auto.* import doobie.util.meta.Meta import cats.* import cats.data.* diff --git a/modules/docs/src/main/mdoc/docs/13-Unit-Testing.md b/modules/docs/src/main/mdoc/docs/13-Unit-Testing.md index 55d6cf404..5cbb5c6d3 100644 --- a/modules/docs/src/main/mdoc/docs/13-Unit-Testing.md +++ b/modules/docs/src/main/mdoc/docs/13-Unit-Testing.md @@ -8,7 +8,8 @@ As with earlier chapters we set up a `Transactor` and YOLO mode. We will also us ```scala mdoc:silent import doobie.syntax.string.* -import doobie.util.Read.Auto.* +import doobie.util.Read +import doobie.util.Write import doobie.util.transactor.Transactor import doobie.util.update.Update0 import cats.* @@ -51,6 +52,10 @@ So here are a few queries we would like to check. Note that we can only check va ```scala mdoc:silent case class Country(code: Int, name: String, pop: Int, gnp: Double) +object Country { + implicit val read: Read[Country] = Read.derived + implicit val write: Write[Country] = Write.derived +} val trivial = sql""" diff --git a/modules/docs/src/main/mdoc/docs/17-FAQ.md b/modules/docs/src/main/mdoc/docs/17-FAQ.md index 9e9de7104..b74721336 100644 --- a/modules/docs/src/main/mdoc/docs/17-FAQ.md +++ b/modules/docs/src/main/mdoc/docs/17-FAQ.md @@ -12,8 +12,8 @@ import doobie.FC import doobie.free.connection.ConnectionIO import doobie.syntax.string.* import doobie.util.ExecutionContexts -import doobie.util.Read.Auto.* -import doobie.util.Write.Auto.* +import doobie.util.Read +import doobie.util.Write import doobie.util.meta.Meta import doobie.util.query.Query0 import doobie.util.transactor.Transactor @@ -83,7 +83,14 @@ As of **doobie** 0.4.0 this is done via [statement fragments](08-Fragments.html) ```scala mdoc:silent case class Code(country: String) +object Code { + implicit val read: Read[Code] = Read.derived + implicit val write: Write[Code] = Write.derived +} case class City(code: Code, name: String, population: Int) +object City { + implicit val read: Read[City] = Read.derived +} def cities(code: Code, asc: Boolean): Query0[City] = { val ord = if (asc) fr"ASC" else fr"DESC" @@ -123,7 +130,13 @@ With an outer join you end up with set of nullable columns, which you typically ```scala mdoc:silent case class Country(name: String, code: String) +object Country { + implicit val read: Read[Country] = Read.derived +} case class City2(name: String, district: String) +object City2 { + implicit val read: Read[City2] = Read.derived +} val join = sql""" diff --git a/modules/docs/src/main/mdoc/index.md b/modules/docs/src/main/mdoc/index.md index d8785a773..057007094 100644 --- a/modules/docs/src/main/mdoc/index.md +++ b/modules/docs/src/main/mdoc/index.md @@ -12,7 +12,7 @@ import doobie.free.connection.ConnectionIO import doobie.syntax.connectionio.* import doobie.syntax.string.* -import doobie.util.Read.Auto.* +import doobie.util.Read import doobie.util.transactor.Transactor import cats.effect.IO import scala.concurrent.ExecutionContext @@ -24,6 +24,9 @@ val xa = Transactor.fromDriverManager[IO]( ) case class Country(code: String, name: String, population: Long) +object Country { + implicit val read: Read[Country] = Read.derived +} def find(n: String): ConnectionIO[Option[Country]] = sql"select code, name, population from country where name = $n".query[Country].option diff --git a/modules/example/src/main/scala/example/AnalysisTest.scala b/modules/example/src/main/scala/example/AnalysisTest.scala index a0a6dec4a..3f8eb678c 100644 --- a/modules/example/src/main/scala/example/AnalysisTest.scala +++ b/modules/example/src/main/scala/example/AnalysisTest.scala @@ -7,6 +7,8 @@ package example import doobie.postgres.instances.array.* import doobie.postgres.instances.geometric.* import doobie.syntax.string.* +import doobie.util.Read +import doobie.util.Write import doobie.util.query.Query0 import doobie.util.update.Update import doobie.util.update.Update0 @@ -14,10 +16,12 @@ import org.postgresql.geometric.* // Some queries to test using the AnalysisTestSpec in src/test object AnalysisTest { - import doobie.util.Read.Auto.* - import doobie.util.Write.Auto.* final case class Country(name: String, indepYear: Int) + object Country { + implicit val read: Read[Country] = Read.derived + implicit val write: Write[Country] = Write.derived + } def speakerQuery(lang: String, pct: Double): Query0[Country] = sql""" diff --git a/modules/example/src/main/scala/example/CustomReadWrite.scala b/modules/example/src/main/scala/example/CustomReadWrite.scala index 93e472ec7..b0b23c859 100644 --- a/modules/example/src/main/scala/example/CustomReadWrite.scala +++ b/modules/example/src/main/scala/example/CustomReadWrite.scala @@ -5,6 +5,8 @@ package example import doobie.syntax.string.* +import doobie.util.Get +import doobie.util.Put import doobie.util.Read import doobie.util.Write import doobie.util.meta.Meta @@ -13,10 +15,12 @@ import doobie.util.query.Query0 import java.sql.Date object CustomReadWrite { - import Read.Auto.* - import Write.Auto.* final case class PosixTime(time: Long) + object PosixTime { + implicit val get: Get[PosixTime] = Get[Long].map(apply(_)) + implicit val put: Put[PosixTime] = Put[Long].contramap(_.time) + } // Create our base Meta by invariant mapping an existing one. implicit val LongPosixTimeScalaType: Meta[PosixTime] = diff --git a/modules/example/src/main/scala/example/FirstExample.scala b/modules/example/src/main/scala/example/FirstExample.scala index 19a887c06..80e9b544b 100644 --- a/modules/example/src/main/scala/example/FirstExample.scala +++ b/modules/example/src/main/scala/example/FirstExample.scala @@ -14,6 +14,8 @@ import doobie.FC import doobie.free.connection.ConnectionIO import doobie.syntax.connectionio.* import doobie.syntax.string.* +import doobie.util.Read +import doobie.util.Write import doobie.util.query.Query0 import doobie.util.transactor.Transactor import doobie.util.update.Update @@ -22,14 +24,19 @@ import fs2.Stream // Example lifted from slick object FirstExample extends IOApp.Simple { - import doobie.util.Read.Auto.* - import doobie.util.Write.Auto.* // Our data model final case class Supplier(id: Int, name: String, street: String, city: String, state: String, zip: String) + object Supplier { + implicit val read: Read[Supplier] = Read.derived + implicit val write: Write[Supplier] = Write.derived + } final case class Coffee(name: String, supId: Int, price: Double, sales: Int, total: Int) object Coffee { implicit val show: Show[Coffee] = Show.fromToString + + implicit val read: Read[Coffee] = Read.derived + implicit val write: Write[Coffee] = Write.derived } // Some suppliers diff --git a/modules/example/src/main/scala/example/HiUsage.scala b/modules/example/src/main/scala/example/HiUsage.scala index 9eb3db775..c7923ef93 100644 --- a/modules/example/src/main/scala/example/HiUsage.scala +++ b/modules/example/src/main/scala/example/HiUsage.scala @@ -12,17 +12,19 @@ import doobie.FC import doobie.free.connection.ConnectionIO import doobie.syntax.connectionio.* import doobie.syntax.string.* +import doobie.util.Read import doobie.util.transactor.Transactor import fs2.Stream // JDBC program using the high-level API object HiUsage extends IOApp.Simple { - import doobie.util.Read.Auto.* // A very simple data type we will read final case class CountryCode(code: Option[String]) object CountryCode { implicit val show: Show[CountryCode] = Show.fromToString + + implicit val read: Read[CountryCode] = Read.derived } // Program entry point diff --git a/modules/example/src/main/scala/example/Join.scala b/modules/example/src/main/scala/example/Join.scala index 04a0d8680..f6147cd4e 100644 --- a/modules/example/src/main/scala/example/Join.scala +++ b/modules/example/src/main/scala/example/Join.scala @@ -6,13 +6,19 @@ package example import cats.syntax.apply.* import doobie.syntax.string.* +import doobie.util.Read import doobie.util.query.Query0 object Join { - import doobie.util.Read.Auto.* final case class Country(code: String, name: String) + object Country { + implicit val read: Read[Country] = Read.derived + } final case class City(id: Int, name: String) + object City { + implicit val read: Read[City] = Read.derived + } // Old style required examining joined columns individually def countriesAndCities1(filter: String): Query0[(Country, Option[City])] = diff --git a/modules/example/src/main/scala/example/StreamToFile.scala b/modules/example/src/main/scala/example/StreamToFile.scala index fcb2d2e40..c5b5fd9d0 100644 --- a/modules/example/src/main/scala/example/StreamToFile.scala +++ b/modules/example/src/main/scala/example/StreamToFile.scala @@ -9,7 +9,6 @@ import cats.effect.IOApp import cats.syntax.show.* import doobie.syntax.stream.* import doobie.syntax.string.* -import doobie.util.Read.Auto.* import doobie.util.transactor.Transactor import fs2.io.file.Files import fs2.io.file.Path diff --git a/modules/munit/src/test/scala/doobie/munit/CheckerTests.scala b/modules/munit/src/test/scala/doobie/munit/CheckerTests.scala index e9e7694e6..ebb259812 100644 --- a/modules/munit/src/test/scala/doobie/munit/CheckerTests.scala +++ b/modules/munit/src/test/scala/doobie/munit/CheckerTests.scala @@ -5,7 +5,6 @@ package doobie.munit import cats.effect.IO -import cats.syntax.apply.* import doobie.syntax.string.* import doobie.util.Read import doobie.util.transactor.Transactor @@ -29,38 +28,16 @@ trait CheckerChecks[M[_]] extends FunSuite with Checker[M] { } test("trivial case-class") { - import doobie.util.Read.Auto.* - - check(sql"select 1".query[CheckerChecks.Foo[cats.Id]]) - } - - test("Read should select correct columns when combined with `product`") { - - val ri = Read[Int] - val rs = Read[String] - - // tupled use product under the hood - val combined: Read[(Int, String)] = (ri, rs).tupled - - check(sql"SELECT 1, '2'".query(combined)) - } - - test("Read should select correct columns for checking when combined with `ap`") { - import doobie.util.Read.Auto.* - - val readInt = Read[(Int, Int)] - val readIntToInt: Read[Tuple2[Int, Int] => String] = - Read[(String, String)].map(i => k => s"$i,$k") - - val combined: Read[String] = readInt.ap(readIntToInt) - - check(sql"SELECT '1', '2', 3, 4".query(combined)) + check(sql"select 1".query[CheckerChecks.Foo]) } } object CheckerChecks { - final case class Foo[F[_]](x: Int) + final case class Foo(x: Int) + object Foo { + implicit val read: Read[Foo] = Read.derived + } } class IOCheckerCheck extends CheckerChecks[IO] with IOChecker {} diff --git a/modules/weaver/src/test/scala/doobie/weaver/CheckerTests.scala b/modules/weaver/src/test/scala/doobie/weaver/CheckerTests.scala index 393058c79..d895d38cf 100644 --- a/modules/weaver/src/test/scala/doobie/weaver/CheckerTests.scala +++ b/modules/weaver/src/test/scala/doobie/weaver/CheckerTests.scala @@ -6,7 +6,6 @@ package doobie.weaver import cats.effect.IO import cats.effect.kernel.Resource -import cats.syntax.apply.* import doobie.syntax.string.* import doobie.util.Read import doobie.util.transactor.Transactor @@ -27,34 +26,13 @@ object CheckerTests extends IOSuite with IOChecker { ) } - final case class Foo[F[_]](x: Int) - - test("trivial case-class") { implicit transactor => - import doobie.util.Read.Auto.* - - check(sql"select 1".query[Foo[cats.Id]]) + final case class Foo(x: Int) + object Foo { + implicit val read: Read[Foo] = Read.derived } - test("Read should select correct columns when combined with `product`") { implicit transactor => - val ri = Read[Int] - val rs = Read[String] - - // tupled use product under the hood - val combined: Read[(Int, String)] = (ri, rs).tupled - - check(sql"SELECT 1, '2'".query(combined)) - } - - test("Read should select correct columns for checking when combined with `ap`") { implicit transactor => - import doobie.util.Read.Auto.* - - val readInt = Read[(Int, Int)] - val readIntToInt: Read[Tuple2[Int, Int] => String] = - Read[(String, String)].map(i => k => s"$i,$k") - - val combined: Read[String] = readInt.ap(readIntToInt) - - check(sql"SELECT '1', '2', 3, 4".query(combined)) + test("trivial case-class") { implicit transactor => + check(sql"select 1".query[Foo]) } }