Skip to content

Commit a3de428

Browse files
feat: full support datetime, date, timestamp types (#158)
1 parent 5c36542 commit a3de428

File tree

14 files changed

+336
-65
lines changed

14 files changed

+336
-65
lines changed

hibernate-dialect/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.0.0 ##
2+
3+
- Fixed: data time type converters
4+
15
## 0.9.5 ##
26

37
- Added query hint for view index for "select * from ... where" queries

hibernate-dialect/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>tech.ydb.dialects</groupId>
88
<artifactId>hibernate-ydb-dialect</artifactId>
9-
<version>0.9.5</version>
9+
<version>1.0.0</version>
1010

1111
<packaging>jar</packaging>
1212

@@ -42,7 +42,7 @@
4242
<log4j2.version>2.17.2</log4j2.version>
4343

4444
<ydb.sdk.version>2.2.6</ydb.sdk.version>
45-
<ydb.jdbc.version>2.1.5</ydb.jdbc.version>
45+
<ydb.jdbc.version>2.2.4</ydb.jdbc.version>
4646
</properties>
4747

4848
<licenses>

hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/YdbDialect.java

+23-3
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,27 @@
4343
import static org.hibernate.type.SqlTypes.NVARCHAR;
4444
import static org.hibernate.type.SqlTypes.REAL;
4545
import static org.hibernate.type.SqlTypes.SMALLINT;
46-
import static org.hibernate.type.SqlTypes.TIME;
4746
import static org.hibernate.type.SqlTypes.TIMESTAMP;
47+
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
4848
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
4949
import static org.hibernate.type.SqlTypes.TIME_WITH_TIMEZONE;
5050
import static org.hibernate.type.SqlTypes.TINYINT;
5151
import static org.hibernate.type.SqlTypes.VARBINARY;
5252
import static org.hibernate.type.SqlTypes.VARCHAR;
5353
import org.hibernate.type.StandardBasicTypes;
54+
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
55+
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
5456
import tech.ydb.hibernate.dialect.exporter.EmptyExporter;
5557
import tech.ydb.hibernate.dialect.exporter.YdbIndexExporter;
5658
import tech.ydb.hibernate.dialect.hint.IndexQueryHintHandler;
5759
import tech.ydb.hibernate.dialect.translator.YdbSqlAstTranslatorFactory;
60+
import tech.ydb.hibernate.dialect.types.InstantJavaType;
61+
import tech.ydb.hibernate.dialect.types.InstantJdbcType;
62+
import tech.ydb.hibernate.dialect.types.LocalDateJavaType;
63+
import tech.ydb.hibernate.dialect.types.LocalDateJdbcType;
5864
import tech.ydb.hibernate.dialect.types.LocalDateTimeJavaType;
5965
import tech.ydb.hibernate.dialect.types.LocalDateTimeJdbcType;
66+
import static tech.ydb.hibernate.dialect.types.LocalDateTimeJdbcType.JDBC_TYPE_DATETIME_CODE;
6067

6168
/**
6269
* @author Kirill Kurdyukov
@@ -82,9 +89,9 @@ protected String columnType(int sqlTypeCode) {
8289
case DOUBLE -> "Double";
8390
case NUMERIC, DECIMAL -> "Decimal (22,9)"; // Fixed
8491
case DATE -> "Date";
85-
case TIME -> "Datetime";
92+
case JDBC_TYPE_DATETIME_CODE -> "Datetime";
8693
case TIME_WITH_TIMEZONE -> "TzDateTime";
87-
case TIMESTAMP -> "Timestamp";
94+
case TIMESTAMP, TIMESTAMP_UTC -> "Timestamp";
8895
case TIMESTAMP_WITH_TIMEZONE -> "TzTimestamp";
8996
case CHAR, VARCHAR, CLOB, NCHAR, NVARCHAR, NCLOB,
9097
LONG32VARCHAR, LONG32NVARCHAR, LONGVARCHAR, LONGNVARCHAR -> "Text";
@@ -100,6 +107,19 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
100107

101108
typeContributions.contributeJavaType(LocalDateTimeJavaType.INSTANCE);
102109
typeContributions.contributeJdbcType(LocalDateTimeJdbcType.INSTANCE);
110+
typeContributions.contributeJavaType(LocalDateJavaType.INSTANCE);
111+
typeContributions.contributeJdbcType(LocalDateJdbcType.INSTANCE);
112+
typeContributions.contributeJavaType(InstantJavaType.INSTANCE);
113+
typeContributions.contributeJdbcType(InstantJdbcType.INSTANCE);
114+
}
115+
116+
@Override
117+
protected void registerColumnTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
118+
super.registerColumnTypes(typeContributions, serviceRegistry);
119+
120+
final DdlTypeRegistry ddlTypeRegistry = typeContributions.getTypeConfiguration().getDdlTypeRegistry();
121+
122+
ddlTypeRegistry.addDescriptor(new DdlTypeImpl(JDBC_TYPE_DATETIME_CODE, "Datetime", "Datetime", this));
103123
}
104124

105125
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package tech.ydb.hibernate.dialect.types;
2+
3+
import org.hibernate.type.descriptor.jdbc.JdbcType;
4+
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
5+
6+
/**
7+
* @author Kirill Kurdyukov
8+
*/
9+
public class InstantJavaType extends org.hibernate.type.descriptor.java.InstantJavaType {
10+
11+
public static final InstantJavaType INSTANCE = new InstantJavaType();
12+
13+
@Override
14+
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
15+
return InstantJdbcType.INSTANCE;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package tech.ydb.hibernate.dialect.types;
2+
3+
import java.sql.CallableStatement;
4+
import java.sql.PreparedStatement;
5+
import java.sql.ResultSet;
6+
import java.sql.SQLException;
7+
import java.sql.Types;
8+
import java.time.Instant;
9+
import org.hibernate.type.descriptor.ValueBinder;
10+
import org.hibernate.type.descriptor.ValueExtractor;
11+
import org.hibernate.type.descriptor.WrapperOptions;
12+
import org.hibernate.type.descriptor.java.JavaType;
13+
import org.hibernate.type.descriptor.jdbc.BasicBinder;
14+
import org.hibernate.type.descriptor.jdbc.TimestampUtcAsJdbcTimestampJdbcType;
15+
16+
/**
17+
* @author Kirill Kurdyukov
18+
*/
19+
public class InstantJdbcType extends TimestampUtcAsJdbcTimestampJdbcType {
20+
21+
public static final InstantJdbcType INSTANCE = new InstantJdbcType();
22+
23+
@Override
24+
public <X> ValueBinder<X> getBinder(final JavaType<X> javaType) {
25+
return new BasicBinder<>(javaType, this) {
26+
@Override
27+
protected void doBind(
28+
PreparedStatement st,
29+
X value,
30+
int index,
31+
WrapperOptions wrapperOptions) throws SQLException {
32+
final Instant instant = javaType.unwrap(value, Instant.class, wrapperOptions);
33+
34+
st.setObject(index, instant, Types.TIMESTAMP);
35+
}
36+
37+
@Override
38+
protected void doBind(
39+
CallableStatement st,
40+
X value,
41+
String name,
42+
WrapperOptions wrapperOptions)
43+
throws SQLException {
44+
final Instant instant = javaType.unwrap(value, Instant.class, wrapperOptions);
45+
46+
st.setObject(name, instant, Types.TIMESTAMP);
47+
}
48+
};
49+
}
50+
51+
@Override
52+
public <X> ValueExtractor<X> getExtractor(final JavaType<X> javaType) {
53+
return new ValueExtractor<>() {
54+
@Override
55+
public X extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
56+
return javaType.wrap(rs.getObject(paramIndex), options);
57+
}
58+
59+
@Override
60+
public X extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException {
61+
return javaType.wrap(statement.getObject(paramIndex), options);
62+
}
63+
64+
@Override
65+
public X extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException {
66+
return javaType.wrap(statement.getObject(paramName), options);
67+
}
68+
};
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package tech.ydb.hibernate.dialect.types;
2+
3+
import org.hibernate.type.descriptor.jdbc.JdbcType;
4+
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
5+
6+
/**
7+
* @author Kirill Kurdyukov
8+
*/
9+
public class LocalDateJavaType extends org.hibernate.type.descriptor.java.LocalDateJavaType {
10+
11+
public static final LocalDateJavaType INSTANCE = new LocalDateJavaType();
12+
13+
@Override
14+
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
15+
return LocalDateJdbcType.INSTANCE;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package tech.ydb.hibernate.dialect.types;
2+
3+
import java.sql.CallableStatement;
4+
import java.sql.PreparedStatement;
5+
import java.sql.ResultSet;
6+
import java.sql.SQLException;
7+
import java.sql.Types;
8+
import java.time.LocalDate;
9+
import org.hibernate.type.descriptor.ValueBinder;
10+
import org.hibernate.type.descriptor.ValueExtractor;
11+
import org.hibernate.type.descriptor.WrapperOptions;
12+
import org.hibernate.type.descriptor.java.JavaType;
13+
import org.hibernate.type.descriptor.jdbc.BasicBinder;
14+
import org.hibernate.type.descriptor.jdbc.DateJdbcType;
15+
import org.hibernate.type.spi.TypeConfiguration;
16+
17+
/**
18+
* @author Kirill Kurdyukov
19+
*/
20+
public class LocalDateJdbcType extends DateJdbcType {
21+
22+
public static final LocalDateJdbcType INSTANCE = new LocalDateJdbcType();
23+
24+
@Override
25+
public Class<?> getPreferredJavaTypeClass(WrapperOptions options) {
26+
return LocalDate.class;
27+
}
28+
29+
@Override
30+
public <T> JavaType<T> getJdbcRecommendedJavaTypeMapping(Integer length, Integer scale,
31+
TypeConfiguration typeConfiguration) {
32+
return typeConfiguration.getJavaTypeRegistry().getDescriptor(LocalDate.class);
33+
}
34+
35+
@Override
36+
public <X> ValueBinder<X> getBinder(final JavaType<X> javaType) {
37+
return new BasicBinder<>(javaType, this) {
38+
@Override
39+
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
40+
final LocalDate date = javaType.unwrap(value, LocalDate.class, options);
41+
42+
st.setObject(index, date, Types.DATE);
43+
}
44+
45+
@Override
46+
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
47+
throws SQLException {
48+
final LocalDate date = javaType.unwrap(value, LocalDate.class, options);
49+
50+
st.setObject(name, date, Types.DATE);
51+
}
52+
};
53+
}
54+
55+
@Override
56+
public <X> ValueExtractor<X> getExtractor(final JavaType<X> javaType) {
57+
return new ValueExtractor<>() {
58+
@Override
59+
public X extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
60+
return javaType.wrap(rs.getObject(paramIndex), options);
61+
}
62+
63+
@Override
64+
public X extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException {
65+
return javaType.wrap(statement.getObject(paramIndex), options);
66+
}
67+
68+
@Override
69+
public X extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException {
70+
return javaType.wrap(statement.getObject(paramName), options);
71+
}
72+
};
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package tech.ydb.hibernate.dialect.types;
22

3-
import jakarta.persistence.TemporalType;
4-
import java.sql.Types;
5-
import org.hibernate.type.descriptor.java.TemporalJavaType;
63
import org.hibernate.type.descriptor.jdbc.JdbcType;
74
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
8-
import org.hibernate.type.spi.TypeConfiguration;
95

106
/**
117
* @author Kirill Kurdyukov
@@ -14,25 +10,8 @@ public class LocalDateTimeJavaType extends org.hibernate.type.descriptor.java.Lo
1410

1511
public static final LocalDateTimeJavaType INSTANCE = new LocalDateTimeJavaType();
1612

17-
@Override
18-
public TemporalType getPrecision() {
19-
return TemporalType.TIME;
20-
}
21-
2213
@Override
2314
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
24-
return context.getJdbcType(Types.TIME);
25-
}
26-
27-
@Override
28-
@SuppressWarnings("unchecked")
29-
protected <X> TemporalJavaType<X> forTimePrecision(TypeConfiguration typeConfiguration) {
30-
return (TemporalJavaType<X>) this;
31-
}
32-
33-
protected <X> TemporalJavaType<X> forTimestampPrecision(TypeConfiguration typeConfiguration) {
34-
throw new UnsupportedOperationException(
35-
this + " as `jakarta.persistence.TemporalType.TIMESTAMP` not supported"
36-
);
15+
return LocalDateTimeJdbcType.INSTANCE;
3716
}
3817
}

0 commit comments

Comments
 (0)