diff --git a/pom.xml b/pom.xml index 8e42a49..dabea04 100644 --- a/pom.xml +++ b/pom.xml @@ -10,15 +10,15 @@ 4.0.0 - pom - com.rbkmoney.db.common.lib + jar + db-common-lib 0.0.1-SNAPSHOT - - UTF-8 + 3.11.5 + 0.6.9 @@ -31,4 +31,25 @@ + + + org.springframework.boot + spring-boot-starter-jdbc + 1.5.10.RELEASE + provided + + + org.jooq + jooq + ${jooq.version} + provided + + + com.rbkmoney.geck + common + ${geck.common.version} + provided + + + diff --git a/src/main/java/com/rbkmoney/dao/DaoException.java b/src/main/java/com/rbkmoney/dao/DaoException.java new file mode 100644 index 0000000..702fc46 --- /dev/null +++ b/src/main/java/com/rbkmoney/dao/DaoException.java @@ -0,0 +1,24 @@ +package com.rbkmoney.dao; + +public class DaoException extends Exception { + + public DaoException() { + } + + public DaoException(String message) { + super(message); + } + + public DaoException(String message, Throwable cause) { + super(message, cause); + } + + public DaoException(Throwable cause) { + super(cause); + } + + public DaoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/src/main/java/com/rbkmoney/dao/GenericDao.java b/src/main/java/com/rbkmoney/dao/GenericDao.java new file mode 100644 index 0000000..3284e7e --- /dev/null +++ b/src/main/java/com/rbkmoney/dao/GenericDao.java @@ -0,0 +1,69 @@ +package com.rbkmoney.dao; + +import org.jooq.Query; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.springframework.jdbc.support.KeyHolder; + +import java.util.List; + +public interface GenericDao { + + T fetchOne(Query query, Class type) throws DaoException; + + T fetchOne(Query query, Class type, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException; + + T fetchOne(Query query, RowMapper rowMapper) throws DaoException; + + T fetchOne(String namedSql, SqlParameterSource parameterSource, RowMapper rowMapper) throws DaoException; + + T fetchOne(Query query, RowMapper rowMapper, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException; + + T fetchOne(String namedSql, SqlParameterSource parameterSource, RowMapper rowMapper, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException; + + List fetch(Query query, RowMapper rowMapper) throws DaoException; + + List fetch(String namedSql, SqlParameterSource parameterSource, RowMapper rowMapper) throws DaoException; + + List fetch(Query query, RowMapper rowMapper, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException; + + List fetch(String namedSql, SqlParameterSource parameterSource, RowMapper rowMapper, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException; + + void executeOne(Query query) throws DaoException; + + void executeOne(String namedSql, SqlParameterSource parameterSource) throws DaoException; + + void executeOne(Query query, KeyHolder keyHolder) throws DaoException; + + void executeOne(String namedSql, SqlParameterSource parameterSource, KeyHolder keyHolder) throws DaoException; + + int execute(Query query) throws DaoException; + + int execute(Query query, int expectedRowsAffected) throws DaoException; + + int execute(Query query, int expectedRowsAffected, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException; + + int execute(String namedSql) throws DaoException; + + int execute(String namedSql, SqlParameterSource parameterSource) throws DaoException; + + int execute(String namedSql, SqlParameterSource parameterSource, int expectedRowsAffected) throws DaoException; + + int execute(String namedSql, SqlParameterSource parameterSource, int expectedRowsAffected, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException; + + int execute(Query query, KeyHolder keyHolder) throws DaoException; + + int execute(Query query, int expectedRowsAffected, KeyHolder keyHolder) throws DaoException; + + int execute(Query query, int expectedRowsAffected, NamedParameterJdbcTemplate namedParameterJdbcTemplate, KeyHolder keyHolder) throws DaoException; + + int execute(String namedSql, KeyHolder keyHolder) throws DaoException; + + int execute(String namedSql, SqlParameterSource parameterSource, KeyHolder keyHolder) throws DaoException; + + int execute(String namedSql, SqlParameterSource parameterSource, int expectedRowsAffected, KeyHolder keyHolder) throws DaoException; + + int execute(String namedSql, SqlParameterSource parameterSource, int expectedRowsAffected, NamedParameterJdbcTemplate namedParameterJdbcTemplate, KeyHolder keyHolder) throws DaoException; + +} diff --git a/src/main/java/com/rbkmoney/dao/impl/AbstractGenericDao.java b/src/main/java/com/rbkmoney/dao/impl/AbstractGenericDao.java new file mode 100644 index 0000000..4ea99c3 --- /dev/null +++ b/src/main/java/com/rbkmoney/dao/impl/AbstractGenericDao.java @@ -0,0 +1,247 @@ +package com.rbkmoney.dao.impl; + +import com.rbkmoney.dao.DaoException; +import com.rbkmoney.dao.GenericDao; +import org.jooq.*; +import org.jooq.conf.ParamType; +import org.jooq.impl.DSL; +import org.jooq.impl.DefaultConfiguration; +import org.springframework.core.NestedRuntimeException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.SingleColumnRowMapper; +import org.springframework.jdbc.core.namedparam.*; +import org.springframework.jdbc.support.KeyHolder; + +import javax.sql.DataSource; +import java.sql.Types; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public abstract class AbstractGenericDao extends NamedParameterJdbcDaoSupport implements GenericDao { + + private final DSLContext dslContext; + + public AbstractGenericDao(DataSource dataSource) { + setDataSource(dataSource); + Configuration configuration = new DefaultConfiguration(); + configuration.set(SQLDialect.POSTGRES); + this.dslContext = DSL.using(configuration); + } + + protected DSLContext getDslContext() { + return dslContext; + } + + @Override + public T fetchOne(Query query, Class type) throws DaoException { + return fetchOne(query, type, getNamedParameterJdbcTemplate()); + } + + @Override + public T fetchOne(Query query, Class type, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException { + return fetchOne(query, new SingleColumnRowMapper<>(type), namedParameterJdbcTemplate); + } + + @Override + public T fetchOne(Query query, RowMapper rowMapper) throws DaoException { + return fetchOne(query, rowMapper, getNamedParameterJdbcTemplate()); + } + + @Override + public T fetchOne(String namedSql, SqlParameterSource parameterSource, RowMapper rowMapper) throws DaoException { + return fetchOne(namedSql, parameterSource, rowMapper, getNamedParameterJdbcTemplate()); + } + + @Override + public T fetchOne(Query query, RowMapper rowMapper, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException { + return fetchOne(query.getSQL(ParamType.NAMED), toSqlParameterSource(query.getParams()), rowMapper, namedParameterJdbcTemplate); + } + + @Override + public T fetchOne(String namedSql, SqlParameterSource parameterSource, RowMapper rowMapper, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException { + try { + return namedParameterJdbcTemplate.queryForObject( + namedSql, + parameterSource, + rowMapper + ); + } catch (EmptyResultDataAccessException ex) { + return null; + } catch (NestedRuntimeException ex) { + throw new DaoException(ex); + } + } + + @Override + public List fetch(Query query, RowMapper rowMapper) throws DaoException { + return fetch(query, rowMapper, getNamedParameterJdbcTemplate()); + } + + @Override + public List fetch(String namedSql, SqlParameterSource parameterSource, RowMapper rowMapper) throws DaoException { + return fetch(namedSql, parameterSource, rowMapper, getNamedParameterJdbcTemplate()); + } + + @Override + public List fetch(Query query, RowMapper rowMapper, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException { + return fetch(query.getSQL(ParamType.NAMED), toSqlParameterSource(query.getParams()), rowMapper, namedParameterJdbcTemplate); + } + + @Override + public List fetch(String namedSql, SqlParameterSource parameterSource, RowMapper rowMapper, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException { + try { + return namedParameterJdbcTemplate.query( + namedSql, + parameterSource, + rowMapper + ); + } catch (NestedRuntimeException e) { + throw new DaoException(e); + } + } + + @Override + public void executeOne(Query query) throws DaoException { + execute(query, 1); + } + + @Override + public void executeOne(String namedSql, SqlParameterSource parameterSource) throws DaoException { + execute(namedSql, parameterSource, 1); + } + + @Override + public void executeOne(Query query, KeyHolder keyHolder) throws DaoException { + executeOne(query.getSQL(ParamType.NAMED), toSqlParameterSource(query.getParams()), keyHolder); + } + + @Override + public void executeOne(String namedSql, SqlParameterSource parameterSource, KeyHolder keyHolder) throws DaoException { + execute(namedSql, parameterSource, 1, keyHolder); + } + + @Override + public int execute(Query query) throws DaoException { + return execute(query, -1); + } + + @Override + public int execute(Query query, int expectedRowsAffected) throws DaoException { + return execute(query, expectedRowsAffected, getNamedParameterJdbcTemplate()); + } + + @Override + public int execute(Query query, int expectedRowsAffected, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException { + return execute(query.getSQL(ParamType.NAMED), toSqlParameterSource(query.getParams()), expectedRowsAffected, namedParameterJdbcTemplate); + } + + @Override + public int execute(String namedSql) throws DaoException { + return execute(namedSql, EmptySqlParameterSource.INSTANCE); + } + + @Override + public int execute(String namedSql, SqlParameterSource parameterSource) throws DaoException { + return execute(namedSql, parameterSource, -1); + } + + @Override + public int execute(String namedSql, SqlParameterSource parameterSource, int expectedRowsAffected) throws DaoException { + return execute(namedSql, parameterSource, expectedRowsAffected, getNamedParameterJdbcTemplate()); + } + + @Override + public int execute(String namedSql, SqlParameterSource parameterSource, int expectedRowsAffected, NamedParameterJdbcTemplate namedParameterJdbcTemplate) throws DaoException { + try { + int rowsAffected = namedParameterJdbcTemplate.update( + namedSql, + parameterSource); + + if (expectedRowsAffected != -1 && rowsAffected != expectedRowsAffected) { + throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(namedSql, expectedRowsAffected, rowsAffected); + } + return rowsAffected; + } catch (NestedRuntimeException ex) { + throw new DaoException(ex); + } + } + + @Override + public int execute(Query query, KeyHolder keyHolder) throws DaoException { + return execute(query.getSQL(ParamType.NAMED), toSqlParameterSource(query.getParams()), -1, keyHolder); + } + + @Override + public int execute(Query query, int expectedRowsAffected, KeyHolder keyHolder) throws DaoException { + return execute(query.getSQL(ParamType.NAMED), toSqlParameterSource(query.getParams()), expectedRowsAffected, getNamedParameterJdbcTemplate(), keyHolder); + } + + @Override + public int execute(Query query, int expectedRowsAffected, NamedParameterJdbcTemplate namedParameterJdbcTemplate, KeyHolder keyHolder) throws DaoException { + return execute(query.getSQL(ParamType.NAMED), toSqlParameterSource(query.getParams()), expectedRowsAffected, namedParameterJdbcTemplate, keyHolder); + } + + @Override + public int execute(String namedSql, KeyHolder keyHolder) throws DaoException { + return execute(namedSql, EmptySqlParameterSource.INSTANCE, keyHolder); + } + + @Override + public int execute(String namedSql, SqlParameterSource parameterSource, KeyHolder keyHolder) throws DaoException { + return execute(namedSql, parameterSource, -1, keyHolder); + } + + @Override + public int execute(String namedSql, SqlParameterSource parameterSource, int expectedRowsAffected, KeyHolder keyHolder) throws DaoException { + return execute(namedSql, parameterSource, expectedRowsAffected, getNamedParameterJdbcTemplate(), keyHolder); + } + + @Override + public int execute(String namedSql, SqlParameterSource parameterSource, int expectedRowsAffected, NamedParameterJdbcTemplate namedParameterJdbcTemplate, KeyHolder keyHolder) throws DaoException { + try { + int rowsAffected = namedParameterJdbcTemplate.update( + namedSql, + parameterSource, + keyHolder); + + if (expectedRowsAffected != -1 && rowsAffected != expectedRowsAffected) { + throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(namedSql, expectedRowsAffected, rowsAffected); + } + return rowsAffected; + } catch (NestedRuntimeException ex) { + throw new DaoException(ex); + } + } + + protected Condition appendDateTimeRangeConditions(Condition condition, + Field field, + Optional fromTime, + Optional toTime) { + if (fromTime.isPresent()) { + condition = condition.and(field.ge(fromTime.get())); + } + + if (toTime.isPresent()) { + condition = condition.and(field.lt(toTime.get())); + } + return condition; + } + + protected SqlParameterSource toSqlParameterSource(Map> params) { + MapSqlParameterSource sqlParameterSource = new MapSqlParameterSource(); + for (Map.Entry> entry : params.entrySet()) { + Param param = entry.getValue(); + if (param.getValue() instanceof LocalDateTime || param.getValue() instanceof EnumType) { + sqlParameterSource.addValue(entry.getKey(), param.getValue(), Types.OTHER); + } else { + sqlParameterSource.addValue(entry.getKey(), param.getValue()); + } + } + return sqlParameterSource; + } + +} diff --git a/src/main/java/com/rbkmoney/mapper/RecordRowMapper.java b/src/main/java/com/rbkmoney/mapper/RecordRowMapper.java new file mode 100644 index 0000000..913b746 --- /dev/null +++ b/src/main/java/com/rbkmoney/mapper/RecordRowMapper.java @@ -0,0 +1,52 @@ +package com.rbkmoney.mapper; + +import com.rbkmoney.geck.common.util.TypeUtil; +import org.jooq.Field; +import org.jooq.Table; +import org.jooq.TableRecord; +import org.jooq.impl.TableRecordImpl; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +public class RecordRowMapper implements RowMapper { + + private final Table table; + + private final Class type; + + public RecordRowMapper(Table table, Class type) { + this.table = table; + this.type = type; + } + + @Override + public T mapRow(ResultSet resultSet, int i) throws SQLException { + ResultSetMetaData rsMetaData = resultSet.getMetaData(); + int columnCount = rsMetaData.getColumnCount(); + + TableRecord record = new TableRecordImpl(table); + for (int column = 1; column <= columnCount; column++) { + String columnName = rsMetaData.getColumnName(column); + Field field = record.field(columnName); + + Object value = getFieldValue(field, resultSet); + if (!resultSet.wasNull()) { + record.set(field, value); + } + } + return record.into(type); + } + + private Object getFieldValue(Field field, ResultSet resultSet) throws SQLException { + if (field.getDataType().isBinary()) { + return resultSet.getBytes(field.getName()); + } + if (field.getType().isEnum()) { + return TypeUtil.toEnumField(resultSet.getString(field.getName()), field.getType()); + } + return resultSet.getObject(field.getName(), field.getType()); + } +}