From dd3c6d76ec4aea60d5b0c54324d88faaaa94e538 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Fri, 27 May 2022 15:38:47 +0100 Subject: [PATCH 01/16] Implement renderInsert for Oracle --- .../zio/sql/oracle/OracleRenderModule.scala | 218 +++++++++++++++++- 1 file changed, 217 insertions(+), 1 deletion(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 756aa783a..0f7884acd 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -1,6 +1,16 @@ package zio.sql.oracle import zio.schema.Schema +import zio.schema.DynamicValue +import zio.schema.StandardType +import java.time.Instant +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.time.ZonedDateTime +import java.time.LocalTime +import java.time.OffsetTime +import java.time.LocalDate trait OracleRenderModule extends OracleSqlModule { self => @@ -10,7 +20,11 @@ trait OracleRenderModule extends OracleSqlModule { self => builder.toString } - override def renderInsert[A: Schema](insert: self.Insert[_, A]): String = ??? + override def renderInsert[A: Schema](insert: self.Insert[_, A]): String = { + val builder = new StringBuilder + buildInsertString(insert, builder) + builder.toString() + } override def renderRead(read: self.Read[_]): String = { val builder = new StringBuilder @@ -219,6 +233,208 @@ trait OracleRenderModule extends OracleSqlModule { self => val _ = builder.append(" (").append(values.mkString(",")).append(") ") // todo fix needs escaping } + private def buildInsertString[A: Schema](insert: self.Insert[_, A], builder: StringBuilder): Unit = { + + builder.append("INSERT INTO ") + renderTable(insert.table, builder) + + builder.append(" (") + renderColumnNames(insert.sources, builder) + builder.append(") VALUES ") + + renderInsertValues(insert.values, builder) + } + + private def renderTable(table: Table, builder: StringBuilder): Unit = table match { + case Table.DerivedTable(read, name) => + builder.append(" ( ") + builder.append(renderRead(read)) + builder.append(" ) ") + builder.append(name) + () + case Table.DialectSpecificTable(tableExtension) => ??? + case Table.Joined(joinType, left, right, on) => + renderTable(left, builder) + val joinTypeRepr = joinType match { + case JoinType.Inner => " INNER JOIN " + case JoinType.LeftOuter => " LEFT JOIN " + case JoinType.RightOuter => " RIGHT JOIN " + case JoinType.FullOuter => " OUTER JOIN " + } + builder.append(joinTypeRepr) + renderTable(right, builder) + builder.append(" ON ") + buildExpr(on, builder) + builder.append(" ") + () + case source: Table.Source => + builder.append(quoted(source.name)) + () + } + private def renderColumnNames(sources: SelectionSet[_], builder: StringBuilder): Unit = + sources match { + case SelectionSet.Empty => () // table is a collection of at least ONE column + case SelectionSet.Cons(columnSelection, tail) => + val _ = columnSelection.name.map { name => + builder.append(quoted(name)) + } + tail.asInstanceOf[SelectionSet[_]] match { + case SelectionSet.Empty => () + case next @ SelectionSet.Cons(_, _) => + builder.append(", ") + renderColumnNames(next.asInstanceOf[SelectionSet[_]], builder) + } + } + private def renderInsertValues[A](values: Seq[A], builder: StringBuilder)(implicit schema: Schema[A]): Unit = + values.toList match { + case head :: Nil => + builder.append("(") + renderInsertValue(head, builder) + builder.append(");") + () + case head :: next => + builder.append("(") + renderInsertValue(head, builder) + builder.append(" ),") + renderInsertValues(next, builder) + case Nil => () + } + + def renderInsertValue[Z](z: Z, builder: StringBuilder)(implicit schema: Schema[Z]): Unit = + schema.toDynamic(z) match { + case DynamicValue.Record(listMap) => + listMap.values.toList match { + case head :: Nil => renderDynamicValue(head, builder) + case head :: next => + renderDynamicValue(head, builder) + builder.append(", ") + renderDynamicValues(next, builder) + case Nil => () + } + case value => renderDynamicValue(value, builder) + } + + def renderDynamicValue(dynValue: DynamicValue, builder: StringBuilder): Unit = + dynValue match { + case DynamicValue.Primitive(value, typeTag) => + // need to do this since StandardType is invariant in A + import StandardType._ + StandardType.fromString(typeTag.tag) match { + case Some(v) => + v match { + case BigDecimalType => + builder.append(value) + () + case StandardType.InstantType(formatter) => + builder.append(s"'${formatter.format(value.asInstanceOf[Instant])}'") + () + case CharType => + builder.append(s"'${value}'") + () + case IntType => + builder.append(value) + () + case StandardType.MonthDayType => + builder.append(s"'${value}'") + () + case BinaryType => + builder.append(s"'${value}'") + () + case StandardType.MonthType => + builder.append(s"'${value}'") + () + case StandardType.LocalDateTimeType(formatter) => + builder.append(s"'${formatter.format(value.asInstanceOf[LocalDateTime])}'") + () + case UnitType => + builder.append("null") // None is encoded as Schema[Unit].transform(_ => None, _ => ()) + () + case StandardType.YearMonthType => + builder.append(s"'${value}'") + () + case DoubleType => + builder.append(value) + () + case StandardType.YearType => + builder.append(s"'${value}'") + () + case StandardType.OffsetDateTimeType(formatter) => + builder.append(s"'${formatter.format(value.asInstanceOf[OffsetDateTime])}'") + () + case StandardType.ZonedDateTimeType(_) => + builder.append(s"'${DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value.asInstanceOf[ZonedDateTime])}'") + () + case BigIntegerType => + builder.append(s"'${value}'") + () + case UUIDType => + builder.append(s"'${value}'") + () + case StandardType.ZoneOffsetType => + builder.append(s"'${value}'") + () + case ShortType => + builder.append(value) + () + case StandardType.LocalTimeType(formatter) => + builder.append(s"'${formatter.format(value.asInstanceOf[LocalTime])}'") + () + case StandardType.OffsetTimeType(formatter) => + builder.append(s"'${formatter.format(value.asInstanceOf[OffsetTime])}'") + () + case LongType => + builder.append(value) + () + case StringType => + builder.append(s"'${value}'") + () + case StandardType.PeriodType => + builder.append(s"'${value}'") + () + case StandardType.ZoneIdType => + builder.append(s"'${value}'") + () + case StandardType.LocalDateType(formatter) => + builder.append(s"'${formatter.format(value.asInstanceOf[LocalDate])}'") + () + case BoolType => + builder.append(value) + () + case DayOfWeekType => + builder.append(s"'${value}'") + () + case FloatType => + builder.append(value) + () + case StandardType.DurationType => + builder.append(s"'${value}'") + () + } + case None => () + } + case DynamicValue.Tuple(left, right) => + renderDynamicValue(left, builder) + builder.append(", ") + renderDynamicValue(right, builder) + case DynamicValue.SomeValue(value) => renderDynamicValue(value, builder) + case DynamicValue.NoneValue => + builder.append("null") + () + case _ => () + } + + def renderDynamicValues(dynValues: List[DynamicValue], builder: StringBuilder): Unit = + dynValues match { + case head :: Nil => renderDynamicValue(head, builder) + case head :: tail => + renderDynamicValue(head, builder) + builder.append(", ") + renderDynamicValues(tail, builder) + case Nil => () + } + + private def quoted(name: String): String = "\"" + name + "\"" + private def buildExprList(expr: Read.ExprSet[_], builder: StringBuilder): Unit = expr match { case Read.ExprSet.ExprCons(head, tail) => From ed98c8aaba78a8b9c2c7983aade8a683766a2225 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Fri, 27 May 2022 15:56:56 +0100 Subject: [PATCH 02/16] fix error --- oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 0f7884acd..b33080c85 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -248,7 +248,7 @@ trait OracleRenderModule extends OracleSqlModule { self => private def renderTable(table: Table, builder: StringBuilder): Unit = table match { case Table.DerivedTable(read, name) => builder.append(" ( ") - builder.append(renderRead(read)) + builder.append(renderRead(read.asInstanceOf[Read[_]])) builder.append(" ) ") builder.append(name) () From 47875987c9ef75ed4dbe28bcbc902e66270f1c55 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Fri, 27 May 2022 16:05:55 +0100 Subject: [PATCH 03/16] fix error --- .../main/scala/zio/sql/oracle/OracleRenderModule.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index b33080c85..db3d5e7d1 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -246,14 +246,14 @@ trait OracleRenderModule extends OracleSqlModule { self => } private def renderTable(table: Table, builder: StringBuilder): Unit = table match { - case Table.DerivedTable(read, name) => + case Table.DerivedTable(read, name) => builder.append(" ( ") builder.append(renderRead(read.asInstanceOf[Read[_]])) builder.append(" ) ") builder.append(name) () - case Table.DialectSpecificTable(tableExtension) => ??? - case Table.Joined(joinType, left, right, on) => + case Table.DialectSpecificTable(_) => ??? // there are no extensions for Oracle + case Table.Joined(joinType, left, right, on) => renderTable(left, builder) val joinTypeRepr = joinType match { case JoinType.Inner => " INNER JOIN " @@ -267,7 +267,7 @@ trait OracleRenderModule extends OracleSqlModule { self => buildExpr(on, builder) builder.append(" ") () - case source: Table.Source => + case source: Table.Source => builder.append(quoted(source.name)) () } From ae60f0ab8b35a906bb0012923dff2ef078ad9ac7 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Fri, 27 May 2022 17:41:53 +0100 Subject: [PATCH 04/16] add test --- .../zio/sql/oracle/OracleSqlModule.scala | 9 +++ .../zio/sql/oracle/OracleModuleSpec.scala | 73 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleSqlModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleSqlModule.scala index 64d7b5ccb..6b24ced1a 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleSqlModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleSqlModule.scala @@ -1,6 +1,10 @@ package zio.sql.oracle import zio.sql.Sql +import zio.schema.Schema +import java.time.LocalDate +import java.time.format.DateTimeFormatter +import java.time.LocalDateTime trait OracleSqlModule extends Sql { self => @@ -8,4 +12,9 @@ trait OracleSqlModule extends Sql { self => val Sind = FunctionDef[Double, Double](FunctionName("sind")) } + implicit val localDateSchema = + Schema.primitive[LocalDate](zio.schema.StandardType.LocalDateType(DateTimeFormatter.ISO_DATE)) + + implicit val localDateTimeSchema = + Schema.primitive[LocalDateTime](zio.schema.StandardType.LocalDateTimeType(DateTimeFormatter.ISO_DATE_TIME)) } diff --git a/oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala b/oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala index 7bbeddaa3..1a5413bf4 100644 --- a/oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala +++ b/oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala @@ -5,10 +5,15 @@ import zio.test.TestAspect._ import zio.test._ import scala.language.postfixOps +import java.util.UUID +import java.time.LocalDate +import java.time.format.DateTimeFormatter +import zio.schema._ object OracleModuleSpec extends OracleRunnableSpec with ShopSchema { import Customers._ + import Orders._ override def specLayered = suite("Postgres module")( test("Can delete from single table with a condition") { @@ -28,6 +33,74 @@ object OracleModuleSpec extends OracleRunnableSpec with ShopSchema { val result = execute(query) assertZIO(result)(equalTo(expected)) + }, + test("Can insert rows") { + final case class CustomerRow( + id: UUID, + dateOfBirth: LocalDate, + firstName: String, + lastName: String, + verified: Boolean + ) + implicit val customerRowSchema = + Schema.CaseClass5[UUID, LocalDate, String, String, Boolean, CustomerRow]( + Schema.Field("id", Schema.primitive[UUID](zio.schema.StandardType.UUIDType)), + Schema.Field( + "dateOfBirth", + Schema.primitive[LocalDate](zio.schema.StandardType.LocalDateType(DateTimeFormatter.ISO_DATE)) + ), + Schema.Field("firstName", Schema.primitive[String](zio.schema.StandardType.StringType)), + Schema.Field("lastName", Schema.primitive[String](zio.schema.StandardType.StringType)), + Schema.Field("verified", Schema.primitive[Boolean](zio.schema.StandardType.BoolType)), + CustomerRow.apply, + _.id, + _.dateOfBirth, + _.firstName, + _.lastName, + _.verified + ) + + val rows = List( + CustomerRow(UUID.randomUUID(), LocalDate.ofYearDay(2001, 8), "Peter", "Parker", true), + CustomerRow(UUID.randomUUID(), LocalDate.ofYearDay(1980, 2), "Stephen", "Strange", false) + ) + + val command = insertInto(customers)( + customerId, + dob, + fName, + lName, + verified + ).values(rows) + + println(renderInsert(command)) + + assertZIO(execute(command))(equalTo(2)) + }, + test("Can insert tuples") { + + val rows = List( + ( + UUID.randomUUID(), + UUID.randomUUID(), + LocalDate.of(2022, 1, 1) + ), + ( + UUID.randomUUID(), + UUID.randomUUID(), + LocalDate.of(2022, 1, 5) + ) + ) + + val command = insertInto(orders)( + orderId, + fkCustomerId, + orderDate + ).values(rows) + + println(renderInsert(command)) + + assertZIO(execute(command))(equalTo(2)) } ) @@ sequential } From f58375b44d9fba2d2743d7e36a88fc94a4e068e7 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Fri, 27 May 2022 18:02:48 +0100 Subject: [PATCH 05/16] fix test --- .../src/main/scala/zio/sql/oracle/OracleRenderModule.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index db3d5e7d1..2005461b5 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -268,7 +268,7 @@ trait OracleRenderModule extends OracleSqlModule { self => builder.append(" ") () case source: Table.Source => - builder.append(quoted(source.name)) + builder.append(source.name) () } private def renderColumnNames(sources: SelectionSet[_], builder: StringBuilder): Unit = @@ -276,7 +276,7 @@ trait OracleRenderModule extends OracleSqlModule { self => case SelectionSet.Empty => () // table is a collection of at least ONE column case SelectionSet.Cons(columnSelection, tail) => val _ = columnSelection.name.map { name => - builder.append(quoted(name)) + builder.append(name) } tail.asInstanceOf[SelectionSet[_]] match { case SelectionSet.Empty => () @@ -433,8 +433,6 @@ trait OracleRenderModule extends OracleSqlModule { self => case Nil => () } - private def quoted(name: String): String = "\"" + name + "\"" - private def buildExprList(expr: Read.ExprSet[_], builder: StringBuilder): Unit = expr match { case Read.ExprSet.ExprCons(head, tail) => From b7f7cc47a0c8d12b25abd81d43958762aa83f36d Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Sat, 28 May 2022 08:58:05 +0100 Subject: [PATCH 06/16] fix error --- oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala | 2 +- oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 2005461b5..858272697 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -290,7 +290,7 @@ trait OracleRenderModule extends OracleSqlModule { self => case head :: Nil => builder.append("(") renderInsertValue(head, builder) - builder.append(");") + builder.append(")") () case head :: next => builder.append("(") diff --git a/oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala b/oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala index 1a5413bf4..3773479e4 100644 --- a/oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala +++ b/oracle/src/test/scala/zio/sql/oracle/OracleModuleSpec.scala @@ -15,7 +15,7 @@ object OracleModuleSpec extends OracleRunnableSpec with ShopSchema { import Customers._ import Orders._ - override def specLayered = suite("Postgres module")( + override def specLayered = suite("Oracle module")( test("Can delete from single table with a condition") { val query = deleteFrom(customers) where (verified isNotTrue) println(renderDelete(query)) From f07a4997cebb362c01b8a9791663b89bcf714e73 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Sat, 28 May 2022 09:25:31 +0100 Subject: [PATCH 07/16] fix error --- .../main/scala/zio/sql/oracle/OracleRenderModule.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 858272697..fc888dfed 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -240,7 +240,7 @@ trait OracleRenderModule extends OracleSqlModule { self => builder.append(" (") renderColumnNames(insert.sources, builder) - builder.append(") VALUES ") + builder.append(") ") renderInsertValues(insert.values, builder) } @@ -288,14 +288,14 @@ trait OracleRenderModule extends OracleSqlModule { self => private def renderInsertValues[A](values: Seq[A], builder: StringBuilder)(implicit schema: Schema[A]): Unit = values.toList match { case head :: Nil => - builder.append("(") + builder.append("SELECT (") renderInsertValue(head, builder) - builder.append(")") + builder.append(") FROM DUAL;") () case head :: next => - builder.append("(") + builder.append("SELECT (") renderInsertValue(head, builder) - builder.append(" ),") + builder.append(" ) FROM DUAL UNION") renderInsertValues(next, builder) case Nil => () } From a1dc3a66e1b51125cc07953cae4525b07952e588 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Sat, 28 May 2022 22:28:31 +0100 Subject: [PATCH 08/16] add blank --- oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index fc888dfed..22a3f929b 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -295,7 +295,7 @@ trait OracleRenderModule extends OracleSqlModule { self => case head :: next => builder.append("SELECT (") renderInsertValue(head, builder) - builder.append(" ) FROM DUAL UNION") + builder.append(" ) FROM DUAL UNION ") renderInsertValues(next, builder) case Nil => () } From 7148e2f9dbf72e30dd04003af92f5ea769f137f5 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Sat, 28 May 2022 22:39:20 +0100 Subject: [PATCH 09/16] fix blank --- oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 22a3f929b..c1d52e482 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -295,7 +295,7 @@ trait OracleRenderModule extends OracleSqlModule { self => case head :: next => builder.append("SELECT (") renderInsertValue(head, builder) - builder.append(" ) FROM DUAL UNION ") + builder.append(") FROM DUAL UNION ") renderInsertValues(next, builder) case Nil => () } From bf8cbbf2c1c87850eb9f2e4e73fa286f2b0fea2e Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Sat, 28 May 2022 23:12:22 +0100 Subject: [PATCH 10/16] fix --- oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index c1d52e482..f06046fde 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -290,7 +290,7 @@ trait OracleRenderModule extends OracleSqlModule { self => case head :: Nil => builder.append("SELECT (") renderInsertValue(head, builder) - builder.append(") FROM DUAL;") + builder.append(") FROM DUAL") () case head :: next => builder.append("SELECT (") From a624add59941d491366d1158f2c94f6e555a1108 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Sat, 28 May 2022 23:26:14 +0100 Subject: [PATCH 11/16] fix --- .../main/scala/zio/sql/oracle/OracleRenderModule.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index f06046fde..6e06eec9a 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -288,14 +288,14 @@ trait OracleRenderModule extends OracleSqlModule { self => private def renderInsertValues[A](values: Seq[A], builder: StringBuilder)(implicit schema: Schema[A]): Unit = values.toList match { case head :: Nil => - builder.append("SELECT (") + builder.append("SELECT ") renderInsertValue(head, builder) - builder.append(") FROM DUAL") + builder.append(" FROM DUAL") () case head :: next => - builder.append("SELECT (") + builder.append("SELECT ") renderInsertValue(head, builder) - builder.append(") FROM DUAL UNION ") + builder.append(" FROM DUAL UNION ALL ") renderInsertValues(next, builder) case Nil => () } From 9645ae07142ebaaae1268b4dace30c442d30b746 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Sat, 28 May 2022 23:46:55 +0100 Subject: [PATCH 12/16] fix --- .../src/main/scala/zio/sql/oracle/OracleRenderModule.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 6e06eec9a..47df971df 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -398,7 +398,12 @@ trait OracleRenderModule extends OracleSqlModule { self => builder.append(s"'${formatter.format(value.asInstanceOf[LocalDate])}'") () case BoolType => - builder.append(value) + val b = value.asInstanceOf[Boolean] + if (b) { + builder.append('1') + } else { + builder.append('0') + } () case DayOfWeekType => builder.append(s"'${value}'") From e53177c59108f25260da720ee5ca65c05f6a31bb Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Sun, 5 Jun 2022 12:52:12 +0200 Subject: [PATCH 13/16] fix datetime --- oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 47df971df..c2e48aea4 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -344,7 +344,7 @@ trait OracleRenderModule extends OracleSqlModule { self => builder.append(s"'${value}'") () case StandardType.LocalDateTimeType(formatter) => - builder.append(s"'${formatter.format(value.asInstanceOf[LocalDateTime])}'") + builder.append(s"DATE '${formatter.format(value.asInstanceOf[LocalDateTime])}'") () case UnitType => builder.append("null") // None is encoded as Schema[Unit].transform(_ => None, _ => ()) From 33bb83f2300f89376c7bdbb58a55b0c59e2a34e0 Mon Sep 17 00:00:00 2001 From: Maxim Schuwalow <16665913+mschuwalow@users.noreply.github.com> Date: Mon, 6 Jun 2022 14:21:56 +0200 Subject: [PATCH 14/16] Add tests for inserting and fix bugs (#1) * wip * wip * wip * formatting * Insert tests * Update oracle/src/test/scala/zio/sql/oracle/OracleSqlModuleSpec.scala Co-authored-by: PeiZ <74068135+peixunzhang@users.noreply.github.com> --- .../test/scala/zio/sql/JdbcRunnableSpec.scala | 10 ++ .../zio/sql/oracle/OracleRenderModule.scala | 82 +++++------ .../zio/sql/oracle/OracleSqlModule.scala | 56 ++++++- oracle/src/test/resources/shop_schema.sql | 34 ++++- .../zio/sql/oracle/OracleSqlModuleSpec.scala | 137 +++++++++++++++++- .../scala/zio/sql/oracle/ShopSchema.scala | 55 ++++++- 6 files changed, 317 insertions(+), 57 deletions(-) diff --git a/jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala b/jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala index 59116b1c4..adee4dc38 100644 --- a/jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala +++ b/jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala @@ -3,6 +3,9 @@ package zio.sql import zio.test.TestEnvironment import zio.ZLayer import zio.test.ZIOSpecDefault +import zio.prelude.AssociativeBoth +import zio.test.Gen +import zio.prelude.Covariant trait JdbcRunnableSpec extends ZIOSpecDefault with Jdbc { @@ -16,4 +19,11 @@ trait JdbcRunnableSpec extends ZIOSpecDefault with Jdbc { ConnectionPool.live.orDie, SqlDriver.live ) + + protected implicit def genInstances[R] + : AssociativeBoth[({ type T[A] = Gen[R, A] })#T] with Covariant[({ type T[+A] = Gen[R, A] })#T] = + new AssociativeBoth[({ type T[A] = Gen[R, A] })#T] with Covariant[({ type T[+A] = Gen[R, A] })#T] { + def map[A, B](f: A => B): Gen[R, A] => Gen[R, B] = _.map(f) + def both[A, B](fa: => Gen[R, A], fb: => Gen[R, B]): Gen[R, (A, B)] = fa.zip(fb) + } } diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 18030fc9a..382fb36fc 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -3,7 +3,6 @@ package zio.sql.oracle import zio.schema.Schema import zio.schema.DynamicValue import zio.schema.StandardType -import java.time.format.DateTimeFormatter import java.time.Instant import java.time.LocalDate import java.time.LocalDateTime @@ -12,9 +11,11 @@ import java.time.OffsetTime import java.time.ZonedDateTime import zio.sql.driver.Renderer import zio.sql.driver.Renderer.Extensions - +import zio.Chunk import scala.collection.mutable import java.time.OffsetDateTime +import java.time.YearMonth +import java.time.Duration trait OracleRenderModule extends OracleSqlModule { self => @@ -339,7 +340,9 @@ trait OracleRenderModule extends OracleSqlModule { self => builder.append(value) () case StandardType.InstantType(formatter) => - builder.append(s"'${formatter.format(value.asInstanceOf[Instant])}'") + builder.append( + s"TO_TIMESTAMP_TZ('${formatter.format(value.asInstanceOf[Instant])}', 'SYYYY-MM-DD\"T\"HH24:MI:SS.FF9TZH:TZM')" + ) () case CharType => builder.append(s"'${value}'") @@ -347,53 +350,51 @@ trait OracleRenderModule extends OracleSqlModule { self => case IntType => builder.append(value) () - case StandardType.MonthDayType => - builder.append(s"'${value}'") - () case BinaryType => - builder.append(s"'${value}'") - () - case StandardType.MonthType => - builder.append(s"'${value}'") + val chunk = value.asInstanceOf[Chunk[Byte]] + builder.append("'") + for (b <- chunk) + builder.append(String.format("%02x", b)) + builder.append(s"'") () case StandardType.LocalDateTimeType(formatter) => - builder.append(s"DATE '${formatter.format(value.asInstanceOf[LocalDateTime])}'") - () - case UnitType => - builder.append("null") // None is encoded as Schema[Unit].transform(_ => None, _ => ()) + builder.append( + s"TO_TIMESTAMP('${formatter.format(value.asInstanceOf[LocalDateTime])}', 'SYYYY-MM-DD\"T\"HH24:MI:SS.FF9')" + ) () case StandardType.YearMonthType => - builder.append(s"'${value}'") + val yearMonth = value.asInstanceOf[YearMonth] + builder.append(s"INTERVAL '${yearMonth.getYear}-${yearMonth.getMonth.getValue}' YEAR(4) TO MONTH") () case DoubleType => builder.append(value) () - case StandardType.YearType => - builder.append(s"'${value}'") - () case StandardType.OffsetDateTimeType(formatter) => - builder.append(s"'${formatter.format(value.asInstanceOf[OffsetDateTime])}'") + builder.append( + s"TO_TIMESTAMP_TZ('${formatter.format(value.asInstanceOf[OffsetDateTime])}', 'SYYYY-MM-DD\"T\"HH24:MI:SS.FF9TZH:TZM')" + ) () - case StandardType.ZonedDateTimeType(_) => - builder.append(s"'${DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value.asInstanceOf[ZonedDateTime])}'") - () - case BigIntegerType => - builder.append(s"'${value}'") + case StandardType.ZonedDateTimeType(formatter) => + builder.append( + s"TO_TIMESTAMP_TZ('${formatter.format(value.asInstanceOf[ZonedDateTime])}', 'SYYYY-MM-DD\"T\"HH24:MI:SS.FF9 TZR')" + ) () case UUIDType => builder.append(s"'${value}'") () - case StandardType.ZoneOffsetType => - builder.append(s"'${value}'") - () case ShortType => builder.append(value) () - case StandardType.LocalTimeType(formatter) => - builder.append(s"'${formatter.format(value.asInstanceOf[LocalTime])}'") + case StandardType.LocalTimeType(_) => + val localTime = value.asInstanceOf[LocalTime] + builder.append( + s"INTERVAL '${localTime.getHour}:${localTime.getMinute}:${localTime.getSecond}.${localTime.getNano}' HOUR TO SECOND(9)" + ) () case StandardType.OffsetTimeType(formatter) => - builder.append(s"'${formatter.format(value.asInstanceOf[OffsetTime])}'") + builder.append( + s"TO_TIMESTAMP_TZ('${formatter.format(value.asInstanceOf[OffsetTime])}', 'HH24:MI:SS.FF9TZH:TZM')" + ) () case LongType => builder.append(value) @@ -401,14 +402,8 @@ trait OracleRenderModule extends OracleSqlModule { self => case StringType => builder.append(s"'${value}'") () - case StandardType.PeriodType => - builder.append(s"'${value}'") - () - case StandardType.ZoneIdType => - builder.append(s"'${value}'") - () case StandardType.LocalDateType(formatter) => - builder.append(s"'${formatter.format(value.asInstanceOf[LocalDate])}'") + builder.append(s"DATE '${formatter.format(value.asInstanceOf[LocalDate])}'") () case BoolType => val b = value.asInstanceOf[Boolean] @@ -418,15 +413,20 @@ trait OracleRenderModule extends OracleSqlModule { self => builder.append('0') } () - case DayOfWeekType => - builder.append(s"'${value}'") - () case FloatType => builder.append(value) () case StandardType.DurationType => - builder.append(s"'${value}'") + val duration = value.asInstanceOf[Duration] + val days = duration.toDays() + val hours = duration.toHours() % 24 + val minutes = duration.toMinutes() % 60 + val seconds = duration.getSeconds % 60 + val nanos = duration.getNano + builder.append(s"INTERVAL '$days $hours:$minutes:$seconds.$nanos' DAY(9) TO SECOND(9)") () + case _ => + throw new IllegalStateException("unsupported") } case None => () } diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleSqlModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleSqlModule.scala index 6b24ced1a..e6b17ff45 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleSqlModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleSqlModule.scala @@ -5,16 +5,68 @@ import zio.schema.Schema import java.time.LocalDate import java.time.format.DateTimeFormatter import java.time.LocalDateTime +import java.time.YearMonth +import java.sql.ResultSet +import scala.util.Try +import java.time.Duration +import java.time.ZonedDateTime +import java.time.LocalTime +import java.time.Instant +import java.time.OffsetTime +import java.time.OffsetDateTime trait OracleSqlModule extends Sql { self => + import ColumnSet._ + + override type TypeTagExtension[+A] = OracleTypeTag[A] + + trait OracleTypeTag[+A] extends Tag[A] with Decodable[A] + + object OracleTypeTag { + implicit case object TYearMonth extends OracleTypeTag[YearMonth] { + def decode(column: Int, resultSet: ResultSet): Either[DecodingError, YearMonth] = + Try(YearMonth.parse(resultSet.getString(column))) + .fold( + _ => Left(DecodingError.UnexpectedNull(column)), + r => Right(r) + ) + } + implicit case object TDuration extends OracleTypeTag[Duration] { + def decode(column: Int, resultSet: ResultSet): Either[DecodingError, Duration] = + Try(Duration.parse(resultSet.getString(column))) + .fold( + _ => Left(DecodingError.UnexpectedNull(column)), + r => Right(r) + ) + } + } object OracleFunctionDef { val Sind = FunctionDef[Double, Double](FunctionName("sind")) } + implicit val instantSchema = + Schema.primitive[Instant](zio.schema.StandardType.InstantType(DateTimeFormatter.ISO_OFFSET_DATE_TIME)) + implicit val localDateSchema = - Schema.primitive[LocalDate](zio.schema.StandardType.LocalDateType(DateTimeFormatter.ISO_DATE)) + Schema.primitive[LocalDate](zio.schema.StandardType.LocalDateType(DateTimeFormatter.ISO_LOCAL_DATE)) + + implicit val localTimeSchema = + Schema.primitive[LocalTime](zio.schema.StandardType.LocalTimeType(DateTimeFormatter.ISO_LOCAL_TIME)) implicit val localDateTimeSchema = - Schema.primitive[LocalDateTime](zio.schema.StandardType.LocalDateTimeType(DateTimeFormatter.ISO_DATE_TIME)) + Schema.primitive[LocalDateTime](zio.schema.StandardType.LocalDateTimeType(DateTimeFormatter.ISO_LOCAL_DATE_TIME)) + + implicit val offsetTimeSchema = + Schema.primitive[OffsetTime](zio.schema.StandardType.OffsetTimeType(DateTimeFormatter.ISO_OFFSET_TIME)) + + implicit val offsetDateTimeSchema = + Schema.primitive[OffsetDateTime](zio.schema.StandardType.OffsetDateTimeType(DateTimeFormatter.ISO_OFFSET_DATE_TIME)) + + implicit val zonedDatetimeSchema = + Schema.primitive[ZonedDateTime](zio.schema.StandardType.ZonedDateTimeType(DateTimeFormatter.ISO_ZONED_DATE_TIME)) + + def yearMonth(name: String): Singleton[YearMonth, name.type] = singleton[YearMonth, name.type](name) + + def duration(name: String): Singleton[Duration, name.type] = singleton[Duration, name.type](name) } diff --git a/oracle/src/test/resources/shop_schema.sql b/oracle/src/test/resources/shop_schema.sql index ebfa197b6..09ac9b119 100644 --- a/oracle/src/test/resources/shop_schema.sql +++ b/oracle/src/test/resources/shop_schema.sql @@ -37,8 +37,34 @@ create table order_details unit_price Number(15,2) not null ); -insert all - into customers (id, first_name, last_name, verified, dob) values ('60b01fc9-c902-4468-8d49-3c0f989def37', 'Ronald', 'Russell', 1, TO_DATE('1983-01-05','YYYY-MM-DD')) +create table all_types +( + id varchar(36) not null primary key, + bytearray blob, + bigdecimal number not null, + boolean_ number(1) not null, + char_ varchar(4) not null, + double_ number not null, + float_ float not null, + instant timestamp with time zone not null, + int_ integer not null, + optional_int integer, + localdate date not null, + localdatetime timestamp not null, + localtime interval day to second not null, + long_ integer not null, + offsetdatetime timestamp with time zone not null, + offsettime timestamp with time zone not null, + short integer not null, + string clob not null, + uuid varchar(36) not null, + zoneddatetime timestamp with time zone not null, + yearmonth interval year(4) to month not null, + duration interval day(9) to second(9) not null +); + +insert all + into customers (id, first_name, last_name, verified, dob) values ('60b01fc9-c902-4468-8d49-3c0f989def37', 'Ronald', 'Russell', 1, TO_DATE('1983-01-05','YYYY-MM-DD')) into customers (id, first_name, last_name, verified, dob) values ('f76c9ace-be07-4bf3-bd4c-4a9c62882e64', 'Terrence', 'Noel', 1, TO_DATE('1999-11-02','YYYY-MM-DD')) into customers (id, first_name, last_name, verified, dob) values ('784426a5-b90a-4759-afbb-571b7a0ba35e', 'Mila', 'Paterso', 1, TO_DATE('1990-11-16','YYYY-MM-DD')) into customers (id, first_name, last_name, verified, dob) values ('df8215a2-d5fd-4c6c-9984-801a1b3a2a0b', 'Alana', 'Murray', 1, TO_DATE('1995-11-12','YYYY-MM-DD')) @@ -106,7 +132,7 @@ insert all ('04912093-cc2e-46ac-b64c-1bd7bb7758c3', '60b01fc9-c902-4468-8d49-3c0f989def37', TO_DATE('2019-03-25', 'YYYY-MM-DD')) into orders (id, customer_id, order_date) - values + values ('a243fa42-817a-44ec-8b67-22193d212d82', '60b01fc9-c902-4468-8d49-3c0f989def37', TO_DATE('2018-06-04', 'YYYY-MM-DD')) into orders (id, customer_id, order_date) @@ -452,4 +478,4 @@ insert all into order_details(order_id, product_id, quantity, unit_price) values ('5883CB62-D792-4EE3-ACBC-FE85B6BAA998', 'D5137D3A-894A-4109-9986-E982541B434F', 1, 55.00) -select * from dual; \ No newline at end of file +select * from dual; diff --git a/oracle/src/test/scala/zio/sql/oracle/OracleSqlModuleSpec.scala b/oracle/src/test/scala/zio/sql/oracle/OracleSqlModuleSpec.scala index b3619b8ca..40007cd4d 100644 --- a/oracle/src/test/scala/zio/sql/oracle/OracleSqlModuleSpec.scala +++ b/oracle/src/test/scala/zio/sql/oracle/OracleSqlModuleSpec.scala @@ -6,16 +6,18 @@ import zio.test._ import scala.language.postfixOps import java.util.UUID -import java.time.LocalDate import java.time.format.DateTimeFormatter import zio.schema.Schema +import zio.prelude._ +import java.time.{ LocalDate, LocalDateTime, Month, Year, YearMonth, ZoneOffset, ZonedDateTime } object OracleSqlModuleSpec extends OracleRunnableSpec with ShopSchema { import Customers._ import Orders._ + import AllTypes._ - override def specLayered: Spec[SqlDriver, Exception] = suite("Oracle module")( + override def specLayered: Spec[SqlDriver with TestConfig with Sized, Exception] = suite("Oracle module")( test("Can update selected rows") { /** @@ -102,8 +104,6 @@ object OracleSqlModuleSpec extends OracleRunnableSpec with ShopSchema { verified ).values(rows) - println(renderInsert(command)) - assertZIO(execute(command))(equalTo(2)) }, test("Can insert tuples") { @@ -127,9 +127,132 @@ object OracleSqlModuleSpec extends OracleRunnableSpec with ShopSchema { orderDate ).values(rows) - println(renderInsert(command)) - assertZIO(execute(command))(equalTo(2)) - } + }, + test("Can insert all supported types") { + val sqlMinDateTime = LocalDateTime.of(-4713, 1, 1, 0, 0) + val sqlMaxDateTime = LocalDateTime.of(9999, 12, 31, 23, 59) + + val sqlInstant = + Gen.instant(sqlMinDateTime.toInstant(ZoneOffset.MIN), sqlMaxDateTime.toInstant(ZoneOffset.MAX)) + + val sqlYear = Gen.int(-4713, 9999).filter(_ != 0).map(Year.of) + + val sqlLocalDate = for { + year <- sqlYear + month <- Gen.int(1, 12) + maxLen = if (!year.isLeap && month == 2) 28 else Month.of(month).maxLength + day <- Gen.int(1, maxLen) + } yield LocalDate.of(year.getValue, month, day) + + val sqlYearMonth = for { + year <- sqlYear + month <- Gen.int(1, 12) + } yield YearMonth.of(year.getValue(), month) + + val sqlLocalDateTime = + Gen.localDateTime(sqlMinDateTime, sqlMaxDateTime) + + val sqlZonedDateTime = for { + dateTime <- sqlLocalDateTime + zoneId <- Gen.zoneId + } yield ZonedDateTime.of(dateTime, zoneId) + + val sqlOffsetTime = + Gen.offsetTime.filter(_.getOffset.getTotalSeconds % 60 == 0) + + val sqlOffsetDateTime = + Gen + .offsetDateTime(sqlMinDateTime.atOffset(ZoneOffset.MIN), sqlMaxDateTime.atOffset(ZoneOffset.MAX)) + .filter(_.getOffset.getTotalSeconds % 60 == 0) + + val gen = ( + Gen.uuid, + Gen.chunkOf(Gen.byte), + Gen.bigDecimal(Long.MinValue, Long.MaxValue), + Gen.boolean, + Gen.char, + Gen.double, + Gen.float, + sqlInstant, + Gen.int, + Gen.option(Gen.int), + sqlLocalDate, + sqlLocalDateTime, + Gen.localTime, + Gen.long, + sqlOffsetDateTime, + sqlOffsetTime, + Gen.short, + Gen.string, + Gen.uuid, + sqlZonedDateTime, + sqlYearMonth, + Gen.finiteDuration + ).tupleN + check(gen) { row => + val insert = insertInto(allTypes)( + id, + bytearrayCol, + bigdecimalCol, + booleanCol, + charCol, + doubleCol, + floatCol, + instantCol, + intCol, + optionalIntCol, + localdateCol, + localdatetimeCol, + localtimeCol, + longCol, + offsetdatetimeCol, + offsettimeCol, + shortCol, + stringCol, + uuidCol, + zonedDatetimeCol, + yearMonthCol, + durationCol + ).values(row) + + // TODO: ensure we can read values back correctly + // val read = + // select( + // id ++ + // bytearrayCol ++ + // bigdecimalCol ++ + // booleanCol ++ + // charCol ++ + // doubleCol ++ + // floatCol ++ + // instantCol ++ + // intCol ++ + // optionalIntCol ++ + // localdateCol ++ + // localdatetimeCol ++ + // localtimeCol ++ + // longCol ++ + // offsetdatetimeCol ++ + // offsettimeCol ++ + // shortCol ++ + // stringCol ++ + // uuidCol ++ + // zonedDatetimeCol ++ + // yearMonthCol ++ + // durationCol + // ).from(allTypes) + + val delete = deleteFrom(allTypes).where(id === row._1) + + for { + _ <- execute(insert) + // result <- execute(read).runHead + _ <- execute(delete) + // } yield assert(result)(isSome(equalTo(row))) + } yield assertCompletes + + } + } @@ samples(1) @@ retries(0) @@ shrinks(0) ) @@ sequential } diff --git a/oracle/src/test/scala/zio/sql/oracle/ShopSchema.scala b/oracle/src/test/scala/zio/sql/oracle/ShopSchema.scala index 284d1ef5f..ec7eaf9d0 100644 --- a/oracle/src/test/scala/zio/sql/oracle/ShopSchema.scala +++ b/oracle/src/test/scala/zio/sql/oracle/ShopSchema.scala @@ -1,8 +1,6 @@ package zio.sql.oracle -import zio.sql.Jdbc - -trait ShopSchema extends Jdbc { self => +trait ShopSchema extends OracleSqlModule { self => import self.ColumnSet._ object Customers { @@ -41,4 +39,55 @@ trait ShopSchema extends Jdbc { self => val (fkOrderId, fkProductId, quantity, unitPrice) = orderDetails.columns } + + object AllTypes { + val allTypes = + (uuid("id") ++ + byteArray("bytearray") ++ + bigDecimal("bigdecimal") ++ + boolean("boolean_") ++ + char("char_") ++ + double("double_") ++ + float("float_") ++ + instant("instant") ++ + int("int_") ++ + (int("optional_int") @@ ColumnSetAspect.nullable) ++ + localDate("localdate") ++ + localDateTime("localdatetime") ++ + localTime("localtime") ++ + long("long_") ++ + offsetDateTime("offsetdatetime") ++ + offsetTime("offsettime") ++ + short("short") ++ + string("string") ++ + uuid("uuid") ++ + zonedDateTime("zoneddatetime") ++ + yearMonth("yearmonth") ++ + duration("duration")).table("all_types") + + val ( + id, + bytearrayCol, + bigdecimalCol, + booleanCol, + charCol, + doubleCol, + floatCol, + instantCol, + intCol, + optionalIntCol, + localdateCol, + localdatetimeCol, + localtimeCol, + longCol, + offsetdatetimeCol, + offsettimeCol, + shortCol, + stringCol, + uuidCol, + zonedDatetimeCol, + yearMonthCol, + durationCol + ) = allTypes.columns + } } From e76446dbbd66dfc2b4b597e01c905ccc785ca01c Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Mon, 6 Jun 2022 14:42:45 +0200 Subject: [PATCH 15/16] fix compiler error --- .../zio/sql/oracle/OracleRenderModule.scala | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala index 382fb36fc..744ffd771 100644 --- a/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala +++ b/oracle/src/main/scala/zio/sql/oracle/OracleRenderModule.scala @@ -341,7 +341,9 @@ trait OracleRenderModule extends OracleSqlModule { self => () case StandardType.InstantType(formatter) => builder.append( - s"TO_TIMESTAMP_TZ('${formatter.format(value.asInstanceOf[Instant])}', 'SYYYY-MM-DD\"T\"HH24:MI:SS.FF9TZH:TZM')" + s"""TO_TIMESTAMP_TZ('${formatter.format( + value.asInstanceOf[Instant] + )}', 'SYYYY-MM-DD"T"HH24:MI:SS.FF9TZH:TZM')""" ) () case CharType => @@ -351,7 +353,7 @@ trait OracleRenderModule extends OracleSqlModule { self => builder.append(value) () case BinaryType => - val chunk = value.asInstanceOf[Chunk[Byte]] + val chunk = value.asInstanceOf[Chunk[Object]] builder.append("'") for (b <- chunk) builder.append(String.format("%02x", b)) @@ -359,7 +361,9 @@ trait OracleRenderModule extends OracleSqlModule { self => () case StandardType.LocalDateTimeType(formatter) => builder.append( - s"TO_TIMESTAMP('${formatter.format(value.asInstanceOf[LocalDateTime])}', 'SYYYY-MM-DD\"T\"HH24:MI:SS.FF9')" + s"""TO_TIMESTAMP('${formatter.format( + value.asInstanceOf[LocalDateTime] + )}', 'SYYYY-MM-DD"T"HH24:MI:SS.FF9')""" ) () case StandardType.YearMonthType => @@ -371,12 +375,16 @@ trait OracleRenderModule extends OracleSqlModule { self => () case StandardType.OffsetDateTimeType(formatter) => builder.append( - s"TO_TIMESTAMP_TZ('${formatter.format(value.asInstanceOf[OffsetDateTime])}', 'SYYYY-MM-DD\"T\"HH24:MI:SS.FF9TZH:TZM')" + s"""TO_TIMESTAMP_TZ('${formatter.format( + value.asInstanceOf[OffsetDateTime] + )}', 'SYYYY-MM-DD"T"HH24:MI:SS.FF9TZH:TZM')""" ) () case StandardType.ZonedDateTimeType(formatter) => builder.append( - s"TO_TIMESTAMP_TZ('${formatter.format(value.asInstanceOf[ZonedDateTime])}', 'SYYYY-MM-DD\"T\"HH24:MI:SS.FF9 TZR')" + s"""TO_TIMESTAMP_TZ('${formatter.format( + value.asInstanceOf[ZonedDateTime] + )}', 'SYYYY-MM-DD"T"HH24:MI:SS.FF9 TZR')""" ) () case UUIDType => From 9ddaa7ab632abfe2f0839d9dcf762c9251729e54 Mon Sep 17 00:00:00 2001 From: Peixun Zhang Date: Tue, 28 Jun 2022 15:33:03 +0200 Subject: [PATCH 16/16] fmt --- jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala b/jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala index be298e5aa..d72bd8c0c 100644 --- a/jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala +++ b/jdbc/src/test/scala/zio/sql/JdbcRunnableSpec.scala @@ -64,7 +64,7 @@ trait JdbcRunnableSpec extends ZIOSpecDefault with Jdbc { def map[A, B](f: A => B): Gen[R, A] => Gen[R, B] = _.map(f) def both[A, B](fa: => Gen[R, A], fb: => Gen[R, B]): Gen[R, (A, B)] = fa.zip(fb) } - + private[this] def testContainer: ZIO[Scope, Throwable, SingleContainer[_] with JdbcDatabaseContainer] = ZIO.acquireRelease { ZIO.attemptBlocking {