Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(postgres to_timestamp): Implementing Postgres to_timestamp funct… #263

Merged
merged 3 commits into from
Nov 24, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions jdbc/src/main/scala/zio/sql/jdbc.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package zio.sql

import java.sql._

import java.io.IOException

import java.time.{ ZoneId, ZoneOffset }
import zio.{ Chunk, Has, IO, Managed, ZIO, ZLayer, ZManaged }
import zio.blocking.Blocking
import zio.stream.{ Stream, ZStream }
Expand Down Expand Up @@ -193,7 +192,14 @@ trait Jdbc extends zio.sql.Sql {
tryDecode[java.util.UUID](
java.util.UUID.fromString(column.fold(resultSet.getString(_), resultSet.getString(_)))
)
case TZonedDateTime => ???
case TZonedDateTime =>
tryDecode[java.time.ZonedDateTime](
java.time.ZonedDateTime
.ofInstant(
column.fold(resultSet.getTimestamp(_), resultSet.getTimestamp(_)).toInstant,
ZoneId.of(ZoneOffset.UTC.getId)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how we'd like to handle this, having it default to utc seems problematic, but I'm not sure how we should go from java.sql.Timestamp -> java.time.ZonedDateTime.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking at the javadoc of getTimestamp, I'm pretty sure that it's converting to UTC, so I believe this is correct. It'd probably be a good idea to add a round trip test to make sure (e.g. insert a timestamp from some other time zone, grab it back out, then compare to ensure that time is the same (accounting for the difference in time zones)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's a good idea, I'll add that in!

)
)
case TDialectSpecific(_) => ???
case t @ Nullable() => extractColumn(column, resultSet, t.typeTag, false).map(Option(_))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package zio.sql.postgresql

import java.time.LocalDate

import java.time.{ LocalDate, ZonedDateTime }
import zio.sql.Jdbc

/**
Expand Down Expand Up @@ -30,6 +29,7 @@ trait PostgresModule extends Jdbc { self =>
val Degrees = FunctionDef[Double, Double](FunctionName("degrees"))
val Div = FunctionDef[(Double, Double), Double](FunctionName("div"))
val Factorial = FunctionDef[Int, Int](FunctionName("factorial"))
val ToTimestamp = FunctionDef[Long, ZonedDateTime](FunctionName("to_timestamp"))
}

override def renderRead(read: self.Read[_]): String = {
Expand Down
16 changes: 15 additions & 1 deletion postgres/src/test/resources/shop_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ create table order_details
unit_price money not null
);

create table timestamp_test
(
timestamp_id uuid not null,
created_timestamp_string varchar not null,
created_timestamp timestamp with time zone default now()
);

insert into customers
(id, first_name, last_name, verified, dob)
Expand Down Expand Up @@ -189,4 +195,12 @@ values
('852E2DC9-4EC3-4225-A6F7-4F42F8FF728E', 'D5137D3A-894A-4109-9986-E982541B434F', 1, 45.45),
('D6D8DDDC-4B0B-4D74-8EDC-A54E9B7F35F7', 'D5137D3A-894A-4109-9986-E982541B434F', 2, 50.00),
('2C3FC180-D0DF-4D7B-A271-E6CCD2440393', 'D5137D3A-894A-4109-9986-E982541B434F', 2, 50.00),
('5883CB62-D792-4EE3-ACBC-FE85B6BAA998', 'D5137D3A-894A-4109-9986-E982541B434F', 1, 55.00);
('5883CB62-D792-4EE3-ACBC-FE85B6BAA998', 'D5137D3A-894A-4109-9986-E982541B434F', 1, 55.00);

insert into timestamp_test
brbrown25 marked this conversation as resolved.
Show resolved Hide resolved
(timestamp_id, created_timestamp_string, created_timestamp)
values
('354ec738-71b6-4166-9c62-aa092ede73c4', '2020-11-21 19:10:25+00', '2020-11-21 19:10:25+00'),
('2f97e2c5-62de-478e-bb30-742f2614f3cd', '2020-11-21 15:10:25-04', '2020-11-21 15:10:25-04'),
('261a4290-2da4-4e3f-bbab-3f0af31d1914', '2020-11-22 02:10:25+07', '2020-11-22 02:10:25+07'),
('2e9d0d70-b947-4126-9149-7a8e6d492171', '2020-11-21 12:10:25-07', '2020-11-21 12:10:25-07')
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package zio.sql.postgresql

import java.time.LocalDate
import java.time.{ LocalDate, ZoneId, ZoneOffset, ZonedDateTime }
import java.util.UUID

import zio.Cause
import zio.test._
import zio.test.Assertion._
Expand Down Expand Up @@ -523,6 +522,34 @@ object FunctionDefSpec extends PostgresRunnableSpec with ShopSchema {
r <- result.runCollect
} yield assert(r)(hasSameElements(expected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
testM("to_timestamp") {
import this.TimestampTests._

val query = select(ToTimestamp(1284352323L)) from customers
val expected = ZonedDateTime.of(2010, 9, 13, 4, 32, 3, 0, ZoneId.of(ZoneOffset.UTC.getId))
val testResult = execute(query).to[ZonedDateTime, ZonedDateTime](identity)

val expectedRoundTripTimestamp = ZonedDateTime.of(2020, 11, 21, 19, 10, 25, 0, ZoneId.of(ZoneOffset.UTC.getId))
val roundTripQuery =
select(createdString ++ createdTimestamp) from timestampTests
brbrown25 marked this conversation as resolved.
Show resolved Hide resolved
val roundTripResults = execute(roundTripQuery).to[String, ZonedDateTime, (String, ZonedDateTime)] { case row =>
row
}
val roundTripExpected = List(
("2020-11-21 19:10:25+00", expectedRoundTripTimestamp),
("2020-11-21 15:10:25-04", expectedRoundTripTimestamp),
("2020-11-22 02:10:25+07", expectedRoundTripTimestamp),
("2020-11-21 12:10:25-07", expectedRoundTripTimestamp)
)

val assertion = for {
single <- testResult.runCollect
roundTrip <- roundTripResults.runCollect
} yield assert(single.head)(equalTo(expected)) &&
assert(roundTrip)(hasSameElementsDistinct(roundTripExpected))

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
}
)
Expand Down
13 changes: 11 additions & 2 deletions postgres/src/test/scala/zio/sql/postgresql/ShopSchema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ trait ShopSchema extends Jdbc { self =>

object Customers {
val customers =
(uuid("id") ++ localDate("dob") ++ string("first_name") ++ string("last_name") ++ boolean("verified"))
(uuid("id") ++ localDate("dob") ++ string("first_name") ++ string("last_name") ++ boolean(
"verified"
) ++ zonedDateTime("created_timestamp"))
brbrown25 marked this conversation as resolved.
Show resolved Hide resolved
.table("customers")

val customerId :*: dob :*: fName :*: lName :*: verified :*: _ = customers.columns
val customerId :*: dob :*: fName :*: lName :*: verified :*: createdTimestamp :*: _ = customers.columns
}
object Orders {
val orders = (uuid("id") ++ uuid("customer_id") ++ localDate("order_date")).table("orders")
Expand Down Expand Up @@ -39,4 +41,11 @@ trait ShopSchema extends Jdbc { self =>

val fkOrderId :*: fkProductId :*: quantity :*: unitPrice :*: _ = orderDetails.columns
}

object TimestampTests {
val timestampTests =
(uuid("timestamp_id") ++ string("created_timestamp_string") ++ zonedDateTime("created_timestamp"))
.table("timestamp_test")
val tId :*: createdString :*: createdTimestamp :*: _ = timestampTests.columns
}
}