From 0b21c2d5b68fbffb453694ecf00bde51bdbdff81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Raddum=20Berg?= Date: Sat, 22 Jun 2024 14:48:11 +0200 Subject: [PATCH] Add `count` in DSL --- typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala | 2 ++ typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala | 3 +++ typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala | 5 +++++ typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala | 2 ++ typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala | 3 +++ typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala | 4 ++++ typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilder.scala | 2 ++ typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderMock.scala | 3 +++ typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderSql.scala | 4 ++++ typo-tester-anorm/src/scala/adventureworks/DSLTest.scala | 1 + typo-tester-doobie/src/scala/adventureworks/DSLTest.scala | 1 + typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala | 1 + 12 files changed, 31 insertions(+) diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala index d60691ac3..4387b0a26 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala @@ -64,6 +64,8 @@ trait SelectBuilder[Fields, Row] { /** Execute the query and return the results as a list */ def toList(implicit c: Connection): List[Row] + def count(implicit c: Connection): Int + /** Return sql for debugging. [[None]] if backed by a mock repository */ def sql: Option[Fragment] diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala index e52f5dc4d..4518d1d16 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala @@ -19,6 +19,9 @@ final case class SelectBuilderMock[Fields, Row]( override def toList(implicit c: Connection): List[Row] = SelectBuilderMock.applyParams(structure, all(), params) + override def count(implicit c: Connection): Int = + toList(c).length + override def joinOn[Fields2, N[_]: Nullability, Row2](other: SelectBuilder[Fields2, Row2])(pred: (Fields ~ Fields2) => SqlExpr[Boolean, N]): SelectBuilderMock[Fields ~ Fields2, Row ~ Row2] = { val otherMock: SelectBuilderMock[Fields2, Row2] = other match { case x: SelectBuilderMock[Fields2, Row2] => x.withPath(Path.RightInJoin) diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala index ab79d9d7b..f4423261c 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala @@ -56,6 +56,11 @@ sealed trait SelectBuilderSql[Fields, Row] extends SelectBuilder[Fields, Row] { val (frag, rowParser) = sqlAndRowParser SimpleSql(SQL(frag.sql), frag.params.map(_.tupled).toMap, RowParser.successful).as(rowParser.*)(c) } + + final override def count(implicit c: Connection): Int = { + val (frag, _) = sqlAndRowParser + SimpleSql(SQL(s"select count(*) from (${frag.sql}) rows"), frag.params.map(_.tupled).toMap, RowParser.successful).as(SqlParser.int(1).single)(c) + } } object SelectBuilderSql { diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala index 6c857648c..d3a0de462 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala @@ -65,6 +65,8 @@ trait SelectBuilder[Fields, Row] { /** Execute the query and return the results as a list */ def toList: ConnectionIO[List[Row]] + def count: ConnectionIO[Int] + /** Return sql for debugging. [[None]] if backed by a mock repository */ def sql: Option[Fragment] diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala index ab5455384..ac452bda8 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala @@ -20,6 +20,9 @@ final case class SelectBuilderMock[Fields, Row]( override def toList: ConnectionIO[List[Row]] = all.map(all => SelectBuilderMock.applyParams(structure, all, params)) + override def count: ConnectionIO[Int] = + all.map(all => SelectBuilderMock.applyParams(structure, all, params)).map(_.length) + override def joinOn[Fields2, N[_]: Nullability, Row2](other: SelectBuilder[Fields2, Row2])(pred: Fields ~ Fields2 => SqlExpr[Boolean, N]): SelectBuilderMock[Fields ~ Fields2, Row ~ Row2] = { val otherMock: SelectBuilderMock[Fields2, Row2] = other match { case x: SelectBuilderMock[Fields2, Row2] => x.withPath(Path.RightInJoin) diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala index ce9e18243..fd2507e55 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala @@ -59,6 +59,10 @@ sealed trait SelectBuilderSql[Fields, Row] extends SelectBuilder[Fields, Row] { val (frag, read) = sqlAndRowParser frag.query(using read).to[List] } + final override def count: ConnectionIO[Int] = { + val (frag, _) = sqlAndRowParser + fr"select count(*) from ($frag) rows".query[Int].unique + } } object SelectBuilderSql { diff --git a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilder.scala b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilder.scala index 4d7407882..5470b8217 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilder.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilder.scala @@ -65,6 +65,8 @@ trait SelectBuilder[Fields, Row] { /** Execute the query and return the results as a list */ def toChunk: ZIO[ZConnection, Throwable, Chunk[Row]] + def count: ZIO[ZConnection, Throwable, Int] + /** Return sql for debugging. [[None]] if backed by a mock repository */ def sql: Option[SqlFragment] diff --git a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderMock.scala b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderMock.scala index af06f6a68..7d140bc65 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderMock.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderMock.scala @@ -20,6 +20,9 @@ final case class SelectBuilderMock[Fields, Row]( override def toChunk: ZIO[ZConnection, Throwable, Chunk[Row]] = all.map(all => SelectBuilderMock.applyParams(structure, all, params)) + override def count: ZIO[ZConnection, Throwable, Int] = + all.map(all => SelectBuilderMock.applyParams(structure, all, params).length) + override def joinOn[Fields2, N[_]: Nullability, Row2](other: SelectBuilder[Fields2, Row2])(pred: Fields ~ Fields2 => SqlExpr[Boolean, N]): SelectBuilderMock[Fields ~ Fields2, Row ~ Row2] = { val otherMock: SelectBuilderMock[Fields2, Row2] = other match { case x: SelectBuilderMock[Fields2, Row2] => x.withPath(Path.RightInJoin) diff --git a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderSql.scala b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderSql.scala index a351f6fba..42c0d3eaa 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderSql.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderSql.scala @@ -52,6 +52,10 @@ select ${SqlFragment(cols.mkString(","))} from ${SqlFragment(ctes.last.name)}""" val (frag, read) = sqlAndRowParser frag.query(using read).selectAll } + final override def count: ZIO[ZConnection, Throwable, Int] = { + val (frag, _) = sqlAndRowParser + sql"select count(*) from ($frag) rows".query[Int].selectOne.map(_.get) + } } object SelectBuilderSql { diff --git a/typo-tester-anorm/src/scala/adventureworks/DSLTest.scala b/typo-tester-anorm/src/scala/adventureworks/DSLTest.scala index 4e0f8e5fb..5b9689223 100644 --- a/typo-tester-anorm/src/scala/adventureworks/DSLTest.scala +++ b/typo-tester-anorm/src/scala/adventureworks/DSLTest.scala @@ -42,6 +42,7 @@ class DSLTest extends SnapshotTest { val doubled = q.join(q).on { case (((_, e1), _), ((_, e2), _)) => e1.businessentityid === e2.businessentityid } doubled.toList.foreach(println) + assert(doubled.count == 1): @nowarn compareFragment("doubled")(doubled.sql) } diff --git a/typo-tester-doobie/src/scala/adventureworks/DSLTest.scala b/typo-tester-doobie/src/scala/adventureworks/DSLTest.scala index 9d8ae1fa6..5dff07fb5 100644 --- a/typo-tester-doobie/src/scala/adventureworks/DSLTest.scala +++ b/typo-tester-doobie/src/scala/adventureworks/DSLTest.scala @@ -40,6 +40,7 @@ class DSLTest extends SnapshotTest { doubled = q.join(q).on { case (((_, e1), _), ((_, e2), _)) => e1.businessentityid === e2.businessentityid } doubledRes <- doubled.toList _ <- delay(doubledRes.foreach(println)) + _ <- doubled.count.map(v => assert(v == 1)) _ <- delay(compareFragment("doubled")(doubled.sql)) } yield () } diff --git a/typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala b/typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala index 901b6e8ab..48f6a9f2b 100644 --- a/typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala +++ b/typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala @@ -40,6 +40,7 @@ class DSLTest extends SnapshotTest { doubled = q.join(q).on { case (((_, e1), _), ((_, e2), _)) => e1.businessentityid === e2.businessentityid } doubledRes <- doubled.toChunk _ <- ZIO.succeed(doubledRes.foreach(println)) + _ <- doubled.count.map(v => assert(v == 1)) _ <- ZIO.succeed(compareFragment("doubled")(doubled.sql)) } yield () }