Skip to content

Adding support for java.util.Date #24

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

Merged
merged 5 commits into from
Aug 25, 2024
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
26 changes: 26 additions & 0 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -7371,6 +7371,29 @@ Expr("2023-11-12 03:22:41").cast[java.time.LocalDateTime]



### ExprOps.cast.utildate



```scala
Expr("2023-11-12 03:22:41").cast[java.util.Date]
```


*
```sql
SELECT CAST(? AS TIMESTAMP) AS res
```



*
```scala
new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2023-11-12 03:22:41")
```



### ExprOps.cast.instant


Expand Down Expand Up @@ -9201,6 +9224,7 @@ case class DataTypes[T[_]](
myLocalDate: T[LocalDate],
myLocalTime: T[LocalTime],
myLocalDateTime: T[LocalDateTime],
myUtilDate: T[Date],
myInstant: T[Instant],
myVarBinary: T[geny.Bytes],
myUUID: T[java.util.UUID],
Expand All @@ -9219,6 +9243,7 @@ val value = DataTypes[Sc](
myLocalDate = LocalDate.parse("2023-12-20"),
myLocalTime = LocalTime.parse("10:15:30"),
myLocalDateTime = LocalDateTime.parse("2011-12-03T10:15:30"),
myUtilDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("2011-12-03T10:15:30.000"),

Choose a reason for hiding this comment

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

Should we use SimpleDateFormat here ?

There are instances where java.text.SimpleDateFormat is used to parse dates. A better approach is to use java.time.format.DateTimeFormatter from the modern Java Time API (java.time) introduced in Java 8, which is thread-safe, more flexible, and offers better support for various date/time formats.

We could also convert from LocalDateTime

import java.time.format.DateTimeFormatter
import java.time.{LocalDateTime, ZoneId, ZoneOffset, ZonedDateTime}
import java.util.Date

val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
val date = Date.from(
  LocalDateTime.parse("2023-11-12 03:22:41", formatter)
    .toInstant(
      ZonedDateTime.now(ZoneId.systemDefault()).getOffset
    )
)

println(date)

myInstant = Instant.parse("2011-12-03T10:15:30Z"),
myVarBinary = new geny.Bytes(Array[Byte](1, 2, 3, 4, 5, 6, 7, 8)),
myUUID = new java.util.UUID(1234567890L, 9876543210L),
Expand All @@ -9236,6 +9261,7 @@ db.run(
_.myLocalDate := value.myLocalDate,
_.myLocalTime := value.myLocalTime,
_.myLocalDateTime := value.myLocalDateTime,
_.myUtilDate := value.myUtilDate,
_.myInstant := value.myInstant,
_.myVarBinary := value.myVarBinary,
_.myUUID := value.myUUID,
Expand Down
1 change: 1 addition & 0 deletions scalasql/core/src/DialectTypeMappers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ trait DialectTypeMappers extends DialectConfig {
implicit def BooleanType: TypeMapper[Boolean]
implicit def UuidType: TypeMapper[UUID]
implicit def BytesType: TypeMapper[geny.Bytes]
implicit def UtilDateType: TypeMapper[java.util.Date]
implicit def LocalDateType: TypeMapper[LocalDate]
implicit def LocalTimeType: TypeMapper[LocalTime]

Expand Down
3 changes: 3 additions & 0 deletions scalasql/core/src/TypeMapper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ object TypeMapper {
d.UuidType
implicit def bytesFromDialectTypeMappers(implicit d: DialectTypeMappers): TypeMapper[geny.Bytes] =
d.BytesType
implicit def utilDateFromDialectTypeMappers(
implicit d: DialectTypeMappers
): TypeMapper[java.util.Date] = d.UtilDateType
implicit def localDateFromDialectTypeMappers(
implicit d: DialectTypeMappers
): TypeMapper[LocalDate] = d.LocalDateType
Expand Down
8 changes: 8 additions & 0 deletions scalasql/src/dialects/Dialect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ trait Dialect extends DialectTypeMappers {
def put(r: PreparedStatement, idx: Int, v: geny.Bytes) = r.setBytes(idx, v.array)
}

implicit def UtilDateType: TypeMapper[java.util.Date] = new UtilDateType
class UtilDateType extends TypeMapper[java.util.Date] {
def jdbcType = JDBCType.TIMESTAMP
def get(r: ResultSet, idx: Int) = new java.util.Date(r.getTimestamp(idx).getTime)
def put(r: PreparedStatement, idx: Int, v: java.util.Date) =
r.setTimestamp(idx, new java.sql.Timestamp(v.getTime))
}

implicit def LocalDateType: TypeMapper[LocalDate] = new LocalDateType
class LocalDateType extends TypeMapper[LocalDate] {
def jdbcType = JDBCType.DATE
Expand Down
3 changes: 3 additions & 0 deletions scalasql/src/dialects/MySqlDialect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ trait MySqlDialect extends Dialect {
override implicit def InstantType: TypeMapper[Instant] = new MySqlInstantType
class MySqlInstantType extends InstantType { override def castTypeString = "DATETIME" }

override implicit def UtilDateType: TypeMapper[java.util.Date] = new MySqlUtilDateType
class MySqlUtilDateType extends UtilDateType { override def castTypeString = "DATETIME" }

override implicit def UuidType: TypeMapper[UUID] = new MySqlUuidType

class MySqlUuidType extends UuidType {
Expand Down
3 changes: 3 additions & 0 deletions scalasql/src/dialects/SqliteDialect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ trait SqliteDialect extends Dialect with ReturningDialect with OnConflictOps {
override implicit def InstantType: TypeMapper[Instant] = new SqliteInstantType
class SqliteInstantType extends InstantType { override def castTypeString = "VARCHAR" }

override implicit def UtilDateType: TypeMapper[java.util.Date] = new SqliteUtilDateType
class SqliteUtilDateType extends UtilDateType { override def castTypeString = "VARCHAR" }

override implicit def ExprStringOpsConv(v: Expr[String]): SqliteDialect.ExprStringOps[String] =
new SqliteDialect.ExprStringOps(v)

Expand Down
1 change: 1 addition & 0 deletions scalasql/test/resources/h2-customer-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ CREATE TABLE data_types (
my_local_date DATE,
my_local_time TIME,
my_local_date_time TIMESTAMP,
my_util_date TIMESTAMP,
my_instant TIMESTAMP WITH TIME ZONE,
my_var_binary VARBINARY(256),
my_uuid UUID,
Expand Down
3 changes: 2 additions & 1 deletion scalasql/test/resources/mysql-customer-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ CREATE TABLE data_types (
my_local_date DATE,
my_local_time TIME,
my_local_date_time TIMESTAMP,
my_util_date TIMESTAMP,
my_instant DATETIME,
my_var_binary VARBINARY(256),
my_uuid CHAR(36),
Expand All @@ -76,4 +77,4 @@ CREATE TABLE enclosing(
my_string VARCHAR(256),
foo_id INTEGER,
my_boolean BOOLEAN
);
);
4 changes: 3 additions & 1 deletion scalasql/test/resources/postgres-customer-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ CREATE TABLE data_types (
my_local_date DATE,
my_local_time TIME,
my_local_date_time TIMESTAMP,
my_util_date TIMESTAMP,
my_instant TIMESTAMP WITH TIME ZONE,
my_var_binary BYTEA,
my_uuid UUID,
Expand Down Expand Up @@ -82,10 +83,11 @@ CREATE TABLE enclosing(
my_boolean BOOLEAN
);


CREATE SCHEMA otherschema;

CREATE TABLE otherschema.invoice(
id SERIAL PRIMARY KEY,
total DECIMAL(20, 2),
vendor_name VARCHAR(256)
);
);
3 changes: 2 additions & 1 deletion scalasql/test/resources/sqlite-customer-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ CREATE TABLE data_types (
my_local_date DATE,
my_local_time TIME,
my_local_date_time TIMESTAMP,
my_util_date TIMESTAMP,
my_instant DATETIME,
my_var_binary VARBINARY,
my_uuid BINARY(16),
Expand Down Expand Up @@ -77,4 +78,4 @@ CREATE TABLE enclosing(
my_string VARCHAR(256),
foo_id INTEGER,
my_boolean BOOLEAN
);
);
6 changes: 6 additions & 0 deletions scalasql/test/src/datatypes/DataTypesTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import java.time.{
ZoneId,
ZonedDateTime
}
import java.util.Date
import java.text.SimpleDateFormat

import _root_.test.scalasql.WorldSqlTests.ArrowAssert

Expand Down Expand Up @@ -56,6 +58,7 @@ trait DataTypesTests extends ScalaSqlSuite {
myLocalDate: T[LocalDate],
myLocalTime: T[LocalTime],
myLocalDateTime: T[LocalDateTime],
myUtilDate: T[Date],
myInstant: T[Instant],
myVarBinary: T[geny.Bytes],
myUUID: T[java.util.UUID],
Expand All @@ -74,6 +77,8 @@ trait DataTypesTests extends ScalaSqlSuite {
myLocalDate = LocalDate.parse("2023-12-20"),
myLocalTime = LocalTime.parse("10:15:30"),
myLocalDateTime = LocalDateTime.parse("2011-12-03T10:15:30"),
myUtilDate =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("2011-12-03T10:15:30.000"),
myInstant = Instant.parse("2011-12-03T10:15:30Z"),
myVarBinary = new geny.Bytes(Array[Byte](1, 2, 3, 4, 5, 6, 7, 8)),
myUUID = new java.util.UUID(1234567890L, 9876543210L),
Expand All @@ -91,6 +96,7 @@ trait DataTypesTests extends ScalaSqlSuite {
_.myLocalDate := value.myLocalDate,
_.myLocalTime := value.myLocalTime,
_.myLocalDateTime := value.myLocalDateTime,
_.myUtilDate := value.myUtilDate,
_.myInstant := value.myInstant,
_.myVarBinary := value.myVarBinary,
_.myUUID := value.myUUID,
Expand Down
10 changes: 10 additions & 0 deletions scalasql/test/src/operations/DbOpsTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ trait ExprOpsTests extends ScalaSqlSuite {
value = java.time.LocalDateTime.parse("2023-11-12T03:22:41")
)

test("utildate") - checker(
query = Expr("2023-11-12 03:22:41").cast[java.util.Date],
sqls = Seq(
"SELECT CAST(? AS DATETIME) AS res",
"SELECT CAST(? AS TIMESTAMP) AS res",
"SELECT CAST(? AS VARCHAR) AS res"
),
value = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2023-11-12 03:22:41")
)

test("instant") - checker(
query = Expr("2007-12-03 10:15:30.00").cast[java.time.Instant],
sqls = Seq(
Expand Down
Loading