diff --git a/changelog.txt b/changelog.txt index ff4abe26c..17e4fa260 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,8 @@ Version 2.7.0 - IN PROGRESS Add support for JSON column values for Oracle #131 +Add support for mapping the Java Period object to a PostgreSQL interval type #128 + Add YearMonthTimestampType #127 Ability to use PostgreSQLEnumType and EnumArrayType with TypedParameterValue #125 diff --git a/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/interval/PostgreSQLPeriodType.java b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/interval/PostgreSQLPeriodType.java new file mode 100644 index 000000000..fa1dbf089 --- /dev/null +++ b/hibernate-types-52/src/main/java/com/vladmihalcea/hibernate/type/interval/PostgreSQLPeriodType.java @@ -0,0 +1,63 @@ +package com.vladmihalcea.hibernate.type.interval; + +import com.vladmihalcea.hibernate.type.ImmutableType; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.postgresql.util.PGInterval; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.time.Duration; +import java.time.Period; + +/** + * Maps a Java {@link Duration} object to a PostgreSQL Interval column type. + * + * @author Jan-Willem Gmelig Meyling + * @author Vlad Mihalcea + * @since 2.6.2 + */ +public class PostgreSQLPeriodType extends ImmutableType { + + public static final PostgreSQLPeriodType INSTANCE = new PostgreSQLPeriodType(); + + public PostgreSQLPeriodType() { + super(Period.class); + } + + @Override + protected Period get(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { + final PGInterval interval = (PGInterval) rs.getObject(names[0]); + + if (interval == null) { + return null; + } + + final int years = interval.getYears(); + final int months = interval.getMonths(); + final int days = interval.getDays(); + + return Period.ofYears(years) + .plusMonths(months) + .plusDays(days); + } + + @Override + protected void set(PreparedStatement st, Period value, int index, SharedSessionContractImplementor session) throws SQLException { + if (value == null) { + st.setNull(index, Types.OTHER); + } else { + final int days = value.getDays(); + final int months = value.getMonths(); + final int years = value.getYears(); + st.setObject(index, new PGInterval(years, months, days, 0, 0, 0)); + } + } + + @Override + public int[] sqlTypes() { + return new int[]{Types.OTHER}; + } + +} diff --git a/hibernate-types-52/src/test/java/com/vladmihalcea/hibernate/type/interval/PostgreSQLPeriodTypeTest.java b/hibernate-types-52/src/test/java/com/vladmihalcea/hibernate/type/interval/PostgreSQLPeriodTypeTest.java new file mode 100644 index 000000000..8e6ae1344 --- /dev/null +++ b/hibernate-types-52/src/test/java/com/vladmihalcea/hibernate/type/interval/PostgreSQLPeriodTypeTest.java @@ -0,0 +1,59 @@ +package com.vladmihalcea.hibernate.type.interval; + +import com.vladmihalcea.hibernate.type.model.BaseEntity; +import com.vladmihalcea.hibernate.type.util.AbstractPostgreSQLIntegrationTest; +import org.hibernate.annotations.TypeDef; +import org.junit.Test; + +import javax.persistence.Column; +import javax.persistence.Entity; +import java.time.Period; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for {@see PostgreSQLIntervalType} Hibernate type. + * + * @author Jan-Willem Gmelig Meyling + */ +public class PostgreSQLPeriodTypeTest extends AbstractPostgreSQLIntegrationTest { + + @Override + protected Class[] entities() { + return new Class[]{WorkShift.class}; + } + + @Test + public void test() { + Period duration = Period.of(1, 2, 3); + + doInJPA(entityManager -> { + WorkShift intervalEntity = new WorkShift(); + intervalEntity.setId(1L); + intervalEntity.setDuration(duration); + + entityManager.persist(intervalEntity); + }); + + doInJPA(entityManager -> { + WorkShift result = entityManager.find(WorkShift.class, 1L); + assertEquals(duration, result.getDuration()); + }); + } + + @Entity(name = "WorkShift") + @TypeDef(typeClass = PostgreSQLPeriodType.class, defaultForType = Period.class) + public static class WorkShift extends BaseEntity { + + @Column(columnDefinition = "interval") + private Period duration; + + public Period getDuration() { + return duration; + } + + public void setDuration(Period duration) { + this.duration = duration; + } + } +}