From 87c5a915aad69cd6ef6a3d70538cc60f8eb58a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Raddum=20Berg?= Date: Thu, 20 Jun 2024 08:59:54 +0200 Subject: [PATCH 1/4] allow mixing `orderBy` and `seek`. original ordering is kept --- .../src/scala/typo/dsl/SelectBuilder.scala | 6 +-- .../scala/typo/dsl/SelectBuilderMock.scala | 3 +- .../src/scala/typo/dsl/SelectParams.scala | 20 +++------ .../src/scala/typo/dsl/SelectBuilder.scala | 6 +-- .../scala/typo/dsl/SelectBuilderMock.scala | 3 +- .../src/scala/typo/dsl/SelectParams.scala | 18 +++----- .../seeks.scala => OrderByOrSeek.scala} | 41 +++++++++++-------- .../src/scala/typo/dsl/SelectBuilder.scala | 6 +-- .../scala/typo/dsl/SelectBuilderMock.scala | 3 +- .../src/scala/typo/dsl/SelectParams.scala | 18 +++----- 10 files changed, 52 insertions(+), 72 deletions(-) rename typo-dsl-shared/typo/dsl/{internal/seeks.scala => OrderByOrSeek.scala} (69%) diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala index a19f3121d..d60691ac3 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilder.scala @@ -48,11 +48,11 @@ trait SelectBuilder[Fields, Row] { withParams(params.orderBy(v)) final def seek[T, N[_]](v: Fields => SortOrder[T, N])(value: SqlExpr.Const[T, N]): SelectBuilder[Fields, Row] = - withParams(params.seek(SelectParams.Seek[Fields, T, N](v, value))) + withParams(params.seek(v, value)) - final def maybeSeek[T, N[_]](v: Fields => SortOrder[T, N])(maybeValue: Option[SqlExpr.Const[T, N]]): SelectBuilder[Fields, Row] = + final def maybeSeek[T, N[_]](v: Fields => SortOrder[T, N])(maybeValue: Option[N[T]])(implicit asConst: SqlExpr.Const.As[T, N]): SelectBuilder[Fields, Row] = maybeValue match { - case Some(value) => seek(v)(value) + case Some(value) => seek(v)(asConst(value)) case None => orderBy(v) } diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala index 053a69506..e52f5dc4d 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderMock.scala @@ -1,7 +1,6 @@ package typo.dsl import java.sql.Connection -import typo.dsl.internal.seeks import typo.dsl.internal.mocks.RowOrdering final case class SelectBuilderMock[Fields, Row]( @@ -66,7 +65,7 @@ final case class SelectBuilderMock[Fields, Row]( object SelectBuilderMock { def applyParams[Fields, R](structure: Structure[Fields, R], rows: List[R], params: SelectParams[Fields, R]): List[R] = { - val (filters, orderBys) = seeks.expand(structure.fields, params) + val (filters, orderBys) = OrderByOrSeek.expand(structure.fields, params) implicit val rowOrdering: Ordering[R] = new RowOrdering(structure, orderBys) rows .filter(row => filters.forall(expr => structure.untypedEval(expr, row).getOrElse(false))) diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SelectParams.scala b/typo-dsl-anorm/src/scala/typo/dsl/SelectParams.scala index 374cec20c..f91909967 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SelectParams.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SelectParams.scala @@ -1,36 +1,28 @@ package typo.dsl import typo.dsl.Fragment.FragmentStringInterpolator -import typo.dsl.internal.seeks import java.util.concurrent.atomic.AtomicInteger final case class SelectParams[Fields, Row]( where: List[Fields => SqlExpr[Boolean, Option]], - orderBy: List[Fields => SortOrderNoHkt[?]], - seeks: List[SelectParams.SeekNoHkt[Fields, ?]], + orderBy: List[OrderByOrSeek[Fields, ?]], offset: Option[Int], limit: Option[Int] ) { - def where(v: Fields => SqlExpr[Boolean, Option]): SelectParams[Fields, Row] = copy(where = where :+ v) - def orderBy(v: Fields => SortOrderNoHkt[?]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ v) - def seek(v: SelectParams.SeekNoHkt[Fields, ?]): SelectParams[Fields, Row] = copy(seeks = seeks :+ v) + def where(f: Fields => SqlExpr[Boolean, Option]): SelectParams[Fields, Row] = copy(where = where :+ f) + def orderBy[T, N[_]](f: Fields => SortOrder[T, N]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ OrderByOrSeek.OrderBy(f)) + def seek[T, N[_]](f: Fields => SortOrder[T, N], value: SqlExpr.Const[T, N]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ OrderByOrSeek.Seek(f, value)) def offset(v: Int): SelectParams[Fields, Row] = copy(offset = Some(v)) def limit(v: Int): SelectParams[Fields, Row] = copy(limit = Some(v)) } object SelectParams { def empty[Fields, R]: SelectParams[Fields, R] = - SelectParams[Fields, R](List.empty, List.empty, List.empty, None, None) - - sealed trait SeekNoHkt[Fields, NT] { - val f: Fields => SortOrderNoHkt[NT] - } - - case class Seek[Fields, T, N[_]](f: Fields => SortOrder[T, N], value: SqlExpr.Const[T, N]) extends SeekNoHkt[Fields, N[T]] + SelectParams[Fields, R](List.empty, List.empty, None, None) def render[Fields, R](fields: Fields, baseSql: Fragment, ctx: RenderCtx, counter: AtomicInteger, params: SelectParams[Fields, R]): Fragment = { - val (filters, orderBys) = seeks.expand(fields, params) + val (filters, orderBys) = OrderByOrSeek.expand(fields, params) val maybeEnd: Option[Fragment] = List[Option[Fragment]]( diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala index f993fbed0..6c857648c 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilder.scala @@ -49,11 +49,11 @@ trait SelectBuilder[Fields, Row] { withParams(params.orderBy(v)) final def seek[T, N[_]](v: Fields => SortOrder[T, N])(value: SqlExpr.Const[T, N]): SelectBuilder[Fields, Row] = - withParams(params.seek(SelectParams.Seek[Fields, T, N](v, value))) + withParams(params.seek(v, value)) - final def maybeSeek[T, N[_]](v: Fields => SortOrder[T, N])(maybeValue: Option[SqlExpr.Const[T, N]]): SelectBuilder[Fields, Row] = + final def maybeSeek[T, N[_]](v: Fields => SortOrder[T, N])(maybeValue: Option[N[T]])(implicit asConst: SqlExpr.Const.As[T, N]): SelectBuilder[Fields, Row] = maybeValue match { - case Some(value) => seek(v)(value) + case Some(value) => seek(v)(asConst(value)) case None => orderBy(v) } diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala index 90b7ed614..ab5455384 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderMock.scala @@ -3,7 +3,6 @@ package typo.dsl import doobie.free.connection.ConnectionIO import doobie.util.fragment.Fragment import typo.dsl.internal.mocks.RowOrdering -import typo.dsl.internal.seeks final case class SelectBuilderMock[Fields, Row]( structure: Structure[Fields, Row], @@ -74,7 +73,7 @@ final case class SelectBuilderMock[Fields, Row]( object SelectBuilderMock { def applyParams[Fields, R](structure: Structure[Fields, R], rows: List[R], params: SelectParams[Fields, R]): List[R] = { - val (filters, orderBys) = seeks.expand(structure.fields, params) + val (filters, orderBys) = OrderByOrSeek.expand(structure.fields, params) implicit val rowOrdering: Ordering[R] = new RowOrdering(structure, orderBys) rows .filter(row => filters.forall(expr => structure.untypedEval(expr, row).getOrElse(false))) diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SelectParams.scala b/typo-dsl-doobie/src/scala/typo/dsl/SelectParams.scala index 390b33353..dfe4d0a3e 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SelectParams.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SelectParams.scala @@ -4,34 +4,26 @@ import cats.data.NonEmptyList import doobie.implicits.toSqlInterpolator import doobie.util.fragment.Fragment import doobie.util.fragments -import typo.dsl.internal.seeks final case class SelectParams[Fields, Row]( where: List[Fields => SqlExpr[Boolean, Option]], - orderBy: List[Fields => SortOrderNoHkt[?]], - seeks: List[SelectParams.SeekNoHkt[Fields, ?]], + orderBy: List[OrderByOrSeek[Fields, ?]], offset: Option[Int], limit: Option[Int] ) { def where(v: Fields => SqlExpr[Boolean, Option]): SelectParams[Fields, Row] = copy(where = where :+ v) - def orderBy(v: Fields => SortOrderNoHkt[?]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ v) - def seek(v: SelectParams.SeekNoHkt[Fields, ?]): SelectParams[Fields, Row] = copy(seeks = seeks :+ v) + def orderBy[T, N[_]](f: Fields => SortOrder[T, N]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ OrderByOrSeek.OrderBy(f)) + def seek[T, N[_]](f: Fields => SortOrder[T, N], value: SqlExpr.Const[T, N]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ OrderByOrSeek.Seek(f, value)) def offset(v: Int): SelectParams[Fields, Row] = copy(offset = Some(v)) def limit(v: Int): SelectParams[Fields, Row] = copy(limit = Some(v)) } object SelectParams { def empty[Fields, R]: SelectParams[Fields, R] = - SelectParams[Fields, R](List.empty, List.empty, List.empty, None, None) - - sealed trait SeekNoHkt[Fields, NT] { - val f: Fields => SortOrderNoHkt[NT] - } - - case class Seek[Fields, T, N[_]](f: Fields => SortOrder[T, N], value: SqlExpr.Const[T, N]) extends SeekNoHkt[Fields, N[T]] + SelectParams[Fields, R](List.empty, List.empty, None, None) def render[Fields, R](fields: Fields, baseSql: Fragment, ctx: RenderCtx, params: SelectParams[Fields, R]): Fragment = { - val (filters, orderBys) = seeks.expand(fields, params) + val (filters, orderBys) = OrderByOrSeek.expand(fields, params) List[Option[Fragment]]( Some(baseSql), diff --git a/typo-dsl-shared/typo/dsl/internal/seeks.scala b/typo-dsl-shared/typo/dsl/OrderByOrSeek.scala similarity index 69% rename from typo-dsl-shared/typo/dsl/internal/seeks.scala rename to typo-dsl-shared/typo/dsl/OrderByOrSeek.scala index e411ff435..669cdd903 100644 --- a/typo-dsl-shared/typo/dsl/internal/seeks.scala +++ b/typo-dsl-shared/typo/dsl/OrderByOrSeek.scala @@ -1,18 +1,25 @@ -package typo.dsl.internal +package typo.dsl -import typo.dsl.SelectParams.Seek -import typo.dsl.* +sealed trait OrderByOrSeek[Fields, NT] { + val f: Fields => SortOrderNoHkt[NT] +} + +object OrderByOrSeek { + case class OrderBy[Fields, NT](f: Fields => SortOrderNoHkt[NT]) extends OrderByOrSeek[Fields, NT] + sealed trait SeekNoHkt[Fields, NT] extends OrderByOrSeek[Fields, NT] + case class Seek[Fields, T, N[_]](f: Fields => SortOrder[T, N], value: SqlExpr.Const[T, N]) extends SeekNoHkt[Fields, N[T]] -object seeks { - def expand[Fields, Row](fields: Fields, params: SelectParams[Fields, Row]): (List[SqlExpr[Boolean, Option]], List[SortOrderNoHkt[?]]) = - params.seeks match { - case Nil => (params.where.map(_.apply(fields)), params.orderBy.map(_.apply(fields))) - case nonEmpty => - require(params.orderBy.isEmpty, "Cannot have both seeks and orderBy") - val seekOrderBys: List[SortOrderNoHkt[?]] = - nonEmpty.map { case seek: Seek[Fields, _, _] @unchecked /* for 2.13*/ => seek.f(fields) } + def expand[Fields, Row](fields: Fields, params: SelectParams[Fields, Row]): (List[SqlExpr[Boolean, Option]], List[SortOrderNoHkt[?]]) = { + val seeks: List[SeekNoHkt[Fields, ?]] = + params.orderBy.collect { case x: OrderByOrSeek.SeekNoHkt[Fields, nt] => x } + + val maybeSeekPredicate: Option[SqlExpr[Boolean, Option]] = + seeks match { + case Nil => None + case nonEmpty => + val seekOrderBys: List[SortOrderNoHkt[?]] = + nonEmpty.map { case seek: Seek[Fields, _, _] @unchecked /* for 2.13*/ => seek.f(fields) } - val seekWhere: SqlExpr[Boolean, Option] = seekOrderBys.map(_.ascending).distinct match { case List(uniformIsAscending) => val dbTuple = SqlExpr.RowExpr(seekOrderBys.map(so => so.expr)) @@ -29,7 +36,7 @@ object seeks { .find(_ != 0) .getOrElse(0) - if (uniformIsAscending) dbTuple > valueTuple else dbTuple < valueTuple + Some(if (uniformIsAscending) dbTuple > valueTuple else dbTuple < valueTuple) case _ => val orConditions: Seq[SqlExpr[Boolean, Option]] = nonEmpty.indices.map { i => @@ -52,9 +59,9 @@ object seeks { } } - orConditions.reduce(_ or _) + Some(orConditions.reduce(_ or _)) } - - (params.where.map(_.apply(fields)) :+ seekWhere, seekOrderBys) - } + } + (params.where.map(_.apply(fields)) ++ maybeSeekPredicate, params.orderBy.map(_.f(fields))) + } } 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 bc744011f..4d7407882 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilder.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilder.scala @@ -49,11 +49,11 @@ trait SelectBuilder[Fields, Row] { withParams(params.orderBy(v)) final def seek[T, N[_]](v: Fields => SortOrder[T, N])(value: SqlExpr.Const[T, N]): SelectBuilder[Fields, Row] = - withParams(params.seek(SelectParams.Seek[Fields, T, N](v, value))) + withParams(params.seek(v, value)) - final def maybeSeek[T, N[_]](v: Fields => SortOrder[T, N])(maybeValue: Option[SqlExpr.Const[T, N]]): SelectBuilder[Fields, Row] = + final def maybeSeek[T, N[_]](v: Fields => SortOrder[T, N])(maybeValue: Option[N[T]])(implicit asConst: SqlExpr.Const.As[T, N]): SelectBuilder[Fields, Row] = maybeValue match { - case Some(value) => seek(v)(value) + case Some(value) => seek(v)(asConst(value)) case None => orderBy(v) } 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 47841ba35..af06f6a68 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderMock.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderMock.scala @@ -1,6 +1,5 @@ package typo.dsl -import typo.dsl.internal.seeks import typo.dsl.internal.mocks.RowOrdering import zio.{Chunk, ZIO} import zio.jdbc.* @@ -75,7 +74,7 @@ final case class SelectBuilderMock[Fields, Row]( object SelectBuilderMock { def applyParams[Fields, R](structure: Structure[Fields, R], rows: Chunk[R], params: SelectParams[Fields, R]): Chunk[R] = { - val (filters, orderBys) = seeks.expand(structure.fields, params) + val (filters, orderBys) = OrderByOrSeek.expand(structure.fields, params) implicit val rowOrdering: Ordering[R] = new RowOrdering(structure, orderBys) rows .filter(row => filters.forall(expr => structure.untypedEval(expr, row).getOrElse(false))) diff --git a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectParams.scala b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectParams.scala index 577d7fc87..1007e8675 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectParams.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectParams.scala @@ -1,35 +1,27 @@ package typo.dsl -import typo.dsl.internal.seeks import zio.NonEmptyChunk import zio.jdbc.* final case class SelectParams[Fields, Row]( where: List[Fields => SqlExpr[Boolean, Option]], - orderBy: List[Fields => SortOrderNoHkt[?]], - seeks: List[SelectParams.SeekNoHkt[Fields, ?]], + orderBy: List[OrderByOrSeek[Fields, ?]], offset: Option[Int], limit: Option[Int] ) { def where(v: Fields => SqlExpr[Boolean, Option]): SelectParams[Fields, Row] = copy(where = where :+ v) - def orderBy(v: Fields => SortOrderNoHkt[?]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ v) - def seek(v: SelectParams.SeekNoHkt[Fields, ?]): SelectParams[Fields, Row] = copy(seeks = seeks :+ v) + def orderBy[T, N[_]](f: Fields => SortOrder[T, N]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ OrderByOrSeek.OrderBy(f)) + def seek[T, N[_]](f: Fields => SortOrder[T, N], value: SqlExpr.Const[T, N]): SelectParams[Fields, Row] = copy(orderBy = orderBy :+ OrderByOrSeek.Seek(f, value)) def offset(v: Int): SelectParams[Fields, Row] = copy(offset = Some(v)) def limit(v: Int): SelectParams[Fields, Row] = copy(limit = Some(v)) } object SelectParams { def empty[Fields, R]: SelectParams[Fields, R] = - SelectParams[Fields, R](List.empty, List.empty, List.empty, None, None) - - sealed trait SeekNoHkt[Fields, NT] { - val f: Fields => SortOrderNoHkt[NT] - } - - case class Seek[Fields, T, N[_]](f: Fields => SortOrder[T, N], value: SqlExpr.Const[T, N]) extends SeekNoHkt[Fields, N[T]] + SelectParams[Fields, R](List.empty, List.empty, None, None) def render[Fields, R](fields: Fields, baseSql: SqlFragment, ctx: RenderCtx, params: SelectParams[Fields, R]): SqlFragment = { - val (filters, orderBys) = seeks.expand(fields, params) + val (filters, orderBys) = OrderByOrSeek.expand(fields, params) List[Option[SqlFragment]]( Some(baseSql), NonEmptyChunk.fromIterableOption(filters.map(f => f.render(ctx))).map(fs => fs.mkFragment(" WHERE ", " AND ", "")), From 4e46af539fd992cc89fa71191fea8efd21c1351e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Raddum=20Berg?= Date: Thu, 20 Jun 2024 22:17:00 +0200 Subject: [PATCH 2/4] snapshot tests for sql --- .../anorm-sql/CompositeIdsTest/query2.sql | 2 + .../anorm-sql/ProductTest/delete.sql | 1 + .../anorm-sql/ProductTest/leftJoined.sql | 7 ++ snapshot-tests/anorm-sql/ProductTest/q.sql | 11 +++ snapshot-tests/anorm-sql/ProductTest/q2.sql | 15 ++++ .../anorm-sql/ProductTest/query.sql | 14 ++++ .../anorm-sql/ProductTest/query0.sql | 13 ++++ .../anorm-sql/ProductTest/updateReturning.sql | 1 + snapshot-tests/anorm-sql/SeekTest/complex.sql | 2 + .../anorm-sql/SeekTest/uniform-ascending.sql | 2 + .../anorm-sql/SeekTest/uniform-descending.sql | 2 + .../dooble-sql/CompositeIdsTest/query2.sql | 1 + .../dooble-sql/ProductTest/delete.sql | 1 + .../dooble-sql/ProductTest/leftJoined.sql | 8 ++ snapshot-tests/dooble-sql/ProductTest/q.sql | 8 ++ snapshot-tests/dooble-sql/ProductTest/q2.sql | 11 +++ .../dooble-sql/ProductTest/query.sql | 11 +++ .../dooble-sql/ProductTest/query0.sql | 14 ++++ .../ProductTest/updateReturning.sql | 1 + .../dooble-sql/SeekTest/complex.sql | 1 + .../dooble-sql/SeekTest/uniform-ascending.sql | 1 + .../SeekTest/uniform-descending.sql | 1 + .../zio-jdbc-sql/CompositeIdsTest/query2.sql | 1 + .../zio-jdbc-sql/ProductTest/delete.sql | 1 + .../zio-jdbc-sql/ProductTest/leftJoined.sql | 8 ++ snapshot-tests/zio-jdbc-sql/ProductTest/q.sql | 8 ++ .../zio-jdbc-sql/ProductTest/q2.sql | 11 +++ .../zio-jdbc-sql/ProductTest/query.sql | 11 +++ .../zio-jdbc-sql/ProductTest/query0.sql | 14 ++++ .../ProductTest/updateReturning.sql | 1 + .../zio-jdbc-sql/SeekTest/complex.sql | 1 + .../SeekTest/uniform-ascending.sql | 1 + .../SeekTest/uniform-descending.sql | 1 + .../scala/adventureworks/SnapshotTest.scala | 64 ++++++++++++++++ .../production/product/CompositeIdsTest.scala | 10 +-- .../production/product/ProductTest.scala | 24 +++--- .../production/product/SeekTest.scala | 23 ++---- .../scala/adventureworks/SnapshotTest.scala | 63 +++++++++++++++ .../production/product/CompositeIdsTest.scala | 10 +-- .../production/product/ProductTest.scala | 27 ++++--- .../production/product/SeekTest.scala | 17 ++--- .../scala/adventureworks/SnapshotTest.scala | 76 +++++++++++++++++++ .../production/product/CompositeIdsTest.scala | 8 +- .../production/product/ProductTest.scala | 27 ++++--- .../production/product/SeekTest.scala | 20 ++--- 45 files changed, 455 insertions(+), 100 deletions(-) create mode 100644 snapshot-tests/anorm-sql/CompositeIdsTest/query2.sql create mode 100644 snapshot-tests/anorm-sql/ProductTest/delete.sql create mode 100644 snapshot-tests/anorm-sql/ProductTest/leftJoined.sql create mode 100644 snapshot-tests/anorm-sql/ProductTest/q.sql create mode 100644 snapshot-tests/anorm-sql/ProductTest/q2.sql create mode 100644 snapshot-tests/anorm-sql/ProductTest/query.sql create mode 100644 snapshot-tests/anorm-sql/ProductTest/query0.sql create mode 100644 snapshot-tests/anorm-sql/ProductTest/updateReturning.sql create mode 100644 snapshot-tests/anorm-sql/SeekTest/complex.sql create mode 100644 snapshot-tests/anorm-sql/SeekTest/uniform-ascending.sql create mode 100644 snapshot-tests/anorm-sql/SeekTest/uniform-descending.sql create mode 100644 snapshot-tests/dooble-sql/CompositeIdsTest/query2.sql create mode 100644 snapshot-tests/dooble-sql/ProductTest/delete.sql create mode 100644 snapshot-tests/dooble-sql/ProductTest/leftJoined.sql create mode 100644 snapshot-tests/dooble-sql/ProductTest/q.sql create mode 100644 snapshot-tests/dooble-sql/ProductTest/q2.sql create mode 100644 snapshot-tests/dooble-sql/ProductTest/query.sql create mode 100644 snapshot-tests/dooble-sql/ProductTest/query0.sql create mode 100644 snapshot-tests/dooble-sql/ProductTest/updateReturning.sql create mode 100644 snapshot-tests/dooble-sql/SeekTest/complex.sql create mode 100644 snapshot-tests/dooble-sql/SeekTest/uniform-ascending.sql create mode 100644 snapshot-tests/dooble-sql/SeekTest/uniform-descending.sql create mode 100644 snapshot-tests/zio-jdbc-sql/CompositeIdsTest/query2.sql create mode 100644 snapshot-tests/zio-jdbc-sql/ProductTest/delete.sql create mode 100644 snapshot-tests/zio-jdbc-sql/ProductTest/leftJoined.sql create mode 100644 snapshot-tests/zio-jdbc-sql/ProductTest/q.sql create mode 100644 snapshot-tests/zio-jdbc-sql/ProductTest/q2.sql create mode 100644 snapshot-tests/zio-jdbc-sql/ProductTest/query.sql create mode 100644 snapshot-tests/zio-jdbc-sql/ProductTest/query0.sql create mode 100644 snapshot-tests/zio-jdbc-sql/ProductTest/updateReturning.sql create mode 100644 snapshot-tests/zio-jdbc-sql/SeekTest/complex.sql create mode 100644 snapshot-tests/zio-jdbc-sql/SeekTest/uniform-ascending.sql create mode 100644 snapshot-tests/zio-jdbc-sql/SeekTest/uniform-descending.sql create mode 100644 typo-tester-anorm/src/scala/adventureworks/SnapshotTest.scala create mode 100644 typo-tester-doobie/src/scala/adventureworks/SnapshotTest.scala create mode 100644 typo-tester-zio-jdbc/src/scala/adventureworks/SnapshotTest.scala diff --git a/snapshot-tests/anorm-sql/CompositeIdsTest/query2.sql b/snapshot-tests/anorm-sql/CompositeIdsTest/query2.sql new file mode 100644 index 000000000..03e3cc274 --- /dev/null +++ b/snapshot-tests/anorm-sql/CompositeIdsTest/query2.sql @@ -0,0 +1,2 @@ +select "businessentityid","emailaddressid","emailaddress","rowguid","modifieddate"::text from person.emailaddress emailaddress0 + where (emailaddress0.businessentityid, emailaddress0.emailaddressid) in (select unnest(?::int4[]), unnest(?::int4[])) diff --git a/snapshot-tests/anorm-sql/ProductTest/delete.sql b/snapshot-tests/anorm-sql/ProductTest/delete.sql new file mode 100644 index 000000000..f06950e1f --- /dev/null +++ b/snapshot-tests/anorm-sql/ProductTest/delete.sql @@ -0,0 +1 @@ +delete from production.product where coalesce((productid = ?::INTEGER), ?::BOOLEAN) \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/ProductTest/leftJoined.sql b/snapshot-tests/anorm-sql/ProductTest/leftJoined.sql new file mode 100644 index 000000000..774f11f05 --- /dev/null +++ b/snapshot-tests/anorm-sql/ProductTest/leftJoined.sql @@ -0,0 +1,7 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate +from ( + select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 +) product0 +left join ( + select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) diff --git a/snapshot-tests/anorm-sql/ProductTest/q.sql b/snapshot-tests/anorm-sql/ProductTest/q.sql new file mode 100644 index 000000000..2fa603533 --- /dev/null +++ b/snapshot-tests/anorm-sql/ProductTest/q.sql @@ -0,0 +1,11 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate +from ( + select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 + where (((NOT (product0.name LIKE ?::VARCHAR) AND NOT ((product0.name || product0.color) LIKE ?::VARCHAR)) AND (product0.daystomanufacture > ?::INTEGER)) AND (product0.modifieddate < ?::timestamp)) +) product0 +join ( + select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 + where (productmodel0.modifieddate < ?::timestamp) +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + + where NOT productmodel0.instructions IS NULL diff --git a/snapshot-tests/anorm-sql/ProductTest/q2.sql b/snapshot-tests/anorm-sql/ProductTest/q2.sql new file mode 100644 index 000000000..4ec4754b5 --- /dev/null +++ b/snapshot-tests/anorm-sql/ProductTest/q2.sql @@ -0,0 +1,15 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productmodel1.productmodelid, productmodel1.name, productmodel1.catalogdescription, productmodel1.instructions, productmodel1.rowguid, productmodel1.modifieddate +from ( + select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 + where ((((product0.productid = ANY(?) AND (length(product0.name) > ?::INTEGER)) AND NOT ((product0.name || product0.color) LIKE ?::VARCHAR)) AND (coalesce(product0.color, ?::VARCHAR) != ?::VARCHAR)) AND (product0.modifieddate < ?::timestamp)) +) product0 +join ( + select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 + where (length(productmodel0.name) > ?::INTEGER) +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) +left join ( + select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel1 + where (length(productmodel1.name) > ?::INTEGER) +) productmodel1 on ((product0.productmodelid = productmodel1.productmodelid) AND ?::BOOLEAN) + + order by productmodel1.name ASC , product0.color DESC NULLS FIRST diff --git a/snapshot-tests/anorm-sql/ProductTest/query.sql b/snapshot-tests/anorm-sql/ProductTest/query.sql new file mode 100644 index 000000000..e78c36664 --- /dev/null +++ b/snapshot-tests/anorm-sql/ProductTest/query.sql @@ -0,0 +1,14 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, unitmeasure0.unitmeasurecode, unitmeasure0.name, unitmeasure0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate +from ( + select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 + where (((product0.class = ?::VARCHAR) AND ((product0.daystomanufacture > ?::INTEGER) OR (product0.daystomanufacture <= ?::INTEGER))) AND (product0.productline = ?::VARCHAR)) +) product0 +join ( + select "unitmeasurecode","name","modifieddate"::text from production.unitmeasure unitmeasure0 + where (unitmeasure0.name LIKE ?::VARCHAR) +) unitmeasure0 on (product0.sizeunitmeasurecode = unitmeasure0.unitmeasurecode) +left join ( + select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + + where (product0.productmodelid = productmodel0.productmodelid) order by product0.productmodelid ASC , productmodel0.name DESC NULLS FIRST diff --git a/snapshot-tests/anorm-sql/ProductTest/query0.sql b/snapshot-tests/anorm-sql/ProductTest/query0.sql new file mode 100644 index 000000000..3db904cad --- /dev/null +++ b/snapshot-tests/anorm-sql/ProductTest/query0.sql @@ -0,0 +1,13 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productsubcategory0.productsubcategoryid, productsubcategory0.productcategoryid, productsubcategory0.name, productsubcategory0.rowguid, productsubcategory0.modifieddate, productcategory0.productcategoryid, productcategory0.name, productcategory0.rowguid, productcategory0.modifieddate +from ( + select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 +) product0 +join ( + select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) +join ( + select "productsubcategoryid","productcategoryid","name","rowguid","modifieddate"::text from production.productsubcategory productsubcategory0 +) productsubcategory0 on (product0.productsubcategoryid = productsubcategory0.productsubcategoryid) +join ( + select "productcategoryid","name","rowguid","modifieddate"::text from production.productcategory productcategory0 +) productcategory0 on (productsubcategory0.productcategoryid = productcategory0.productcategoryid) diff --git a/snapshot-tests/anorm-sql/ProductTest/updateReturning.sql b/snapshot-tests/anorm-sql/ProductTest/updateReturning.sql new file mode 100644 index 000000000..5265ee020 --- /dev/null +++ b/snapshot-tests/anorm-sql/ProductTest/updateReturning.sql @@ -0,0 +1 @@ +update production.product set name = substring((upper(reverse(name)) || ?::"public"."Name"), ?::INTEGER, ?::INTEGER)::varchar, listprice = ?::DECIMAL::numeric, reorderpoint = (reorderpoint + ?::int2)::int2, sizeunitmeasurecode = ?::VARCHAR::bpchar, sellstartdate = ?::timestamp::timestamp where coalesce((productid = ?::INTEGER), ?::BOOLEAN) returning "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/SeekTest/complex.sql b/snapshot-tests/anorm-sql/SeekTest/complex.sql new file mode 100644 index 000000000..c2a477576 --- /dev/null +++ b/snapshot-tests/anorm-sql/SeekTest/complex.sql @@ -0,0 +1,2 @@ +select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 + where (((product0.name > ?::"public"."Name") OR ((product0.name = ?::"public"."Name") AND (product0.weight < ?::DECIMAL))) OR (((product0.name = ?::"public"."Name") AND (product0.weight = ?::DECIMAL)) AND (product0.listprice < ?::DECIMAL))) order by product0.name ASC , product0.weight DESC , product0.listprice DESC diff --git a/snapshot-tests/anorm-sql/SeekTest/uniform-ascending.sql b/snapshot-tests/anorm-sql/SeekTest/uniform-ascending.sql new file mode 100644 index 000000000..63a6982a2 --- /dev/null +++ b/snapshot-tests/anorm-sql/SeekTest/uniform-ascending.sql @@ -0,0 +1,2 @@ +select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 + where ((product0.name,product0.weight,product0.listprice) > (?::"public"."Name",?::DECIMAL,?::DECIMAL)) order by product0.name ASC , product0.weight ASC , product0.listprice ASC diff --git a/snapshot-tests/anorm-sql/SeekTest/uniform-descending.sql b/snapshot-tests/anorm-sql/SeekTest/uniform-descending.sql new file mode 100644 index 000000000..de6db8b6a --- /dev/null +++ b/snapshot-tests/anorm-sql/SeekTest/uniform-descending.sql @@ -0,0 +1,2 @@ +select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 + where ((product0.name,product0.weight,product0.listprice) < (?::"public"."Name",?::DECIMAL,?::DECIMAL)) order by product0.name DESC , product0.weight DESC , product0.listprice DESC diff --git a/snapshot-tests/dooble-sql/CompositeIdsTest/query2.sql b/snapshot-tests/dooble-sql/CompositeIdsTest/query2.sql new file mode 100644 index 000000000..64dd41728 --- /dev/null +++ b/snapshot-tests/dooble-sql/CompositeIdsTest/query2.sql @@ -0,0 +1 @@ +select "businessentityid", "emailaddressid", "emailaddress", "rowguid", "modifieddate"::text from person.emailaddress emailaddress0 WHERE (emailaddress0.businessentityid , emailaddress0.emailaddressid ) in (select unnest(?::_int4 ), unnest(?::_int4 )) \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/delete.sql b/snapshot-tests/dooble-sql/ProductTest/delete.sql new file mode 100644 index 000000000..0f2b7b948 --- /dev/null +++ b/snapshot-tests/dooble-sql/ProductTest/delete.sql @@ -0,0 +1 @@ +delete from production.product where coalesce((productid = ? ) , ? ) \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/leftJoined.sql b/snapshot-tests/dooble-sql/ProductTest/leftJoined.sql new file mode 100644 index 000000000..7f770b6d6 --- /dev/null +++ b/snapshot-tests/dooble-sql/ProductTest/leftJoined.sql @@ -0,0 +1,8 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate +from ( + select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 +) product0 + left join ( +select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/q.sql b/snapshot-tests/dooble-sql/ProductTest/q.sql new file mode 100644 index 000000000..9abde7a82 --- /dev/null +++ b/snapshot-tests/dooble-sql/ProductTest/q.sql @@ -0,0 +1,8 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate +from ( +select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE NOT (product0.name LIKE ? ) AND NOT ((product0.name || product0.color) LIKE ? ) AND (product0.daystomanufacture > ? ) AND (product0.modifieddate < ?::timestamp ) +) product0 + join ( +select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 WHERE (productmodel0.modifieddate < ?::timestamp ) +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + WHERE NOT productmodel0.instructions IS NULL \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/q2.sql b/snapshot-tests/dooble-sql/ProductTest/q2.sql new file mode 100644 index 000000000..0c34eaae2 --- /dev/null +++ b/snapshot-tests/dooble-sql/ProductTest/q2.sql @@ -0,0 +1,11 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productmodel1.productmodelid, productmodel1.name, productmodel1.catalogdescription, productmodel1.instructions, productmodel1.rowguid, productmodel1.modifieddate +from ( + select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE product0.productid = ANY(?) AND (length(product0.name) > ? ) AND NOT ((product0.name || product0.color) LIKE ? ) AND (coalesce(length(product0.color) , ? ) > ? ) AND (product0.modifieddate < ?::timestamp ) +) product0 + join ( +select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 WHERE NOT (productmodel0.name LIKE ? ) +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + left join ( +select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel1 WHERE NOT (productmodel1.name LIKE ? ) +) productmodel1 on ((product0.productmodelid = productmodel1.productmodelid) AND ? ) + ORDER BY product0.name ASC , productmodel0.rowguid DESC NULLS FIRST , productmodel1.rowguid ASC \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/query.sql b/snapshot-tests/dooble-sql/ProductTest/query.sql new file mode 100644 index 000000000..4b0c1f88f --- /dev/null +++ b/snapshot-tests/dooble-sql/ProductTest/query.sql @@ -0,0 +1,11 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, unitmeasure0.unitmeasurecode, unitmeasure0.name, unitmeasure0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate +from ( + select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (product0.class = ? ) AND ((product0.daystomanufacture > ? ) OR (product0.daystomanufacture <= ? ) ) AND (product0.productline = ? ) +) product0 + join ( +select "unitmeasurecode", "name", "modifieddate"::text from production.unitmeasure unitmeasure0 WHERE (unitmeasure0.name LIKE ? ) +) unitmeasure0 on (product0.sizeunitmeasurecode = unitmeasure0.unitmeasurecode) + left join ( +select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + WHERE (product0.productmodelid = productmodel0.productmodelid) ORDER BY product0.productmodelid ASC , productmodel0.name DESC NULLS FIRST \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/query0.sql b/snapshot-tests/dooble-sql/ProductTest/query0.sql new file mode 100644 index 000000000..a40b569da --- /dev/null +++ b/snapshot-tests/dooble-sql/ProductTest/query0.sql @@ -0,0 +1,14 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productsubcategory0.productsubcategoryid, productsubcategory0.productcategoryid, productsubcategory0.name, productsubcategory0.rowguid, productsubcategory0.modifieddate, productcategory0.productcategoryid, productcategory0.name, productcategory0.rowguid, productcategory0.modifieddate +from ( +select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 +) product0 + join ( +select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 +) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + join ( +select "productsubcategoryid", "productcategoryid", "name", "rowguid", "modifieddate"::text from production.productsubcategory productsubcategory0 +) productsubcategory0 on (product0.productsubcategoryid = productsubcategory0.productsubcategoryid) + join ( +select "productcategoryid", "name", "rowguid", "modifieddate"::text from production.productcategory productcategory0 +) productcategory0 on (productsubcategory0.productcategoryid = productcategory0.productcategoryid) + \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/updateReturning.sql b/snapshot-tests/dooble-sql/ProductTest/updateReturning.sql new file mode 100644 index 000000000..aafaf3e98 --- /dev/null +++ b/snapshot-tests/dooble-sql/ProductTest/updateReturning.sql @@ -0,0 +1 @@ +update production.product SET name = substring((upper(reverse(name) ) || ? ) , ? , ? ) ::varchar , listprice = ? ::numeric , reorderpoint = (reorderpoint + ?::int2 ) ::int2 WHERE coalesce((productid = ? ) , ? ) returning "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/SeekTest/complex.sql b/snapshot-tests/dooble-sql/SeekTest/complex.sql new file mode 100644 index 000000000..8d64880f6 --- /dev/null +++ b/snapshot-tests/dooble-sql/SeekTest/complex.sql @@ -0,0 +1 @@ +select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (((product0.name > ? ) OR ((product0.name = ? ) AND (product0.weight < ? ) ) ) OR (((product0.name = ? ) AND (product0.weight = ? ) ) AND (product0.listprice < ? ) ) ) ORDER BY product0.name ASC , product0.weight DESC , product0.listprice DESC \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/SeekTest/uniform-ascending.sql b/snapshot-tests/dooble-sql/SeekTest/uniform-ascending.sql new file mode 100644 index 000000000..d8dd2b447 --- /dev/null +++ b/snapshot-tests/dooble-sql/SeekTest/uniform-ascending.sql @@ -0,0 +1 @@ +select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name, product0.weight, product0.listprice) > (? , ? , ? ) ) ORDER BY product0.name ASC , product0.weight ASC , product0.listprice ASC \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/SeekTest/uniform-descending.sql b/snapshot-tests/dooble-sql/SeekTest/uniform-descending.sql new file mode 100644 index 000000000..6001fc291 --- /dev/null +++ b/snapshot-tests/dooble-sql/SeekTest/uniform-descending.sql @@ -0,0 +1 @@ +select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name, product0.weight, product0.listprice) < (? , ? , ? ) ) ORDER BY product0.name DESC , product0.weight DESC , product0.listprice DESC \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/CompositeIdsTest/query2.sql b/snapshot-tests/zio-jdbc-sql/CompositeIdsTest/query2.sql new file mode 100644 index 000000000..4ba284596 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/CompositeIdsTest/query2.sql @@ -0,0 +1 @@ +select "businessentityid", "emailaddressid", "emailaddress", "rowguid", "modifieddate"::text from person.emailaddress emailaddress0 WHERE (emailaddress0.businessentityid, emailaddress0.emailaddressid) in (select unnest(?::int4[]), unnest(?::int4[])) \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/delete.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/delete.sql new file mode 100644 index 000000000..91b007ef3 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/delete.sql @@ -0,0 +1 @@ +DELETE FROM production.product where coalesce((productid = ?::int4), ?::boolean) \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/leftJoined.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/leftJoined.sql new file mode 100644 index 000000000..ab5cc5e93 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/leftJoined.sql @@ -0,0 +1,8 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate + from ( + select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 + ) product0 + left join ( + select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 + ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/q.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/q.sql new file mode 100644 index 000000000..4b61e02a6 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/q.sql @@ -0,0 +1,8 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate + from ( + select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE NOT (product0.name LIKE ?::text) AND NOT ((product0.name || product0.color) LIKE ?::text) AND (product0.daystomanufacture > ?::int4) AND (product0.modifieddate < ?::timestamp) + ) product0 + join ( + select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 WHERE (productmodel0.modifieddate < ?::timestamp) + ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + WHERE NOT productmodel0.instructions IS NULL \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/q2.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/q2.sql new file mode 100644 index 000000000..b44fd91e3 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/q2.sql @@ -0,0 +1,11 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productmodel1.productmodelid, productmodel1.name, productmodel1.catalogdescription, productmodel1.instructions, productmodel1.rowguid, productmodel1.modifieddate + from ( + select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE product0.productid = ANY(?) AND (length(product0.name) > ?::int4) AND NOT ((product0.name || product0.color) LIKE ?::text) AND (coalesce(length(product0.color), ?::int4) > ?::int4) AND (product0.modifieddate < ?::timestamp) + ) product0 + join ( + select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 WHERE NOT (productmodel0.name LIKE ?::text) + ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + left join ( + select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel1 WHERE NOT (productmodel1.name LIKE ?::text) + ) productmodel1 on ((product0.productmodelid = productmodel1.productmodelid) AND ?::boolean) + ORDER BY product0.name ASC , productmodel0.rowguid DESC NULLS FIRST, productmodel1.rowguid ASC \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/query.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/query.sql new file mode 100644 index 000000000..ec1887b57 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/query.sql @@ -0,0 +1,11 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, unitmeasure0.unitmeasurecode, unitmeasure0.name, unitmeasure0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate + from ( + select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (product0.class = ?::text) AND ((product0.daystomanufacture > ?::int4) OR (product0.daystomanufacture <= ?::int4)) AND (product0.productline = ?::text) + ) product0 + join ( + select "unitmeasurecode", "name", "modifieddate"::text from production.unitmeasure unitmeasure0 WHERE (unitmeasure0.name LIKE ?::text) + ) unitmeasure0 on (product0.sizeunitmeasurecode = unitmeasure0.unitmeasurecode) + left join ( + select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 + ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + WHERE (product0.productmodelid = productmodel0.productmodelid) ORDER BY product0.productmodelid ASC , productmodel0.name DESC NULLS FIRST \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/query0.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/query0.sql new file mode 100644 index 000000000..448e5ab6a --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/query0.sql @@ -0,0 +1,14 @@ +select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productsubcategory0.productsubcategoryid, productsubcategory0.productcategoryid, productsubcategory0.name, productsubcategory0.rowguid, productsubcategory0.modifieddate, productcategory0.productcategoryid, productcategory0.name, productcategory0.rowguid, productcategory0.modifieddate + from ( + select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 + ) product0 + join ( + select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 + ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) + join ( + select "productsubcategoryid", "productcategoryid", "name", "rowguid", "modifieddate"::text from production.productsubcategory productsubcategory0 + ) productsubcategory0 on (product0.productsubcategoryid = productsubcategory0.productsubcategoryid) + join ( + select "productcategoryid", "name", "rowguid", "modifieddate"::text from production.productcategory productcategory0 + ) productcategory0 on (productsubcategory0.productcategoryid = productcategory0.productcategoryid) + \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/updateReturning.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/updateReturning.sql new file mode 100644 index 000000000..9a221aa50 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/updateReturning.sql @@ -0,0 +1 @@ +UPDATE production.product SET name = substring((upper(reverse(name)) || ?::"public"."Name"), ?::int4, ?::int4)::varchar, listprice = ?::numeric::numeric, reorderpoint = (reorderpoint + ?::int2)::int2 WHERE coalesce((productid = ?::int4), ?::boolean) returning "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/SeekTest/complex.sql b/snapshot-tests/zio-jdbc-sql/SeekTest/complex.sql new file mode 100644 index 000000000..afe561b3c --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/SeekTest/complex.sql @@ -0,0 +1 @@ +select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (((product0.name > ?::"public"."Name") OR ((product0.name = ?::"public"."Name") AND (product0.weight < ?::numeric))) OR (((product0.name = ?::"public"."Name") AND (product0.weight = ?::numeric)) AND (product0.listprice < ?::numeric))) ORDER BY product0.name ASC , product0.weight DESC , product0.listprice DESC \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-ascending.sql b/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-ascending.sql new file mode 100644 index 000000000..5dbb15cb6 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-ascending.sql @@ -0,0 +1 @@ +select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name,product0.weight,product0.listprice) > (?::"public"."Name",?::numeric,?::numeric)) ORDER BY product0.name ASC , product0.weight ASC , product0.listprice ASC \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-descending.sql b/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-descending.sql new file mode 100644 index 000000000..2611cc0d3 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-descending.sql @@ -0,0 +1 @@ +select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name,product0.weight,product0.listprice) < (?::"public"."Name",?::numeric,?::numeric)) ORDER BY product0.name DESC , product0.weight DESC , product0.listprice DESC \ No newline at end of file diff --git a/typo-tester-anorm/src/scala/adventureworks/SnapshotTest.scala b/typo-tester-anorm/src/scala/adventureworks/SnapshotTest.scala new file mode 100644 index 000000000..aa552a07f --- /dev/null +++ b/typo-tester-anorm/src/scala/adventureworks/SnapshotTest.scala @@ -0,0 +1,64 @@ +package adventureworks + +import org.scalactic.TypeCheckedTripleEquals +import org.scalatest.Assertion +import org.scalatest.funsuite.AnyFunSuite +import typo.dsl.Fragment + +import java.nio.file.{Files, Path} +import scala.annotation.nowarn + +trait SnapshotTest extends AnyFunSuite with TypeCheckedTripleEquals { + val outFolder: Path = + SnapshotTest.projectRoot.resolve("snapshot-tests/anorm-sql") + + def compareFragment(fragmentname: String)(ot: Option[Fragment]): Unit = { + ot.foreach(sql => { + val str = sql.sql.replaceAll("\\{param[\\d]+\\}", "?") + writeAndCompare(outFolder.resolve(s"${getClass.getSimpleName}/$fragmentname.sql"), str) + }) + } + + def writeAndCompare(in: Path, contents: String): Assertion = { + if (SnapshotTest.isCi) { + if (Files.exists(in)) { + val existing = Files.readString(in) + assert(existing == contents) + } else { + fail(s"Expected $in to exist") + } + } else { + Files.createDirectories(in.getParent) + Files.writeString(in, contents) + // burde sikkert ta en fil-lås, men dette dekker tester i samme JVM + SnapshotTest.GitLock.synchronized { + import scala.sys.process.* + List("git", "add", in.toString).!! : @nowarn + () + } + succeed + } + } +} + +object SnapshotTest { + val `.git`: Path = Path.of(".git") + val cwd: Path = Path.of(sys.props("user.dir")) + + /** intellij and sbt uses different working directories. This will place us somewhere predictable + */ + val projectRoot: Path = { + def lookUpwards(p: Path): Option[Path] = + if (Files.list(p).anyMatch(p => p.getFileName == `.git`)) Some(p) + else Option(p.getParent).flatMap(lookUpwards) + + lookUpwards(cwd).getOrElse { + sys.error(s"Cannot find root of repo (uses ${`.git`} to determine where)") + } + } + + val isCi: Boolean = + sys.env.contains("BUILD_NUMBER") || sys.env.contains("CI") // from sbt + + private object GitLock +} diff --git a/typo-tester-anorm/src/scala/adventureworks/production/product/CompositeIdsTest.scala b/typo-tester-anorm/src/scala/adventureworks/production/product/CompositeIdsTest.scala index 14bbc4976..3c9ba7247 100644 --- a/typo-tester-anorm/src/scala/adventureworks/production/product/CompositeIdsTest.scala +++ b/typo-tester-anorm/src/scala/adventureworks/production/product/CompositeIdsTest.scala @@ -1,23 +1,21 @@ package adventureworks.production.product import adventureworks.customtypes.{TypoLocalDateTime, TypoShort, TypoUUID, TypoXml} -import adventureworks.person.businessentity.{BusinessentityId, BusinessentityRepo, BusinessentityRepoImpl, BusinessentityRepoMock, BusinessentityRow} +import adventureworks.person.businessentity.* import adventureworks.person.emailaddress.{EmailaddressRepo, EmailaddressRepoImpl, EmailaddressRepoMock, EmailaddressRow} import adventureworks.person.person.{PersonRepo, PersonRepoImpl, PersonRepoMock, PersonRow} import adventureworks.production.productcosthistory.* import adventureworks.production.unitmeasure.UnitmeasureId import adventureworks.public.{Name, NameStyle} import adventureworks.userdefined.FirstName -import adventureworks.{DomainInsert, TestInsert, withConnection} -import org.scalactic.TypeCheckedTripleEquals +import adventureworks.{DomainInsert, SnapshotTest, TestInsert, withConnection} import org.scalatest.Assertion -import org.scalatest.funsuite.AnyFunSuite import java.time.LocalDateTime import scala.annotation.nowarn import scala.util.Random -class CompositeIdsTest extends AnyFunSuite with TypeCheckedTripleEquals { +class CompositeIdsTest extends SnapshotTest { implicit class Foo(x: TypoLocalDateTime) { def map(f: LocalDateTime => LocalDateTime): TypoLocalDateTime = TypoLocalDateTime(f(x.value)) } @@ -103,7 +101,7 @@ class CompositeIdsTest extends AnyFunSuite with TypeCheckedTripleEquals { ) ) val res2 = query2.toList - query2.sql.foreach(x => println(x)) + compareFragment("query2")(query2.sql) assert(res2 === List(emailaddress1_2, emailaddress1_3)) } } diff --git a/typo-tester-anorm/src/scala/adventureworks/production/product/ProductTest.scala b/typo-tester-anorm/src/scala/adventureworks/production/product/ProductTest.scala index 7786ab71d..2913bc44d 100644 --- a/typo-tester-anorm/src/scala/adventureworks/production/product/ProductTest.scala +++ b/typo-tester-anorm/src/scala/adventureworks/production/product/ProductTest.scala @@ -7,16 +7,14 @@ import adventureworks.production.productmodel.* import adventureworks.production.productsubcategory.* import adventureworks.production.unitmeasure.* import adventureworks.public.{Flag, Name} -import adventureworks.{DomainInsert, TestInsert, withConnection} -import org.scalactic.TypeCheckedTripleEquals +import adventureworks.{DomainInsert, SnapshotTest, TestInsert, withConnection} import org.scalatest.Assertion -import org.scalatest.funsuite.AnyFunSuite import java.time.LocalDateTime import scala.annotation.nowarn import scala.util.Random -class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { +class ProductTest extends SnapshotTest { val personDynamicSqlRepo = new PersonDynamicSqlRepoImpl test("flaf") { @@ -129,8 +127,8 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .joinFk(_.fkProductmodel)(projectModelRepo.select) .joinFk(_._1.fkProductsubcategory)(productsubcategoryRepo.select) .joinFk(_._2.fkProductcategory)(productcategoryRepo.select) + compareFragment("query0")(query0.sql) query0.toList.foreach(println) - query0.sql.foreach(println) println("foo") val query = @@ -146,15 +144,14 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .orderBy { case ((product, _), _) => product.productmodelid.asc } .orderBy { case ((_, _), productModel) => productModel(_.name).desc.withNullsFirst } - query.sql.foreach(f => println(f.sql)) - + compareFragment("query")(query.sql) println(query.toList) val leftJoined = productRepo.select .join(projectModelRepo.select) .leftOn { case (p, pm) => p.productmodelid === pm.productmodelid } - leftJoined.sql.foreach(f => println(f.sql)) + compareFragment("leftJoined")(leftJoined.sql) leftJoined.toList.foreach(println) val sellStartDate = TypoLocalDateTime.now @@ -166,7 +163,7 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .setComputedValue(_.sellstartdate)(_ => sellStartDate) .where(_.productid === saved1.productid) - update.sql(returning = true).foreach(f => println(f.sql)) + compareFragment("updateReturning")(update.sql(returning = true)) val List(updated) = update.executeReturnChanged() assert(updated.name === Name("MANf")): @nowarn assert(updated.listprice === BigDecimal(2)): @nowarn @@ -182,7 +179,7 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .on { case (p, pm) => p.productmodelid === pm.productmodelid } .where { case (_, pm) => !pm.instructions.isNull } - q.sql.foreach(f => println(f.sql)) + compareFragment("q")(q.sql) q.toList.foreach(println) val q2 = productRepo.select @@ -210,7 +207,7 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .orderBy { case (_, pm2) => pm2(_.name).asc } .orderBy { case ((p, _), _) => p.color.desc.withNullsFirst } - q2.sql.foreach(println) + compareFragment("q2")(q2.sql) q2.toList.foreach { case ((p, pm1), pm2) => println(p) println(pm1) @@ -218,7 +215,10 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { } // delete - productRepo.delete.where(_.productid === saved1.productid).execute(): @nowarn + val delete = productRepo.delete.where(_.productid === saved1.productid) + compareFragment("delete")(delete.sql) + + delete.execute(): @nowarn val List() = productRepo.selectAll: @unchecked diff --git a/typo-tester-anorm/src/scala/adventureworks/production/product/SeekTest.scala b/typo-tester-anorm/src/scala/adventureworks/production/product/SeekTest.scala index 2b7502afe..bd8ee769c 100644 --- a/typo-tester-anorm/src/scala/adventureworks/production/product/SeekTest.scala +++ b/typo-tester-anorm/src/scala/adventureworks/production/product/SeekTest.scala @@ -1,10 +1,9 @@ package adventureworks.production.product +import adventureworks.SnapshotTest import adventureworks.public.Name -import org.scalactic.TypeCheckedTripleEquals -import org.scalatest.funsuite.AnyFunSuite -class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { +class SeekTest extends SnapshotTest { val productRepo = new ProductRepoImpl test("uniform ascending") { @@ -12,11 +11,7 @@ class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { .seek(_.name.asc)(Name("foo")) .seek(_.weight.asc)(Some(BigDecimal(22.2))) .seek(_.listprice.asc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Fragment(List(NamedParameter(param1,ParameterValue(Name(foo))), NamedParameter(param2,ParameterValue(Some(22.2))), NamedParameter(param3,ParameterValue(33.3))),select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - | where ((product0.name,product0.weight,product0.listprice) > ({param1}::"public"."Name",{param2}::DECIMAL,{param3}::DECIMAL)) order by product0.name ASC , product0.weight ASC , product0.listprice ASC${" "} - |)""".stripMargin - ) + compareFragment("uniform-ascending")(query.sql) } test("uniform descending") { @@ -24,11 +19,7 @@ class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { .seek(_.name.desc)(Name("foo")) .seek(_.weight.desc)(Some(BigDecimal(22.2))) .seek(_.listprice.desc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Fragment(List(NamedParameter(param1,ParameterValue(Name(foo))), NamedParameter(param2,ParameterValue(Some(22.2))), NamedParameter(param3,ParameterValue(33.3))),select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - | where ((product0.name,product0.weight,product0.listprice) < ({param1}::"public"."Name",{param2}::DECIMAL,{param3}::DECIMAL)) order by product0.name DESC , product0.weight DESC , product0.listprice DESC${" "} - |)""".stripMargin - ) + compareFragment("uniform-descending")(query.sql) } test("complex") { @@ -36,10 +27,6 @@ class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { .seek(_.name.asc)(Name("foo")) .seek(_.weight.desc)(Some(BigDecimal(22.2))) .seek(_.listprice.desc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Fragment(List(NamedParameter(param1,ParameterValue(Name(foo))), NamedParameter(param2,ParameterValue(Name(foo))), NamedParameter(param3,ParameterValue(Some(22.2))), NamedParameter(param4,ParameterValue(Name(foo))), NamedParameter(param5,ParameterValue(Some(22.2))), NamedParameter(param6,ParameterValue(33.3))),select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - | where (((product0.name > {param1}::"public"."Name") OR ((product0.name = {param2}::"public"."Name") AND (product0.weight < {param3}::DECIMAL))) OR (((product0.name = {param4}::"public"."Name") AND (product0.weight = {param5}::DECIMAL)) AND (product0.listprice < {param6}::DECIMAL))) order by product0.name ASC , product0.weight DESC , product0.listprice DESC${' '} - |)""".stripMargin - ) + compareFragment("complex")(query.sql) } } diff --git a/typo-tester-doobie/src/scala/adventureworks/SnapshotTest.scala b/typo-tester-doobie/src/scala/adventureworks/SnapshotTest.scala new file mode 100644 index 000000000..27e587f47 --- /dev/null +++ b/typo-tester-doobie/src/scala/adventureworks/SnapshotTest.scala @@ -0,0 +1,63 @@ +package adventureworks + +import doobie.util.fragment.Fragment +import org.scalactic.TypeCheckedTripleEquals +import org.scalatest.Assertion +import org.scalatest.funsuite.AnyFunSuite + +import java.nio.file.{Files, Path} +import scala.annotation.nowarn + +trait SnapshotTest extends AnyFunSuite with TypeCheckedTripleEquals { + val outFolder: Path = + SnapshotTest.projectRoot.resolve("snapshot-tests/dooble-sql") + + def compareFragment(fragmentname: String)(ot: Option[Fragment]): Unit = { + ot.foreach(sql => { + writeAndCompare(outFolder.resolve(s"${getClass.getSimpleName}/$fragmentname.sql"), sql.internals.sql) + }) + } + + def writeAndCompare(in: Path, contents: String): Assertion = { + if (SnapshotTest.isCi) { + if (Files.exists(in)) { + val existing = Files.readString(in) + assert(existing == contents) + } else { + fail(s"Expected $in to exist") + } + } else { + Files.createDirectories(in.getParent) + Files.writeString(in, contents) + // burde sikkert ta en fil-lås, men dette dekker tester i samme JVM + SnapshotTest.GitLock.synchronized { + import scala.sys.process.* + List("git", "add", in.toString).!! : @nowarn + () + } + succeed + } + } +} + +object SnapshotTest { + val `.git`: Path = Path.of(".git") + val cwd: Path = Path.of(sys.props("user.dir")) + + /** intellij and sbt uses different working directories. This will place us somewhere predictable + */ + val projectRoot: Path = { + def lookUpwards(p: Path): Option[Path] = + if (Files.list(p).anyMatch(p => p.getFileName == `.git`)) Some(p) + else Option(p.getParent).flatMap(lookUpwards) + + lookUpwards(cwd).getOrElse { + sys.error(s"Cannot find root of repo (uses ${`.git`} to determine where)") + } + } + + val isCi: Boolean = + sys.env.contains("BUILD_NUMBER") || sys.env.contains("CI") // from sbt + + private object GitLock +} diff --git a/typo-tester-doobie/src/scala/adventureworks/production/product/CompositeIdsTest.scala b/typo-tester-doobie/src/scala/adventureworks/production/product/CompositeIdsTest.scala index 90e1deac5..846e76375 100644 --- a/typo-tester-doobie/src/scala/adventureworks/production/product/CompositeIdsTest.scala +++ b/typo-tester-doobie/src/scala/adventureworks/production/product/CompositeIdsTest.scala @@ -1,23 +1,21 @@ package adventureworks.production.product import adventureworks.customtypes.{TypoLocalDateTime, TypoShort, TypoUUID, TypoXml} -import adventureworks.person.businessentity.{BusinessentityId, BusinessentityRepo, BusinessentityRepoImpl, BusinessentityRepoMock, BusinessentityRow} +import adventureworks.person.businessentity.* import adventureworks.person.emailaddress.{EmailaddressRepo, EmailaddressRepoImpl, EmailaddressRepoMock, EmailaddressRow} import adventureworks.person.person.{PersonRepo, PersonRepoImpl, PersonRepoMock, PersonRow} import adventureworks.production.productcosthistory.* import adventureworks.production.unitmeasure.UnitmeasureId import adventureworks.public.{Name, NameStyle} -import adventureworks.{DomainInsert, TestInsert, withConnection} import adventureworks.userdefined.FirstName -import org.scalactic.TypeCheckedTripleEquals -import org.scalatest.funsuite.AnyFunSuite +import adventureworks.{DomainInsert, SnapshotTest, TestInsert, withConnection} import doobie.free.connection.delay import org.scalatest.Assertion import java.time.LocalDateTime import scala.util.Random -class CompositeIdsTest extends AnyFunSuite with TypeCheckedTripleEquals { +class CompositeIdsTest extends SnapshotTest { implicit class Foo(x: TypoLocalDateTime) { def map(f: LocalDateTime => LocalDateTime): TypoLocalDateTime = TypoLocalDateTime(f(x.value)) } @@ -107,7 +105,7 @@ class CompositeIdsTest extends AnyFunSuite with TypeCheckedTripleEquals { ) ) res2 <- query2.toList - _ <- delay(query2.sql.foreach(x => println(x))) + _ <- delay(compareFragment("query2")(query2.sql)) } yield assert(res2 === List(emailaddress1_2, emailaddress1_3)) } } diff --git a/typo-tester-doobie/src/scala/adventureworks/production/product/ProductTest.scala b/typo-tester-doobie/src/scala/adventureworks/production/product/ProductTest.scala index 4f50d4a41..4b2866ca3 100644 --- a/typo-tester-doobie/src/scala/adventureworks/production/product/ProductTest.scala +++ b/typo-tester-doobie/src/scala/adventureworks/production/product/ProductTest.scala @@ -6,15 +6,13 @@ import adventureworks.production.productmodel.* import adventureworks.production.productsubcategory.* import adventureworks.production.unitmeasure.* import adventureworks.public.{Flag, Name} -import adventureworks.withConnection +import adventureworks.{SnapshotTest, withConnection} import doobie.free.connection.delay -import org.scalactic.TypeCheckedTripleEquals import org.scalatest.Assertion -import org.scalatest.funsuite.AnyFunSuite import java.time.LocalDateTime -class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { +class ProductTest extends SnapshotTest { def runTest( productRepo: ProductRepo, projectModelRepo: ProductmodelRepo, @@ -95,8 +93,7 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .joinFk(_._1.fkProductsubcategory)(productsubcategoryRepo.select) .joinFk(_._2.fkProductcategory)(productcategoryRepo.select) _ <- query0.toList.map(println(_)) - _ <- delay(query0.sql.foreach(f => println(f))) - _ <- delay(println("foo")) + _ <- delay(compareFragment("query0")(query0.sql)) query = productRepo.select .where(_.`class` === "H ") @@ -110,10 +107,10 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .orderBy { case ((product, _), _) => product.productmodelid.asc } .orderBy { case ((_, _), productModel) => productModel(_.name).desc.withNullsFirst } - _ <- delay(query.sql.foreach(f => println(f))) + _ <- delay(compareFragment("query")(query.sql)) _ <- query.toList.map(println(_)) leftJoined = productRepo.select.join(projectModelRepo.select).leftOn { case (p, pm) => p.productmodelid === pm.productmodelid } - _ <- delay(leftJoined.sql.foreach(println)) + _ <- delay(compareFragment("leftJoined")(leftJoined.sql)) _ <- leftJoined.toList.map(println) update = productRepo.update @@ -123,7 +120,7 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { // .setComputedValue(_.sizeunitmeasurecode)(_ => Some(unitmeasure.unitmeasurecode)) .where(_.productid === saved1.productid) - _ <- delay(update.sql(returning = true).foreach(println(_))) + _ <- delay(compareFragment("updateReturning")(update.sql(returning = true))) foo <- update.executeReturnChanged List(updated) = foo _ <- delay(assert(updated.name === Name("MANf"))) @@ -139,11 +136,11 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .on { case (p, pm) => p.productmodelid === pm.productmodelid } .where { case (_, pm) => !pm.instructions.isNull } - q.sql.foreach(f => println(f)) + compareFragment("q")(q.sql) q.toList.map(list => list.foreach(println)) } _ <- { - val q = productRepo.select + val q2 = productRepo.select // select from id, arrays work .where(p => p.productid.in(Array(saved1.productid, new ProductId(22)))) // call `length` function and compare result @@ -168,8 +165,8 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .orderBy { case ((_, pm), _) => pm.rowguid.desc.withNullsFirst } .orderBy { case ((_, _), pm2) => pm2(_.rowguid).asc } -// q.sql.foreach(f => println(f.sql)) - q.toList.map { + compareFragment("q2")(q2.sql) + q2.toList.map { _.map { case ((p, pm1), pm2) => println(p) println(pm1) @@ -178,7 +175,9 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { } } // delete - _ <- productRepo.deleteById(saved1.productid) + delete = productRepo.delete.where(_.productid === saved1.productid) + _ <- delay(compareFragment("delete")(delete.sql)) + _ <- delete.execute _ <- productRepo.selectAll.compile.toList.map { case Nil => () case other => throw new MatchError(other) diff --git a/typo-tester-doobie/src/scala/adventureworks/production/product/SeekTest.scala b/typo-tester-doobie/src/scala/adventureworks/production/product/SeekTest.scala index dcdbbb67b..36a79ee49 100644 --- a/typo-tester-doobie/src/scala/adventureworks/production/product/SeekTest.scala +++ b/typo-tester-doobie/src/scala/adventureworks/production/product/SeekTest.scala @@ -1,11 +1,10 @@ package adventureworks.production.product +import adventureworks.SnapshotTest import adventureworks.public.Name -import org.scalactic.TypeCheckedTripleEquals -import org.scalatest.funsuite.AnyFunSuite import typo.dsl.SqlExpr -class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { +class SeekTest extends SnapshotTest { val productRepo = new ProductRepoImpl test("uniform ascending") { @@ -13,9 +12,7 @@ class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { .seek(_.name.asc)(Name("foo")) .seek(_.weight.asc)(SqlExpr.asConstOpt(Some(BigDecimal(22.2)))) .seek(_.listprice.asc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Fragment("select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name, product0.weight, product0.listprice) > (? , ? , ? ) ) ORDER BY product0.name ASC , product0.weight ASC , product0.listprice ASC ")""" - ) + compareFragment("uniform-ascending")(query.sql) } test("uniform descending") { @@ -23,9 +20,7 @@ class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { .seek(_.name.desc)(Name("foo")) .seek(_.weight.desc)(Some(BigDecimal(22.2))) .seek(_.listprice.desc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Fragment("select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name, product0.weight, product0.listprice) < (? , ? , ? ) ) ORDER BY product0.name DESC , product0.weight DESC , product0.listprice DESC ")""" - ) + compareFragment("uniform-descending")(query.sql) } test("complex") { @@ -33,8 +28,6 @@ class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { .seek(_.name.asc)(Name("foo")) .seek(_.weight.desc)(Some(BigDecimal(22.2))) .seek(_.listprice.desc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Fragment("select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (((product0.name > ? ) OR ((product0.name = ? ) AND (product0.weight < ? ) ) ) OR (((product0.name = ? ) AND (product0.weight = ? ) ) AND (product0.listprice < ? ) ) ) ORDER BY product0.name ASC , product0.weight DESC , product0.listprice DESC ")""" - ) + compareFragment("complex")(query.sql) } } diff --git a/typo-tester-zio-jdbc/src/scala/adventureworks/SnapshotTest.scala b/typo-tester-zio-jdbc/src/scala/adventureworks/SnapshotTest.scala new file mode 100644 index 000000000..059391ef6 --- /dev/null +++ b/typo-tester-zio-jdbc/src/scala/adventureworks/SnapshotTest.scala @@ -0,0 +1,76 @@ +package adventureworks + +import org.scalactic.TypeCheckedTripleEquals +import org.scalatest.Assertion +import org.scalatest.funsuite.AnyFunSuite +import zio.jdbc.SqlFragment +import zio.jdbc.SqlFragment.Segment + +import java.nio.file.{Files, Path} +import scala.annotation.nowarn + +trait SnapshotTest extends AnyFunSuite with TypeCheckedTripleEquals { + val outFolder: Path = + SnapshotTest.projectRoot.resolve("snapshot-tests/zio-jdbc-sql") + + def asString(frag: SqlFragment): String = { + val sql = new StringBuilder() + + def go(frag: SqlFragment): Unit = + frag.segments.foreach { + case Segment.Empty => () + case syntax: Segment.Syntax => sql.append(syntax.value) + case _: Segment.Param => sql.append('?') + case nested: Segment.Nested => go(nested.sql) + } + + go(frag) + sql.result() + } + + def compareFragment(fragmentname: String)(ot: Option[SqlFragment]): Unit = + ot.foreach(sql => writeAndCompare(outFolder.resolve(s"${getClass.getSimpleName}/$fragmentname.sql"), asString(sql))) + + def writeAndCompare(in: Path, contents: String): Assertion = { + if (SnapshotTest.isCi) { + if (Files.exists(in)) { + val existing = Files.readString(in) + assert(existing == contents) + } else { + fail(s"Expected $in to exist") + } + } else { + Files.createDirectories(in.getParent) + Files.writeString(in, contents) + // burde sikkert ta en fil-lås, men dette dekker tester i samme JVM + SnapshotTest.GitLock.synchronized { + import scala.sys.process.* + List("git", "add", in.toString).!! : @nowarn + () + } + succeed + } + } +} + +object SnapshotTest { + val `.git`: Path = Path.of(".git") + val cwd: Path = Path.of(sys.props("user.dir")) + + /** intellij and sbt uses different working directories. This will place us somewhere predictable + */ + val projectRoot: Path = { + def lookUpwards(p: Path): Option[Path] = + if (Files.list(p).anyMatch(p => p.getFileName == `.git`)) Some(p) + else Option(p.getParent).flatMap(lookUpwards) + + lookUpwards(cwd).getOrElse { + sys.error(s"Cannot find root of repo (uses ${`.git`} to determine where)") + } + } + + val isCi: Boolean = + sys.env.contains("BUILD_NUMBER") || sys.env.contains("CI") // from sbt + + private object GitLock +} diff --git a/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/CompositeIdsTest.scala b/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/CompositeIdsTest.scala index 0a593d1b0..187dd18a8 100644 --- a/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/CompositeIdsTest.scala +++ b/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/CompositeIdsTest.scala @@ -8,16 +8,14 @@ import adventureworks.production.productcosthistory.ProductcosthistoryRepoImpl import adventureworks.production.unitmeasure.UnitmeasureId import adventureworks.public.{Name, NameStyle} import adventureworks.userdefined.FirstName -import adventureworks.{DomainInsert, TestInsert, withConnection} -import org.scalactic.TypeCheckedTripleEquals +import adventureworks.{DomainInsert, SnapshotTest, TestInsert, withConnection} import org.scalatest.Assertion -import org.scalatest.funsuite.AnyFunSuite import zio.{Chunk, ZIO} import java.time.LocalDateTime import scala.util.Random -class CompositeIdsTest extends AnyFunSuite with TypeCheckedTripleEquals { +class CompositeIdsTest extends SnapshotTest { implicit class Foo(x: TypoLocalDateTime) { def map(f: LocalDateTime => LocalDateTime): TypoLocalDateTime = TypoLocalDateTime(f(x.value)) } @@ -107,7 +105,7 @@ class CompositeIdsTest extends AnyFunSuite with TypeCheckedTripleEquals { ) ) res2 <- query2.toChunk - _ <- ZIO.attempt(query2.sql.foreach(x => println(x))) + _ <- ZIO.attempt(compareFragment("query2")(query2.sql)) } yield assert(res2.toList === List(emailaddress1_2, emailaddress1_3)) } } diff --git a/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/ProductTest.scala b/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/ProductTest.scala index 40206d21a..54fe271fd 100644 --- a/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/ProductTest.scala +++ b/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/ProductTest.scala @@ -6,15 +6,13 @@ import adventureworks.production.productmodel.* import adventureworks.production.productsubcategory.* import adventureworks.production.unitmeasure.* import adventureworks.public.{Flag, Name} -import adventureworks.withConnection -import org.scalactic.TypeCheckedTripleEquals +import adventureworks.{SnapshotTest, withConnection} import org.scalatest.Assertion -import org.scalatest.funsuite.AnyFunSuite import zio.{Chunk, ZIO} import java.time.LocalDateTime -class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { +class ProductTest extends SnapshotTest { def runTest( productRepo: ProductRepo, projectModelRepo: ProductmodelRepo, @@ -95,8 +93,7 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .joinFk(_._1.fkProductsubcategory)(productsubcategoryRepo.select) .joinFk(_._2.fkProductcategory)(productcategoryRepo.select) _ <- query0.toChunk.map(println(_)) - _ <- ZIO.succeed(query0.sql.foreach(f => println(f))) - _ <- ZIO.succeed(println("foo")) + _ <- ZIO.succeed(compareFragment("query0")(query0.sql)) query = productRepo.select .where(_.`class` === "H ") .where(x => (x.daystomanufacture > 25).or(x.daystomanufacture <= 0)) @@ -109,10 +106,10 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .orderBy { case ((product, _), _) => product.productmodelid.asc } .orderBy { case ((_, _), productModel) => productModel(_.name).desc.withNullsFirst } - _ <- ZIO.succeed(query.sql.foreach(f => println(f))) + _ <- ZIO.succeed(compareFragment("query")(query.sql)) _ <- query.toChunk.map(println(_)) leftJoined = productRepo.select.join(projectModelRepo.select).leftOn { case (p, pm) => p.productmodelid === pm.productmodelid } - _ <- ZIO.succeed(leftJoined.sql.foreach(println)) + _ <- ZIO.succeed(compareFragment("leftJoined")(leftJoined.sql)) _ <- leftJoined.toChunk.map(println) update = productRepo.update @@ -122,7 +119,7 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { // .setComputedValue(_.sizeunitmeasurecode)(_ => Some(unitmeasure.unitmeasurecode)) .where(_.productid === saved1.productid) - _ <- ZIO.succeed(update.sql(returning = true).foreach(println(_))) + _ <- ZIO.succeed(compareFragment("updateReturning")(update.sql(returning = true))) foo <- update.executeReturnChanged Chunk(updated) = foo _ <- ZIO.succeed(assert(updated.name === Name("MANf"))) @@ -138,11 +135,11 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .on { case (p, pm) => p.productmodelid === pm.productmodelid } .where { case (_, pm) => !pm.instructions.isNull } - q.sql.foreach(f => println(f)) + compareFragment("q")(q.sql) q.toChunk.map(list => list.foreach(println)) } _ <- { - val q = productRepo.select + val q2 = productRepo.select // select from id, arrays work .where(p => p.productid.in(Array(saved1.productid, new ProductId(22)))) // call `length` function and compare result @@ -167,8 +164,8 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { .orderBy { case ((_, pm), _) => pm.rowguid.desc.withNullsFirst } .orderBy { case ((_, _), pm2) => pm2(_.rowguid).asc } -// q.sql.foreach(f => println(f.sql)) - q.toChunk.map { + compareFragment("q2")(q2.sql) + q2.toChunk.map { _.map { case ((p, pm1), pm2) => println(p) println(pm1) @@ -177,7 +174,9 @@ class ProductTest extends AnyFunSuite with TypeCheckedTripleEquals { } } // delete - _ <- productRepo.deleteById(saved1.productid) + delete = productRepo.delete.where(_.productid === saved1.productid) + _ <- ZIO.succeed(compareFragment("delete")(delete.sql)) + _ <- delete.execute _ <- productRepo.selectAll.runCollect.map(_.toList).map { case Nil => () case other => throw new MatchError(other) diff --git a/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/SeekTest.scala b/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/SeekTest.scala index 6b84d0a3b..36a79ee49 100644 --- a/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/SeekTest.scala +++ b/typo-tester-zio-jdbc/src/scala/adventureworks/production/product/SeekTest.scala @@ -1,20 +1,18 @@ package adventureworks.production.product +import adventureworks.SnapshotTest import adventureworks.public.Name -import org.scalactic.TypeCheckedTripleEquals -import org.scalatest.funsuite.AnyFunSuite +import typo.dsl.SqlExpr -class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { +class SeekTest extends SnapshotTest { val productRepo = new ProductRepoImpl test("uniform ascending") { val query = productRepo.select .seek(_.name.asc)(Name("foo")) - .seek(_.weight.asc)(Some(BigDecimal(22.2))) + .seek(_.weight.asc)(SqlExpr.asConstOpt(Some(BigDecimal(22.2)))) .seek(_.listprice.asc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Sql(select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name,product0.weight,product0.listprice) > (?::"public"."Name",?::numeric,?::numeric)) ORDER BY product0.name ASC , product0.weight ASC , product0.listprice ASC , foo, Some(22.2), 33.3)""" - ) + compareFragment("uniform-ascending")(query.sql) } test("uniform descending") { @@ -22,9 +20,7 @@ class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { .seek(_.name.desc)(Name("foo")) .seek(_.weight.desc)(Some(BigDecimal(22.2))) .seek(_.listprice.desc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Sql(select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name,product0.weight,product0.listprice) < (?::"public"."Name",?::numeric,?::numeric)) ORDER BY product0.name DESC , product0.weight DESC , product0.listprice DESC , foo, Some(22.2), 33.3)""" - ) + compareFragment("uniform-descending")(query.sql) } test("complex") { @@ -32,8 +28,6 @@ class SeekTest extends AnyFunSuite with TypeCheckedTripleEquals { .seek(_.name.asc)(Name("foo")) .seek(_.weight.desc)(Some(BigDecimal(22.2))) .seek(_.listprice.desc)(BigDecimal(33.3)) - assertResult(query.sql.get.toString)( - s"""Sql(select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (((product0.name > ?::"public"."Name") OR ((product0.name = ?::"public"."Name") AND (product0.weight < ?::numeric))) OR (((product0.name = ?::"public"."Name") AND (product0.weight = ?::numeric)) AND (product0.listprice < ?::numeric))) ORDER BY product0.name ASC , product0.weight DESC , product0.listprice DESC , foo, foo, Some(22.2), foo, Some(22.2), 33.3)""" - ) + compareFragment("complex")(query.sql) } } From aef6dcdab35bc88b958674d90be1e27b9b26f825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Raddum=20Berg?= Date: Thu, 20 Jun 2024 22:17:57 +0200 Subject: [PATCH 3/4] Revamp SQL generation The previous method for SQL generation was not powerful enough ## Create scopes for all levels The previous method failed to create "scopes" for all joins, which meant that predicates, sorting, limits and so on wouldn't apply where usage of the DSL indicated they would. Now we create these scopes with CTEs at all levels of the query. CTEs should be fine, performance-wise, as they were fixed for PG12 ## Better compositionality The previous method failed when performing (joined query).join(joined query), it only worked with relations on the left side. This is also fixed ## Refactoring The old SQL generation code was neither understandable nor correct. Now I hope it's both ## Lost predicates for intermediate joins Since the old code was hard to understand, --- .../anorm-sql/CompositeIdsTest/query2.sql | 7 +- snapshot-tests/anorm-sql/DSLTest/doubled.sql | 115 +++++++++ .../anorm-sql/ProductTest/leftJoined.sql | 22 +- snapshot-tests/anorm-sql/ProductTest/q.sql | 26 +- snapshot-tests/anorm-sql/ProductTest/q2.sql | 40 ++-- .../anorm-sql/ProductTest/query.sql | 39 +-- .../anorm-sql/ProductTest/query0.sql | 48 +++- snapshot-tests/anorm-sql/SeekTest/complex.sql | 7 +- .../anorm-sql/SeekTest/uniform-ascending.sql | 7 +- .../anorm-sql/SeekTest/uniform-descending.sql | 7 +- .../dooble-sql/CompositeIdsTest/query2.sql | 6 +- snapshot-tests/dooble-sql/DSLTest/doubled.sql | 115 +++++++++ .../dooble-sql/ProductTest/leftJoined.sql | 23 +- snapshot-tests/dooble-sql/ProductTest/q.sql | 23 +- snapshot-tests/dooble-sql/ProductTest/q2.sql | 36 ++- .../dooble-sql/ProductTest/query.sql | 36 ++- .../dooble-sql/ProductTest/query0.sql | 49 ++-- .../dooble-sql/SeekTest/complex.sql | 6 +- .../dooble-sql/SeekTest/uniform-ascending.sql | 6 +- .../SeekTest/uniform-descending.sql | 6 +- .../zio-jdbc-sql/CompositeIdsTest/query2.sql | 6 +- .../zio-jdbc-sql/DSLTest/doubled.sql | 115 +++++++++ .../zio-jdbc-sql/ProductTest/leftJoined.sql | 23 +- snapshot-tests/zio-jdbc-sql/ProductTest/q.sql | 23 +- .../zio-jdbc-sql/ProductTest/q2.sql | 36 ++- .../zio-jdbc-sql/ProductTest/query.sql | 36 ++- .../zio-jdbc-sql/ProductTest/query0.sql | 49 ++-- .../zio-jdbc-sql/SeekTest/complex.sql | 6 +- .../SeekTest/uniform-ascending.sql | 6 +- .../SeekTest/uniform-descending.sql | 6 +- .../src/scala/typo/dsl/SelectBuilderSql.scala | 213 +++++++---------- .../src/scala/typo/dsl/SelectParams.scala | 33 +-- .../src/scala/typo/dsl/SqlExpr.scala | 2 +- .../src/scala/typo/dsl/SelectBuilderSql.scala | 215 +++++++---------- .../src/scala/typo/dsl/SelectParams.scala | 5 +- .../src/scala/typo/dsl/SqlExpr.scala | 2 +- typo-dsl-shared/typo/dsl/RenderCtx.scala | 6 +- typo-dsl-shared/typo/dsl/Structure.scala | 24 +- .../src/scala/typo/dsl/SelectBuilderSql.scala | 225 +++++++----------- .../src/scala/typo/dsl/SelectParams.scala | 5 +- .../src/scala/typo/dsl/SqlExpr.scala | 2 +- .../src/scala/adventureworks/DSLTest.scala | 49 ++++ .../scala/adventureworks/PaginationTest.scala | 10 +- .../production/product/ProductTest.scala | 1 - .../src/scala/adventureworks/DSLTest.scala | 47 ++++ .../scala/adventureworks/PaginationTest.scala | 10 +- .../src/scala/adventureworks/DSLTest.scala | 47 ++++ .../scala/adventureworks/PaginationTest.scala | 10 +- 48 files changed, 1197 insertions(+), 639 deletions(-) create mode 100644 snapshot-tests/anorm-sql/DSLTest/doubled.sql create mode 100644 snapshot-tests/dooble-sql/DSLTest/doubled.sql create mode 100644 snapshot-tests/zio-jdbc-sql/DSLTest/doubled.sql create mode 100644 typo-tester-anorm/src/scala/adventureworks/DSLTest.scala create mode 100644 typo-tester-doobie/src/scala/adventureworks/DSLTest.scala create mode 100644 typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala diff --git a/snapshot-tests/anorm-sql/CompositeIdsTest/query2.sql b/snapshot-tests/anorm-sql/CompositeIdsTest/query2.sql index 03e3cc274..96641b183 100644 --- a/snapshot-tests/anorm-sql/CompositeIdsTest/query2.sql +++ b/snapshot-tests/anorm-sql/CompositeIdsTest/query2.sql @@ -1,2 +1,5 @@ -select "businessentityid","emailaddressid","emailaddress","rowguid","modifieddate"::text from person.emailaddress emailaddress0 - where (emailaddress0.businessentityid, emailaddress0.emailaddressid) in (select unnest(?::int4[]), unnest(?::int4[])) +with +emailaddress0 as ( + (select emailaddress0 from person.emailaddress emailaddress0 where ((emailaddress0).businessentityid, (emailaddress0).emailaddressid) in (select unnest(?::int4[]), unnest(?::int4[]))) +) +select (emailaddress0)."businessentityid",(emailaddress0)."emailaddressid",(emailaddress0)."emailaddress",(emailaddress0)."rowguid",(emailaddress0)."modifieddate"::text from emailaddress0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/DSLTest/doubled.sql b/snapshot-tests/anorm-sql/DSLTest/doubled.sql new file mode 100644 index 000000000..17dff5eb9 --- /dev/null +++ b/snapshot-tests/anorm-sql/DSLTest/doubled.sql @@ -0,0 +1,115 @@ +with +salesperson0 as ( + (select salesperson0 from sales.salesperson salesperson0 where ((salesperson0).rowguid = ?::uuid)) +), +employee0 as ( + (select employee0 from humanresources.employee employee0 ) +), +join_cte5 as ( + select salesperson0, employee0 + from salesperson0 + join employee0 + on ((salesperson0).businessentityid = (employee0).businessentityid) + +), +person0 as ( + (select person0 from person.person person0 ) +), +join_cte4 as ( + select salesperson0, employee0, person0 + from join_cte5 + join person0 + on ((employee0).businessentityid = (person0).businessentityid) + +), +businessentity0 as ( + (select businessentity0 from person.businessentity businessentity0 ) +), +join_cte3 as ( + select salesperson0, employee0, person0, businessentity0 + from join_cte4 + join businessentity0 + on ((person0).businessentityid = (businessentity0).businessentityid) + +), +emailaddress0 as ( + (select emailaddress0 from person.emailaddress emailaddress0 order by (emailaddress0).rowguid ASC ) +), +join_cte2 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0 + from join_cte3 + join emailaddress0 + on ((emailaddress0).businessentityid = (businessentity0).businessentityid) + +), +salesperson1 as ( + (select salesperson1 from sales.salesperson salesperson1 ) +), +join_cte1 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0, salesperson1 + from join_cte2 + join salesperson1 + on ((emailaddress0).businessentityid = (salesperson1).businessentityid) + +), +salesperson2 as ( + (select salesperson2 from sales.salesperson salesperson2 where ((salesperson2).rowguid = ?::uuid)) +), +employee1 as ( + (select employee1 from humanresources.employee employee1 ) +), +join_cte10 as ( + select salesperson2, employee1 + from salesperson2 + join employee1 + on ((salesperson2).businessentityid = (employee1).businessentityid) + +), +person1 as ( + (select person1 from person.person person1 ) +), +join_cte9 as ( + select salesperson2, employee1, person1 + from join_cte10 + join person1 + on ((employee1).businessentityid = (person1).businessentityid) + +), +businessentity1 as ( + (select businessentity1 from person.businessentity businessentity1 ) +), +join_cte8 as ( + select salesperson2, employee1, person1, businessentity1 + from join_cte9 + join businessentity1 + on ((person1).businessentityid = (businessentity1).businessentityid) + +), +emailaddress1 as ( + (select emailaddress1 from person.emailaddress emailaddress1 order by (emailaddress1).rowguid ASC ) +), +join_cte7 as ( + select salesperson2, employee1, person1, businessentity1, emailaddress1 + from join_cte8 + join emailaddress1 + on ((emailaddress1).businessentityid = (businessentity1).businessentityid) + +), +salesperson3 as ( + (select salesperson3 from sales.salesperson salesperson3 ) +), +join_cte6 as ( + select salesperson2, employee1, person1, businessentity1, emailaddress1, salesperson3 + from join_cte7 + join salesperson3 + on ((emailaddress1).businessentityid = (salesperson3).businessentityid) + +), +join_cte0 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0, salesperson1, salesperson2, employee1, person1, businessentity1, emailaddress1, salesperson3 + from join_cte1 + join join_cte6 + on ((emailaddress0).businessentityid = (emailaddress1).businessentityid) + +) +select (salesperson0)."businessentityid",(salesperson0)."territoryid",(salesperson0)."salesquota",(salesperson0)."bonus",(salesperson0)."commissionpct",(salesperson0)."salesytd",(salesperson0)."saleslastyear",(salesperson0)."rowguid",(salesperson0)."modifieddate"::text,(employee0)."businessentityid",(employee0)."nationalidnumber",(employee0)."loginid",(employee0)."jobtitle",(employee0)."birthdate"::text,(employee0)."maritalstatus",(employee0)."gender",(employee0)."hiredate"::text,(employee0)."salariedflag",(employee0)."vacationhours",(employee0)."sickleavehours",(employee0)."currentflag",(employee0)."rowguid",(employee0)."modifieddate"::text,(employee0)."organizationnode",(person0)."businessentityid",(person0)."persontype",(person0)."namestyle",(person0)."title",(person0)."firstname",(person0)."middlename",(person0)."lastname",(person0)."suffix",(person0)."emailpromotion",(person0)."additionalcontactinfo",(person0)."demographics",(person0)."rowguid",(person0)."modifieddate"::text,(businessentity0)."businessentityid",(businessentity0)."rowguid",(businessentity0)."modifieddate"::text,(emailaddress0)."businessentityid",(emailaddress0)."emailaddressid",(emailaddress0)."emailaddress",(emailaddress0)."rowguid",(emailaddress0)."modifieddate"::text,(salesperson1)."businessentityid",(salesperson1)."territoryid",(salesperson1)."salesquota",(salesperson1)."bonus",(salesperson1)."commissionpct",(salesperson1)."salesytd",(salesperson1)."saleslastyear",(salesperson1)."rowguid",(salesperson1)."modifieddate"::text,(salesperson2)."businessentityid",(salesperson2)."territoryid",(salesperson2)."salesquota",(salesperson2)."bonus",(salesperson2)."commissionpct",(salesperson2)."salesytd",(salesperson2)."saleslastyear",(salesperson2)."rowguid",(salesperson2)."modifieddate"::text,(employee1)."businessentityid",(employee1)."nationalidnumber",(employee1)."loginid",(employee1)."jobtitle",(employee1)."birthdate"::text,(employee1)."maritalstatus",(employee1)."gender",(employee1)."hiredate"::text,(employee1)."salariedflag",(employee1)."vacationhours",(employee1)."sickleavehours",(employee1)."currentflag",(employee1)."rowguid",(employee1)."modifieddate"::text,(employee1)."organizationnode",(person1)."businessentityid",(person1)."persontype",(person1)."namestyle",(person1)."title",(person1)."firstname",(person1)."middlename",(person1)."lastname",(person1)."suffix",(person1)."emailpromotion",(person1)."additionalcontactinfo",(person1)."demographics",(person1)."rowguid",(person1)."modifieddate"::text,(businessentity1)."businessentityid",(businessentity1)."rowguid",(businessentity1)."modifieddate"::text,(emailaddress1)."businessentityid",(emailaddress1)."emailaddressid",(emailaddress1)."emailaddress",(emailaddress1)."rowguid",(emailaddress1)."modifieddate"::text,(salesperson3)."businessentityid",(salesperson3)."territoryid",(salesperson3)."salesquota",(salesperson3)."bonus",(salesperson3)."commissionpct",(salesperson3)."salesytd",(salesperson3)."saleslastyear",(salesperson3)."rowguid",(salesperson3)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/ProductTest/leftJoined.sql b/snapshot-tests/anorm-sql/ProductTest/leftJoined.sql index 774f11f05..52682cd64 100644 --- a/snapshot-tests/anorm-sql/ProductTest/leftJoined.sql +++ b/snapshot-tests/anorm-sql/ProductTest/leftJoined.sql @@ -1,7 +1,15 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate -from ( - select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 -) product0 -left join ( - select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) +with +product0 as ( + (select product0 from production.product product0 ) +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +), +left_join_cte0 as ( + select product0, productmodel0 + from product0 + left join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/ProductTest/q.sql b/snapshot-tests/anorm-sql/ProductTest/q.sql index 2fa603533..96ff7a6a9 100644 --- a/snapshot-tests/anorm-sql/ProductTest/q.sql +++ b/snapshot-tests/anorm-sql/ProductTest/q.sql @@ -1,11 +1,15 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate -from ( - select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - where (((NOT (product0.name LIKE ?::VARCHAR) AND NOT ((product0.name || product0.color) LIKE ?::VARCHAR)) AND (product0.daystomanufacture > ?::INTEGER)) AND (product0.modifieddate < ?::timestamp)) -) product0 -join ( - select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 - where (productmodel0.modifieddate < ?::timestamp) -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - - where NOT productmodel0.instructions IS NULL +with +product0 as ( + (select product0 from production.product product0 where (((NOT ((product0).name LIKE ?::VARCHAR) AND NOT (((product0).name || (product0).color) LIKE ?::VARCHAR)) AND ((product0).daystomanufacture > ?::INTEGER)) AND ((product0).modifieddate < ?::timestamp))) +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 where ((productmodel0).modifieddate < ?::timestamp)) +), +join_cte0 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + where NOT (productmodel0).instructions IS NULL +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/ProductTest/q2.sql b/snapshot-tests/anorm-sql/ProductTest/q2.sql index 4ec4754b5..6951d3d2f 100644 --- a/snapshot-tests/anorm-sql/ProductTest/q2.sql +++ b/snapshot-tests/anorm-sql/ProductTest/q2.sql @@ -1,15 +1,25 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productmodel1.productmodelid, productmodel1.name, productmodel1.catalogdescription, productmodel1.instructions, productmodel1.rowguid, productmodel1.modifieddate -from ( - select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - where ((((product0.productid = ANY(?) AND (length(product0.name) > ?::INTEGER)) AND NOT ((product0.name || product0.color) LIKE ?::VARCHAR)) AND (coalesce(product0.color, ?::VARCHAR) != ?::VARCHAR)) AND (product0.modifieddate < ?::timestamp)) -) product0 -join ( - select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 - where (length(productmodel0.name) > ?::INTEGER) -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) -left join ( - select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel1 - where (length(productmodel1.name) > ?::INTEGER) -) productmodel1 on ((product0.productmodelid = productmodel1.productmodelid) AND ?::BOOLEAN) - - order by productmodel1.name ASC , product0.color DESC NULLS FIRST +with +product0 as ( + (select product0 from production.product product0 where (((((product0).productid = ANY(?) AND (length((product0).name) > ?::INTEGER)) AND NOT (((product0).name || (product0).color) LIKE ?::VARCHAR)) AND (coalesce((product0).color, ?::VARCHAR) != ?::VARCHAR)) AND ((product0).modifieddate < ?::timestamp))) +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 where (length((productmodel0).name) > ?::INTEGER)) +), +join_cte0 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + where ((productmodel0).name != ?::VARCHAR) +), +productmodel1 as ( + (select productmodel1 from production.productmodel productmodel1 where (length((productmodel1).name) > ?::INTEGER)) +), +left_join_cte0 as ( + select product0, productmodel0, productmodel1 + from join_cte0 + left join productmodel1 + on (((product0).productmodelid = (productmodel1).productmodelid) AND ?::BOOLEAN) + order by (productmodel1).name ASC , (product0).color DESC NULLS FIRST +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text,(productmodel1)."productmodelid",(productmodel1)."name",(productmodel1)."catalogdescription",(productmodel1)."instructions",(productmodel1)."rowguid",(productmodel1)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/ProductTest/query.sql b/snapshot-tests/anorm-sql/ProductTest/query.sql index e78c36664..558f8350b 100644 --- a/snapshot-tests/anorm-sql/ProductTest/query.sql +++ b/snapshot-tests/anorm-sql/ProductTest/query.sql @@ -1,14 +1,25 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, unitmeasure0.unitmeasurecode, unitmeasure0.name, unitmeasure0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate -from ( - select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - where (((product0.class = ?::VARCHAR) AND ((product0.daystomanufacture > ?::INTEGER) OR (product0.daystomanufacture <= ?::INTEGER))) AND (product0.productline = ?::VARCHAR)) -) product0 -join ( - select "unitmeasurecode","name","modifieddate"::text from production.unitmeasure unitmeasure0 - where (unitmeasure0.name LIKE ?::VARCHAR) -) unitmeasure0 on (product0.sizeunitmeasurecode = unitmeasure0.unitmeasurecode) -left join ( - select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - - where (product0.productmodelid = productmodel0.productmodelid) order by product0.productmodelid ASC , productmodel0.name DESC NULLS FIRST +with +product0 as ( + (select product0 from production.product product0 where ((((product0).class = ?::VARCHAR) AND (((product0).daystomanufacture > ?::INTEGER) OR ((product0).daystomanufacture <= ?::INTEGER))) AND ((product0).productline = ?::VARCHAR))) +), +unitmeasure0 as ( + (select unitmeasure0 from production.unitmeasure unitmeasure0 where ((unitmeasure0).name LIKE ?::VARCHAR)) +), +join_cte0 as ( + select product0, unitmeasure0 + from product0 + join unitmeasure0 + on ((product0).sizeunitmeasurecode = (unitmeasure0).unitmeasurecode) + +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +), +left_join_cte0 as ( + select product0, unitmeasure0, productmodel0 + from join_cte0 + left join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + where ((product0).productmodelid = (productmodel0).productmodelid) order by (product0).productmodelid ASC , (productmodel0).name DESC NULLS FIRST +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(unitmeasure0)."unitmeasurecode",(unitmeasure0)."name",(unitmeasure0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/ProductTest/query0.sql b/snapshot-tests/anorm-sql/ProductTest/query0.sql index 3db904cad..4a3bf1a66 100644 --- a/snapshot-tests/anorm-sql/ProductTest/query0.sql +++ b/snapshot-tests/anorm-sql/ProductTest/query0.sql @@ -1,13 +1,35 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productsubcategory0.productsubcategoryid, productsubcategory0.productcategoryid, productsubcategory0.name, productsubcategory0.rowguid, productsubcategory0.modifieddate, productcategory0.productcategoryid, productcategory0.name, productcategory0.rowguid, productcategory0.modifieddate -from ( - select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 -) product0 -join ( - select "productmodelid","name","catalogdescription","instructions","rowguid","modifieddate"::text from production.productmodel productmodel0 -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) -join ( - select "productsubcategoryid","productcategoryid","name","rowguid","modifieddate"::text from production.productsubcategory productsubcategory0 -) productsubcategory0 on (product0.productsubcategoryid = productsubcategory0.productsubcategoryid) -join ( - select "productcategoryid","name","rowguid","modifieddate"::text from production.productcategory productcategory0 -) productcategory0 on (productsubcategory0.productcategoryid = productcategory0.productcategoryid) +with +product0 as ( + (select product0 from production.product product0 ) +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +), +join_cte2 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + +), +productsubcategory0 as ( + (select productsubcategory0 from production.productsubcategory productsubcategory0 ) +), +join_cte1 as ( + select product0, productmodel0, productsubcategory0 + from join_cte2 + join productsubcategory0 + on ((product0).productsubcategoryid = (productsubcategory0).productsubcategoryid) + +), +productcategory0 as ( + (select productcategory0 from production.productcategory productcategory0 ) +), +join_cte0 as ( + select product0, productmodel0, productsubcategory0, productcategory0 + from join_cte1 + join productcategory0 + on ((productsubcategory0).productcategoryid = (productcategory0).productcategoryid) + +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text,(productsubcategory0)."productsubcategoryid",(productsubcategory0)."productcategoryid",(productsubcategory0)."name",(productsubcategory0)."rowguid",(productsubcategory0)."modifieddate"::text,(productcategory0)."productcategoryid",(productcategory0)."name",(productcategory0)."rowguid",(productcategory0)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/SeekTest/complex.sql b/snapshot-tests/anorm-sql/SeekTest/complex.sql index c2a477576..58454573a 100644 --- a/snapshot-tests/anorm-sql/SeekTest/complex.sql +++ b/snapshot-tests/anorm-sql/SeekTest/complex.sql @@ -1,2 +1,5 @@ -select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - where (((product0.name > ?::"public"."Name") OR ((product0.name = ?::"public"."Name") AND (product0.weight < ?::DECIMAL))) OR (((product0.name = ?::"public"."Name") AND (product0.weight = ?::DECIMAL)) AND (product0.listprice < ?::DECIMAL))) order by product0.name ASC , product0.weight DESC , product0.listprice DESC +with +product0 as ( + (select product0 from production.product product0 where ((((product0).name > ?::"public"."Name") OR (((product0).name = ?::"public"."Name") AND ((product0).weight < ?::DECIMAL))) OR ((((product0).name = ?::"public"."Name") AND ((product0).weight = ?::DECIMAL)) AND ((product0).listprice < ?::DECIMAL))) order by (product0).name ASC , (product0).weight DESC , (product0).listprice DESC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/SeekTest/uniform-ascending.sql b/snapshot-tests/anorm-sql/SeekTest/uniform-ascending.sql index 63a6982a2..ba1886c42 100644 --- a/snapshot-tests/anorm-sql/SeekTest/uniform-ascending.sql +++ b/snapshot-tests/anorm-sql/SeekTest/uniform-ascending.sql @@ -1,2 +1,5 @@ -select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - where ((product0.name,product0.weight,product0.listprice) > (?::"public"."Name",?::DECIMAL,?::DECIMAL)) order by product0.name ASC , product0.weight ASC , product0.listprice ASC +with +product0 as ( + (select product0 from production.product product0 where (((product0).name,(product0).weight,(product0).listprice) > (?::"public"."Name",?::DECIMAL,?::DECIMAL)) order by (product0).name ASC , (product0).weight ASC , (product0).listprice ASC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/snapshot-tests/anorm-sql/SeekTest/uniform-descending.sql b/snapshot-tests/anorm-sql/SeekTest/uniform-descending.sql index de6db8b6a..0cfadff5a 100644 --- a/snapshot-tests/anorm-sql/SeekTest/uniform-descending.sql +++ b/snapshot-tests/anorm-sql/SeekTest/uniform-descending.sql @@ -1,2 +1,5 @@ -select "productid","name","productnumber","makeflag","finishedgoodsflag","color","safetystocklevel","reorderpoint","standardcost","listprice","size","sizeunitmeasurecode","weightunitmeasurecode","weight","daystomanufacture","productline","class","style","productsubcategoryid","productmodelid","sellstartdate"::text,"sellenddate"::text,"discontinueddate"::text,"rowguid","modifieddate"::text from production.product product0 - where ((product0.name,product0.weight,product0.listprice) < (?::"public"."Name",?::DECIMAL,?::DECIMAL)) order by product0.name DESC , product0.weight DESC , product0.listprice DESC +with +product0 as ( + (select product0 from production.product product0 where (((product0).name,(product0).weight,(product0).listprice) < (?::"public"."Name",?::DECIMAL,?::DECIMAL)) order by (product0).name DESC , (product0).weight DESC , (product0).listprice DESC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/CompositeIdsTest/query2.sql b/snapshot-tests/dooble-sql/CompositeIdsTest/query2.sql index 64dd41728..3a2dd13e2 100644 --- a/snapshot-tests/dooble-sql/CompositeIdsTest/query2.sql +++ b/snapshot-tests/dooble-sql/CompositeIdsTest/query2.sql @@ -1 +1,5 @@ -select "businessentityid", "emailaddressid", "emailaddress", "rowguid", "modifieddate"::text from person.emailaddress emailaddress0 WHERE (emailaddress0.businessentityid , emailaddress0.emailaddressid ) in (select unnest(?::_int4 ), unnest(?::_int4 )) \ No newline at end of file +with +emailaddress0 as ( + (select emailaddress0 from person.emailaddress emailaddress0 WHERE ((emailaddress0).businessentityid , (emailaddress0).emailaddressid ) in (select unnest(?::_int4 ), unnest(?::_int4 ))) +) +select (emailaddress0)."businessentityid",(emailaddress0)."emailaddressid",(emailaddress0)."emailaddress",(emailaddress0)."rowguid",(emailaddress0)."modifieddate"::text from emailaddress0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/DSLTest/doubled.sql b/snapshot-tests/dooble-sql/DSLTest/doubled.sql new file mode 100644 index 000000000..2b87b4697 --- /dev/null +++ b/snapshot-tests/dooble-sql/DSLTest/doubled.sql @@ -0,0 +1,115 @@ +with +salesperson0 as ( + (select salesperson0 from sales.salesperson salesperson0 WHERE ((salesperson0).rowguid = ?::uuid ) ) +) , +employee0 as ( + (select employee0 from humanresources.employee employee0 ) +) , +join_cte5 as ( + select salesperson0, employee0 + from salesperson0 + join employee0 + on ((salesperson0).businessentityid = (employee0).businessentityid) + +) , +person0 as ( + (select person0 from person.person person0 ) +) , +join_cte4 as ( + select salesperson0, employee0, person0 + from join_cte5 + join person0 + on ((employee0).businessentityid = (person0).businessentityid) + +) , +businessentity0 as ( + (select businessentity0 from person.businessentity businessentity0 ) +) , +join_cte3 as ( + select salesperson0, employee0, person0, businessentity0 + from join_cte4 + join businessentity0 + on ((person0).businessentityid = (businessentity0).businessentityid) + +) , +emailaddress0 as ( + (select emailaddress0 from person.emailaddress emailaddress0 ORDER BY (emailaddress0).rowguid ASC ) +) , +join_cte2 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0 + from join_cte3 + join emailaddress0 + on ((emailaddress0).businessentityid = (businessentity0).businessentityid) + +) , +salesperson1 as ( + (select salesperson1 from sales.salesperson salesperson1 ) +) , +join_cte1 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0, salesperson1 + from join_cte2 + join salesperson1 + on ((emailaddress0).businessentityid = (salesperson1).businessentityid) + +) , +salesperson2 as ( + (select salesperson2 from sales.salesperson salesperson2 WHERE ((salesperson2).rowguid = ?::uuid ) ) +) , +employee1 as ( + (select employee1 from humanresources.employee employee1 ) +) , +join_cte10 as ( + select salesperson2, employee1 + from salesperson2 + join employee1 + on ((salesperson2).businessentityid = (employee1).businessentityid) + +) , +person1 as ( + (select person1 from person.person person1 ) +) , +join_cte9 as ( + select salesperson2, employee1, person1 + from join_cte10 + join person1 + on ((employee1).businessentityid = (person1).businessentityid) + +) , +businessentity1 as ( + (select businessentity1 from person.businessentity businessentity1 ) +) , +join_cte8 as ( + select salesperson2, employee1, person1, businessentity1 + from join_cte9 + join businessentity1 + on ((person1).businessentityid = (businessentity1).businessentityid) + +) , +emailaddress1 as ( + (select emailaddress1 from person.emailaddress emailaddress1 ORDER BY (emailaddress1).rowguid ASC ) +) , +join_cte7 as ( + select salesperson2, employee1, person1, businessentity1, emailaddress1 + from join_cte8 + join emailaddress1 + on ((emailaddress1).businessentityid = (businessentity1).businessentityid) + +) , +salesperson3 as ( + (select salesperson3 from sales.salesperson salesperson3 ) +) , +join_cte6 as ( + select salesperson2, employee1, person1, businessentity1, emailaddress1, salesperson3 + from join_cte7 + join salesperson3 + on ((emailaddress1).businessentityid = (salesperson3).businessentityid) + +) , +join_cte0 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0, salesperson1, salesperson2, employee1, person1, businessentity1, emailaddress1, salesperson3 + from join_cte1 + join join_cte6 + on ((emailaddress0).businessentityid = (emailaddress1).businessentityid) + +) +select (salesperson0)."businessentityid",(salesperson0)."territoryid",(salesperson0)."salesquota",(salesperson0)."bonus",(salesperson0)."commissionpct",(salesperson0)."salesytd",(salesperson0)."saleslastyear",(salesperson0)."rowguid",(salesperson0)."modifieddate"::text,(employee0)."businessentityid",(employee0)."nationalidnumber",(employee0)."loginid",(employee0)."jobtitle",(employee0)."birthdate"::text,(employee0)."maritalstatus",(employee0)."gender",(employee0)."hiredate"::text,(employee0)."salariedflag",(employee0)."vacationhours",(employee0)."sickleavehours",(employee0)."currentflag",(employee0)."rowguid",(employee0)."modifieddate"::text,(employee0)."organizationnode",(person0)."businessentityid",(person0)."persontype",(person0)."namestyle",(person0)."title",(person0)."firstname",(person0)."middlename",(person0)."lastname",(person0)."suffix",(person0)."emailpromotion",(person0)."additionalcontactinfo",(person0)."demographics",(person0)."rowguid",(person0)."modifieddate"::text,(businessentity0)."businessentityid",(businessentity0)."rowguid",(businessentity0)."modifieddate"::text,(emailaddress0)."businessentityid",(emailaddress0)."emailaddressid",(emailaddress0)."emailaddress",(emailaddress0)."rowguid",(emailaddress0)."modifieddate"::text,(salesperson1)."businessentityid",(salesperson1)."territoryid",(salesperson1)."salesquota",(salesperson1)."bonus",(salesperson1)."commissionpct",(salesperson1)."salesytd",(salesperson1)."saleslastyear",(salesperson1)."rowguid",(salesperson1)."modifieddate"::text,(salesperson2)."businessentityid",(salesperson2)."territoryid",(salesperson2)."salesquota",(salesperson2)."bonus",(salesperson2)."commissionpct",(salesperson2)."salesytd",(salesperson2)."saleslastyear",(salesperson2)."rowguid",(salesperson2)."modifieddate"::text,(employee1)."businessentityid",(employee1)."nationalidnumber",(employee1)."loginid",(employee1)."jobtitle",(employee1)."birthdate"::text,(employee1)."maritalstatus",(employee1)."gender",(employee1)."hiredate"::text,(employee1)."salariedflag",(employee1)."vacationhours",(employee1)."sickleavehours",(employee1)."currentflag",(employee1)."rowguid",(employee1)."modifieddate"::text,(employee1)."organizationnode",(person1)."businessentityid",(person1)."persontype",(person1)."namestyle",(person1)."title",(person1)."firstname",(person1)."middlename",(person1)."lastname",(person1)."suffix",(person1)."emailpromotion",(person1)."additionalcontactinfo",(person1)."demographics",(person1)."rowguid",(person1)."modifieddate"::text,(businessentity1)."businessentityid",(businessentity1)."rowguid",(businessentity1)."modifieddate"::text,(emailaddress1)."businessentityid",(emailaddress1)."emailaddressid",(emailaddress1)."emailaddress",(emailaddress1)."rowguid",(emailaddress1)."modifieddate"::text,(salesperson3)."businessentityid",(salesperson3)."territoryid",(salesperson3)."salesquota",(salesperson3)."bonus",(salesperson3)."commissionpct",(salesperson3)."salesytd",(salesperson3)."saleslastyear",(salesperson3)."rowguid",(salesperson3)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/leftJoined.sql b/snapshot-tests/dooble-sql/ProductTest/leftJoined.sql index 7f770b6d6..90eb93cb9 100644 --- a/snapshot-tests/dooble-sql/ProductTest/leftJoined.sql +++ b/snapshot-tests/dooble-sql/ProductTest/leftJoined.sql @@ -1,8 +1,15 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate -from ( - select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 -) product0 - left join ( -select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 ) +) , +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +) , +left_join_cte0 as ( + select product0, productmodel0 + from product0 + left join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/q.sql b/snapshot-tests/dooble-sql/ProductTest/q.sql index 9abde7a82..1f6b30adf 100644 --- a/snapshot-tests/dooble-sql/ProductTest/q.sql +++ b/snapshot-tests/dooble-sql/ProductTest/q.sql @@ -1,8 +1,15 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate -from ( -select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE NOT (product0.name LIKE ? ) AND NOT ((product0.name || product0.color) LIKE ? ) AND (product0.daystomanufacture > ? ) AND (product0.modifieddate < ?::timestamp ) -) product0 - join ( -select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 WHERE (productmodel0.modifieddate < ?::timestamp ) -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - WHERE NOT productmodel0.instructions IS NULL \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE NOT ((product0).name LIKE ? ) AND NOT (((product0).name || (product0).color) LIKE ? ) AND ((product0).daystomanufacture > ? ) AND ((product0).modifieddate < ?::timestamp ) ) +) , +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 WHERE ((productmodel0).modifieddate < ?::timestamp ) ) +) , +join_cte0 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + WHERE NOT (productmodel0).instructions IS NULL +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/q2.sql b/snapshot-tests/dooble-sql/ProductTest/q2.sql index 0c34eaae2..4ef423071 100644 --- a/snapshot-tests/dooble-sql/ProductTest/q2.sql +++ b/snapshot-tests/dooble-sql/ProductTest/q2.sql @@ -1,11 +1,25 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productmodel1.productmodelid, productmodel1.name, productmodel1.catalogdescription, productmodel1.instructions, productmodel1.rowguid, productmodel1.modifieddate -from ( - select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE product0.productid = ANY(?) AND (length(product0.name) > ? ) AND NOT ((product0.name || product0.color) LIKE ? ) AND (coalesce(length(product0.color) , ? ) > ? ) AND (product0.modifieddate < ?::timestamp ) -) product0 - join ( -select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 WHERE NOT (productmodel0.name LIKE ? ) -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - left join ( -select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel1 WHERE NOT (productmodel1.name LIKE ? ) -) productmodel1 on ((product0.productmodelid = productmodel1.productmodelid) AND ? ) - ORDER BY product0.name ASC , productmodel0.rowguid DESC NULLS FIRST , productmodel1.rowguid ASC \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE (product0).productid = ANY(?) AND (length((product0).name) > ? ) AND NOT (((product0).name || (product0).color) LIKE ? ) AND (coalesce(length((product0).color) , ? ) > ? ) AND ((product0).modifieddate < ?::timestamp ) ) +) , +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 WHERE NOT ((productmodel0).name LIKE ? ) ) +) , +join_cte0 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + WHERE ((productmodel0).productmodelid > ? ) +) , +productmodel1 as ( + (select productmodel1 from production.productmodel productmodel1 WHERE NOT ((productmodel1).name LIKE ? ) ) +) , +left_join_cte0 as ( + select product0, productmodel0, productmodel1 + from join_cte0 + left join productmodel1 + on (((product0).productmodelid = (productmodel1).productmodelid) AND ? ) + ORDER BY (product0).name ASC , (productmodel0).rowguid DESC NULLS FIRST , (productmodel1).rowguid ASC +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text,(productmodel1)."productmodelid",(productmodel1)."name",(productmodel1)."catalogdescription",(productmodel1)."instructions",(productmodel1)."rowguid",(productmodel1)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/query.sql b/snapshot-tests/dooble-sql/ProductTest/query.sql index 4b0c1f88f..4a7dc865a 100644 --- a/snapshot-tests/dooble-sql/ProductTest/query.sql +++ b/snapshot-tests/dooble-sql/ProductTest/query.sql @@ -1,11 +1,25 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, unitmeasure0.unitmeasurecode, unitmeasure0.name, unitmeasure0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate -from ( - select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (product0.class = ? ) AND ((product0.daystomanufacture > ? ) OR (product0.daystomanufacture <= ? ) ) AND (product0.productline = ? ) -) product0 - join ( -select "unitmeasurecode", "name", "modifieddate"::text from production.unitmeasure unitmeasure0 WHERE (unitmeasure0.name LIKE ? ) -) unitmeasure0 on (product0.sizeunitmeasurecode = unitmeasure0.unitmeasurecode) - left join ( -select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - WHERE (product0.productmodelid = productmodel0.productmodelid) ORDER BY product0.productmodelid ASC , productmodel0.name DESC NULLS FIRST \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE ((product0).class = ? ) AND (((product0).daystomanufacture > ? ) OR ((product0).daystomanufacture <= ? ) ) AND ((product0).productline = ? ) ) +) , +unitmeasure0 as ( + (select unitmeasure0 from production.unitmeasure unitmeasure0 WHERE ((unitmeasure0).name LIKE ? ) ) +) , +join_cte0 as ( + select product0, unitmeasure0 + from product0 + join unitmeasure0 + on ((product0).sizeunitmeasurecode = (unitmeasure0).unitmeasurecode) + +) , +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +) , +left_join_cte0 as ( + select product0, unitmeasure0, productmodel0 + from join_cte0 + left join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + WHERE ((product0).productmodelid = (productmodel0).productmodelid) ORDER BY (product0).productmodelid ASC , (productmodel0).name DESC NULLS FIRST +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(unitmeasure0)."unitmeasurecode",(unitmeasure0)."name",(unitmeasure0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/ProductTest/query0.sql b/snapshot-tests/dooble-sql/ProductTest/query0.sql index a40b569da..3e26c46fb 100644 --- a/snapshot-tests/dooble-sql/ProductTest/query0.sql +++ b/snapshot-tests/dooble-sql/ProductTest/query0.sql @@ -1,14 +1,35 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productsubcategory0.productsubcategoryid, productsubcategory0.productcategoryid, productsubcategory0.name, productsubcategory0.rowguid, productsubcategory0.modifieddate, productcategory0.productcategoryid, productcategory0.name, productcategory0.rowguid, productcategory0.modifieddate -from ( -select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 -) product0 - join ( -select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 -) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - join ( -select "productsubcategoryid", "productcategoryid", "name", "rowguid", "modifieddate"::text from production.productsubcategory productsubcategory0 -) productsubcategory0 on (product0.productsubcategoryid = productsubcategory0.productsubcategoryid) - join ( -select "productcategoryid", "name", "rowguid", "modifieddate"::text from production.productcategory productcategory0 -) productcategory0 on (productsubcategory0.productcategoryid = productcategory0.productcategoryid) - \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 ) +) , +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +) , +join_cte2 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + +) , +productsubcategory0 as ( + (select productsubcategory0 from production.productsubcategory productsubcategory0 ) +) , +join_cte1 as ( + select product0, productmodel0, productsubcategory0 + from join_cte2 + join productsubcategory0 + on ((product0).productsubcategoryid = (productsubcategory0).productsubcategoryid) + +) , +productcategory0 as ( + (select productcategory0 from production.productcategory productcategory0 ) +) , +join_cte0 as ( + select product0, productmodel0, productsubcategory0, productcategory0 + from join_cte1 + join productcategory0 + on ((productsubcategory0).productcategoryid = (productcategory0).productcategoryid) + +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text,(productsubcategory0)."productsubcategoryid",(productsubcategory0)."productcategoryid",(productsubcategory0)."name",(productsubcategory0)."rowguid",(productsubcategory0)."modifieddate"::text,(productcategory0)."productcategoryid",(productcategory0)."name",(productcategory0)."rowguid",(productcategory0)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/SeekTest/complex.sql b/snapshot-tests/dooble-sql/SeekTest/complex.sql index 8d64880f6..2411321a2 100644 --- a/snapshot-tests/dooble-sql/SeekTest/complex.sql +++ b/snapshot-tests/dooble-sql/SeekTest/complex.sql @@ -1 +1,5 @@ -select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (((product0.name > ? ) OR ((product0.name = ? ) AND (product0.weight < ? ) ) ) OR (((product0.name = ? ) AND (product0.weight = ? ) ) AND (product0.listprice < ? ) ) ) ORDER BY product0.name ASC , product0.weight DESC , product0.listprice DESC \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE ((((product0).name > ? ) OR (((product0).name = ? ) AND ((product0).weight < ? ) ) ) OR ((((product0).name = ? ) AND ((product0).weight = ? ) ) AND ((product0).listprice < ? ) ) ) ORDER BY (product0).name ASC , (product0).weight DESC , (product0).listprice DESC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/SeekTest/uniform-ascending.sql b/snapshot-tests/dooble-sql/SeekTest/uniform-ascending.sql index d8dd2b447..bb28fbe38 100644 --- a/snapshot-tests/dooble-sql/SeekTest/uniform-ascending.sql +++ b/snapshot-tests/dooble-sql/SeekTest/uniform-ascending.sql @@ -1 +1,5 @@ -select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name, product0.weight, product0.listprice) > (? , ? , ? ) ) ORDER BY product0.name ASC , product0.weight ASC , product0.listprice ASC \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE (((product0).name, (product0).weight, (product0).listprice) > (? , ? , ? ) ) ORDER BY (product0).name ASC , (product0).weight ASC , (product0).listprice ASC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/snapshot-tests/dooble-sql/SeekTest/uniform-descending.sql b/snapshot-tests/dooble-sql/SeekTest/uniform-descending.sql index 6001fc291..b5c8f4310 100644 --- a/snapshot-tests/dooble-sql/SeekTest/uniform-descending.sql +++ b/snapshot-tests/dooble-sql/SeekTest/uniform-descending.sql @@ -1 +1,5 @@ -select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name, product0.weight, product0.listprice) < (? , ? , ? ) ) ORDER BY product0.name DESC , product0.weight DESC , product0.listprice DESC \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE (((product0).name, (product0).weight, (product0).listprice) < (? , ? , ? ) ) ORDER BY (product0).name DESC , (product0).weight DESC , (product0).listprice DESC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/CompositeIdsTest/query2.sql b/snapshot-tests/zio-jdbc-sql/CompositeIdsTest/query2.sql index 4ba284596..25ee3b147 100644 --- a/snapshot-tests/zio-jdbc-sql/CompositeIdsTest/query2.sql +++ b/snapshot-tests/zio-jdbc-sql/CompositeIdsTest/query2.sql @@ -1 +1,5 @@ -select "businessentityid", "emailaddressid", "emailaddress", "rowguid", "modifieddate"::text from person.emailaddress emailaddress0 WHERE (emailaddress0.businessentityid, emailaddress0.emailaddressid) in (select unnest(?::int4[]), unnest(?::int4[])) \ No newline at end of file +with +emailaddress0 as ( + (select emailaddress0 from person.emailaddress emailaddress0 WHERE ((emailaddress0).businessentityid, (emailaddress0).emailaddressid) in (select unnest(?::int4[]), unnest(?::int4[]))) +) +select (emailaddress0)."businessentityid",(emailaddress0)."emailaddressid",(emailaddress0)."emailaddress",(emailaddress0)."rowguid",(emailaddress0)."modifieddate"::text from emailaddress0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/DSLTest/doubled.sql b/snapshot-tests/zio-jdbc-sql/DSLTest/doubled.sql new file mode 100644 index 000000000..4a8455750 --- /dev/null +++ b/snapshot-tests/zio-jdbc-sql/DSLTest/doubled.sql @@ -0,0 +1,115 @@ +with +salesperson0 as ( + (select salesperson0 from sales.salesperson salesperson0 WHERE ((salesperson0).rowguid = ?::uuid)) +), +employee0 as ( + (select employee0 from humanresources.employee employee0 ) +), +join_cte5 as ( + select salesperson0, employee0 + from salesperson0 + join employee0 + on ((salesperson0).businessentityid = (employee0).businessentityid) + +), +person0 as ( + (select person0 from person.person person0 ) +), +join_cte4 as ( + select salesperson0, employee0, person0 + from join_cte5 + join person0 + on ((employee0).businessentityid = (person0).businessentityid) + +), +businessentity0 as ( + (select businessentity0 from person.businessentity businessentity0 ) +), +join_cte3 as ( + select salesperson0, employee0, person0, businessentity0 + from join_cte4 + join businessentity0 + on ((person0).businessentityid = (businessentity0).businessentityid) + +), +emailaddress0 as ( + (select emailaddress0 from person.emailaddress emailaddress0 ORDER BY (emailaddress0).rowguid ASC ) +), +join_cte2 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0 + from join_cte3 + join emailaddress0 + on ((emailaddress0).businessentityid = (businessentity0).businessentityid) + +), +salesperson1 as ( + (select salesperson1 from sales.salesperson salesperson1 ) +), +join_cte1 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0, salesperson1 + from join_cte2 + join salesperson1 + on ((emailaddress0).businessentityid = (salesperson1).businessentityid) + +), +salesperson2 as ( + (select salesperson2 from sales.salesperson salesperson2 WHERE ((salesperson2).rowguid = ?::uuid)) +), +employee1 as ( + (select employee1 from humanresources.employee employee1 ) +), +join_cte10 as ( + select salesperson2, employee1 + from salesperson2 + join employee1 + on ((salesperson2).businessentityid = (employee1).businessentityid) + +), +person1 as ( + (select person1 from person.person person1 ) +), +join_cte9 as ( + select salesperson2, employee1, person1 + from join_cte10 + join person1 + on ((employee1).businessentityid = (person1).businessentityid) + +), +businessentity1 as ( + (select businessentity1 from person.businessentity businessentity1 ) +), +join_cte8 as ( + select salesperson2, employee1, person1, businessentity1 + from join_cte9 + join businessentity1 + on ((person1).businessentityid = (businessentity1).businessentityid) + +), +emailaddress1 as ( + (select emailaddress1 from person.emailaddress emailaddress1 ORDER BY (emailaddress1).rowguid ASC ) +), +join_cte7 as ( + select salesperson2, employee1, person1, businessentity1, emailaddress1 + from join_cte8 + join emailaddress1 + on ((emailaddress1).businessentityid = (businessentity1).businessentityid) + +), +salesperson3 as ( + (select salesperson3 from sales.salesperson salesperson3 ) +), +join_cte6 as ( + select salesperson2, employee1, person1, businessentity1, emailaddress1, salesperson3 + from join_cte7 + join salesperson3 + on ((emailaddress1).businessentityid = (salesperson3).businessentityid) + +), +join_cte0 as ( + select salesperson0, employee0, person0, businessentity0, emailaddress0, salesperson1, salesperson2, employee1, person1, businessentity1, emailaddress1, salesperson3 + from join_cte1 + join join_cte6 + on ((emailaddress0).businessentityid = (emailaddress1).businessentityid) + +) +select (salesperson0)."businessentityid",(salesperson0)."territoryid",(salesperson0)."salesquota",(salesperson0)."bonus",(salesperson0)."commissionpct",(salesperson0)."salesytd",(salesperson0)."saleslastyear",(salesperson0)."rowguid",(salesperson0)."modifieddate"::text,(employee0)."businessentityid",(employee0)."nationalidnumber",(employee0)."loginid",(employee0)."jobtitle",(employee0)."birthdate"::text,(employee0)."maritalstatus",(employee0)."gender",(employee0)."hiredate"::text,(employee0)."salariedflag",(employee0)."vacationhours",(employee0)."sickleavehours",(employee0)."currentflag",(employee0)."rowguid",(employee0)."modifieddate"::text,(employee0)."organizationnode",(person0)."businessentityid",(person0)."persontype",(person0)."namestyle",(person0)."title",(person0)."firstname",(person0)."middlename",(person0)."lastname",(person0)."suffix",(person0)."emailpromotion",(person0)."additionalcontactinfo",(person0)."demographics",(person0)."rowguid",(person0)."modifieddate"::text,(businessentity0)."businessentityid",(businessentity0)."rowguid",(businessentity0)."modifieddate"::text,(emailaddress0)."businessentityid",(emailaddress0)."emailaddressid",(emailaddress0)."emailaddress",(emailaddress0)."rowguid",(emailaddress0)."modifieddate"::text,(salesperson1)."businessentityid",(salesperson1)."territoryid",(salesperson1)."salesquota",(salesperson1)."bonus",(salesperson1)."commissionpct",(salesperson1)."salesytd",(salesperson1)."saleslastyear",(salesperson1)."rowguid",(salesperson1)."modifieddate"::text,(salesperson2)."businessentityid",(salesperson2)."territoryid",(salesperson2)."salesquota",(salesperson2)."bonus",(salesperson2)."commissionpct",(salesperson2)."salesytd",(salesperson2)."saleslastyear",(salesperson2)."rowguid",(salesperson2)."modifieddate"::text,(employee1)."businessentityid",(employee1)."nationalidnumber",(employee1)."loginid",(employee1)."jobtitle",(employee1)."birthdate"::text,(employee1)."maritalstatus",(employee1)."gender",(employee1)."hiredate"::text,(employee1)."salariedflag",(employee1)."vacationhours",(employee1)."sickleavehours",(employee1)."currentflag",(employee1)."rowguid",(employee1)."modifieddate"::text,(employee1)."organizationnode",(person1)."businessentityid",(person1)."persontype",(person1)."namestyle",(person1)."title",(person1)."firstname",(person1)."middlename",(person1)."lastname",(person1)."suffix",(person1)."emailpromotion",(person1)."additionalcontactinfo",(person1)."demographics",(person1)."rowguid",(person1)."modifieddate"::text,(businessentity1)."businessentityid",(businessentity1)."rowguid",(businessentity1)."modifieddate"::text,(emailaddress1)."businessentityid",(emailaddress1)."emailaddressid",(emailaddress1)."emailaddress",(emailaddress1)."rowguid",(emailaddress1)."modifieddate"::text,(salesperson3)."businessentityid",(salesperson3)."territoryid",(salesperson3)."salesquota",(salesperson3)."bonus",(salesperson3)."commissionpct",(salesperson3)."salesytd",(salesperson3)."saleslastyear",(salesperson3)."rowguid",(salesperson3)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/leftJoined.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/leftJoined.sql index ab5cc5e93..049467cbe 100644 --- a/snapshot-tests/zio-jdbc-sql/ProductTest/leftJoined.sql +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/leftJoined.sql @@ -1,8 +1,15 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate - from ( - select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 - ) product0 - left join ( - select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 - ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 ) +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +), +left_join_cte0 as ( + select product0, productmodel0 + from product0 + left join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/q.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/q.sql index 4b61e02a6..850bfc53b 100644 --- a/snapshot-tests/zio-jdbc-sql/ProductTest/q.sql +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/q.sql @@ -1,8 +1,15 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate - from ( - select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE NOT (product0.name LIKE ?::text) AND NOT ((product0.name || product0.color) LIKE ?::text) AND (product0.daystomanufacture > ?::int4) AND (product0.modifieddate < ?::timestamp) - ) product0 - join ( - select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 WHERE (productmodel0.modifieddate < ?::timestamp) - ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - WHERE NOT productmodel0.instructions IS NULL \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE NOT ((product0).name LIKE ?::text) AND NOT (((product0).name || (product0).color) LIKE ?::text) AND ((product0).daystomanufacture > ?::int4) AND ((product0).modifieddate < ?::timestamp)) +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 WHERE ((productmodel0).modifieddate < ?::timestamp)) +), +join_cte0 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + WHERE NOT (productmodel0).instructions IS NULL +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/q2.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/q2.sql index b44fd91e3..dd2375c14 100644 --- a/snapshot-tests/zio-jdbc-sql/ProductTest/q2.sql +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/q2.sql @@ -1,11 +1,25 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productmodel1.productmodelid, productmodel1.name, productmodel1.catalogdescription, productmodel1.instructions, productmodel1.rowguid, productmodel1.modifieddate - from ( - select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE product0.productid = ANY(?) AND (length(product0.name) > ?::int4) AND NOT ((product0.name || product0.color) LIKE ?::text) AND (coalesce(length(product0.color), ?::int4) > ?::int4) AND (product0.modifieddate < ?::timestamp) - ) product0 - join ( - select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 WHERE NOT (productmodel0.name LIKE ?::text) - ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - left join ( - select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel1 WHERE NOT (productmodel1.name LIKE ?::text) - ) productmodel1 on ((product0.productmodelid = productmodel1.productmodelid) AND ?::boolean) - ORDER BY product0.name ASC , productmodel0.rowguid DESC NULLS FIRST, productmodel1.rowguid ASC \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE (product0).productid = ANY(?) AND (length((product0).name) > ?::int4) AND NOT (((product0).name || (product0).color) LIKE ?::text) AND (coalesce(length((product0).color), ?::int4) > ?::int4) AND ((product0).modifieddate < ?::timestamp)) +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 WHERE NOT ((productmodel0).name LIKE ?::text)) +), +join_cte0 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + WHERE ((productmodel0).productmodelid > ?::int4) +), +productmodel1 as ( + (select productmodel1 from production.productmodel productmodel1 WHERE NOT ((productmodel1).name LIKE ?::text)) +), +left_join_cte0 as ( + select product0, productmodel0, productmodel1 + from join_cte0 + left join productmodel1 + on (((product0).productmodelid = (productmodel1).productmodelid) AND ?::boolean) + ORDER BY (product0).name ASC , (productmodel0).rowguid DESC NULLS FIRST, (productmodel1).rowguid ASC +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text,(productmodel1)."productmodelid",(productmodel1)."name",(productmodel1)."catalogdescription",(productmodel1)."instructions",(productmodel1)."rowguid",(productmodel1)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/query.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/query.sql index ec1887b57..5ce5f3eef 100644 --- a/snapshot-tests/zio-jdbc-sql/ProductTest/query.sql +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/query.sql @@ -1,11 +1,25 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, unitmeasure0.unitmeasurecode, unitmeasure0.name, unitmeasure0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate - from ( - select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (product0.class = ?::text) AND ((product0.daystomanufacture > ?::int4) OR (product0.daystomanufacture <= ?::int4)) AND (product0.productline = ?::text) - ) product0 - join ( - select "unitmeasurecode", "name", "modifieddate"::text from production.unitmeasure unitmeasure0 WHERE (unitmeasure0.name LIKE ?::text) - ) unitmeasure0 on (product0.sizeunitmeasurecode = unitmeasure0.unitmeasurecode) - left join ( - select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 - ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - WHERE (product0.productmodelid = productmodel0.productmodelid) ORDER BY product0.productmodelid ASC , productmodel0.name DESC NULLS FIRST \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE ((product0).class = ?::text) AND (((product0).daystomanufacture > ?::int4) OR ((product0).daystomanufacture <= ?::int4)) AND ((product0).productline = ?::text)) +), +unitmeasure0 as ( + (select unitmeasure0 from production.unitmeasure unitmeasure0 WHERE ((unitmeasure0).name LIKE ?::text)) +), +join_cte0 as ( + select product0, unitmeasure0 + from product0 + join unitmeasure0 + on ((product0).sizeunitmeasurecode = (unitmeasure0).unitmeasurecode) + +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +), +left_join_cte0 as ( + select product0, unitmeasure0, productmodel0 + from join_cte0 + left join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + WHERE ((product0).productmodelid = (productmodel0).productmodelid) ORDER BY (product0).productmodelid ASC , (productmodel0).name DESC NULLS FIRST +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(unitmeasure0)."unitmeasurecode",(unitmeasure0)."name",(unitmeasure0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text from left_join_cte0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/ProductTest/query0.sql b/snapshot-tests/zio-jdbc-sql/ProductTest/query0.sql index 448e5ab6a..29ea0f6ec 100644 --- a/snapshot-tests/zio-jdbc-sql/ProductTest/query0.sql +++ b/snapshot-tests/zio-jdbc-sql/ProductTest/query0.sql @@ -1,14 +1,35 @@ -select product0.productid, product0.name, product0.productnumber, product0.makeflag, product0.finishedgoodsflag, product0.color, product0.safetystocklevel, product0.reorderpoint, product0.standardcost, product0.listprice, product0.size, product0.sizeunitmeasurecode, product0.weightunitmeasurecode, product0.weight, product0.daystomanufacture, product0.productline, product0.class, product0.style, product0.productsubcategoryid, product0.productmodelid, product0.sellstartdate, product0.sellenddate, product0.discontinueddate, product0.rowguid, product0.modifieddate, productmodel0.productmodelid, productmodel0.name, productmodel0.catalogdescription, productmodel0.instructions, productmodel0.rowguid, productmodel0.modifieddate, productsubcategory0.productsubcategoryid, productsubcategory0.productcategoryid, productsubcategory0.name, productsubcategory0.rowguid, productsubcategory0.modifieddate, productcategory0.productcategoryid, productcategory0.name, productcategory0.rowguid, productcategory0.modifieddate - from ( - select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 - ) product0 - join ( - select "productmodelid", "name", "catalogdescription", "instructions", "rowguid", "modifieddate"::text from production.productmodel productmodel0 - ) productmodel0 on (product0.productmodelid = productmodel0.productmodelid) - join ( - select "productsubcategoryid", "productcategoryid", "name", "rowguid", "modifieddate"::text from production.productsubcategory productsubcategory0 - ) productsubcategory0 on (product0.productsubcategoryid = productsubcategory0.productsubcategoryid) - join ( - select "productcategoryid", "name", "rowguid", "modifieddate"::text from production.productcategory productcategory0 - ) productcategory0 on (productsubcategory0.productcategoryid = productcategory0.productcategoryid) - \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 ) +), +productmodel0 as ( + (select productmodel0 from production.productmodel productmodel0 ) +), +join_cte2 as ( + select product0, productmodel0 + from product0 + join productmodel0 + on ((product0).productmodelid = (productmodel0).productmodelid) + +), +productsubcategory0 as ( + (select productsubcategory0 from production.productsubcategory productsubcategory0 ) +), +join_cte1 as ( + select product0, productmodel0, productsubcategory0 + from join_cte2 + join productsubcategory0 + on ((product0).productsubcategoryid = (productsubcategory0).productsubcategoryid) + +), +productcategory0 as ( + (select productcategory0 from production.productcategory productcategory0 ) +), +join_cte0 as ( + select product0, productmodel0, productsubcategory0, productcategory0 + from join_cte1 + join productcategory0 + on ((productsubcategory0).productcategoryid = (productcategory0).productcategoryid) + +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text,(productmodel0)."productmodelid",(productmodel0)."name",(productmodel0)."catalogdescription",(productmodel0)."instructions",(productmodel0)."rowguid",(productmodel0)."modifieddate"::text,(productsubcategory0)."productsubcategoryid",(productsubcategory0)."productcategoryid",(productsubcategory0)."name",(productsubcategory0)."rowguid",(productsubcategory0)."modifieddate"::text,(productcategory0)."productcategoryid",(productcategory0)."name",(productcategory0)."rowguid",(productcategory0)."modifieddate"::text from join_cte0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/SeekTest/complex.sql b/snapshot-tests/zio-jdbc-sql/SeekTest/complex.sql index afe561b3c..63e1db8a9 100644 --- a/snapshot-tests/zio-jdbc-sql/SeekTest/complex.sql +++ b/snapshot-tests/zio-jdbc-sql/SeekTest/complex.sql @@ -1 +1,5 @@ -select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE (((product0.name > ?::"public"."Name") OR ((product0.name = ?::"public"."Name") AND (product0.weight < ?::numeric))) OR (((product0.name = ?::"public"."Name") AND (product0.weight = ?::numeric)) AND (product0.listprice < ?::numeric))) ORDER BY product0.name ASC , product0.weight DESC , product0.listprice DESC \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE ((((product0).name > ?::"public"."Name") OR (((product0).name = ?::"public"."Name") AND ((product0).weight < ?::numeric))) OR ((((product0).name = ?::"public"."Name") AND ((product0).weight = ?::numeric)) AND ((product0).listprice < ?::numeric))) ORDER BY (product0).name ASC , (product0).weight DESC , (product0).listprice DESC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-ascending.sql b/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-ascending.sql index 5dbb15cb6..265dd2e3b 100644 --- a/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-ascending.sql +++ b/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-ascending.sql @@ -1 +1,5 @@ -select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name,product0.weight,product0.listprice) > (?::"public"."Name",?::numeric,?::numeric)) ORDER BY product0.name ASC , product0.weight ASC , product0.listprice ASC \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE (((product0).name,(product0).weight,(product0).listprice) > (?::"public"."Name",?::numeric,?::numeric)) ORDER BY (product0).name ASC , (product0).weight ASC , (product0).listprice ASC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-descending.sql b/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-descending.sql index 2611cc0d3..627122413 100644 --- a/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-descending.sql +++ b/snapshot-tests/zio-jdbc-sql/SeekTest/uniform-descending.sql @@ -1 +1,5 @@ -select "productid", "name", "productnumber", "makeflag", "finishedgoodsflag", "color", "safetystocklevel", "reorderpoint", "standardcost", "listprice", "size", "sizeunitmeasurecode", "weightunitmeasurecode", "weight", "daystomanufacture", "productline", "class", "style", "productsubcategoryid", "productmodelid", "sellstartdate"::text, "sellenddate"::text, "discontinueddate"::text, "rowguid", "modifieddate"::text from production.product product0 WHERE ((product0.name,product0.weight,product0.listprice) < (?::"public"."Name",?::numeric,?::numeric)) ORDER BY product0.name DESC , product0.weight DESC , product0.listprice DESC \ No newline at end of file +with +product0 as ( + (select product0 from production.product product0 WHERE (((product0).name,(product0).weight,(product0).listprice) < (?::"public"."Name",?::numeric,?::numeric)) ORDER BY (product0).name DESC , (product0).weight DESC , (product0).listprice DESC ) +) +select (product0)."productid",(product0)."name",(product0)."productnumber",(product0)."makeflag",(product0)."finishedgoodsflag",(product0)."color",(product0)."safetystocklevel",(product0)."reorderpoint",(product0)."standardcost",(product0)."listprice",(product0)."size",(product0)."sizeunitmeasurecode",(product0)."weightunitmeasurecode",(product0)."weight",(product0)."daystomanufacture",(product0)."productline",(product0)."class",(product0)."style",(product0)."productsubcategoryid",(product0)."productmodelid",(product0)."sellstartdate"::text,(product0)."sellenddate"::text,(product0)."discontinueddate"::text,(product0)."rowguid",(product0)."modifieddate"::text from product0 \ No newline at end of file diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala index cf1330701..ab79d9d7b 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SelectBuilderSql.scala @@ -1,6 +1,6 @@ package typo.dsl -import anorm.{AnormException, RowParser, SQL, SimpleSql} +import anorm.{AnormException, RowParser, SQL, SimpleSql, SqlParser} import typo.dsl.Fragment.FragmentStringInterpolator import java.sql.Connection @@ -9,11 +9,33 @@ import java.util.concurrent.atomic.AtomicInteger sealed trait SelectBuilderSql[Fields, Row] extends SelectBuilder[Fields, Row] { def withPath(path: Path): SelectBuilderSql[Fields, Row] def instantiate(ctx: RenderCtx, counter: AtomicInteger): SelectBuilderSql.Instantiated[Fields, Row] - def sqlFor(ctx: RenderCtx, counter: AtomicInteger): (Fragment, RowParser[Row]) override lazy val renderCtx: RenderCtx = RenderCtx.from(this) - override lazy val sql: Option[Fragment] = Some(sqlFor(renderCtx, new AtomicInteger(0))._1) + lazy val sqlAndRowParser: (Fragment, RowParser[Row]) = { + val instance = this.instantiate(renderCtx, new AtomicInteger(0)) + + val cols: List[String] = + instance.columns.map { case (alias, col) => + col.sqlReadCast.foldLeft(s"($alias).\"${col.name}\"") { case (acc, cast) => s"$acc::$cast" } + } + + val ctes = instance.asCTEs + val formattedCTEs = ctes.map { cte => + frag"""|${Fragment(cte.name)} as ( + | ${cte.sql} + |)""".stripMargin + } + + val frag = + frag"""|with + |${formattedCTEs.mkFragment(",\n")} + |select ${Fragment(cols.mkString(","))} from ${Fragment(ctes.last.name)}""".stripMargin + + (frag, instance.rowParser(1)) + } + + override lazy val sql: Option[Fragment] = Some(sqlAndRowParser._1) final override def joinOn[Fields2, N[_]: Nullability, Row2](other: SelectBuilder[Fields2, Row2])(pred: Fields ~ Fields2 => SqlExpr[Boolean, N]): SelectBuilder[Fields ~ Fields2, Row ~ Row2] = other match { case otherSql: SelectBuilderSql[Fields2, Row2] => @@ -31,7 +53,7 @@ sealed trait SelectBuilderSql[Fields, Row] extends SelectBuilder[Fields, Row] { } final override def toList(implicit c: Connection): List[Row] = { - val (frag, rowParser) = sqlFor(renderCtx, new AtomicInteger(0)) + val (frag, rowParser) = sqlAndRowParser SimpleSql(SQL(frag.sql), frag.params.map(_.tupled).toMap, RowParser.successful).as(rowParser.*)(c) } } @@ -56,27 +78,19 @@ object SelectBuilderSql { override def withParams(sqlParams: SelectParams[Fields, Row]): SelectBuilder[Fields, Row] = copy(params = sqlParams) - private def sql(ctx: RenderCtx, counter: AtomicInteger): Fragment = { - val cols = structure.columns - .map(x => x.sqlReadCast.foldLeft(s"\"${x.name}\"") { case (acc, cast) => s"$acc::$cast" }) - .mkString(",") + override def instantiate(ctx: RenderCtx, counter: AtomicInteger): SelectBuilderSql.Instantiated[Fields, Row] = { val alias = ctx.alias(structure._path) - val baseSql = frag"select ${Fragment(cols)} from ${Fragment(name)} ${Fragment(alias)}" - SelectParams.render(structure.fields, baseSql, ctx, counter, params) - } - - override def sqlFor(ctx: RenderCtx, counter: AtomicInteger): (Fragment, RowParser[Row]) = - (sql(ctx, counter), rowParser(1)) + val sql = frag"(select ${Fragment(alias)} from ${Fragment(name)} ${Fragment(alias)} ${SelectParams.render(structure.fields, ctx, counter, params).getOrElse(Fragment.empty)})" - override def instantiate(ctx: RenderCtx, counter: AtomicInteger): SelectBuilderSql.Instantiated[Fields, Row] = { - val part = SelectBuilderSql.InstantiatedPart( - alias = ctx.alias(structure._path), - columns = structure.columns, - sqlFrag = sql(ctx, counter), - joinFrag = Fragment.empty, - joinType = JoinType.Inner + SelectBuilderSql.Instantiated( + alias = alias, + isJoin = false, + columns = structure.columns.map(c => (alias, c)), + sqlFrag = sql, + upstreamCTEs = Nil, + structure = structure, + rowParser = rowParser ) - SelectBuilderSql.Instantiated(structure, List(part), rowParser = rowParser) } } @@ -96,56 +110,31 @@ object SelectBuilderSql { copy(params = sqlParams) override def instantiate(ctx: RenderCtx, counter: AtomicInteger): Instantiated[Fields1 ~ Fields2, Row1 ~ Row2] = { - - val leftInstantiated: Instantiated[Fields1, Row1] = left.instantiate(ctx, counter) - val rightInstantiated: Instantiated[Fields2, Row2] = right.instantiate(ctx, counter) - - val newStructure = leftInstantiated.structure.join(rightInstantiated.structure) - val newRightInstantiatedParts = rightInstantiated.parts - .mapLast( - _.copy( - joinFrag = pred(newStructure.fields).render(ctx, counter), - joinType = JoinType.Inner - ) - ) - + val alias = ctx.alias(structure._path) + val leftInstance = left.instantiate(ctx, counter) + val rightInstance = right.instantiate(ctx, counter) + val newStructure = leftInstance.structure.join(rightInstance.structure) + val ctes = leftInstance.asCTEs ++ rightInstance.asCTEs + val sql = + frag"""|select ${ctes.filterNot(_.isJoin).map(cte => Fragment(cte.name)).mkFragment(", ")} + | from ${Fragment(leftInstance.alias)} + | join ${Fragment(rightInstance.alias)} + | on ${pred(newStructure.fields).render(ctx, counter)} + | ${SelectParams.render(newStructure.fields, ctx, counter, params).getOrElse(Fragment.empty)}""".stripMargin SelectBuilderSql.Instantiated( + alias = alias, + isJoin = true, + columns = leftInstance.columns ++ rightInstance.columns, + sqlFrag = sql, + upstreamCTEs = ctes, structure = newStructure, - parts = leftInstantiated.parts ++ newRightInstantiatedParts, rowParser = (i: Int) => for { - r1 <- leftInstantiated.rowParser(i) - r2 <- rightInstantiated.rowParser(i + leftInstantiated.columns.size) + r1 <- leftInstance.rowParser(i) + r2 <- rightInstance.rowParser(i + leftInstance.columns.size) } yield (r1, r2) ) } - - override def sqlFor(ctx: RenderCtx, counter: AtomicInteger): (Fragment, RowParser[Row1 ~ Row2]) = { - val instance = instantiate(ctx, counter) - val combinedFrag = instance.parts match { - case Nil => sys.error("unreachable (tm)") - case List(one) => one.sqlFrag - case first :: rest => - val prelude = - frag"""|select ${instance.columns.map(c => c.render(ctx, counter)).mkFragment(", ")} - |from ( - |${first.sqlFrag.indent(2)} - |) ${Fragment(first.alias)} - |""".stripMargin - - val joins = rest.map { case SelectBuilderSql.InstantiatedPart(alias, _, sqlFrag, joinFrag, joinType) => - frag"""|${joinType.frag} ( - |${sqlFrag.indent(2)} - |) ${Fragment(alias)} on $joinFrag - |""".stripMargin - } - - prelude ++ joins.mkFragment("") - } - val newCombinedFrag = SelectParams.render[Fields1 ~ Fields2, Row1 ~ Row2](instance.structure.fields, combinedFrag, ctx, counter, params) - - (newCombinedFrag, instance.rowParser(1)) - } } final case class TableLeftJoin[Fields1, Fields2, N[_]: Nullability, Row1, Row2]( @@ -164,27 +153,33 @@ object SelectBuilderSql { copy(params = sqlParams) override def instantiate(ctx: RenderCtx, counter: AtomicInteger): Instantiated[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = { - val leftInstantiated = left.instantiate(ctx, counter) - val rightInstantiated = right.instantiate(ctx, counter) - - val newStructure = leftInstantiated.structure.leftJoin(rightInstantiated.structure) - val newRightInstantiatedParts = rightInstantiated.parts - .mapLast( - _.copy( - joinFrag = pred(leftInstantiated.structure.join(rightInstantiated.structure).fields).render(ctx, counter), - joinType = JoinType.LeftJoin - ) - ) + val alias = ctx.alias(structure._path) + val leftInstance = left.instantiate(ctx, counter) + val rightInstance = right.instantiate(ctx, counter) + + val joinedStructure = leftInstance.structure.join(rightInstance.structure) + val newStructure = leftInstance.structure.leftJoin(rightInstance.structure) + val ctes = leftInstance.asCTEs ++ rightInstance.asCTEs + val sql = + frag"""|select ${ctes.filterNot(_.isJoin).map(cte => Fragment(cte.name)).mkFragment(", ")} + | from ${Fragment(leftInstance.alias)} + | left join ${Fragment(rightInstance.alias)} + | on ${pred(joinedStructure.fields).render(ctx, counter)} + | ${SelectParams.render(newStructure.fields, ctx, counter, params).getOrElse(Fragment.empty)}""".stripMargin SelectBuilderSql.Instantiated( - newStructure, - leftInstantiated.parts ++ newRightInstantiatedParts, + alias = alias, + isJoin = true, + columns = leftInstance.columns ++ rightInstance.columns, + sqlFrag = sql, + upstreamCTEs = ctes, + structure = newStructure, rowParser = (i: Int) => for { - r1 <- leftInstantiated.rowParser(i) + r1 <- leftInstance.rowParser(i) /** note, `RowParser` has a `?` combinator, but it doesn't work. fails with exception instead of [[anorm.Error]] */ r2 <- RowParser[Option[Row2]] { row => - try rightInstantiated.rowParser(i + leftInstantiated.columns.size)(row).map(Some.apply) + try rightInstance.rowParser(i + leftInstance.columns.size)(row).map(Some.apply) catch { case x: AnormException if x.message.contains("not found, available columns") => anorm.Success(None) } @@ -192,65 +187,21 @@ object SelectBuilderSql { } yield (r1, r2) ) } - - override def sqlFor(ctx: RenderCtx, counter: AtomicInteger): (Fragment, RowParser[Row1 ~ Option[Row2]]) = { - val instance = instantiate(ctx, counter) - val combinedFrag = instance.parts match { - case Nil => sys.error("unreachable (tm)") - case List(one) => one.sqlFrag - case first :: rest => - val prelude = - frag"""|select ${instance.columns.map(c => c.render(ctx, counter)).mkFragment(", ")} - |from ( - |${first.sqlFrag.indent(2)} - |) ${Fragment(first.alias)} - |""".stripMargin - - val joins = rest.map { case SelectBuilderSql.InstantiatedPart(alias, _, sqlFrag, joinFrag, joinType) => - frag"""|${joinType.frag} ( - |${sqlFrag.indent(2)} - |) ${Fragment(alias)} on $joinFrag - |""".stripMargin - } - prelude ++ joins.mkFragment("") - } - val newCombinedFrag = - SelectParams.render[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]](instance.structure.fields, combinedFrag, ctx, counter, params) - - (newCombinedFrag, instance.rowParser(1)) - } - } - - implicit class ListMapLastOps[T](private val ts: List[T]) extends AnyVal { - def mapLast(f: T => T): List[T] = if (ts.isEmpty) ts else ts.updated(ts.length - 1, f(ts.last)) } /** Need this intermediate data structure to generate aliases for tables (and prefixes for column selections) when we have a tree of joined tables. Need to start from the root after the user has * constructed the tree */ final case class Instantiated[Fields, Row]( + alias: String, + isJoin: Boolean, + columns: List[(String, SqlExpr.FieldLikeNoHkt[?, ?])], + sqlFrag: Fragment, + upstreamCTEs: List[CTE], structure: Structure[Fields, Row], - parts: List[SelectBuilderSql.InstantiatedPart], rowParser: Int => RowParser[Row] ) { - val columns: List[SqlExpr.FieldLikeNoHkt[?, ?]] = parts.flatMap(_.columns) - } - sealed abstract class JoinType(_frag: String) { - val frag = Fragment(_frag) + def asCTEs: List[CTE] = upstreamCTEs :+ CTE(alias, sqlFrag, isJoin) } - - object JoinType { - case object Inner extends JoinType("join") - case object LeftJoin extends JoinType("left join") - case object RightJoin extends JoinType("right join") - } - - /** This is needlessly awkward because the we start with a tree, but we need to make it linear to render it */ - final case class InstantiatedPart( - alias: String, - columns: List[SqlExpr.FieldLikeNoHkt[?, ?]], - sqlFrag: Fragment, - joinFrag: Fragment, - joinType: JoinType - ) + case class CTE(name: String, sql: Fragment, isJoin: Boolean) } diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SelectParams.scala b/typo-dsl-anorm/src/scala/typo/dsl/SelectParams.scala index f91909967..158a01227 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SelectParams.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SelectParams.scala @@ -21,28 +21,19 @@ object SelectParams { def empty[Fields, R]: SelectParams[Fields, R] = SelectParams[Fields, R](List.empty, List.empty, None, None) - def render[Fields, R](fields: Fields, baseSql: Fragment, ctx: RenderCtx, counter: AtomicInteger, params: SelectParams[Fields, R]): Fragment = { + def render[Fields, R](fields: Fields, ctx: RenderCtx, counter: AtomicInteger, params: SelectParams[Fields, R]): Option[Fragment] = { val (filters, orderBys) = OrderByOrSeek.expand(fields, params) - val maybeEnd: Option[Fragment] = - List[Option[Fragment]]( - filters.reduceLeftOption(_.and(_)).map { where => - Fragment(" where ") ++ where.render(ctx, counter) - }, - orderBys match { - case Nil => None - case nonEmpty => Some(frag" order by ${nonEmpty.map(x => x.render(ctx, counter)).mkFragment(", ")}") - }, - params.offset.map(value => Fragment(" offset " + value)), - params.limit.map { value => Fragment(" limit " + value) } - ).flatten.reduceOption(_ ++ _) - - val completeSql = maybeEnd match { - case Some(end) => frag"""|$baseSql - |$end - |""".stripMargin - case None => baseSql - } - completeSql + List[Option[Fragment]]( + filters.reduceLeftOption(_.and(_)).map { where => + Fragment("where ") ++ where.render(ctx, counter) + }, + orderBys match { + case Nil => None + case nonEmpty => Some(frag"order by ${nonEmpty.map(x => x.render(ctx, counter)).mkFragment(", ")}") + }, + params.offset.map(value => Fragment("offset " + value)), + params.limit.map { value => Fragment("limit " + value) } + ).flatten.reduceOption(_ ++ Fragment(" ") ++ _) } } diff --git a/typo-dsl-anorm/src/scala/typo/dsl/SqlExpr.scala b/typo-dsl-anorm/src/scala/typo/dsl/SqlExpr.scala index f37dd4406..b52e5975f 100644 --- a/typo-dsl-anorm/src/scala/typo/dsl/SqlExpr.scala +++ b/typo-dsl-anorm/src/scala/typo/dsl/SqlExpr.scala @@ -107,7 +107,7 @@ object SqlExpr { val sqlReadCast: Option[String] val sqlWriteCast: Option[String] - final def value(ctx: RenderCtx): String = ctx.alias.get(path).fold("")(_ + ".") + name + final def value(ctx: RenderCtx): String = ctx.alias.get(path).fold("")(alias => s"($alias).") + name final def render(ctx: RenderCtx, counter: AtomicInteger): Fragment = Fragment(value(ctx)) } diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala index 05e8943b9..ce9e18243 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SelectBuilderSql.scala @@ -1,23 +1,43 @@ package typo.dsl -import cats.data.NonEmptyList import cats.syntax.apply.* import cats.syntax.foldable.* import doobie.free.connection.ConnectionIO import doobie.implicits.toSqlInterpolator +import doobie.util.Read import doobie.util.fragment.Fragment -import doobie.util.query.Query0 -import doobie.util.{Read, fragments} +import typo.dsl.internal.mkFragment.* import scala.util.Try sealed trait SelectBuilderSql[Fields, Row] extends SelectBuilder[Fields, Row] { def withPath(path: Path): SelectBuilderSql[Fields, Row] def instantiate(ctx: RenderCtx): SelectBuilderSql.Instantiated[Fields, Row] - def sqlFor(ctx: RenderCtx): Query0[Row] override lazy val renderCtx: RenderCtx = RenderCtx.from(this) - override lazy val sql: Option[Fragment] = Some(sqlFor(renderCtx).toFragment) + + lazy val sqlAndRowParser: (Fragment, Read[Row]) = { + val instance = this.instantiate(renderCtx) + val cols = instance.columns.map { case (alias, col) => + col.sqlReadCast.foldLeft(s"($alias).\"${col.name}\"") { case (acc, cast) => s"$acc::$cast" } + } + + val ctes = instance.asCTEs + val formattedCTEs = ctes.map { cte => + fr"""|${Fragment.const0(cte.name)} as ( + | ${cte.sql} + |)""".stripMargin + } + + val frag = + fr"""|with + |${formattedCTEs.mkFragment(Fragment.const0(",\n"))} + |select ${Fragment.const0(cols.mkString(","))} from ${Fragment.const0(ctes.last.name)}""".stripMargin + + (frag, instance.read) + } + + override lazy val sql: Option[Fragment] = Some(sqlAndRowParser._1) final override def joinOn[Fields2, N[_]: Nullability, Row2](other: SelectBuilder[Fields2, Row2])(pred: Fields ~ Fields2 => SqlExpr[Boolean, N]): SelectBuilder[Fields ~ Fields2, Row ~ Row2] = other match { @@ -35,17 +55,19 @@ sealed trait SelectBuilderSql[Fields, Row] extends SelectBuilder[Fields, Row] { case _ => sys.error("you cannot mix mock and sql repos") } - final override def toList: ConnectionIO[List[Row]] = - sqlFor(renderCtx).to[List] + final override def toList: ConnectionIO[List[Row]] = { + val (frag, read) = sqlAndRowParser + frag.query(using read).to[List] + } } object SelectBuilderSql { def apply[Fields, Row]( name: String, structure: Structure.Relation[Fields, Row], - read: Read[Row] + rowParser: Read[Row] ): SelectBuilderSql[Fields, Row] = - Relation(name, structure, read, SelectParams.empty) + Relation(name, structure, rowParser, SelectParams.empty) final case class Relation[Fields, Row]( name: String, @@ -59,27 +81,19 @@ object SelectBuilderSql { override def withParams(sqlParams: SelectParams[Fields, Row]): SelectBuilder[Fields, Row] = copy(params = sqlParams) - private def sql(ctx: RenderCtx): Fragment = { - val cols = structure.columns - .map(x => Fragment.const0(x.sqlReadCast.foldLeft("\"" + x.name + "\"") { case (acc, cast) => s"$acc::$cast" })) - .intercalate(Fragment.const0(", ")) + override def instantiate(ctx: RenderCtx): SelectBuilderSql.Instantiated[Fields, Row] = { val alias = ctx.alias(structure._path) - val baseSql = fr"select $cols from ${Fragment.const0(name)} ${Fragment.const0(alias)}" - SelectParams.render(structure.fields, baseSql, ctx, params) - } - - override def sqlFor(ctx: RenderCtx): Query0[Row] = - sql(ctx).query(using read) + val sql = fr"(select ${Fragment.const0(alias)} from ${Fragment.const0(name)} ${Fragment.const0(alias)} ${SelectParams.render(structure.fields, ctx, params).getOrElse(Fragment.empty)})" - override def instantiate(ctx: RenderCtx): SelectBuilderSql.Instantiated[Fields, Row] = { - val part = SelectBuilderSql.InstantiatedPart( - alias = ctx.alias(structure._path), - columns = NonEmptyList.fromListUnsafe(structure.columns), - sqlFrag = sql(ctx), - joinFrag = Fragment.empty, - joinType = JoinType.Inner + SelectBuilderSql.Instantiated( + alias = alias, + isJoin = false, + columns = structure.columns.map(c => (alias, c)), + sqlFrag = sql, + upstreamCTEs = Nil, + structure = structure, + read = read ) - SelectBuilderSql.Instantiated(structure, NonEmptyList.of(part), read) } } @@ -99,45 +113,27 @@ object SelectBuilderSql { copy(params = sqlParams) override def instantiate(ctx: RenderCtx): Instantiated[Fields1 ~ Fields2, Row1 ~ Row2] = { - val leftInstantiated: Instantiated[Fields1, Row1] = left.instantiate(ctx) - val rightInstantiated: Instantiated[Fields2, Row2] = right.instantiate(ctx) - - val newStructure = leftInstantiated.structure.join(rightInstantiated.structure) - val newRightInstantiatedParts = rightInstantiated.parts - .mapLast(_.copy(joinFrag = pred(newStructure.fields).render(ctx), joinType = JoinType.Inner)) - + val alias = ctx.alias(structure._path) + val leftInstance = left.instantiate(ctx) + val rightInstance = right.instantiate(ctx) + val newStructure = leftInstance.structure.join(rightInstance.structure) + val ctes = leftInstance.asCTEs ++ rightInstance.asCTEs + val sql = + fr"""|select ${ctes.filterNot(_.isJoin).map(cte => Fragment.const0(cte.name)).mkFragment(Fragment.const0(", "))} + | from ${Fragment.const0(leftInstance.alias)} + | join ${Fragment.const0(rightInstance.alias)} + | on ${pred(newStructure.fields).render(ctx)} + | ${SelectParams.render(newStructure.fields, ctx, params).getOrElse(Fragment.empty)}""".stripMargin SelectBuilderSql.Instantiated( + alias = alias, + isJoin = true, + columns = leftInstance.columns ++ rightInstance.columns, + sqlFrag = sql, + upstreamCTEs = ctes, structure = newStructure, - parts = leftInstantiated.parts ++ newRightInstantiatedParts.toList, - read = (leftInstantiated.read, rightInstantiated.read).tupled + read = (leftInstance.read, rightInstance.read).tupled ) } - override def sqlFor(ctx: RenderCtx): Query0[Row1 ~ Row2] = { - val instance = instantiate(ctx) - val combinedFrag = instance.parts match { - case NonEmptyList(one, Nil) => one.sqlFrag - case NonEmptyList(first, rest) => - val prelude = - fr"""|select ${instance.columns.map(c => Fragment.const0(c.value(ctx))).intercalate(Fragment.const0(", "))} - |from ( - |${first.sqlFrag} - |) ${Fragment.const0(first.alias)} - |""".stripMargin - - val joins = rest.map { case SelectBuilderSql.InstantiatedPart(alias, _, sqlFrag, joinFrag, joinType) => - fr"""|${joinType.frag} ( - |$sqlFrag - |) ${Fragment.const0(alias)} on $joinFrag - |""".stripMargin - } - - prelude ++ joins.reduce(_ ++ _) - } - - val newCombinedFrag = SelectParams.render[Fields1 ~ Fields2, Row1 ~ Row2](instance.structure.fields, combinedFrag, ctx, params) - - newCombinedFrag.query(using instance.read) - } } final case class TableLeftJoin[Fields1, Fields2, N[_]: Nullability, Row1, Row2]( @@ -152,9 +148,7 @@ object SelectBuilderSql { override def withPath(path: Path): SelectBuilderSql[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = copy(left = left.withPath(path), right = right.withPath(path)) - override def withParams( - sqlParams: SelectParams[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] - ): SelectBuilder[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = + override def withParams(sqlParams: SelectParams[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]]): SelectBuilder[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = copy(params = sqlParams) def opt[A](read: Read[A]): Read[Option[A]] = { @@ -165,82 +159,45 @@ object SelectBuilderSql { } override def instantiate(ctx: RenderCtx): Instantiated[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = { - val leftInstantiated = left.instantiate(ctx) - val rightInstantiated = right.instantiate(ctx) - - val newStructure = leftInstantiated.structure.leftJoin(rightInstantiated.structure) - val newRightInstantiatedParts = rightInstantiated.parts - .mapLast( - _.copy( - joinFrag = pred(leftInstantiated.structure.join(rightInstantiated.structure).fields).render(ctx), - joinType = JoinType.LeftJoin - ) - ) + val alias = ctx.alias(structure._path) + val leftInstance = left.instantiate(ctx) + val rightInstance = right.instantiate(ctx) + + val joinedStructure = leftInstance.structure.join(rightInstance.structure) + val newStructure = leftInstance.structure.leftJoin(rightInstance.structure) + val ctes = leftInstance.asCTEs ++ rightInstance.asCTEs + val sql = + fr"""|select ${ctes.filterNot(_.isJoin).map(cte => Fragment.const0(cte.name)).mkFragment(Fragment.const0(", "))} + | from ${Fragment.const0(leftInstance.alias)} + | left join ${Fragment.const0(rightInstance.alias)} + | on ${pred(joinedStructure.fields).render(ctx)} + | ${SelectParams.render(newStructure.fields, ctx, params).getOrElse(Fragment.empty)}""".stripMargin SelectBuilderSql.Instantiated( - newStructure, - leftInstantiated.parts ++ newRightInstantiatedParts.toList, - read = (leftInstantiated.read, opt(rightInstantiated.read)).tupled + alias = alias, + isJoin = true, + columns = leftInstance.columns ++ rightInstance.columns, + sqlFrag = sql, + upstreamCTEs = ctes, + structure = newStructure, + read = (leftInstance.read, opt(rightInstance.read)).tupled ) } - - override def sqlFor(ctx: RenderCtx): Query0[Row1 ~ Option[Row2]] = { - val instance = instantiate(ctx) - val combinedFrag = instance.parts match { - case NonEmptyList(one, Nil) => one.sqlFrag - case NonEmptyList(first, rest) => - val prelude = - fr"""|select ${fragments.comma(instance.columns.map(c => Fragment.const0(c.value(ctx))))} - |from ( - | ${first.sqlFrag} - |) ${Fragment.const0(first.alias)} - |""".stripMargin - - val joins = rest.map { case SelectBuilderSql.InstantiatedPart(alias, _, sqlFrag, joinFrag, joinType) => - fr"""|${joinType.frag} ( - |${sqlFrag} - |) ${Fragment.const0(alias)} on $joinFrag - |""".stripMargin - } - prelude ++ joins.reduce(_ ++ _) - } - val newCombinedFrag = - SelectParams.render[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]](instance.structure.fields, combinedFrag, ctx, params) - - newCombinedFrag.query(using instance.read) - } - } - - implicit class ListMapLastOps[T](private val ts: NonEmptyList[T]) extends AnyVal { - def mapLast(f: T => T): NonEmptyList[T] = NonEmptyList.fromListUnsafe(ts.toList.updated(ts.length - 1, f(ts.last))) } /** Need this intermediate data structure to generate aliases for tables (and prefixes for column selections) when we have a tree of joined tables. Need to start from the root after the user has * constructed the tree */ final case class Instantiated[Fields, Row]( + alias: String, + isJoin: Boolean, + columns: List[(String, SqlExpr.FieldLikeNoHkt[?, ?])], + sqlFrag: Fragment, + upstreamCTEs: List[CTE], structure: Structure[Fields, Row], - parts: NonEmptyList[SelectBuilderSql.InstantiatedPart], read: Read[Row] ) { - val columns: NonEmptyList[SqlExpr.FieldLikeNoHkt[?, ?]] = parts.flatMap(_.columns) - } - - sealed abstract class JoinType(_frag: String) { - val frag = Fragment.const0(_frag) + def asCTEs: List[CTE] = upstreamCTEs :+ CTE(alias, sqlFrag, isJoin) } - object JoinType { - case object Inner extends JoinType("join") - case object LeftJoin extends JoinType("left join") - case object RightJoin extends JoinType("right join") - } - - /** This is needlessly awkward because the we start with a tree, but we need to make it linear to render it */ - final case class InstantiatedPart( - alias: String, - columns: NonEmptyList[SqlExpr.FieldLikeNoHkt[?, ?]], - sqlFrag: Fragment, - joinFrag: Fragment, - joinType: JoinType - ) + case class CTE(name: String, sql: Fragment, isJoin: Boolean) } diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SelectParams.scala b/typo-dsl-doobie/src/scala/typo/dsl/SelectParams.scala index dfe4d0a3e..4877d6f54 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SelectParams.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SelectParams.scala @@ -22,15 +22,14 @@ object SelectParams { def empty[Fields, R]: SelectParams[Fields, R] = SelectParams[Fields, R](List.empty, List.empty, None, None) - def render[Fields, R](fields: Fields, baseSql: Fragment, ctx: RenderCtx, params: SelectParams[Fields, R]): Fragment = { + def render[Fields, R](fields: Fields, ctx: RenderCtx, params: SelectParams[Fields, R]): Option[Fragment] = { val (filters, orderBys) = OrderByOrSeek.expand(fields, params) List[Option[Fragment]]( - Some(baseSql), NonEmptyList.fromFoldable(filters.map(f => f.render(ctx))).map(fragments.whereAnd(_)), NonEmptyList.fromFoldable(orderBys.map(f => f.render(ctx))).map(fragments.orderBy(_)), params.offset.map(value => fr"offset $value"), params.limit.map(value => fr"limit $value") - ).flatten.reduce(_ ++ _) + ).flatten.reduceOption(_ ++ _) } } diff --git a/typo-dsl-doobie/src/scala/typo/dsl/SqlExpr.scala b/typo-dsl-doobie/src/scala/typo/dsl/SqlExpr.scala index 2345bf5da..95d1bc8b8 100644 --- a/typo-dsl-doobie/src/scala/typo/dsl/SqlExpr.scala +++ b/typo-dsl-doobie/src/scala/typo/dsl/SqlExpr.scala @@ -108,7 +108,7 @@ object SqlExpr { val set: (R, NT) => R val sqlReadCast: Option[String] val sqlWriteCast: Option[String] - final def value(ctx: RenderCtx): String = ctx.alias.get(path).fold("")(_ + ".") + name + final def value(ctx: RenderCtx): String = ctx.alias.get(path).fold("")(alias => s"($alias).") + name final def render(ctx: RenderCtx): Fragment = Fragment.const0(value(ctx)) } diff --git a/typo-dsl-shared/typo/dsl/RenderCtx.scala b/typo-dsl-shared/typo/dsl/RenderCtx.scala index c410b5ffb..27c0ec83a 100644 --- a/typo-dsl-shared/typo/dsl/RenderCtx.scala +++ b/typo-dsl-shared/typo/dsl/RenderCtx.scala @@ -11,9 +11,9 @@ object RenderCtx { def from[F, R](s: SelectBuilderSql[F, R]): RenderCtx = { def findPathsAndTableNames(s: SelectBuilderSql[?, ?]): List[(List[Path], String)] = s match { - case SelectBuilderSql.Relation(name, structure, _, _) => List(structure._path -> name) - case SelectBuilderSql.TableJoin(left, right, _, _) => findPathsAndTableNames(left) ++ findPathsAndTableNames(right) - case SelectBuilderSql.TableLeftJoin(left, right, _, _) => findPathsAndTableNames(left) ++ findPathsAndTableNames(right) + case SelectBuilderSql.Relation(name, structure, _, _) => List(structure._path -> name) + case x @ SelectBuilderSql.TableJoin(left, right, _, _) => List(x.structure._path -> "join_cte") ++ findPathsAndTableNames(left) ++ findPathsAndTableNames(right) + case x @ SelectBuilderSql.TableLeftJoin(left, right, _, _) => List(x.structure._path -> "left_join_cte") ++ findPathsAndTableNames(left) ++ findPathsAndTableNames(right) } val nameForPathsMap: Map[List[Path], String] = diff --git a/typo-dsl-shared/typo/dsl/Structure.scala b/typo-dsl-shared/typo/dsl/Structure.scala index dc79937c9..b9201633c 100644 --- a/typo-dsl-shared/typo/dsl/Structure.scala +++ b/typo-dsl-shared/typo/dsl/Structure.scala @@ -7,7 +7,7 @@ package typo.dsl trait Structure[Fields, Row] { def fields: Fields def columns: List[SqlExpr.FieldLikeNoHkt[?, ?]] - + def _path: List[Path] def withPath(path: Path): Structure[Fields, Row] // It's up to you to ensure that the `Row` in `field` is the same type as `row` @@ -64,21 +64,23 @@ trait Structure[Fields, Row] { } final def join[Fields2, Row2](other: Structure[Fields2, Row2]): Structure[Fields ~ Fields2, Row ~ Row2] = - new Structure.Tupled(left = this, right = other) + new Structure.Tupled(Structure.sharedPrefix(this._path, other._path), left = this, right = other) final def leftJoin[Fields2, Row2](other: Structure[Fields2, Row2]): Structure[Fields ~ OuterJoined[Fields2], Row ~ Option[Row2]] = - new Structure.LeftTupled(left = this, right = other) + new Structure.LeftTupled(Structure.sharedPrefix(this._path, other._path), left = this, right = other) } object Structure { + def sharedPrefix[T](left: List[T], right: List[T]): List[T] = { + val prefix = left.zip(right).takeWhile { case (a, b) => a == b } + prefix.map(_._1) + } // some of the row types are discarded, exchanging some type-safety for a cleaner API implicit class FieldOps[T, N[_], R0](private val field: SqlExpr.FieldLike[T, N, R0]) extends AnyVal { def castRow[R1]: SqlExpr.FieldLike[T, N, R1] = field.asInstanceOf[SqlExpr.FieldLike[T, N, R1]] } trait Relation[Fields, Row] extends Structure[Fields, Row] { outer => - val _path: List[Path] - def copy(path: List[Path]): Relation[Fields, Row] override def withPath(newPath: Path): Relation[Fields, Row] = @@ -88,7 +90,7 @@ object Structure { field.castRow[Row].get(row) } - private class Tupled[Fields1, Fields2, Row1, Row2](val left: Structure[Fields1, Row1], val right: Structure[Fields2, Row2]) extends Structure[Fields1 ~ Fields2, Row1 ~ Row2] { + private class Tupled[Fields1, Fields2, Row1, Row2](val _path: List[Path], val left: Structure[Fields1, Row1], val right: Structure[Fields2, Row2]) extends Structure[Fields1 ~ Fields2, Row1 ~ Row2] { override val fields: Fields1 ~ Fields2 = (left.fields, right.fields) @@ -99,11 +101,11 @@ object Structure { if (left.columns.contains(field)) left.untypedGet(field.castRow, row._1) else right.untypedGet(field.castRow, row._2) - override def withPath(path: Path): Tupled[Fields1, Fields2, Row1, Row2] = - new Tupled(left.withPath(path), right.withPath(path)) + override def withPath(newPath: Path): Tupled[Fields1, Fields2, Row1, Row2] = + new Tupled(newPath :: _path, left.withPath(newPath), right.withPath(newPath)) } - private class LeftTupled[Fields1, Fields2, Row1, Row2](val left: Structure[Fields1, Row1], val right: Structure[Fields2, Row2]) + private class LeftTupled[Fields1, Fields2, Row1, Row2](val _path: List[Path], val left: Structure[Fields1, Row1], val right: Structure[Fields2, Row2]) extends Structure[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] { override val fields: Fields1 ~ OuterJoined[Fields2] = @@ -125,7 +127,7 @@ object Structure { flattened.asInstanceOf[N[T]] } - override def withPath(path: Path): LeftTupled[Fields1, Fields2, Row1, Row2] = - new LeftTupled(left.withPath(path), right.withPath(path)) + override def withPath(newPath: Path): LeftTupled[Fields1, Fields2, Row1, Row2] = + new LeftTupled(newPath :: _path, left.withPath(newPath), right.withPath(newPath)) } } 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 390e1cd43..a351f6fba 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderSql.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectBuilderSql.scala @@ -1,15 +1,36 @@ package typo.dsl import zio.jdbc.* -import zio.{Chunk, NonEmptyChunk, ZIO} +import zio.{Chunk, ZIO} sealed trait SelectBuilderSql[Fields, Row] extends SelectBuilder[Fields, Row] { def withPath(path: Path): SelectBuilderSql[Fields, Row] def instantiate(ctx: RenderCtx): SelectBuilderSql.Instantiated[Fields, Row] - def sqlFor(ctx: RenderCtx): Query[Row] override lazy val renderCtx: RenderCtx = RenderCtx.from(this) - override def sql: Option[SqlFragment] = Some(sqlFor(renderCtx).sql) + + lazy val sqlAndRowParser: (SqlFragment, JdbcDecoder[Row]) = { + val instance = this.instantiate(renderCtx) + val cols = instance.columns.map { case (alias, x) => + x.sqlReadCast.foldLeft(s"($alias).\"${x.name}\"") { case (acc, cast) => s"$acc::$cast" } + } + + val ctes = instance.asCTEs + val formattedCTEs = ctes.map { cte => + sql"""${SqlFragment(cte.name)} as ( + ${cte.sql} +)""" + } + + val frag = + sql"""with +${formattedCTEs.mkFragment(SqlFragment(",\n"))} +select ${SqlFragment(cols.mkString(","))} from ${SqlFragment(ctes.last.name)}""" + + (frag, instance.read) + } + + override lazy val sql: Option[SqlFragment] = Some(sqlAndRowParser._1) final override def joinOn[Fields2, N[_]: Nullability, Row2](other: SelectBuilder[Fields2, Row2])(pred: Fields ~ Fields2 => SqlExpr[Boolean, N]): SelectBuilder[Fields ~ Fields2, Row ~ Row2] = other match { @@ -27,17 +48,19 @@ sealed trait SelectBuilderSql[Fields, Row] extends SelectBuilder[Fields, Row] { case _ => sys.error("you cannot mix mock and sql repos") } - final override def toChunk: ZIO[ZConnection, Throwable, Chunk[Row]] = - sqlFor(renderCtx).selectAll + final override def toChunk: ZIO[ZConnection, Throwable, Chunk[Row]] = { + val (frag, read) = sqlAndRowParser + frag.query(using read).selectAll + } } object SelectBuilderSql { def apply[Fields, Row]( name: String, structure: Structure.Relation[Fields, Row], - read: JdbcDecoder[Row] + rowParser: JdbcDecoder[Row] ): SelectBuilderSql[Fields, Row] = - Relation(name, structure, read, SelectParams.empty) + Relation(name, structure, rowParser, SelectParams.empty) final case class Relation[Fields, Row]( name: String, @@ -51,27 +74,19 @@ object SelectBuilderSql { override def withParams(sqlParams: SelectParams[Fields, Row]): SelectBuilder[Fields, Row] = copy(params = sqlParams) - private def sql(ctx: RenderCtx): SqlFragment = { - val cols = structure.columns - .map(x => SqlFragment(x.sqlReadCast.foldLeft("\"" + x.name + "\"") { case (acc, cast) => s"$acc::$cast" })) - .mkFragment(", ") + override def instantiate(ctx: RenderCtx): SelectBuilderSql.Instantiated[Fields, Row] = { val alias = ctx.alias(structure._path) - val baseSql = sql"select $cols from ${SqlFragment(name)} ${SqlFragment(alias)}" - SelectParams.render(structure.fields, baseSql, ctx, params) - } + val sql = sql"(select ${SqlFragment(alias)} from ${SqlFragment(name)} ${SqlFragment(alias)} ${SelectParams.render(structure.fields, ctx, params).getOrElse[SqlFragment](SqlFragment.empty)})" - override def sqlFor(ctx: RenderCtx): Query[Row] = - sql(ctx).query[Row](using read) - - override def instantiate(ctx: RenderCtx): SelectBuilderSql.Instantiated[Fields, Row] = { - val part = SelectBuilderSql.InstantiatedPart( - alias = ctx.alias(structure._path), - columns = NonEmptyChunk.fromIterableOption(structure.columns).get, - sqlFrag = sql(ctx), - joinFrag = SqlFragment.empty, - joinType = JoinType.Inner + SelectBuilderSql.Instantiated( + alias = alias, + isJoin = false, + columns = structure.columns.map(c => (alias, c)), + sqlFrag = sql, + upstreamCTEs = Nil, + structure = structure, + read = read ) - SelectBuilderSql.Instantiated(structure, NonEmptyChunk.single(part), read) } } @@ -91,54 +106,29 @@ object SelectBuilderSql { copy(params = sqlParams) override def instantiate(ctx: RenderCtx): Instantiated[Fields1 ~ Fields2, Row1 ~ Row2] = { - val leftInstantiated: Instantiated[Fields1, Row1] = left.instantiate(ctx) - val rightInstantiated: Instantiated[Fields2, Row2] = right.instantiate(ctx) - - val newStructure = leftInstantiated.structure.join(rightInstantiated.structure) - val newRightInstantiatedParts = rightInstantiated.parts - .mapLast( - _.copy( - joinFrag = pred(newStructure.fields).render(ctx), - joinType = JoinType.Inner - ) - ) + val alias = ctx.alias(structure._path) + val leftInstance = left.instantiate(ctx) + val rightInstance = right.instantiate(ctx) + val newStructure = leftInstance.structure.join(rightInstance.structure) + val ctes = leftInstance.asCTEs ++ rightInstance.asCTEs + val renderedCtes = ctes.filterNot(_.isJoin).map(cte => SqlFragment(cte.name)).mkFragment(SqlFragment(", ")) + val sql = + sql"""select $renderedCtes + from ${SqlFragment(leftInstance.alias)} + join ${SqlFragment(rightInstance.alias)} + on ${pred(newStructure.fields).render(ctx)} + ${SelectParams.render(newStructure.fields, ctx, params).getOrElse[SqlFragment](SqlFragment.empty)}""" SelectBuilderSql.Instantiated( + alias = alias, + isJoin = true, + columns = leftInstance.columns ++ rightInstance.columns, + sqlFrag = sql, + upstreamCTEs = ctes, structure = newStructure, - parts = leftInstantiated.parts ++ newRightInstantiatedParts, - decoder = JdbcDecoder.tuple2Decoder(leftInstantiated.decoder, rightInstantiated.decoder) + read = JdbcDecoder.tuple2Decoder(leftInstance.read, rightInstance.read) ) } - override def sqlFor(ctx: RenderCtx): Query[Row1 ~ Row2] = { - val instance = instantiate(ctx) - val combinedFrag = { - val size = instance.parts.size - if (size == 1) instance.parts.head.sqlFrag - else { - val first = instance.parts.head - val rest = instance.parts.tail - - val prelude = - sql"""select ${instance.columns.map(c => c.render(ctx)).mkFragment(", ")} - from ( - ${first.sqlFrag} - ) ${SqlFragment(first.alias)} - """ - - val joins = rest.map { case SelectBuilderSql.InstantiatedPart(alias, _, sqlFrag, joinFrag, joinType) => - sql"""${joinType.frag} ( - $sqlFrag - ) ${SqlFragment(alias)} on $joinFrag - """ - } - - prelude ++ joins.reduce(_ ++ _) - } - } - val newCombinedFrag = SelectParams.render[Fields1 ~ Fields2, Row1 ~ Row2](instance.structure.fields, combinedFrag, ctx, params) - - newCombinedFrag.query(using instance.decoder) - } } final case class TableLeftJoin[Fields1, Fields2, N[_]: Nullability, Row1, Row2]( @@ -153,92 +143,49 @@ object SelectBuilderSql { override def withPath(path: Path): SelectBuilderSql[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = copy(left = left.withPath(path), right = right.withPath(path)) - override def withParams( - sqlParams: SelectParams[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] - ): SelectBuilder[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = + override def withParams(sqlParams: SelectParams[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]]): SelectBuilder[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = copy(params = sqlParams) override def instantiate(ctx: RenderCtx): Instantiated[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]] = { - val leftInstantiated = left.instantiate(ctx) - val rightInstantiated = right.instantiate(ctx) - - val newStructure = leftInstantiated.structure.leftJoin(rightInstantiated.structure) - val newRightInstantiatedParts = rightInstantiated.parts - .mapLast( - _.copy( - joinFrag = pred(leftInstantiated.structure.join(rightInstantiated.structure).fields).render(ctx), - joinType = JoinType.LeftJoin - ) - ) + val alias = ctx.alias(structure._path) + val leftInstance = left.instantiate(ctx) + val rightInstance = right.instantiate(ctx) + + val joinedStructure = leftInstance.structure.join(rightInstance.structure) + val newStructure = leftInstance.structure.leftJoin(rightInstance.structure) + val ctes = leftInstance.asCTEs ++ rightInstance.asCTEs + val sql = + sql"""select ${ctes.filterNot(_.isJoin).map(cte => SqlFragment(cte.name)).mkFragment(SqlFragment(", "))} + from ${SqlFragment(leftInstance.alias)} + left join ${SqlFragment(rightInstance.alias)} + on ${pred(joinedStructure.fields).render(ctx)} + ${SelectParams.render(newStructure.fields, ctx, params).getOrElse[SqlFragment](SqlFragment.empty)}""" SelectBuilderSql.Instantiated( + alias = alias, + isJoin = true, + columns = leftInstance.columns ++ rightInstance.columns, + sqlFrag = sql, + upstreamCTEs = ctes, structure = newStructure, - parts = leftInstantiated.parts ++ newRightInstantiatedParts, - decoder = JdbcDecoder.tuple2Decoder(leftInstantiated.decoder, JdbcDecoder.optionDecoder(rightInstantiated.decoder)) + read = JdbcDecoder.tuple2Decoder(leftInstance.read, JdbcDecoder.optionDecoder(rightInstance.read)) ) } - - override def sqlFor(ctx: RenderCtx): Query[Row1 ~ Option[Row2]] = { - val instance = instantiate(ctx) - val combinedFrag = { - val size = instance.parts.size - if (size == 1) instance.parts.head.sqlFrag - else { - val first = instance.parts.head - val rest = instance.parts.tail - - val prelude = - sql"""select ${instance.columns.map(c => c.render(ctx)).mkFragment(", ")} - from ( - ${first.sqlFrag} - ) ${SqlFragment(first.alias)} - """ - - val joins = rest.map { case SelectBuilderSql.InstantiatedPart(alias, _, sqlFrag, joinFrag, joinType) => - sql"""${joinType.frag} ( - ${sqlFrag} - ) ${SqlFragment(alias)} on $joinFrag - """ - } - prelude ++ joins.reduce(_ ++ _) - } - } - val newCombinedFrag = - SelectParams.render[Fields1 ~ OuterJoined[Fields2], Row1 ~ Option[Row2]](instance.structure.fields, combinedFrag, ctx, params) - - newCombinedFrag.query(using instance.decoder) - } - } - - implicit class ListMapLastOps[T](private val ts: NonEmptyChunk[T]) extends AnyVal { - def mapLast(f: T => T): NonEmptyChunk[T] = NonEmptyChunk.fromChunk(ts.updated(ts.length - 1, f(ts.last))).get // unsafe } /** Need this intermediate data structure to generate aliases for tables (and prefixes for column selections) when we have a tree of joined tables. Need to start from the root after the user has * constructed the tree */ final case class Instantiated[Fields, Row]( + alias: String, + isJoin: Boolean, + columns: List[(String, SqlExpr.FieldLikeNoHkt[?, ?])], + sqlFrag: SqlFragment, + upstreamCTEs: List[CTE], structure: Structure[Fields, Row], - parts: NonEmptyChunk[SelectBuilderSql.InstantiatedPart], - decoder: JdbcDecoder[Row] + read: JdbcDecoder[Row] ) { - val columns: NonEmptyChunk[SqlExpr.FieldLikeNoHkt[?, ?]] = parts.flatMap(_.columns) - } - sealed abstract class JoinType(_frag: String) { - val frag = SqlFragment(_frag) - } - object JoinType { - case object Inner extends JoinType("join") - case object LeftJoin extends JoinType("left join") - case object RightJoin extends JoinType("right join") + def asCTEs: List[CTE] = upstreamCTEs :+ CTE(alias, sqlFrag, isJoin) } - - /** This is needlessly awkward because the we start with a tree, but we need to make it linear to render it */ - final case class InstantiatedPart( - alias: String, - columns: NonEmptyChunk[SqlExpr.FieldLikeNoHkt[?, ?]], - sqlFrag: SqlFragment, - joinFrag: SqlFragment, - joinType: JoinType - ) + case class CTE(name: String, sql: SqlFragment, isJoin: Boolean) } diff --git a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectParams.scala b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectParams.scala index 1007e8675..00143903d 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectParams.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SelectParams.scala @@ -20,14 +20,13 @@ object SelectParams { def empty[Fields, R]: SelectParams[Fields, R] = SelectParams[Fields, R](List.empty, List.empty, None, None) - def render[Fields, R](fields: Fields, baseSql: SqlFragment, ctx: RenderCtx, params: SelectParams[Fields, R]): SqlFragment = { + def render[Fields, R](fields: Fields, ctx: RenderCtx, params: SelectParams[Fields, R]): Option[SqlFragment] = { val (filters, orderBys) = OrderByOrSeek.expand(fields, params) List[Option[SqlFragment]]( - Some(baseSql), NonEmptyChunk.fromIterableOption(filters.map(f => f.render(ctx))).map(fs => fs.mkFragment(" WHERE ", " AND ", "")), NonEmptyChunk.fromIterableOption(orderBys.map(f => f.render(ctx))).map(fs => fs.mkFragment(" ORDER BY ", ", ", "")), params.offset.map(value => sql" offset $value"), params.limit.map(value => sql" limit $value") - ).flatten.reduce(_ ++ _) + ).flatten.reduceOption(_ ++ _) } } diff --git a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SqlExpr.scala b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SqlExpr.scala index 4893faf4c..94bc5b291 100644 --- a/typo-dsl-zio-jdbc/src/scala/typo/dsl/SqlExpr.scala +++ b/typo-dsl-zio-jdbc/src/scala/typo/dsl/SqlExpr.scala @@ -104,7 +104,7 @@ object SqlExpr { val set: (R, NT) => R val sqlReadCast: Option[String] val sqlWriteCast: Option[String] - final def value(ctx: RenderCtx): String = ctx.alias.get(path).fold("")(_ + ".") + name + final def value(ctx: RenderCtx): String = ctx.alias.get(path).fold("")(alias => s"($alias).") + name final def render(ctx: RenderCtx): SqlFragment = SqlFragment(value(ctx)) } diff --git a/typo-tester-anorm/src/scala/adventureworks/DSLTest.scala b/typo-tester-anorm/src/scala/adventureworks/DSLTest.scala new file mode 100644 index 000000000..4e0f8e5fb --- /dev/null +++ b/typo-tester-anorm/src/scala/adventureworks/DSLTest.scala @@ -0,0 +1,49 @@ +package adventureworks + +import adventureworks.customtypes.* +import adventureworks.humanresources.employee.EmployeeRepoImpl +import adventureworks.person.businessentity.BusinessentityRepoImpl +import adventureworks.person.emailaddress.EmailaddressRepoImpl +import adventureworks.person.person.PersonRepoImpl +import adventureworks.sales.salesperson.SalespersonRepoImpl +import adventureworks.userdefined.FirstName + +import scala.annotation.nowarn +import scala.util.Random + +class DSLTest extends SnapshotTest { + val businessentityRepoImpl = new BusinessentityRepoImpl + val personRepoImpl = new PersonRepoImpl + val employeeRepoImpl = new EmployeeRepoImpl() + val salespersonRepoImpl = new SalespersonRepoImpl + val emailaddressRepoImpl = new EmailaddressRepoImpl + + test("works") { + withConnection { implicit c => + val testInsert = new TestInsert(new Random(0), DomainInsert) + val businessentityRow = testInsert.personBusinessentity() + val personRow = testInsert.personPerson(businessentityRow.businessentityid, persontype = "EM", FirstName("a")) + testInsert.personEmailaddress(personRow.businessentityid, Some("a@b.c")): @nowarn + val employeeRow = + testInsert.humanresourcesEmployee(personRow.businessentityid, gender = "M", maritalstatus = "M", birthdate = TypoLocalDate("1998-01-01"), hiredate = TypoLocalDate("1997-01-01")) + val salespersonRow = testInsert.salesSalesperson(employeeRow.businessentityid) + + def q = salespersonRepoImpl.select + .where(_.rowguid === salespersonRow.rowguid) + .joinFk(_.fkHumanresourcesEmployee)(employeeRepoImpl.select) + .joinFk { case (_, e) => e.fkPersonPerson }(personRepoImpl.select) + .joinFk { case ((_, _), p) => p.fkBusinessentity }(businessentityRepoImpl.select) + .join(emailaddressRepoImpl.select.orderBy(_.rowguid.asc)) + .on { case ((_, b), email) => email.businessentityid === b.businessentityid } + .joinOn(salespersonRepoImpl.select) { case ((_, e), s2) => + e.businessentityid.underlying === s2.businessentityid.underlying + } + + val doubled = q.join(q).on { case (((_, e1), _), ((_, e2), _)) => e1.businessentityid === e2.businessentityid } + + doubled.toList.foreach(println) + + compareFragment("doubled")(doubled.sql) + } + } +} diff --git a/typo-tester-anorm/src/scala/adventureworks/PaginationTest.scala b/typo-tester-anorm/src/scala/adventureworks/PaginationTest.scala index 79d178ea6..314a98239 100644 --- a/typo-tester-anorm/src/scala/adventureworks/PaginationTest.scala +++ b/typo-tester-anorm/src/scala/adventureworks/PaginationTest.scala @@ -40,7 +40,7 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { def patch(c: ClientCursor[JsValue]): ClientCursor[JsValue] = businessentityRepo match { case _: BusinessentityRepoMock => - c.copy(parts = c.parts.map { case (k, v) => (SortOrderRepr(k.expr.replace("businessentity0.", "")), v) }) + c.copy(parts = c.parts.map { case (k, v) => (SortOrderRepr(k.expr.replace("(businessentity0).", "")), v) }) case _ => c } @@ -74,8 +74,8 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { patch( ClientCursor( Map( - SortOrderRepr("businessentity0.modifieddate") -> JsString("2020-12-29T00:00:00"), - SortOrderRepr("(businessentity0.businessentityid - {param1}::INTEGER):2") -> JsNumber(BigDecimal(1)) + SortOrderRepr("(businessentity0).modifieddate") -> JsString("2020-12-29T00:00:00"), + SortOrderRepr("((businessentity0).businessentityid - {param1}::INTEGER):2") -> JsNumber(BigDecimal(1)) ) ) ) @@ -90,8 +90,8 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { patch( ClientCursor( Map( - SortOrderRepr("businessentity0.modifieddate") -> JsString("2020-12-25T00:00:00"), - SortOrderRepr("(businessentity0.businessentityid - {param1}::INTEGER):2") -> JsNumber(BigDecimal(15)) + SortOrderRepr("(businessentity0).modifieddate") -> JsString("2020-12-25T00:00:00"), + SortOrderRepr("((businessentity0).businessentityid - {param1}::INTEGER):2") -> JsNumber(BigDecimal(15)) ) ) ) diff --git a/typo-tester-anorm/src/scala/adventureworks/production/product/ProductTest.scala b/typo-tester-anorm/src/scala/adventureworks/production/product/ProductTest.scala index 2913bc44d..251414997 100644 --- a/typo-tester-anorm/src/scala/adventureworks/production/product/ProductTest.scala +++ b/typo-tester-anorm/src/scala/adventureworks/production/product/ProductTest.scala @@ -129,7 +129,6 @@ class ProductTest extends SnapshotTest { .joinFk(_._2.fkProductcategory)(productcategoryRepo.select) compareFragment("query0")(query0.sql) query0.toList.foreach(println) - println("foo") val query = productRepo.select diff --git a/typo-tester-doobie/src/scala/adventureworks/DSLTest.scala b/typo-tester-doobie/src/scala/adventureworks/DSLTest.scala new file mode 100644 index 000000000..9d8ae1fa6 --- /dev/null +++ b/typo-tester-doobie/src/scala/adventureworks/DSLTest.scala @@ -0,0 +1,47 @@ +package adventureworks + +import adventureworks.customtypes.* +import adventureworks.humanresources.employee.EmployeeRepoImpl +import adventureworks.person.businessentity.BusinessentityRepoImpl +import adventureworks.person.emailaddress.EmailaddressRepoImpl +import adventureworks.person.person.PersonRepoImpl +import adventureworks.sales.salesperson.SalespersonRepoImpl +import adventureworks.userdefined.FirstName +import doobie.free.connection.delay + +import scala.util.Random + +class DSLTest extends SnapshotTest { + val businessentityRepoImpl = new BusinessentityRepoImpl + val personRepoImpl = new PersonRepoImpl + val employeeRepoImpl = new EmployeeRepoImpl() + val salespersonRepoImpl = new SalespersonRepoImpl + val emailaddressRepoImpl = new EmailaddressRepoImpl + + test("works") { + withConnection { + val testInsert = new TestInsert(new Random(0), DomainInsert) + for { + businessentityRow <- testInsert.personBusinessentity() + personRow <- testInsert.personPerson(businessentityRow.businessentityid, persontype = "EM", FirstName("a")) + _ <- testInsert.personEmailaddress(personRow.businessentityid, Some("a@b.c")) + employeeRow <- testInsert.humanresourcesEmployee(personRow.businessentityid, gender = "M", maritalstatus = "M", birthdate = TypoLocalDate("1998-01-01"), hiredate = TypoLocalDate("1997-01-01")) + salespersonRow <- testInsert.salesSalesperson(employeeRow.businessentityid) + q = salespersonRepoImpl.select + .where(_.rowguid === salespersonRow.rowguid) + .joinFk(_.fkHumanresourcesEmployee)(employeeRepoImpl.select) + .joinFk { case (_, e) => e.fkPersonPerson }(personRepoImpl.select) + .joinFk { case ((_, _), p) => p.fkBusinessentity }(businessentityRepoImpl.select) + .join(emailaddressRepoImpl.select.orderBy(_.rowguid.asc)) + .on { case ((_, b), email) => email.businessentityid === b.businessentityid } + .joinOn(salespersonRepoImpl.select) { case ((_, e), s2) => + e.businessentityid.underlying === s2.businessentityid.underlying + } + doubled = q.join(q).on { case (((_, e1), _), ((_, e2), _)) => e1.businessentityid === e2.businessentityid } + doubledRes <- doubled.toList + _ <- delay(doubledRes.foreach(println)) + _ <- delay(compareFragment("doubled")(doubled.sql)) + } yield () + } + } +} diff --git a/typo-tester-doobie/src/scala/adventureworks/PaginationTest.scala b/typo-tester-doobie/src/scala/adventureworks/PaginationTest.scala index 61ce692ab..13165e759 100644 --- a/typo-tester-doobie/src/scala/adventureworks/PaginationTest.scala +++ b/typo-tester-doobie/src/scala/adventureworks/PaginationTest.scala @@ -40,7 +40,7 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { def patch(c: ClientCursor[Json]): ClientCursor[Json] = businessentityRepo match { case _: BusinessentityRepoMock => - c.copy(parts = c.parts.map { case (k, v) => (SortOrderRepr(k.expr.replace("businessentity0.", "")), v) }) + c.copy(parts = c.parts.map { case (k, v) => (SortOrderRepr(k.expr.replace("(businessentity0).", "")), v) }) case _ => c } @@ -77,8 +77,8 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { patch( ClientCursor( Map( - SortOrderRepr("businessentity0.modifieddate") -> Json.fromString("2020-12-29T00:00:00"), - SortOrderRepr("(businessentity0.businessentityid - ? ) :2") -> Json.fromInt(1) + SortOrderRepr("(businessentity0).modifieddate") -> Json.fromString("2020-12-29T00:00:00"), + SortOrderRepr("((businessentity0).businessentityid - ? ) :2") -> Json.fromInt(1) ) ) ) @@ -96,8 +96,8 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { patch( ClientCursor( Map( - SortOrderRepr("businessentity0.modifieddate") -> Json.fromString("2020-12-25T00:00:00"), - SortOrderRepr("(businessentity0.businessentityid - ? ) :2") -> Json.fromInt(15) + SortOrderRepr("(businessentity0).modifieddate") -> Json.fromString("2020-12-25T00:00:00"), + SortOrderRepr("((businessentity0).businessentityid - ? ) :2") -> Json.fromInt(15) ) ) ) diff --git a/typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala b/typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala new file mode 100644 index 000000000..901b6e8ab --- /dev/null +++ b/typo-tester-zio-jdbc/src/scala/adventureworks/DSLTest.scala @@ -0,0 +1,47 @@ +package adventureworks + +import adventureworks.customtypes.* +import adventureworks.humanresources.employee.EmployeeRepoImpl +import adventureworks.person.businessentity.BusinessentityRepoImpl +import adventureworks.person.emailaddress.EmailaddressRepoImpl +import adventureworks.person.person.PersonRepoImpl +import adventureworks.sales.salesperson.SalespersonRepoImpl +import adventureworks.userdefined.FirstName +import zio.ZIO + +import scala.util.Random + +class DSLTest extends SnapshotTest { + val businessentityRepoImpl = new BusinessentityRepoImpl + val personRepoImpl = new PersonRepoImpl + val employeeRepoImpl = new EmployeeRepoImpl() + val salespersonRepoImpl = new SalespersonRepoImpl + val emailaddressRepoImpl = new EmailaddressRepoImpl + + test("works") { + withConnection { + val testInsert = new TestInsert(new Random(0), DomainInsert) + for { + businessentityRow <- testInsert.personBusinessentity() + personRow <- testInsert.personPerson(businessentityRow.businessentityid, persontype = "EM", FirstName("a")) + _ <- testInsert.personEmailaddress(personRow.businessentityid, Some("a@b.c")) + employeeRow <- testInsert.humanresourcesEmployee(personRow.businessentityid, gender = "M", maritalstatus = "M", birthdate = TypoLocalDate("1998-01-01"), hiredate = TypoLocalDate("1997-01-01")) + salespersonRow <- testInsert.salesSalesperson(employeeRow.businessentityid) + q = salespersonRepoImpl.select + .where(_.rowguid === salespersonRow.rowguid) + .joinFk(_.fkHumanresourcesEmployee)(employeeRepoImpl.select) + .joinFk { case (_, e) => e.fkPersonPerson }(personRepoImpl.select) + .joinFk { case ((_, _), p) => p.fkBusinessentity }(businessentityRepoImpl.select) + .join(emailaddressRepoImpl.select.orderBy(_.rowguid.asc)) + .on { case ((_, b), email) => email.businessentityid === b.businessentityid } + .joinOn(salespersonRepoImpl.select) { case ((_, e), s2) => + e.businessentityid.underlying === s2.businessentityid.underlying + } + doubled = q.join(q).on { case (((_, e1), _), ((_, e2), _)) => e1.businessentityid === e2.businessentityid } + doubledRes <- doubled.toChunk + _ <- ZIO.succeed(doubledRes.foreach(println)) + _ <- ZIO.succeed(compareFragment("doubled")(doubled.sql)) + } yield () + } + } +} diff --git a/typo-tester-zio-jdbc/src/scala/adventureworks/PaginationTest.scala b/typo-tester-zio-jdbc/src/scala/adventureworks/PaginationTest.scala index 2d8cff605..bf8e12c7d 100644 --- a/typo-tester-zio-jdbc/src/scala/adventureworks/PaginationTest.scala +++ b/typo-tester-zio-jdbc/src/scala/adventureworks/PaginationTest.scala @@ -28,7 +28,7 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { def patch(c: ClientCursor[Json]): ClientCursor[Json] = businessentityRepo match { case _: BusinessentityRepoMock => - c.copy(parts = c.parts.map { case (k, v) => (SortOrderRepr(k.expr.replace("businessentity0.", "")), v) }) + c.copy(parts = c.parts.map { case (k, v) => (SortOrderRepr(k.expr.replace("(businessentity0).", "")), v) }) case _ => c } @@ -65,8 +65,8 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { patch( ClientCursor( Map( - SortOrderRepr("businessentity0.modifieddate") -> new Json.Str("2020-12-29T00:00:00"), - SortOrderRepr("(businessentity0.businessentityid - 2::int4)") -> new Json.Num(java.math.BigDecimal.valueOf(1)) + SortOrderRepr("(businessentity0).modifieddate") -> new Json.Str("2020-12-29T00:00:00"), + SortOrderRepr("((businessentity0).businessentityid - 2::int4)") -> new Json.Num(java.math.BigDecimal.valueOf(1)) ) ) ) @@ -83,8 +83,8 @@ class PaginationTest extends AnyFunSuite with TypeCheckedTripleEquals { patch( ClientCursor( Map( - SortOrderRepr("businessentity0.modifieddate") -> new Json.Str("2020-12-25T00:00:00"), - SortOrderRepr("(businessentity0.businessentityid - 2::int4)") -> new Json.Num(java.math.BigDecimal.valueOf(15)) + SortOrderRepr("(businessentity0).modifieddate") -> new Json.Str("2020-12-25T00:00:00"), + SortOrderRepr("((businessentity0).businessentityid - 2::int4)") -> new Json.Num(java.math.BigDecimal.valueOf(15)) ) ) ) From a858f5720f21edaa4e1d5f86889cdd8584fdca5d 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 4/4] 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 () }