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

fix: add Date TypeHandler #290

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ public static ColumnTypeHandler getTypeHandler(DatabendRawType type) {
return new DecimalHandler(type.isNullable());
case DatabendTypes.GEOMETRY:
return new GeometryHandler(type.isNullable());
case DatabendTypes.ARRAY:
case DatabendTypes.DATE:
return new DateHandler(type.isNullable());
case DatabendTypes.DATETIME:
case DatabendTypes.DATETIME64:
case DatabendTypes.TIMESTAMP:
return new TimestampHandler(type.isNullable());
case DatabendTypes.ARRAY:
case DatabendTypes.STRING:
case DatabendTypes.NULL:
case DatabendTypes.STRUCT:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.databend.client.data;

/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class DateHandler implements ColumnTypeHandler {
private final boolean isNullable;
private final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE;

public DateHandler() {
this.isNullable = false;
}

public DateHandler(boolean isNullable) {
this.isNullable = isNullable;
}

@Override
public Object parseValue(Object value) {
if (value == null) {
if (isNullable) {
return null;
}
throw new IllegalArgumentException("Date type is not nullable");
}

if (value instanceof LocalDate) {
return value;
}

if (value instanceof String) {
try {
return LocalDate.parse((String) value, formatter);
}
catch (DateTimeParseException e) {
throw new IllegalArgumentException("Invalid date format: " + value, e);
}
}

throw new IllegalArgumentException("Cannot convert " + value.getClass().getName() + " to Date");
}

@Override
public void setNullable(boolean isNullable) {
// do nothing
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.databend.client.data;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.util.Arrays;
import java.util.List;

class TimestampHandler implements ColumnTypeHandler {
private static final DateTimeFormatter TIMESTAMP_FORMATTER = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss")
.optionalStart()
.appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
.optionalEnd()
.toFormatter();

private static final List<DateTimeFormatter> FORMATTERS = Arrays.asList(
TIMESTAMP_FORMATTER,
DateTimeFormatter.ISO_INSTANT,
DateTimeFormatter.ISO_LOCAL_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
);

private final ZoneId zoneId;
private boolean isNullable;

public TimestampHandler() {
this(false);
}

public TimestampHandler(boolean isNullable) {
this(isNullable, ZoneId.systemDefault());
}

public TimestampHandler(boolean isNullable, ZoneId zoneId) {
this.isNullable = isNullable;
this.zoneId = zoneId;
}

@Override
public Object parseValue(Object value) {
if (value == null) {
if (isNullable) {
return null;
}
throw new IllegalArgumentException("Timestamp type is not nullable");
}

if (value instanceof Instant) {
return value;
}

if (value instanceof LocalDateTime) {
return ((LocalDateTime) value).atZone(zoneId).toInstant();
}

if (value instanceof ZonedDateTime) {
return ((ZonedDateTime) value).toInstant();
}

if (value instanceof String) {
String timestampStr = ((String) value).trim();

try {
long epochSeconds = Long.parseLong(timestampStr);
return Instant.ofEpochSecond(epochSeconds);
}
catch (NumberFormatException ignored) {
}

try {
LocalDateTime localDateTime = LocalDateTime.parse(timestampStr, TIMESTAMP_FORMATTER);
return localDateTime.atZone(zoneId).toInstant();
}
catch (DateTimeParseException e) {
for (DateTimeFormatter formatter : FORMATTERS) {
try {
if (timestampStr.contains("T") && timestampStr.contains("Z")) {
return Instant.parse(timestampStr);
}
else {
LocalDateTime localDateTime = LocalDateTime.parse(timestampStr, formatter);
return localDateTime.atZone(zoneId).toInstant();
}
}
catch (DateTimeParseException ignored) {
}
}
}

throw new IllegalArgumentException("Unable to parse timestamp: " + timestampStr);
}

if (value instanceof Number) {
return Instant.ofEpochMilli(((Number) value).longValue());
}

throw new IllegalArgumentException("Cannot convert " + value.getClass().getName() + " to Timestamp");
}

@Override
public void setNullable(boolean isNullable) {
this.isNullable = isNullable;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ public void testGetTypeFunction() {
assertTypeHandler("Nullable(Float64)", Float64Handler.class, true);
assertTypeHandler("String", StringHandler.class, false);
assertTypeHandler("Nullable(String)", StringHandler.class, true);
assertTypeHandler("Date", StringHandler.class, false);
assertTypeHandler("Nullable(Date)", StringHandler.class, true);
assertTypeHandler("DateTime", StringHandler.class, false);
assertTypeHandler("Nullable(DateTime)", StringHandler.class, true);
assertTypeHandler("DateTime64", StringHandler.class, false);
assertTypeHandler("Nullable(DateTime64)", StringHandler.class, true);
assertTypeHandler("Timestamp", StringHandler.class, false);
assertTypeHandler("Nullable(Timestamp)", StringHandler.class, true);
assertTypeHandler("Date", DateHandler.class, false);
assertTypeHandler("Nullable(Date)", DateHandler.class, true);
assertTypeHandler("DateTime", TimestampHandler.class, false);
assertTypeHandler("Nullable(DateTime)", TimestampHandler.class, true);
assertTypeHandler("DateTime64", TimestampHandler.class, false);
assertTypeHandler("Nullable(DateTime64)", TimestampHandler.class, true);
assertTypeHandler("Timestamp", TimestampHandler.class, false);
assertTypeHandler("Nullable(Timestamp)", TimestampHandler.class, true);
assertTypeHandler("Array(String)", StringHandler.class, false);
assertTypeHandler("Nullable(Array(Int32))", StringHandler.class, true);
assertTypeHandler("Struct", StringHandler.class, false);
Expand Down
2 changes: 1 addition & 1 deletion databend-jdbc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.6</version>
<version>2.0.16</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
Expand Down
Loading