-
Notifications
You must be signed in to change notification settings - Fork 369
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for mapping the Java Period object to a PostgreSQL interv…
…al type #128 In PostgreSQL, an interval may comprise years, months, days, hours, minutes and seconds. In Java, an interval is distinguished between a temporal interval (Duration) and a quantity in terms of days, months and years (Period). For example `age(timestamp, timestamp)` returns an interval between two timestamps in days, months and years. The result of this function should as such be mapped to a Java Period instead of an Duration. On the contrary, `timestamp - timestamp` returns an interval between two timestamps in days, hours, minutes and seconds, for which the existing Duration-based type is appropiate.
- Loading branch information
1 parent
956747d
commit 589e08d
Showing
3 changed files
with
124 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
...types-52/src/main/java/com/vladmihalcea/hibernate/type/interval/PostgreSQLPeriodType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Period> { | ||
|
||
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}; | ||
} | ||
|
||
} |
59 changes: 59 additions & 0 deletions
59
...s-52/src/test/java/com/vladmihalcea/hibernate/type/interval/PostgreSQLPeriodTypeTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} | ||
} |