/* * 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.sqlobject; import org.jdbi.v3.core.rule.H2DatabaseRule; import org.jdbi.v3.core.statement.StatementContext; import org.jdbi.v3.core.statement.TimingCollector; import org.jdbi.v3.core.mapper.RowMapper; import org.jdbi.v3.sqlobject.config.RegisterRowMapper; import org.jdbi.v3.sqlobject.customizer.Bind; import org.jdbi.v3.sqlobject.customizer.BindBean; import org.jdbi.v3.sqlobject.customizer.Timestamped; import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys; import org.jdbi.v3.sqlobject.statement.SqlQuery; import org.jdbi.v3.sqlobject.statement.SqlUpdate; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.time.LocalDateTime; import static org.assertj.core.api.Assertions.assertThat; /** * Tests for the {@link Timestamped} annotation */ public class TestTimestamped { public PersonDAO personDAO; @Rule public H2DatabaseRule dbRule = new H2DatabaseRule(); @Before public void beforeEach() { dbRule.getJdbi().installPlugin(new SqlObjectPlugin()); personDAO = dbRule.getJdbi().onDemand(PersonDAO.class); personDAO.createTable(); } @Test public void shouldInsertCreatedAndModifiedFields() { // This is one way we can get the binding information of the executed query dbRule.getJdbi().setTimingCollector((l, statementContext) -> { assertThat(statementContext.getBinding().findForName("now")).isPresent(); }); Person p = new Person("John", "Phiri"); p.setId(1); personDAO.insert(p); // Clear the timing colletor dbRule.getJdbi().setTimingCollector(TimingCollector.NOP_TIMING_COLLECTOR); Person found = personDAO.get(1); assertThat(found.getCreated()).isNotNull(); assertThat(found.getModified()).isNotNull(); } @Test public void shouldAllowCustomTimestampParameter() { LocalDateTime timeBefore = LocalDateTime.now().minusMinutes(1); Person p = new Person("John", "Phiri"); p.setId(1); dbRule.getJdbi().setTimingCollector((l, statementContext) -> { assertThat(statementContext.getBinding().findForName("createdAt")).isPresent(); }); personDAO.insertWithCustomTimestampFields(p); dbRule.getJdbi().setTimingCollector(TimingCollector.NOP_TIMING_COLLECTOR); Person fetched = personDAO.get(1); assertThat(p.getFirstName()).isEqualTo(fetched.getFirstName()); assertThat(p.getLastName()).isEqualTo(fetched.getLastName()); assertThat(fetched.getCreated()).isNotNull(); assertThat(fetched.getModified()).isNotNull(); assertThat(fetched.getCreated()).isEqualTo(fetched.getModified()); assertThat(timeBefore).isBefore(fetched.getCreated().toLocalDateTime()); } @Test public void shouldUpdateModifiedTimestamp() { Person p = new Person("John", "Phiri"); p.setId(3); dbRule.getJdbi().setTimingCollector((l, statementContext) -> { assertThat(statementContext.getBinding().findForName("now")).isPresent(); }); personDAO.insert(p); dbRule.getJdbi().setTimingCollector(TimingCollector.NOP_TIMING_COLLECTOR); Person personAfterCreate = personDAO.get(3); personAfterCreate.setLastName("Banda"); personDAO.updatePerson(personAfterCreate); Person personAfterUpdate = personDAO.get(3); assertThat(personAfterUpdate.getLastName()).isEqualToIgnoringCase("Banda"); assertThat(personAfterUpdate.getCreated()).isEqualTo(personAfterCreate.getCreated()); assertThat(personAfterUpdate.getModified()).isAfter(personAfterCreate.getModified()); } @RegisterRowMapper(PersonRowMapper.class) public interface PersonDAO { @SqlUpdate("CREATE TABLE people(id identity primary key, firstName varchar(50), lastName varchar(50), created timestamp, modified timestamp);") void createTable(); @GetGeneratedKeys @SqlUpdate("INSERT INTO people(id, firstName, lastName, created, modified) VALUES (:p.id, :p.firstName, :p.lastName, :now, :now)") @Timestamped int insert(@BindBean("p") Person person); @SqlUpdate("INSERT INTO people(id, firstName, lastName, created, modified) VALUES (:p.id, :p.firstName, :p.lastName, :createdAt, :createdAt)") @Timestamped("createdAt") int insertWithCustomTimestampFields(@BindBean("p") Person person); @SqlUpdate("UPDATE people SET firstName = :p.firstName, lastName = :p.lastName, modified = :now WHERE id = :p.id") @Timestamped int updatePerson(@BindBean("p") Person person); @SqlQuery("SELECT id, firstName, lastName, created, modified from people WHERE id=:id") Person get(@Bind("id") int id); } public final static class PersonRowMapper implements RowMapper<Person> { @Override public Person map(ResultSet resultSet, StatementContext statementContext) throws SQLException { Person person = new Person(resultSet.getString("firstName"), resultSet.getString("lastName")); person.setId(resultSet.getInt("id")); person.setCreated(resultSet.getTimestamp("created")); person.setModified(resultSet.getTimestamp("modified")); return person; } } /** * Person JavaBean for tests */ public final static class Person { private int id; private String firstName; private String lastName; private Timestamp created; private Timestamp modified; public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Timestamp getCreated() { return created; } public void setCreated(Timestamp created) { this.created = created; } public Timestamp getModified() { return modified; } public void setModified(Timestamp modified) { this.modified = modified; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; if (id != person.id) return false; if (!firstName.equals(person.firstName)) return false; return lastName != null ? lastName.equals(person.lastName) : person.lastName== null; } @Override public int hashCode() { int result = id; result = 31 * result + firstName.hashCode(); result = 31 * result + lastName.hashCode(); result = 31 * result + (created != null ? created.hashCode() : 0); result = 31 * result + (modified != null ? modified.hashCode() : 0); return result; } } }