Merge pull request #3286 from ebean-orm/feature/dbarray-instant-and-localdate

Add support for LocalDate and Instant with DbArray
This commit is contained in:
Rob Bygrave
2023-12-07 08:57:40 +13:00
committed by GitHub
5 changed files with 97 additions and 2 deletions
@@ -1,9 +1,12 @@
package io.ebeaninternal.server.type;
import io.ebean.core.type.ScalarType;
import io.ebean.core.type.BasicTypeConverter;
import io.ebean.core.type.ScalarType;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.util.UUID;
/**
@@ -32,6 +35,8 @@ interface ArrayElementConverter<T> {
ArrayElementConverter<Double> DOUBLE = new DoubleConverter();
ArrayElementConverter<Float> FLOAT = new FloatConverter();
ArrayElementConverter<BigDecimal> BIG_DECIMAL = new BigDecimalConverter();
ArrayElementConverter<Instant> INSTANT = new InstantConverter();
ArrayElementConverter<LocalDate> LOCAL_DATE = new LocalDateConverter();
class LongConverter implements ArrayElementConverter<Long> {
@@ -101,6 +106,48 @@ interface ArrayElementConverter<T> {
}
}
class InstantConverter implements ArrayElementConverter<Instant> {
@Override
public Instant fromSerialized(Object rawValue) {
return fromDbArray(rawValue);
}
@Override
public Instant fromDbArray(Object rawValue) {
if (rawValue instanceof Instant) {
return (Instant) rawValue;
} else if (rawValue instanceof Timestamp) {
return ((Timestamp) rawValue).toInstant();
} else if (rawValue instanceof String) {
return Instant.parse((String) rawValue);
} else {
throw new IllegalStateException("Instant fromDbArray unsupported for " + rawValue);
}
}
}
class LocalDateConverter implements ArrayElementConverter<LocalDate> {
@Override
public LocalDate fromSerialized(Object rawValue) {
return fromDbArray(rawValue);
}
@Override
public LocalDate fromDbArray(Object rawValue) {
if (rawValue instanceof LocalDate) {
return (LocalDate) rawValue;
} else if (rawValue instanceof java.sql.Date) {
return ((java.sql.Date) rawValue).toLocalDate();
} else if (rawValue instanceof String) {
return LocalDate.parse((String) rawValue);
} else {
throw new IllegalStateException("Instant fromDbArray unsupported for " + rawValue);
}
}
}
class BigDecimalConverter implements ArrayElementConverter<BigDecimal> {
@Override
@@ -141,7 +188,7 @@ interface ArrayElementConverter<T> {
@Override
public java.util.UUID fromSerialized(Object rawValue) {
return java.util.UUID.fromString((String)rawValue);
return java.util.UUID.fromString((String) rawValue);
}
@Override
@@ -16,6 +16,8 @@ import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
@@ -63,6 +65,12 @@ class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements ScalarTyp
if (valueType.equals(String.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
}
if (valueType.equals(Instant.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "timestamptz", DocPropertyType.TEXT, ArrayElementConverter.INSTANT));
}
if (valueType.equals(LocalDate.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "date", DocPropertyType.TEXT, ArrayElementConverter.LOCAL_DATE));
}
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
} finally {
lock.unlock();
@@ -8,6 +8,8 @@ import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -58,6 +60,12 @@ final class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
if (valueType.equals(String.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
}
if (valueType.equals(Instant.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "timestamp", DocPropertyType.TEXT, ArrayElementConverter.INSTANT));
}
if (valueType.equals(LocalDate.class)) {
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "date", DocPropertyType.TEXT, ArrayElementConverter.LOCAL_DATE));
}
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
} finally {
lock.unlock();
@@ -9,6 +9,8 @@ import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Version;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -58,6 +60,12 @@ public class EArrayBean {
@DbArray
Set<Status> status2;
@DbArray
List<Instant> times;
@DbArray
List<LocalDate> dates;
@Version
Long version;
@@ -165,6 +173,24 @@ public class EArrayBean {
this.status2 = status2;
}
public List<Instant> getTimes() {
return times;
}
public EArrayBean setTimes(List<Instant> times) {
this.times = times;
return this;
}
public List<LocalDate> getDates() {
return dates;
}
public EArrayBean setDates(List<LocalDate> dates) {
this.dates = dates;
return this;
}
public Long getVersion() {
return version;
}
@@ -10,6 +10,8 @@ import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.time.Instant;
import java.time.LocalDate;
import java.util.*;
import static org.assertj.core.api.Assertions.assertThat;
@@ -58,6 +60,8 @@ class TestDbArray_basic extends BaseTestCase {
bean.setStatus2(new LinkedHashSet<>());
bean.getStatus2().add(EArrayBean.Status.TWO);
bean.getStatus2().add(EArrayBean.Status.ONE);
bean.setTimes(List.of(Instant.now(), Instant.now().minusSeconds(60)));
bean.setDates(List.of(LocalDate.now(), LocalDate.now().minusDays(1)));
DB.save(bean);
@@ -66,6 +70,8 @@ class TestDbArray_basic extends BaseTestCase {
assertThat(found.getPhoneNumbers()).containsExactly("4321", "9823");
assertThat(found.getDoubs()).hasSize(2);
assertThat(found.getFloats()).hasSize(2);
assertThat(found.getTimes()).hasSize(2);
assertThat(found.getDates()).hasSize(2);
if (isPostgresCompatible()) {
Query<EArrayBean> query = DB.find(EArrayBean.class)