/*
* 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 org.jdbi.v3.postgres;
import com.google.common.collect.ImmutableList;
import org.jdbi.v3.core.Handle;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import java.time.Duration;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class TestDuration {
@ClassRule
public static PostgresDbRule postgresDbRule = new PostgresDbRule();
private Handle handle;
private final Duration testDuration = Duration.ofDays(39).plusHours(23).plusMinutes(59).plusSeconds(1);
@Before
public void setUp() throws Exception {
handle = postgresDbRule.getSharedHandle();
handle.useTransaction(h -> {
h.execute("drop table if exists intervals");
h.execute("create table intervals(id int not null, foo interval)");
// Can be durations.
h.execute("insert into intervals(id, foo) values(1, interval '1 day 15:00:00')");
h.execute("insert into intervals(id, foo) values(2, interval '40 days 22 minutes')");
// Can't be.
h.execute("insert into intervals(id, foo) values(3, interval '10 years -3 months 100 seconds')");
});
}
@Test
public void testReadsViaFluentAPI() {
List<Duration> periods = handle.createQuery("select foo from intervals where id = 1 or id = 2 order by id")
.mapTo(Duration.class)
.list();
assertThat(periods).isEqualTo(ImmutableList.of(
Duration.ofDays(1).plusHours(15),
Duration.ofDays(40).plusMinutes(22)
));
}
@Test
public void testTrivialDuration() {
handle.execute("insert into intervals(id, foo) values(?, ?)", 4, Duration.ZERO);
Duration d = handle.createQuery("select foo from intervals where id=?")
.bind(0, 4)
.mapTo(Duration.class)
.findOnly();
assertThat(d.isZero());
}
@Test
public void testHandlesNulls() {
handle.execute("insert into intervals(id, foo) values(?, ?)", 5, null);
final Duration d = handle.createQuery("select foo from intervals where id=?")
.bind(0, 5)
.mapTo(Duration.class)
.findOnly();
assertThat(d).isNull();
}
@Test
public void testWritesViaFluentApi() {
handle.execute("insert into intervals(id, foo) values(?, ?)", 6, testDuration);
final Duration d = handle.createQuery("select foo from intervals where id=?")
.bind(0, 6)
.mapTo(Duration.class)
.findOnly();
assertThat(d).isEqualTo(testDuration);
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidDuration() {
handle.createQuery("select foo from intervals where id=?")
.bind(0, 3) // The bad one.
.mapTo(Duration.class)
.findOnly();
}
@Test
public void testReadNegativeDuration() {
handle.execute("insert into intervals(id, foo) values(?, interval '-2 days -3 hours')", 7);
final Duration d = handle.createQuery("select foo from intervals where id=?")
.bind(0, 7)
.mapTo(Duration.class)
.findOnly();
assertThat(d).isEqualTo(Duration.ofDays(-2).plusHours(-3));
}
@Test
public void testWriteReadNegativeDuration() {
handle.execute("insert into intervals(id, foo) values(?, ?)",
8, Duration.ofDays(-3).plusMinutes(2));
final Duration d = handle.createQuery("select foo from intervals where id=?")
.bind(0, 8)
.mapTo(Duration.class)
.findOnly();
assertThat(d).isEqualTo(Duration.ofDays(-3).plusMinutes(2));
}
@Test(expected = IllegalArgumentException.class)
public void testWriteDurationTooBig() {
handle.execute("insert into intervals(id, foo) values(?, ?)",
9, Duration.ofDays((long)Integer.MAX_VALUE + 1));
}
/**
* This is admittedly a test of an implementation detail, but this detail is documented in
* {@link DurationArgumentFactory}, so this test failing is a good signal to update the documentation there.
*/
@Test(expected = ArithmeticException.class)
public void testWriteDurationTooSmall() {
handle.execute("insert into intervals(id, foo) values(?, ?)",
10, Duration.ofSeconds(Long.MIN_VALUE));
}
@Test
public void testTinyDuration() {
handle.execute("insert into intervals(id, foo) values(?, interval '13us')", 11);
final Duration d = handle.createQuery("select foo from intervals where id=?")
.bind(0, 11)
.mapTo(Duration.class)
.findOnly();
assertThat(d).isEqualTo(Duration.ofNanos(13_000));
}
@Test(expected = IllegalArgumentException.class)
public void testDurationTooPrecise() {
handle.execute("insert into intervals(id, foo) values(?, ?)",
12, Duration.ofNanos(100));
}
// We guard against reading intervals with seconds too big or too small (i.e., more extreme than Long minimum and
// maximum values), but it's unclear how to actually create such intervals in Postgres.
}