From 30bb2ffd3a08a353b28919fd6ad1c8606f4c85f4 Mon Sep 17 00:00:00 2001 From: Carlos Ernesto Alvarez Berumen Date: Sun, 28 Dec 2025 14:01:32 -0600 Subject: [PATCH 1/3] v1 --- .../amber/core/tuple/AttributeTypeUtils.scala | 13 ++++-- .../core/tuple/AttributeTypeUtilsSpec.scala | 42 +++++++++++++++++-- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala b/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala index efb119e6640..17c0000ccf1 100644 --- a/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala +++ b/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala @@ -201,10 +201,15 @@ object AttributeTypeUtils extends Serializable { def parseTimestamp(fieldValue: Any): Timestamp = { val attempt: Try[Timestamp] = Try { fieldValue match { - case str: String => new Timestamp(DateParserUtils.parseDate(str.trim).getTime) - case long: java.lang.Long => new Timestamp(long) - case timestamp: Timestamp => timestamp - case date: java.util.Date => new Timestamp(date.getTime) + case str: String => new Timestamp(DateParserUtils.parseDate(str.trim).getTime) + case long: java.lang.Long => new Timestamp(long) + case timestamp: Timestamp => timestamp + case date: java.util.Date => new Timestamp(date.getTime) + case ldt: java.time.LocalDateTime => Timestamp.valueOf(ldt) + case inst: java.time.Instant => Timestamp.from(inst) + case odt: java.time.OffsetDateTime => Timestamp.from(odt.toInstant) + case zdt: java.time.ZonedDateTime => Timestamp.from(zdt.toInstant) + case ld: java.time.LocalDate => Timestamp.valueOf(ld.atStartOfDay()) // Integer, Double, Boolean, Binary are considered to be illegal here. case _ => throw new AttributeTypeException( diff --git a/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala b/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala index 08b9774607e..2120869d2f4 100644 --- a/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala +++ b/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala @@ -22,17 +22,20 @@ package org.apache.texera.amber.core.tuple import org.apache.texera.amber.core.tuple.AttributeType._ import org.apache.texera.amber.core.tuple.AttributeTypeUtils.{ AttributeTypeException, + add, + compare, inferField, inferSchemaFromRows, - parseField, - compare, - add, - minValue, maxValue, + minValue, + parseField, zeroValue } import org.scalatest.funsuite.AnyFunSuite +import java.sql.Timestamp +import java.time.{Instant, LocalDate, LocalDateTime, OffsetDateTime, ZoneId, ZonedDateTime} + class AttributeTypeUtilsSpec extends AnyFunSuite { // Unit Test for Infer Schema @@ -179,9 +182,40 @@ class AttributeTypeUtilsSpec extends AnyFunSuite { .getTime == 1699820130000L ) + val ldt = LocalDateTime.of(2023, 11, 13, 10, 15, 30) + val tsFromLdt = parseField(ldt, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(tsFromLdt == Timestamp.valueOf(ldt)) + + val inst = Instant.parse("2023-11-13T10:15:30Z") + val tsFromInst = parseField(inst, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(tsFromInst == Timestamp.from(inst)) + + val odt = OffsetDateTime.parse("2023-11-13T12:15:30+02:00") + val tsFromOdt = parseField(odt, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(tsFromOdt == Timestamp.from(odt.toInstant)) + + val zdt = ZonedDateTime.of(2023, 11, 13, 2, 15, 30, 0, ZoneId.of("America/Los_Angeles")) + val tsFromZdt = parseField(zdt, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(tsFromZdt == Timestamp.from(zdt.toInstant)) + + val ld = LocalDate.of(2023, 11, 13) + val tsFromLd = parseField(ld, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(tsFromLd == Timestamp.valueOf(ld.atStartOfDay())) + + val utilDate = new java.util.Date(1699820130000L) + val tsFromDate = parseField(utilDate, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(tsFromDate.getTime == 1699820130000L) + + val ts = new Timestamp(1699820130000L) + val tsFromTs = parseField(ts, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(tsFromTs eq ts) + assertThrows[AttributeTypeException] { parseField("invalid", AttributeType.TIMESTAMP) } + assertThrows[AttributeTypeException] { + parseField(123.45, AttributeType.TIMESTAMP) + } } test("parseField correctly parses to STRING") { From 6d2068672f9e43b3ba7fbd878d6927882e71dddd Mon Sep 17 00:00:00 2001 From: Carlos Ernesto Alvarez Berumen Date: Sun, 28 Dec 2025 15:31:14 -0600 Subject: [PATCH 2/3] v2 --- .../amber/core/tuple/AttributeTypeUtils.scala | 10 ++--- .../core/tuple/AttributeTypeUtilsSpec.scala | 38 +++++++++---------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala b/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala index 17c0000ccf1..3790765716f 100644 --- a/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala +++ b/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala @@ -205,11 +205,11 @@ object AttributeTypeUtils extends Serializable { case long: java.lang.Long => new Timestamp(long) case timestamp: Timestamp => timestamp case date: java.util.Date => new Timestamp(date.getTime) - case ldt: java.time.LocalDateTime => Timestamp.valueOf(ldt) - case inst: java.time.Instant => Timestamp.from(inst) - case odt: java.time.OffsetDateTime => Timestamp.from(odt.toInstant) - case zdt: java.time.ZonedDateTime => Timestamp.from(zdt.toInstant) - case ld: java.time.LocalDate => Timestamp.valueOf(ld.atStartOfDay()) + case localDateTime: java.time.LocalDateTime => Timestamp.valueOf(localDateTime) + case instant: java.time.Instant => Timestamp.from(instant) + case offsetDateTime: java.time.OffsetDateTime => Timestamp.from(offsetDateTime.toInstant) + case zonedDateTime: java.time.ZonedDateTime => Timestamp.from(zonedDateTime.toInstant) + case localDate: java.time.LocalDate => Timestamp.valueOf(localDate.atStartOfDay()) // Integer, Double, Boolean, Binary are considered to be illegal here. case _ => throw new AttributeTypeException( diff --git a/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala b/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala index 2120869d2f4..70bed8a0658 100644 --- a/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala +++ b/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala @@ -182,33 +182,29 @@ class AttributeTypeUtilsSpec extends AnyFunSuite { .getTime == 1699820130000L ) - val ldt = LocalDateTime.of(2023, 11, 13, 10, 15, 30) - val tsFromLdt = parseField(ldt, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] - assert(tsFromLdt == Timestamp.valueOf(ldt)) + val localDateTime = LocalDateTime.of(2023, 11, 13, 10, 15, 30) + val timestampFromLocalDateTime = parseField(localDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(timestampFromLocalDateTime == Timestamp.valueOf(localDateTime)) - val inst = Instant.parse("2023-11-13T10:15:30Z") - val tsFromInst = parseField(inst, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] - assert(tsFromInst == Timestamp.from(inst)) + val instant = Instant.parse("2023-11-13T10:15:30Z") + val timestampFromInstant = parseField(instant, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(timestampFromInstant == Timestamp.from(instant)) - val odt = OffsetDateTime.parse("2023-11-13T12:15:30+02:00") - val tsFromOdt = parseField(odt, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] - assert(tsFromOdt == Timestamp.from(odt.toInstant)) + val offsetDateTime = OffsetDateTime.parse("2023-11-13T12:15:30+02:00") + val timestampFromOffsetDateTime = parseField(offsetDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(timestampFromOffsetDateTime == Timestamp.from(offsetDateTime.toInstant)) - val zdt = ZonedDateTime.of(2023, 11, 13, 2, 15, 30, 0, ZoneId.of("America/Los_Angeles")) - val tsFromZdt = parseField(zdt, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] - assert(tsFromZdt == Timestamp.from(zdt.toInstant)) + val zonedDateTime = ZonedDateTime.of(2023, 11, 13, 2, 15, 30, 0, ZoneId.of("America/Los_Angeles")) + val timestampFromZonedDateTime = parseField(zonedDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(timestampFromZonedDateTime == Timestamp.from(zonedDateTime.toInstant)) - val ld = LocalDate.of(2023, 11, 13) - val tsFromLd = parseField(ld, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] - assert(tsFromLd == Timestamp.valueOf(ld.atStartOfDay())) + val localDate = LocalDate.of(2023, 11, 13) + val timestampFromLocalDate = parseField(localDate, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(timestampFromLocalDate == Timestamp.valueOf(localDate.atStartOfDay())) val utilDate = new java.util.Date(1699820130000L) - val tsFromDate = parseField(utilDate, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] - assert(tsFromDate.getTime == 1699820130000L) - - val ts = new Timestamp(1699820130000L) - val tsFromTs = parseField(ts, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] - assert(tsFromTs eq ts) + val timestampFromDate = parseField(utilDate, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + assert(timestampFromDate.getTime == 1699820130000L) assertThrows[AttributeTypeException] { parseField("invalid", AttributeType.TIMESTAMP) From d25d4b763464cb653438d4ae511f45c42d0ccc60 Mon Sep 17 00:00:00 2001 From: Carlos Ernesto Alvarez Berumen Date: Sun, 28 Dec 2025 22:16:21 -0600 Subject: [PATCH 3/3] scala fix&fmt All --- .../amber/core/tuple/AttributeTypeUtils.scala | 16 ++++++++-------- .../core/tuple/AttributeTypeUtilsSpec.scala | 15 ++++++++++----- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala b/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala index 3790765716f..208f94d0407 100644 --- a/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala +++ b/common/workflow-core/src/main/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtils.scala @@ -201,15 +201,15 @@ object AttributeTypeUtils extends Serializable { def parseTimestamp(fieldValue: Any): Timestamp = { val attempt: Try[Timestamp] = Try { fieldValue match { - case str: String => new Timestamp(DateParserUtils.parseDate(str.trim).getTime) - case long: java.lang.Long => new Timestamp(long) - case timestamp: Timestamp => timestamp - case date: java.util.Date => new Timestamp(date.getTime) - case localDateTime: java.time.LocalDateTime => Timestamp.valueOf(localDateTime) - case instant: java.time.Instant => Timestamp.from(instant) + case str: String => new Timestamp(DateParserUtils.parseDate(str.trim).getTime) + case long: java.lang.Long => new Timestamp(long) + case timestamp: Timestamp => timestamp + case date: java.util.Date => new Timestamp(date.getTime) + case localDateTime: java.time.LocalDateTime => Timestamp.valueOf(localDateTime) + case instant: java.time.Instant => Timestamp.from(instant) case offsetDateTime: java.time.OffsetDateTime => Timestamp.from(offsetDateTime.toInstant) - case zonedDateTime: java.time.ZonedDateTime => Timestamp.from(zonedDateTime.toInstant) - case localDate: java.time.LocalDate => Timestamp.valueOf(localDate.atStartOfDay()) + case zonedDateTime: java.time.ZonedDateTime => Timestamp.from(zonedDateTime.toInstant) + case localDate: java.time.LocalDate => Timestamp.valueOf(localDate.atStartOfDay()) // Integer, Double, Boolean, Binary are considered to be illegal here. case _ => throw new AttributeTypeException( diff --git a/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala b/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala index 70bed8a0658..defa567480a 100644 --- a/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala +++ b/common/workflow-core/src/test/scala/org/apache/texera/amber/core/tuple/AttributeTypeUtilsSpec.scala @@ -183,7 +183,8 @@ class AttributeTypeUtilsSpec extends AnyFunSuite { ) val localDateTime = LocalDateTime.of(2023, 11, 13, 10, 15, 30) - val timestampFromLocalDateTime = parseField(localDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + val timestampFromLocalDateTime = + parseField(localDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] assert(timestampFromLocalDateTime == Timestamp.valueOf(localDateTime)) val instant = Instant.parse("2023-11-13T10:15:30Z") @@ -191,15 +192,19 @@ class AttributeTypeUtilsSpec extends AnyFunSuite { assert(timestampFromInstant == Timestamp.from(instant)) val offsetDateTime = OffsetDateTime.parse("2023-11-13T12:15:30+02:00") - val timestampFromOffsetDateTime = parseField(offsetDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + val timestampFromOffsetDateTime = + parseField(offsetDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] assert(timestampFromOffsetDateTime == Timestamp.from(offsetDateTime.toInstant)) - val zonedDateTime = ZonedDateTime.of(2023, 11, 13, 2, 15, 30, 0, ZoneId.of("America/Los_Angeles")) - val timestampFromZonedDateTime = parseField(zonedDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + val zonedDateTime = + ZonedDateTime.of(2023, 11, 13, 2, 15, 30, 0, ZoneId.of("America/Los_Angeles")) + val timestampFromZonedDateTime = + parseField(zonedDateTime, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] assert(timestampFromZonedDateTime == Timestamp.from(zonedDateTime.toInstant)) val localDate = LocalDate.of(2023, 11, 13) - val timestampFromLocalDate = parseField(localDate, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] + val timestampFromLocalDate = + parseField(localDate, AttributeType.TIMESTAMP).asInstanceOf[Timestamp] assert(timestampFromLocalDate == Timestamp.valueOf(localDate.atStartOfDay())) val utilDate = new java.util.Date(1699820130000L)