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 all commits
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 @@ -32,6 +31,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
17 changes: 9 additions & 8 deletions postgres/src/test/resources/shop_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ create table customers
first_name varchar not null,
last_name varchar not null,
verified boolean not null,
dob date not null
dob date not null,
created_timestamp_string varchar not null,
created_timestamp timestamp with time zone default now()
);

create table orders
Expand Down Expand Up @@ -37,15 +39,14 @@ create table order_details
unit_price money not null
);


insert into customers
(id, first_name, last_name, verified, dob)
(id, first_name, last_name, verified, dob, created_timestamp_string, created_timestamp)
values
('60b01fc9-c902-4468-8d49-3c0f989def37', 'Ronald', 'Russell', true, '1983-01-05'),
('f76c9ace-be07-4bf3-bd4c-4a9c62882e64', 'Terrence', 'Noel', true, '1999-11-02'),
('784426a5-b90a-4759-afbb-571b7a0ba35e', 'Mila', 'Paterso', true, '1990-11-16'),
('df8215a2-d5fd-4c6c-9984-801a1b3a2a0b', 'Alana', 'Murray', true, '1995-11-12'),
('636ae137-5b1a-4c8c-b11f-c47c624d9cdc', 'Jose', 'Wiggins', false, '1987-03-23');
('60b01fc9-c902-4468-8d49-3c0f989def37', 'Ronald', 'Russell', true, '1983-01-05', '2020-11-21T19:10:25+00:00', '2020-11-21 19:10:25+00'),
('f76c9ace-be07-4bf3-bd4c-4a9c62882e64', 'Terrence', 'Noel', true, '1999-11-02', '2020-11-21T15:10:25-04:00', '2020-11-21 15:10:25-04'),
('784426a5-b90a-4759-afbb-571b7a0ba35e', 'Mila', 'Paterso', true, '1990-11-16', '2020-11-22T02:10:25+07:00', '2020-11-22 02:10:25+07'),
('df8215a2-d5fd-4c6c-9984-801a1b3a2a0b', 'Alana', 'Murray', true, '1995-11-12', '2020-11-21T12:10:25-07:00', '2020-11-21 12:10:25-07'),
('636ae137-5b1a-4c8c-b11f-c47c624d9cdc', 'Jose', 'Wiggins', false, '1987-03-23', '2020-11-21T19:10:25+00:00', '2020-11-21 19:10:25+00');

insert into products
(id, name, description, image_url)
Expand Down
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.random.Random
import zio.test.Assertion._
Expand Down Expand Up @@ -687,6 +686,33 @@ object FunctionDefSpec extends PostgresRunnableSpec with ShopSchema {

assertion.mapErrorCause(cause => Cause.stackless(cause.untraced))
},
testM("to_timestamp") {
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 customers
val roundTripResults = execute(roundTripQuery).to[String, ZonedDateTime, (String, ZonedDateTime, ZonedDateTime)] {
case row =>
(row._1, ZonedDateTime.parse(row._1), row._2)
}
val roundTripExpected = List(
("2020-11-21T19:10:25+00:00", ZonedDateTime.parse("2020-11-21T19:10:25+00:00"), expectedRoundTripTimestamp),
("2020-11-21T15:10:25-04:00", ZonedDateTime.parse("2020-11-21T15:10:25-04:00"), expectedRoundTripTimestamp),
("2020-11-22T02:10:25+07:00", ZonedDateTime.parse("2020-11-22T02:10:25+07:00"), expectedRoundTripTimestamp),
("2020-11-21T12:10:25-07:00", ZonedDateTime.parse("2020-11-21T12:10:25-07:00"), 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))
},
testM("replace") {
val lastNameReplaced = Replace(lName, "'ll'", "'_'") as "lastNameReplaced"
val computedReplace = Replace("'special ::ąę::'", "'ąę'", "'__'") as "computedReplace"
Expand Down
8 changes: 6 additions & 2 deletions postgres/src/test/scala/zio/sql/postgresql/ShopSchema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ trait ShopSchema extends Jdbc { self =>
import self.ColumnSet._

object Customers {
//https://github.com/zio/zio-sql/issues/320 Once Insert is supported, we can remove created_timestamp_string
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"
) ++ string("created_timestamp_string") ++ zonedDateTime("created_timestamp"))
.table("customers")

val customerId :*: dob :*: fName :*: lName :*: verified :*: _ = customers.columns
val customerId :*: dob :*: fName :*: lName :*: verified :*: createdString :*: createdTimestamp :*: _ =
customers.columns
}
object Orders {
val orders = (uuid("id") ++ uuid("customer_id") ++ localDate("order_date")).table("orders")
Expand Down