diff --git a/src/main/java/jp/co/future/uroborosql/AbstractAgent.java b/src/main/java/jp/co/future/uroborosql/AbstractAgent.java index 83569696..cb5e7dd4 100644 --- a/src/main/java/jp/co/future/uroborosql/AbstractAgent.java +++ b/src/main/java/jp/co/future/uroborosql/AbstractAgent.java @@ -21,6 +21,10 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import jp.co.future.uroborosql.config.SqlConfig; import jp.co.future.uroborosql.context.SqlContext; import jp.co.future.uroborosql.coverage.CoverageData; @@ -47,10 +51,6 @@ import jp.co.future.uroborosql.utils.CaseFormat; import jp.co.future.uroborosql.utils.StringFunction; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * SqlAgentの抽象親クラス * @@ -294,7 +294,8 @@ protected void transformContext(final SqlContext sqlContext, final boolean isQue } LOG.trace("Template SQL[{}{}{}]", System.lineSeparator(), originalSql, System.lineSeparator()); - LOG.debug("Executed SQL[{}{}{}]", System.lineSeparator(), sqlContext.getExecutableSql(), System.lineSeparator()); + LOG.debug("Executed SQL[{}{}{}]", System.lineSeparator(), sqlContext.getExecutableSql(), + System.lineSeparator()); } /** @@ -609,9 +610,9 @@ public SqlEntityQuery query(final Class entityType) { try { TableMetadata metadata = handler.getMetadata(this.transactionManager, entityType); - SqlContext context = handler.createSelectContext(this, metadata, entityType); + SqlContext context = handler.createSelectContext(this, metadata, entityType, false); - return new SqlEntityQueryImpl<>(this, handler, context, entityType); + return new SqlEntityQueryImpl<>(this, handler, metadata, context, entityType); } catch (SQLException e) { throw new EntitySqlRuntimeException(EntitySqlRuntimeException.EntityProcKind.SELECT, e); } diff --git a/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java b/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java index 8748cfa5..eb6d1d04 100644 --- a/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java +++ b/src/main/java/jp/co/future/uroborosql/SqlAgentImpl.java @@ -25,6 +25,11 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; +import org.apache.commons.lang3.time.StopWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + import jp.co.future.uroborosql.config.SqlConfig; import jp.co.future.uroborosql.context.SqlContext; import jp.co.future.uroborosql.context.SqlContextImpl; @@ -39,11 +44,6 @@ import jp.co.future.uroborosql.parameter.Parameter; import jp.co.future.uroborosql.utils.CaseFormat; -import org.apache.commons.lang3.time.StopWatch; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - /** * SQL実行用クラス。 * @@ -118,7 +118,8 @@ public ResultSet query(final SqlContext sqlContext) throws SQLException { if (maxRetryCount > 0 && getSqlConfig().getDialect().isRollbackToSavepointBeforeRetry()) { setSavepoint(RETRY_SAVEPOINT_NAME); } - rs = new InnerResultSet(getSqlFilterManager().doQuery(sqlContext, stmt, stmt.executeQuery()), stmt); + rs = new InnerResultSet(getSqlFilterManager().doQuery(sqlContext, stmt, stmt.executeQuery()), + stmt); stmt.closeOnCompletion(); return rs; } catch (SQLException ex) { @@ -154,7 +155,7 @@ public ResultSet query(final SqlContext sqlContext) throws SQLException { } } while (maxRetryCount > loopCount++); } catch (SQLException | RuntimeException e) { - if(rs != null && !rs.isClosed()) { + if (rs != null && !rs.isClosed()) { rs.close(); } throw e; @@ -571,15 +572,15 @@ protected void handleException(final SqlContext sqlContext, final SQLException e if (LOG.isErrorEnabled() && isOutputExceptionLog()) { StringBuilder builder = new StringBuilder(); builder.append(System.lineSeparator()).append("Exception occurred in SQL execution.") - .append(System.lineSeparator()); + .append(System.lineSeparator()); builder.append("Executed SQL[").append(sqlContext.getExecutableSql()).append("]") - .append(System.lineSeparator()); + .append(System.lineSeparator()); if (sqlContext instanceof SqlContextImpl) { Parameter[] bindParameters = ((SqlContextImpl) sqlContext).getBindParameters(); for (int i = 0; i < bindParameters.length; i++) { Parameter parameter = getSqlFilterManager().doParameter(bindParameters[i]); builder.append("Bind Parameter.[INDEX[").append(i + 1).append("], ").append(parameter.toString()) - .append("]").append(System.lineSeparator()); + .append("]").append(System.lineSeparator()); } } LOG.error(builder.toString(), cause); @@ -631,7 +632,7 @@ public Optional find(final Class entityType, final Object... params.put(keyNames[i], keys[i]); } - SqlContext context = handler.createSelectContext(this, metadata, entityType); + SqlContext context = handler.createSelectContext(this, metadata, entityType, true); context.paramMap(params); try (Stream stream = handler.doSelect(this, context, entityType)) { @@ -684,7 +685,7 @@ public int update(final Object entity) { try { Class type = entity.getClass(); TableMetadata metadata = handler.getMetadata(this.transactionManager, type); - SqlContext context = handler.createUpdateContext(this, metadata, type); + SqlContext context = handler.createUpdateContext(this, metadata, type, true); handler.setUpdateParams(context, entity); int count = handler.doUpdate(this, context, entity); @@ -714,7 +715,7 @@ public int delete(final Object entity) { try { Class type = entity.getClass(); TableMetadata metadata = handler.getMetadata(this.transactionManager, type); - SqlContext context = handler.createDeleteContext(this, metadata, type); + SqlContext context = handler.createDeleteContext(this, metadata, type, true); handler.setDeleteParams(context, entity); return handler.doDelete(this, context, entity); } catch (SQLException e) { @@ -873,7 +874,7 @@ public boolean tryAdvance(final Consumer action) { */ private static class InnerResultSet extends AbstractResultSetWrapper { /** 同期してクローズするStatement */ - private Statement stmt; + private final Statement stmt; /** * コンストラクタ diff --git a/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java b/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java index bb5299e3..0868071a 100644 --- a/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java +++ b/src/main/java/jp/co/future/uroborosql/SqlEntityQueryImpl.java @@ -7,16 +7,24 @@ package jp.co.future.uroborosql; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import jp.co.future.uroborosql.context.SqlContext; +import jp.co.future.uroborosql.dialect.Dialect; import jp.co.future.uroborosql.exception.EntitySqlRuntimeException; import jp.co.future.uroborosql.exception.EntitySqlRuntimeException.EntityProcKind; +import jp.co.future.uroborosql.exception.UroborosqlRuntimeException; import jp.co.future.uroborosql.fluent.SqlEntityQuery; import jp.co.future.uroborosql.mapping.EntityHandler; +import jp.co.future.uroborosql.mapping.TableMetadata; +import jp.co.future.uroborosql.parameter.Parameter; +import jp.co.future.uroborosql.utils.CaseFormat; /** * SqlEntityQuery実装 @@ -26,21 +34,35 @@ */ final class SqlEntityQueryImpl extends AbstractSqlFluent> implements SqlEntityQuery { private final EntityHandler entityHandler; + private final TableMetadata tableMetadata; private final Class entityType; + private CharSequence rawString; + private List orderByColumns; + private boolean ascendingOrder; + private long limit; + private long offset; /** - * コンストラクタ + * Constructor * * @param agent SqlAgent * @param entityHandler EntityHandler + * @param tableMetadata TableMetadata * @param context SqlContext * @param entityType エンティティタイプ */ - SqlEntityQueryImpl(final SqlAgent agent, final EntityHandler entityHandler, final SqlContext context, + SqlEntityQueryImpl(final SqlAgent agent, final EntityHandler entityHandler, final TableMetadata tableMetadata, + final SqlContext context, final Class entityType) { super(agent, context); this.entityHandler = entityHandler; + this.tableMetadata = tableMetadata; this.entityType = entityType; + this.rawString = null; + this.orderByColumns = null; + this.ascendingOrder = true; + this.limit = -1; + this.offset = -1; } /** @@ -75,11 +97,1002 @@ public Optional first() { @Override public Stream stream() { try { - return this.entityHandler.doSelect(agent(), context(), entityType); - } catch (SQLException e) { + StringBuilder sql = new StringBuilder(context().getSql()).append(whereAndOrderClause()); + Dialect dialect = agent().getSqlConfig().getDialect(); + if (dialect.supportsLimitClause()) { + sql.append(dialect.getLimitClause(this.limit, this.offset)); + } + + context().setSql(sql.toString()); + return this.entityHandler.doSelect(agent(), context(), this.entityType); + } catch (final SQLException e) { throw new EntitySqlRuntimeException(EntityProcKind.SELECT, e); } } + /** + * SELECT文のWHERE句とORDER BY句を生成する + * + * @return WHERE句とORDER BY句の文字列 + */ + @SuppressWarnings("unchecked") + private String whereAndOrderClause() { + final List columns = this.tableMetadata.getColumns(); + + StringBuilder where = new StringBuilder(); + for (final TableMetadata.Column col : columns) { + final String camelColName = col.getCamelColumnName(); + + Parameter param = context().getParam(camelColName); + if (param != null) { + if (param.getValue() instanceof Operator) { + Operator ope = (Operator) param.getValue(); + where.append("\t").append("AND ").append(col.getColumnIdentifier()) + .append(ope.toConditionString()).append(System.lineSeparator()); + } else { + where.append("\t").append("AND ").append(col.getColumnIdentifier()) + .append(" = ").append("/*").append(camelColName).append("*/''") + .append(System.lineSeparator()); + } + } + } + if (rawString != null) { + where.append(rawString).append(System.lineSeparator()); + } + + StringBuilder sql = new StringBuilder(); + if (where.length() > 0) { + sql.append("WHERE").append(System.lineSeparator()).append(where.toString()); + } + + boolean firstFlag = true; + List keys; + if (this.orderByColumns == null || this.orderByColumns.isEmpty()) { + // ソート条件の指定がない場合は主キーでソートする + keys = (List) this.tableMetadata.getKeyColumns(); + } else { + // ソート条件の指定がある場合は指定されたカラムでソートする + keys = new ArrayList<>(); + for (String col : orderByColumns) { + String snakeCol = CaseFormat.UPPER_SNAKE_CASE.convert(col); + for (TableMetadata.Column metaCol : columns) { + if (snakeCol.equalsIgnoreCase(metaCol.getColumnName())) { + keys.add(metaCol); + break; + } + } + } + } + + if (!keys.isEmpty()) { + sql.append("ORDER BY").append(System.lineSeparator()); + firstFlag = true; + for (final TableMetadata.Column col : keys) { + sql.append("\t"); + if (firstFlag) { + sql.append(" "); + firstFlag = false; + } else { + sql.append(", "); + } + sql.append(col.getColumnIdentifier()).append(System.lineSeparator()); + } + sql.append(this.ascendingOrder ? "ASC" : "DESC").append(System.lineSeparator()); + } + + return sql.toString(); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#equal(java.lang.String, java.lang.Object) + */ + @Override + public SqlEntityQuery equal(final String col, final Object value) { + context().param(col, new Equal(col, value)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#notEqual(java.lang.String, java.lang.Object) + */ + @Override + public SqlEntityQuery notEqual(final String col, final Object value) { + context().param(col, new NotEqual(col, value)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#greaterThan(java.lang.String, java.lang.Object) + */ + @Override + public SqlEntityQuery greaterThan(final String col, final Object value) { + context().param(col, new GreaterThan(col, value)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#lessThan(java.lang.String, java.lang.Object) + */ + @Override + public SqlEntityQuery lessThan(final String col, final Object value) { + context().param(col, new LessThan(col, value)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#greaterEqual(java.lang.String, java.lang.Object) + */ + @Override + public SqlEntityQuery greaterEqual(final String col, final Object value) { + context().param(col, new GreaterEqual(col, value)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#lessEqual(java.lang.String, java.lang.Object) + */ + @Override + public SqlEntityQuery lessEqual(final String col, final Object value) { + context().param(col, new LessEqual(col, value)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#in(java.lang.String, java.lang.Object[]) + */ + @Override + public SqlEntityQuery in(final String col, final Object... values) { + context().param(col, new In(col, values)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#in(java.lang.String, java.lang.Iterable) + */ + @Override + public SqlEntityQuery in(final String col, final Iterable valueList) { + context().param(col, new In(col, valueList)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#notIn(java.lang.String, java.lang.Object[]) + */ + @Override + public SqlEntityQuery notIn(final String col, final Object... values) { + context().param(col, new NotIn(col, values)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#notIn(java.lang.String, java.lang.Iterable) + */ + @Override + public SqlEntityQuery notIn(final String col, final Iterable valueList) { + context().param(col, new NotIn(col, valueList)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#like(java.lang.String, java.lang.CharSequence) + */ + @Override + public SqlEntityQuery like(final String col, final CharSequence searchValue) { + context().param(col, new Like(col, searchValue)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#startsWith(java.lang.String, java.lang.CharSequence) + */ + @Override + public SqlEntityQuery startsWith(final String col, final CharSequence searchValue) { + String escaped = agent().getSqlConfig().getDialect().escapeLikePattern(searchValue); + context().param(col, new Like(col, escaped, true)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#endsWith(java.lang.String, java.lang.CharSequence) + */ + @Override + public SqlEntityQuery endsWith(final String col, final CharSequence searchValue) { + String escaped = agent().getSqlConfig().getDialect().escapeLikePattern(searchValue); + context().param(col, new Like(col, true, escaped)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#contains(java.lang.String, java.lang.CharSequence) + */ + @Override + public SqlEntityQuery contains(final String col, final CharSequence searchValue) { + String escaped = agent().getSqlConfig().getDialect().escapeLikePattern(searchValue); + context().param(col, new Like(col, true, escaped, true)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#notLike(java.lang.String, java.lang.CharSequence) + */ + @Override + public SqlEntityQuery notLike(final String col, final CharSequence searchValue) { + context().param(col, new NotLike(col, searchValue)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#notStartsWith(java.lang.String, java.lang.CharSequence) + */ + @Override + public SqlEntityQuery notStartsWith(final String col, final CharSequence searchValue) { + String escaped = agent().getSqlConfig().getDialect().escapeLikePattern(searchValue); + context().param(col, new NotLike(col, escaped, true)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#notEndsWith(java.lang.String, java.lang.CharSequence) + */ + @Override + public SqlEntityQuery notEndsWith(final String col, final CharSequence searchValue) { + String escaped = agent().getSqlConfig().getDialect().escapeLikePattern(searchValue); + context().param(col, new NotLike(col, true, escaped)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#notContains(java.lang.String, java.lang.CharSequence) + */ + @Override + public SqlEntityQuery notContains(final String col, final CharSequence searchValue) { + String escaped = agent().getSqlConfig().getDialect().escapeLikePattern(searchValue); + context().param(col, new NotLike(col, true, escaped, true)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#between(java.lang.String, java.lang.Object, java.lang.Object) + */ + @Override + public SqlEntityQuery between(final String col, final Object fromValue, final Object toValue) { + context().param(col, new Between(col, fromValue, toValue)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#isNull(java.lang.String) + */ + @Override + public SqlEntityQuery isNull(final String col) { + context().param(col, new IsNull(col)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#isNotNull(java.lang.String) + */ + @Override + public SqlEntityQuery isNotNull(final String col) { + context().param(col, new IsNotNull(col)); + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#where(java.lang.CharSequence) + */ + @Override + public SqlEntityQuery where(final CharSequence rawString) { + this.rawString = rawString; + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#orderByAsc(java.lang.String[]) + */ + @Override + public SqlEntityQuery orderByAsc(final String... cols) { + this.orderByColumns = Arrays.asList(cols); + this.ascendingOrder = true; + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#orderByDesc(java.lang.String[]) + */ + @Override + public SqlEntityQuery orderByDesc(final String... cols) { + this.orderByColumns = Arrays.asList(cols); + this.ascendingOrder = false; + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#limit(long) + */ + @Override + public SqlEntityQuery limit(final long limit) { + if (!agent().getSqlConfig().getDialect().supportsLimitClause()) { + throw new UroborosqlRuntimeException("Unsupported limit clause."); + } + this.limit = limit; + return this; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.fluent.SqlEntityQuery#offset(long) + */ + @Override + public SqlEntityQuery offset(final long offset) { + if (!agent().getSqlConfig().getDialect().supportsLimitClause()) { + throw new UroborosqlRuntimeException("Unsupported offset clause."); + } + this.offset = offset; + return this; + } + + /** + * 条件指定用のラップクラス + */ + public static abstract class Operator { + protected final String col; + + /** + * Constructor + * + * @param col バインドしたカラム名 + */ + public Operator(final String col) { + this.col = col; + } + + /** + * バインドしたカラム名の取得 + * + * @return カラム名 + */ + public String getCol() { + return col; + } + + /** + * オペレータを取得する + * + * @return オペレータ + */ + public abstract String getOperator(); + + /** + * 評価式に変換する + * + * @return 評価式 + */ + public String toConditionString() { + return " " + getOperator(); + } + + /** + * バインド変数文字列を生成する + * + * @param keyNames バインド変数名。複数指定した場合、"."区切りで結合する + * @return バインド変数文字列 + */ + protected String wrap(final String... keyNames) { + return "/*" + String.join(".", keyNames) + "*/"; + } + } + + /** + * 値を1つもつオペレータ + */ + public static abstract class SingleOperator extends Operator { + protected final Object value; + + /** + * Constructor + * @param col bind column name + * @param value 値 + */ + public SingleOperator(final String col, final Object value) { + super(col); + this.value = value; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getCol() + */ + @Override + public String getCol() { + return col; + } + + /** + * 値の取得 + * @return 値 + */ + public Object getValue() { + return value; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#toConditionString() + */ + @Override + public String toConditionString() { + return " " + getOperator() + " " + wrap(getCol(), "value"); + } + } + + /** + * Listを持つオペレータ + */ + public static abstract class ListOperator extends Operator { + protected final Iterable valueList; + + /** + * Constructor + * + * @param col bind column name + * @param valueList 値のリスト + */ + public ListOperator(final String col, final Iterable valueList) { + super(col); + this.valueList = valueList; + } + + /** + * Constructor + * + * @param col bind column name + * @param values 値の配列 + */ + public ListOperator(final String col, final Object... values) { + super(col); + valueList = Arrays.asList(values); + } + + /** + * 値のリストを取得する + * + * @return 値のリスト + */ + public Iterable getValueList() { + return valueList; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#toConditionString() + */ + @Override + public String toConditionString() { + return " " + getOperator() + " " + wrap(getCol(), "valueList") + "()"; + } + } + + /** + * Equal Operator + */ + public static class Equal extends SingleOperator { + /** + * Constructor + * + * @param col bind column name + * @param value 値 + */ + public Equal(final String col, final Object value) { + super(col, value); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "="; + } + } + + /** + * NotEqual Operator + */ + public static class NotEqual extends SingleOperator { + /** + * Constructor + * + * @param col bind column name + * @param value 値 + */ + public NotEqual(final String col, final Object value) { + super(col, value); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "!="; + } + } + + /** + * Greater Than Operator + */ + public static class GreaterThan extends SingleOperator { + /** + * Constructor + * + * @param col bind column name + * @param value 値 + */ + public GreaterThan(final String col, final Object value) { + super(col, value); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return ">"; + } + } + + /** + * Less Than Operator + */ + public static class LessThan extends SingleOperator { + /** + * Constructor + * + * @param col bind column name + * @param value 値 + */ + public LessThan(final String col, final Object value) { + super(col, value); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "<"; + } + } + + /** + * Greater Equal Operator + */ + public static class GreaterEqual extends SingleOperator { + /** + * Constructor + * + * @param col bind column name + * @param value 値 + */ + public GreaterEqual(final String col, final Object value) { + super(col, value); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return ">="; + } + } + + /** + * Less Than Operator + */ + public static class LessEqual extends SingleOperator { + /** + * Constructor + * + * @param col bind column name + * @param value 値 + */ + public LessEqual(final String col, final Object value) { + super(col, value); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "<="; + } + } + + /** + * In Operator + */ + public static class In extends ListOperator { + /** + * Constructor + * + * @param col bind column name + * @param valueList 値リスト + */ + public In(final String col, final Iterable valueList) { + super(col, valueList); + } + + /** + * Constructor + * + * @param col bind column name + * @param values 値の配列 + */ + public In(final String col, final Object... values) { + super(col, values); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "IN"; + } + } + + /** + * Not In Operator + */ + public static class NotIn extends In { + /** + * Constructor + * + * @param col bind column name + * @param valueList 値リスト + */ + public NotIn(final String col, final Iterable valueList) { + super(col, valueList); + } + + /** + * Constructor + * + * @param col bind column name + * @param values 値の配列 + */ + public NotIn(final String col, final Object... values) { + super(col, values); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.In#getOperator() + */ + @Override + public String getOperator() { + return "NOT IN"; + } + } + + /** + * Like Operator + */ + public static class Like extends SingleOperator { + protected boolean prefix; + protected boolean suffix; + + /** + * Constructor + * + * @param col bind column name + * @param value 値 + */ + public Like(final String col, final Object value) { + this(col, true, value, true); + } + + /** + * Constructor + * + * @param col bind column name + * @param prefix 前にワイルドカードを挿入するかどうか。trueの場合%を追加 + * @param value 値 + */ + public Like(final String col, final boolean prefix, final Object value) { + this(col, prefix, value, false); + } + + /** + * Constructor + * + * @param col bind column name + * @param value 値 + * @param prefix 後ろにワイルドカードを挿入するかどうか。trueの場合%を追加 + */ + public Like(final String col, final Object value, final boolean suffix) { + this(col, false, value, suffix); + } + + /** + * Constructor + * + * @param col bind column name + * @param prefix 前にワイルドカードを挿入するかどうか。trueの場合%を追加 + * @param value 値 + * @param prefix 後ろにワイルドカードを挿入するかどうか。trueの場合%を追加 + */ + public Like(final String col, final boolean prefix, final Object value, final boolean suffix) { + super(col, value); + this.prefix = prefix; + this.suffix = suffix; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.SingleOperator#getValue() + */ + @Override + public Object getValue() { + String searchValue = Objects.toString(super.getValue(), ""); + if (prefix) { + searchValue = "%" + searchValue; + } + if (suffix) { + searchValue = searchValue + "%"; + } + return searchValue; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "LIKE"; + } + } + + /** + * Not Like Operator + */ + public static class NotLike extends Like { + /** + * Constructor + * + * @param col bind column name + * @param value 値 + */ + public NotLike(final String col, final Object value) { + super(col, value); + } + + /** + * Constructor + * + * @param col bind column name + * @param prefix 前にワイルドカードを挿入するかどうか。trueの場合%を追加 + * @param value 値 + */ + public NotLike(final String col, final boolean prefix, final Object value) { + super(col, prefix, value); + } + + /** + * Constructor + * + * @param col bind column name + * @param value 値 + * @param prefix 後ろにワイルドカードを挿入するかどうか。trueの場合%を追加 + */ + public NotLike(final String col, final Object value, final boolean suffix) { + super(col, value, suffix); + } + + /** + * Constructor + * + * @param col bind column name + * @param prefix 前にワイルドカードを挿入するかどうか。trueの場合%を追加 + * @param value 値 + * @param prefix 後ろにワイルドカードを挿入するかどうか。trueの場合%を追加 + */ + public NotLike(final String col, final boolean prefix, final Object value, final boolean suffix) { + super(col, prefix, value, suffix); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Like#getOperator() + */ + @Override + public String getOperator() { + return "NOT LIKE"; + } + } + + /** + * Between Operator + */ + public static class Between extends Operator { + protected final Object from; + protected final Object to; + + /** + * Constructor + * + * @param col bind column name + * @param from from value + * @param to to value + */ + public Between(final String col, final Object from, final Object to) { + super(col); + this.from = from; + this.to = to; + } + + /** + * From値の取得 + * + * @return From値 + */ + public Object getFrom() { + return from; + } + + /** + * To値の取得 + * + * @return To値 + */ + public Object getTo() { + return to; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#toConditionString() + */ + @Override + public String toConditionString() { + return " " + getOperator() + " " + wrap(getCol(), "from") + " AND " + wrap(getCol(), "to"); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "BETWEEN"; + } + } + + /** + * IS NULL Operator + */ + public static class IsNull extends Operator { + /** + * Constructor + * + * @param col bind column name + */ + public IsNull(final String col) { + super(col); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "IS NULL"; + } + } + + /** + * IS NOT NULL Operator + */ + public static class IsNotNull extends Operator { + /** + * Constructor + * + * @param col bind column name + */ + public IsNotNull(final String col) { + super(col); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.SqlEntityQueryImpl.Operator#getOperator() + */ + @Override + public String getOperator() { + return "IS NOT NULL"; + } + } + } diff --git a/src/main/java/jp/co/future/uroborosql/client/SqlREPL.java b/src/main/java/jp/co/future/uroborosql/client/SqlREPL.java index 49b1de64..4223c751 100644 --- a/src/main/java/jp/co/future/uroborosql/client/SqlREPL.java +++ b/src/main/java/jp/co/future/uroborosql/client/SqlREPL.java @@ -14,7 +14,6 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -46,6 +45,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.commons.lang3.time.DateUtils; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; import jline.console.ConsoleReader; import jline.console.UserInterruptException; import jline.console.completer.CandidateListCompletionHandler; @@ -73,15 +80,6 @@ import ognl.Ognl; import ognl.OgnlException; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.math.NumberUtils; -import org.apache.commons.lang3.time.DateUtils; -import org.slf4j.LoggerFactory; - -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.Logger; - /** * SQL REPL実装クラス * @@ -600,7 +598,7 @@ private boolean commandExecute(final String line) throws Exception { if (parts.length < 3) { console.println(Command.GENERATE.toString() + " parameter missing. " + Command.GENERATE.toString() - + " [SQL_KEYWORD] [TABLE NAME]."); + + " [SQL_KEYWORD] [TABLE NAME]."); return true; } @@ -630,15 +628,15 @@ public String getName() { break; case "update": - ctx = config.getEntityHandler().createUpdateContext(agent, metadata, null); + ctx = config.getEntityHandler().createUpdateContext(agent, metadata, null, true); break; case "delete": - ctx = config.getEntityHandler().createDeleteContext(agent, metadata, null); + ctx = config.getEntityHandler().createDeleteContext(agent, metadata, null, true); break; default: - ctx = config.getEntityHandler().createSelectContext(agent, metadata, null); + ctx = config.getEntityHandler().createSelectContext(agent, metadata, null, true); break; } console.println(ctx.getSql()); @@ -898,7 +896,7 @@ private Set getSqlParams(final String sql) { ContextTransformer transformer = parser.parse(); Node rootNode = transformer.getRoot(); - Set params = new LinkedHashSet(); + Set params = new LinkedHashSet<>(); traverseNode(rootNode, params); params.removeIf(s -> CONSTANT_PAT.matcher(s).matches()); @@ -1000,7 +998,7 @@ private void showProps() throws IOException { * */ class SqlNameCompleter implements Completer { - private final SortedSet sqlNames = new TreeSet(); + private final SortedSet sqlNames = new TreeSet<>(); /** * コンストラクタ @@ -1030,9 +1028,9 @@ public int complete(final String buffer, final int cursor, final List keyword == null || c.startsWith(keyword.toLowerCase())).forEach(candidates::add); + .filter(c -> keyword == null || c.startsWith(keyword.toLowerCase())).forEach(candidates::add); // カーソルポジションの計算 int pos = 0; diff --git a/src/main/java/jp/co/future/uroborosql/connection/CloseIgnoringConnectionWrapper.java b/src/main/java/jp/co/future/uroborosql/connection/CloseIgnoringConnectionWrapper.java new file mode 100644 index 00000000..ad83334e --- /dev/null +++ b/src/main/java/jp/co/future/uroborosql/connection/CloseIgnoringConnectionWrapper.java @@ -0,0 +1,321 @@ +/** + * Copyright (c) 2017-present, Future Corporation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package jp.co.future.uroborosql.connection; + +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * Closeを無視するConnectionを提供するためのWrapper + * {@link DoNotCloseConnectionWrapper} の代わりにこちらを使用してください + * + * @author H.Sugimoto + */ +public class CloseIgnoringConnectionWrapper implements Connection { + private final Connection original; + + /** + * コンストラクタ + * + * @param original 元となるコネクション + */ + public CloseIgnoringConnectionWrapper(final Connection original) { + this.original = original; + } + + @Override + public Statement createStatement() throws SQLException { + return original.createStatement(); + } + + @Override + public PreparedStatement prepareStatement(final String sql) throws SQLException { + return original.prepareStatement(sql); + } + + @Override + public CallableStatement prepareCall(final String sql) throws SQLException { + return original.prepareCall(sql); + } + + @Override + public String nativeSQL(final String sql) throws SQLException { + return original.nativeSQL(sql); + } + + @Override + public void setAutoCommit(final boolean autoCommit) throws SQLException { + original.setAutoCommit(autoCommit); + } + + @Override + public boolean getAutoCommit() throws SQLException { + return original.getAutoCommit(); + } + + @Override + public void commit() throws SQLException { + original.commit(); + } + + @Override + public void rollback() throws SQLException { + original.rollback(); + } + + @Override + public void close() throws SQLException { + // do nothing + } + + @Override + public boolean isClosed() throws SQLException { + return original.isClosed(); + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + return original.getMetaData(); + } + + @Override + public void setReadOnly(final boolean readOnly) throws SQLException { + original.setReadOnly(readOnly); + } + + @Override + public boolean isReadOnly() throws SQLException { + return original.isReadOnly(); + } + + @Override + public void setCatalog(final String catalog) throws SQLException { + original.setCatalog(catalog); + } + + @Override + public String getCatalog() throws SQLException { + return original.getCatalog(); + } + + @Override + public void setTransactionIsolation(final int level) throws SQLException { + original.setTransactionIsolation(level); + } + + @Override + public int getTransactionIsolation() throws SQLException { + return original.getTransactionIsolation(); + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return original.getWarnings(); + } + + @Override + public void clearWarnings() throws SQLException { + original.clearWarnings(); + } + + @Override + public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException { + return original.createStatement(resultSetType, resultSetConcurrency); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) + throws SQLException { + return original.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + @Override + public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) + throws SQLException { + return original.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + @Override + public Map> getTypeMap() throws SQLException { + return original.getTypeMap(); + } + + @Override + public void setTypeMap(final Map> map) throws SQLException { + original.setTypeMap(map); + } + + @Override + public void setHoldability(final int holdability) throws SQLException { + original.setHoldability(holdability); + } + + @Override + public int getHoldability() throws SQLException { + return original.getHoldability(); + } + + @Override + public Savepoint setSavepoint() throws SQLException { + return original.setSavepoint(); + } + + @Override + public Savepoint setSavepoint(final String name) throws SQLException { + return original.setSavepoint(name); + } + + @Override + public void rollback(final Savepoint savepoint) throws SQLException { + original.rollback(savepoint); + } + + @Override + public void releaseSavepoint(final Savepoint savepoint) throws SQLException { + original.releaseSavepoint(savepoint); + } + + @Override + public Statement createStatement(final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) + throws SQLException { + return original.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) throws SQLException { + return original.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) throws SQLException { + return original.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { + return original.prepareStatement(sql, autoGeneratedKeys); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { + return original.prepareStatement(sql, columnIndexes); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { + return original.prepareStatement(sql, columnNames); + } + + @Override + public Clob createClob() throws SQLException { + return original.createClob(); + } + + @Override + public Blob createBlob() throws SQLException { + return original.createBlob(); + } + + @Override + public NClob createNClob() throws SQLException { + return original.createNClob(); + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return original.createSQLXML(); + } + + @Override + public boolean isValid(final int timeout) throws SQLException { + return original.isValid(timeout); + } + + @Override + public void setClientInfo(final String name, final String value) throws SQLClientInfoException { + original.setClientInfo(name, value); + } + + @Override + public void setClientInfo(final Properties properties) throws SQLClientInfoException { + original.setClientInfo(properties); + } + + @Override + public String getClientInfo(final String name) throws SQLException { + return original.getClientInfo(name); + } + + @Override + public Properties getClientInfo() throws SQLException { + return original.getClientInfo(); + } + + @Override + public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException { + return original.createArrayOf(typeName, elements); + } + + @Override + public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException { + return original.createStruct(typeName, attributes); + } + + @Override + public void setSchema(final String schema) throws SQLException { + original.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return original.getSchema(); + } + + @Override + public void abort(final Executor executor) throws SQLException { + original.abort(executor); + } + + @Override + public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException { + original.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return original.getNetworkTimeout(); + } + + @Override + public T unwrap(final Class iface) throws SQLException { + return original.unwrap(iface); + } + + @Override + public boolean isWrapperFor(final Class iface) throws SQLException { + return original.isWrapperFor(iface); + } +} diff --git a/src/main/java/jp/co/future/uroborosql/connection/ConnectionSupplier.java b/src/main/java/jp/co/future/uroborosql/connection/ConnectionSupplier.java index ed386b0e..f52c8527 100644 --- a/src/main/java/jp/co/future/uroborosql/connection/ConnectionSupplier.java +++ b/src/main/java/jp/co/future/uroborosql/connection/ConnectionSupplier.java @@ -42,7 +42,8 @@ default String getDatabaseName() { try { conn = getConnection(); DatabaseMetaData metaData = conn.getMetaData(); - return metaData.getDatabaseProductName() + "-" + metaData.getDatabaseProductVersion(); + return metaData.getDatabaseProductName() + "-" + metaData.getDatabaseMajorVersion() + "." + + metaData.getDatabaseMinorVersion(); } catch (SQLException ex) { throw new UroborosqlSQLException(ex); } finally { diff --git a/src/main/java/jp/co/future/uroborosql/connection/DefaultConnectionSupplierImpl.java b/src/main/java/jp/co/future/uroborosql/connection/DefaultConnectionSupplierImpl.java index 6580e718..a13c5826 100644 --- a/src/main/java/jp/co/future/uroborosql/connection/DefaultConnectionSupplierImpl.java +++ b/src/main/java/jp/co/future/uroborosql/connection/DefaultConnectionSupplierImpl.java @@ -6,7 +6,7 @@ */ package jp.co.future.uroborosql.connection; -import java.sql.*; +import java.sql.Connection; /** * デフォルトコネクション供給クラス
@@ -24,7 +24,7 @@ public class DefaultConnectionSupplierImpl implements ConnectionSupplier { * @param connection コネクション */ public DefaultConnectionSupplierImpl(final Connection connection) { - this.connection = new DoNotCloseConnectionWrapper(connection); + this.connection = new CloseIgnoringConnectionWrapper(connection); } /** diff --git a/src/main/java/jp/co/future/uroborosql/connection/DoNotCloseConnectionWrapper.java b/src/main/java/jp/co/future/uroborosql/connection/DoNotCloseConnectionWrapper.java index f43dc491..3b5af072 100644 --- a/src/main/java/jp/co/future/uroborosql/connection/DoNotCloseConnectionWrapper.java +++ b/src/main/java/jp/co/future/uroborosql/connection/DoNotCloseConnectionWrapper.java @@ -6,7 +6,21 @@ */ package jp.co.future.uroborosql.connection; -import java.sql.*; +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; @@ -15,286 +29,293 @@ * CloseしないConnectionを提供するためのWrapper * * @author H.Sugimoto + * @deprecated use {@link CloseIgnoringConnectionWrapper} */ +@Deprecated public class DoNotCloseConnectionWrapper implements Connection { - private final Connection original; - - /** - * コンストラクタ - * - * @param original 元となるコネクション - */ - public DoNotCloseConnectionWrapper(Connection original) { - this.original = original; - } - - @Override - public Statement createStatement() throws SQLException { - return original.createStatement(); - } - - @Override - public PreparedStatement prepareStatement(String sql) throws SQLException { - return original.prepareStatement(sql); - } - - @Override - public CallableStatement prepareCall(String sql) throws SQLException { - return original.prepareCall(sql); - } - - @Override - public String nativeSQL(String sql) throws SQLException { - return original.nativeSQL(sql); - } - - @Override - public void setAutoCommit(boolean autoCommit) throws SQLException { - original.setAutoCommit(autoCommit); - } - - @Override - public boolean getAutoCommit() throws SQLException { - return original.getAutoCommit(); - } - - @Override - public void commit() throws SQLException { - original.commit(); - } - - @Override - public void rollback() throws SQLException { - original.rollback(); - } - - @Override - public void close() throws SQLException { - // do nothing - } - - @Override - public boolean isClosed() throws SQLException { - return original.isClosed(); - } - - @Override - public DatabaseMetaData getMetaData() throws SQLException { - return original.getMetaData(); - } - - @Override - public void setReadOnly(boolean readOnly) throws SQLException { - original.setReadOnly(readOnly); - } - - @Override - public boolean isReadOnly() throws SQLException { - return original.isReadOnly(); - } - - @Override - public void setCatalog(String catalog) throws SQLException { - original.setCatalog(catalog); - } - - @Override - public String getCatalog() throws SQLException { - return original.getCatalog(); - } - - @Override - public void setTransactionIsolation(int level) throws SQLException { - original.setTransactionIsolation(level); - } - - @Override - public int getTransactionIsolation() throws SQLException { - return original.getTransactionIsolation(); - } - - @Override - public SQLWarning getWarnings() throws SQLException { - return original.getWarnings(); - } - - @Override - public void clearWarnings() throws SQLException { - original.clearWarnings(); - } - - @Override - public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { - return original.createStatement(resultSetType, resultSetConcurrency); - } - - @Override - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - return original.prepareStatement(sql, resultSetType, resultSetConcurrency); - } - - @Override - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - return original.prepareCall(sql, resultSetType, resultSetConcurrency); - } - - @Override - public Map> getTypeMap() throws SQLException { - return original.getTypeMap(); - } - - @Override - public void setTypeMap(Map> map) throws SQLException { - original.setTypeMap(map); - } - - @Override - public void setHoldability(int holdability) throws SQLException { - original.setHoldability(holdability); - } - - @Override - public int getHoldability() throws SQLException { - return original.getHoldability(); - } - - @Override - public Savepoint setSavepoint() throws SQLException { - return original.setSavepoint(); - } - - @Override - public Savepoint setSavepoint(String name) throws SQLException { - return original.setSavepoint(name); - } - - @Override - public void rollback(Savepoint savepoint) throws SQLException { - original.rollback(savepoint); - } - - @Override - public void releaseSavepoint(Savepoint savepoint) throws SQLException { - original.releaseSavepoint(savepoint); - } - - @Override - public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return original.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); - } - - @Override - public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return original.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); - } - - @Override - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - return original.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); - } - - @Override - public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { - return original.prepareStatement(sql, autoGeneratedKeys); - } - - @Override - public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - return original.prepareStatement(sql, columnIndexes); - } - - @Override - public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { - return original.prepareStatement(sql, columnNames); - } - - @Override - public Clob createClob() throws SQLException { - return original.createClob(); - } - - @Override - public Blob createBlob() throws SQLException { - return original.createBlob(); - } - - @Override - public NClob createNClob() throws SQLException { - return original.createNClob(); - } - - @Override - public SQLXML createSQLXML() throws SQLException { - return original.createSQLXML(); - } - - @Override - public boolean isValid(int timeout) throws SQLException { - return original.isValid(timeout); - } - - @Override - public void setClientInfo(String name, String value) throws SQLClientInfoException { - original.setClientInfo(name, value); - } - - @Override - public void setClientInfo(Properties properties) throws SQLClientInfoException { - original.setClientInfo(properties); - } - - @Override - public String getClientInfo(String name) throws SQLException { - return original.getClientInfo(name); - } - - @Override - public Properties getClientInfo() throws SQLException { - return original.getClientInfo(); - } - - @Override - public Array createArrayOf(String typeName, Object[] elements) throws SQLException { - return original.createArrayOf(typeName, elements); - } - - @Override - public Struct createStruct(String typeName, Object[] attributes) throws SQLException { - return original.createStruct(typeName, attributes); - } - - @Override - public void setSchema(String schema) throws SQLException { - original.setSchema(schema); - } - - @Override - public String getSchema() throws SQLException { - return original.getSchema(); - } - - @Override - public void abort(Executor executor) throws SQLException { - original.abort(executor); - } - - @Override - public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { - original.setNetworkTimeout(executor, milliseconds); - } - - @Override - public int getNetworkTimeout() throws SQLException { - return original.getNetworkTimeout(); - } - - @Override - public T unwrap(Class iface) throws SQLException { - return original.unwrap(iface); - } - - @Override - public boolean isWrapperFor(Class iface) throws SQLException { - return original.isWrapperFor(iface); - } + private final Connection original; + + /** + * コンストラクタ + * + * @param original 元となるコネクション + */ + public DoNotCloseConnectionWrapper(final Connection original) { + this.original = original; + } + + @Override + public Statement createStatement() throws SQLException { + return original.createStatement(); + } + + @Override + public PreparedStatement prepareStatement(final String sql) throws SQLException { + return original.prepareStatement(sql); + } + + @Override + public CallableStatement prepareCall(final String sql) throws SQLException { + return original.prepareCall(sql); + } + + @Override + public String nativeSQL(final String sql) throws SQLException { + return original.nativeSQL(sql); + } + + @Override + public void setAutoCommit(final boolean autoCommit) throws SQLException { + original.setAutoCommit(autoCommit); + } + + @Override + public boolean getAutoCommit() throws SQLException { + return original.getAutoCommit(); + } + + @Override + public void commit() throws SQLException { + original.commit(); + } + + @Override + public void rollback() throws SQLException { + original.rollback(); + } + + @Override + public void close() throws SQLException { + // do nothing + } + + @Override + public boolean isClosed() throws SQLException { + return original.isClosed(); + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + return original.getMetaData(); + } + + @Override + public void setReadOnly(final boolean readOnly) throws SQLException { + original.setReadOnly(readOnly); + } + + @Override + public boolean isReadOnly() throws SQLException { + return original.isReadOnly(); + } + + @Override + public void setCatalog(final String catalog) throws SQLException { + original.setCatalog(catalog); + } + + @Override + public String getCatalog() throws SQLException { + return original.getCatalog(); + } + + @Override + public void setTransactionIsolation(final int level) throws SQLException { + original.setTransactionIsolation(level); + } + + @Override + public int getTransactionIsolation() throws SQLException { + return original.getTransactionIsolation(); + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return original.getWarnings(); + } + + @Override + public void clearWarnings() throws SQLException { + original.clearWarnings(); + } + + @Override + public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException { + return original.createStatement(resultSetType, resultSetConcurrency); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) + throws SQLException { + return original.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + @Override + public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) + throws SQLException { + return original.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + @Override + public Map> getTypeMap() throws SQLException { + return original.getTypeMap(); + } + + @Override + public void setTypeMap(final Map> map) throws SQLException { + original.setTypeMap(map); + } + + @Override + public void setHoldability(final int holdability) throws SQLException { + original.setHoldability(holdability); + } + + @Override + public int getHoldability() throws SQLException { + return original.getHoldability(); + } + + @Override + public Savepoint setSavepoint() throws SQLException { + return original.setSavepoint(); + } + + @Override + public Savepoint setSavepoint(final String name) throws SQLException { + return original.setSavepoint(name); + } + + @Override + public void rollback(final Savepoint savepoint) throws SQLException { + original.rollback(savepoint); + } + + @Override + public void releaseSavepoint(final Savepoint savepoint) throws SQLException { + original.releaseSavepoint(savepoint); + } + + @Override + public Statement createStatement(final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) throws SQLException { + return original.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) throws SQLException { + return original.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) throws SQLException { + return original.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { + return original.prepareStatement(sql, autoGeneratedKeys); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { + return original.prepareStatement(sql, columnIndexes); + } + + @Override + public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { + return original.prepareStatement(sql, columnNames); + } + + @Override + public Clob createClob() throws SQLException { + return original.createClob(); + } + + @Override + public Blob createBlob() throws SQLException { + return original.createBlob(); + } + + @Override + public NClob createNClob() throws SQLException { + return original.createNClob(); + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return original.createSQLXML(); + } + + @Override + public boolean isValid(final int timeout) throws SQLException { + return original.isValid(timeout); + } + + @Override + public void setClientInfo(final String name, final String value) throws SQLClientInfoException { + original.setClientInfo(name, value); + } + + @Override + public void setClientInfo(final Properties properties) throws SQLClientInfoException { + original.setClientInfo(properties); + } + + @Override + public String getClientInfo(final String name) throws SQLException { + return original.getClientInfo(name); + } + + @Override + public Properties getClientInfo() throws SQLException { + return original.getClientInfo(); + } + + @Override + public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException { + return original.createArrayOf(typeName, elements); + } + + @Override + public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException { + return original.createStruct(typeName, attributes); + } + + @Override + public void setSchema(final String schema) throws SQLException { + original.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return original.getSchema(); + } + + @Override + public void abort(final Executor executor) throws SQLException { + original.abort(executor); + } + + @Override + public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException { + original.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return original.getNetworkTimeout(); + } + + @Override + public T unwrap(final Class iface) throws SQLException { + return original.unwrap(iface); + } + + @Override + public boolean isWrapperFor(final Class iface) throws SQLException { + return original.isWrapperFor(iface); + } } diff --git a/src/main/java/jp/co/future/uroborosql/dialect/AbstractDialect.java b/src/main/java/jp/co/future/uroborosql/dialect/AbstractDialect.java index 812a30d4..01839390 100644 --- a/src/main/java/jp/co/future/uroborosql/dialect/AbstractDialect.java +++ b/src/main/java/jp/co/future/uroborosql/dialect/AbstractDialect.java @@ -6,22 +6,87 @@ */ package jp.co.future.uroborosql.dialect; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Dialectの抽象親クラス * * @author H.Sugimoto */ public abstract class AbstractDialect implements Dialect { - private final String dialectName = this.getClass().getSimpleName().replace("Dialect", "").toLowerCase(); + private static final char[] DEFAULT_WILDCARDS = { '%', '_' }; + + private final char escapeChar; + private final char[] wildcards; + private final Pattern escapePattern; + + protected AbstractDialect() { + this('$', DEFAULT_WILDCARDS); + } + + protected AbstractDialect(final char escapeChar, final char[] wildcards) { + this.escapeChar = escapeChar; + this.wildcards = wildcards != null ? wildcards : DEFAULT_WILDCARDS; + this.escapePattern = generateEscapePattern(this.escapeChar, this.wildcards); + } + + /** + * LIKEパターン文字列をエスケープする正規表現を生成する + * @param escapeChar エスケープ文字 + * @param wildcards ワイルドカードキャラクタ配列 + * @return LIKEパターン文字列をエスケープする正規表現 + */ + protected Pattern generateEscapePattern(final char escapeChar, final char[] wildcards) { + StringBuilder builder = new StringBuilder(); + builder.append("["); + for (char wildcard : wildcards) { + if (escapeChar == '[' || escapeChar == ']') { + builder.append("\\"); + } + builder.append(Matcher.quoteReplacement(String.valueOf(escapeChar))); + if (wildcard == '[' || wildcard == ']') { + builder.append("\\"); + } + builder.append(wildcard); + } + builder.append("]"); + return Pattern.compile(builder.toString()); + } /** - * Dialect識別用の文字列を取得する + * {@inheritDoc} * - * @return Dialect識別用文字列 + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseType() */ @Override - public String getDialectName() { - return dialectName; + public String getDatabaseType() { + return getDatabaseName().toLowerCase(); } + @Override + public String escapeLikePattern(final CharSequence pattern) { + Matcher matcher = escapePattern.matcher(pattern); + return matcher.replaceAll(Matcher.quoteReplacement(String.valueOf(escapeChar)) + "$0"); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getLimitClause(long, long) + */ + @Override + public String getLimitClause(final long limit, final long offset) { + StringBuilder builder = new StringBuilder(); + if (limit > 0) { + builder.append("LIMIT ").append(limit).append(" "); + } + if (offset > 0) { + builder.append("OFFSET ").append(offset); + } + if (builder.length() > 0) { + builder.append(System.lineSeparator()); + } + return builder.toString(); + } } diff --git a/src/main/java/jp/co/future/uroborosql/dialect/DefaultDialect.java b/src/main/java/jp/co/future/uroborosql/dialect/DefaultDialect.java index c96bc648..05a97dd0 100644 --- a/src/main/java/jp/co/future/uroborosql/dialect/DefaultDialect.java +++ b/src/main/java/jp/co/future/uroborosql/dialect/DefaultDialect.java @@ -21,13 +21,23 @@ public DefaultDialect() { super(); } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName() + */ @Override public String getDatabaseName() { return "default"; } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#accept(jp.co.future.uroborosql.connection.ConnectionSupplier) + */ @Override - public boolean accept(ConnectionSupplier supplier) { + public boolean accept(final ConnectionSupplier supplier) { return true; } } diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Dialect.java index 892d71cf..c3a62b6b 100644 --- a/src/main/java/jp/co/future/uroborosql/dialect/Dialect.java +++ b/src/main/java/jp/co/future/uroborosql/dialect/Dialect.java @@ -39,7 +39,9 @@ default boolean isRemoveTerminator() { * * @return ロールバックする場合true */ - default boolean isRollbackToSavepointBeforeRetry() { return false; } + default boolean isRollbackToSavepointBeforeRetry() { + return false; + } /** * BULK INSERTをサポートするかどうか @@ -50,10 +52,33 @@ default boolean supportsBulkInsert() { } /** - * Dialect名を取得する + * LIMIT 句をサポートするかどうか + * @return LIMIT句をサポートする場合はtrue + */ + default boolean supportsLimitClause() { + return false; + } + + /** + * LIMIT句(とOFFSET句)を取得する + * @param limit limit + * @param offset offset + * @return LIMIT句(とOFFSET句)を表す文字列 + */ + String getLimitClause(long limit, long offset); + + /** + * LIKE 演算子のパターン文字列をエスケープする + * @param pattern パターン文字列 + * @return エスケープ後のパターン文字列 + */ + String escapeLikePattern(CharSequence pattern); + + /** + * Databaseの種別を表す名前を取得する * - * @return Dialect名 + * @return Database種別名 */ - String getDialectName(); + String getDatabaseType(); } diff --git a/src/main/java/jp/co/future/uroborosql/dialect/H2Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/H2Dialect.java index 64d48ed1..6d4efefe 100644 --- a/src/main/java/jp/co/future/uroborosql/dialect/H2Dialect.java +++ b/src/main/java/jp/co/future/uroborosql/dialect/H2Dialect.java @@ -6,7 +6,6 @@ */ package jp.co.future.uroborosql.dialect; - /** * H2用のDialect * @@ -20,13 +19,33 @@ public H2Dialect() { super(); } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName() + */ @Override public String getDatabaseName() { return "H2"; } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#supportsBulkInsert() + */ @Override public boolean supportsBulkInsert() { return true; } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#supportsLimitClause() + */ + @Override + public boolean supportsLimitClause() { + return true; + } } diff --git a/src/main/java/jp/co/future/uroborosql/dialect/MsSqlDialect.java b/src/main/java/jp/co/future/uroborosql/dialect/MsSqlDialect.java index 341ebc4e..f609b8a8 100644 --- a/src/main/java/jp/co/future/uroborosql/dialect/MsSqlDialect.java +++ b/src/main/java/jp/co/future/uroborosql/dialect/MsSqlDialect.java @@ -19,13 +19,33 @@ public MsSqlDialect() { super(); } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName() + */ @Override public String getDatabaseName() { return "Microsoft SQL Server"; } /** - * MSSQLではMerge文で;を使用するため終端文字の削除を行わない + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.AbstractDialect#getDatabaseType() + */ + @Override + public String getDatabaseType() { + return "mssql"; + } + + /** + * {@inheritDoc} + * + *
MSSQLではMerge文で;を使用するため終端文字の削除を行わない + * + * @see jp.co.future.uroborosql.dialect.Dialect#isRemoveTerminator() + * * @return false */ @Override diff --git a/src/main/java/jp/co/future/uroborosql/dialect/MySqlDialect.java b/src/main/java/jp/co/future/uroborosql/dialect/MySqlDialect.java index c761346c..f6e6994d 100644 --- a/src/main/java/jp/co/future/uroborosql/dialect/MySqlDialect.java +++ b/src/main/java/jp/co/future/uroborosql/dialect/MySqlDialect.java @@ -19,13 +19,33 @@ public MySqlDialect() { super(); } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName() + */ @Override public String getDatabaseName() { return "MySQL"; } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#supportsBulkInsert() + */ @Override public boolean supportsBulkInsert() { return true; } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#supportsLimitClause() + */ + @Override + public boolean supportsLimitClause() { + return true; + } } diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Oracle10Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Oracle10Dialect.java new file mode 100644 index 00000000..8184ef92 --- /dev/null +++ b/src/main/java/jp/co/future/uroborosql/dialect/Oracle10Dialect.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2017-present, Future Corporation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package jp.co.future.uroborosql.dialect; + +import jp.co.future.uroborosql.connection.ConnectionSupplier; + +/** + * Oracle10(以前のバージョンも含む)用のDialect + * + * @author H.Sugimoto + */ +public class Oracle10Dialect extends AbstractDialect { + /** + * コンストラクタ + */ + public Oracle10Dialect() { + super('\\', new char[] { '%', '_' }); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName() + */ + @Override + public String getDatabaseName() { + return "Oracle"; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#accept(jp.co.future.uroborosql.connection.ConnectionSupplier) + */ + @Override + public boolean accept(final ConnectionSupplier supplier) { + if (supplier == null) { + return false; + } + + String[] parts = supplier.getDatabaseName().split("-", 2); + String databaseName = parts[0]; + + if (!databaseName.startsWith(getDatabaseName())) { + return false; + } + + String databaseVersion = parts[1]; + + try { + int majorVersion = Integer.parseInt(databaseVersion.substring(0, databaseVersion.indexOf("."))); + return majorVersion < 11; + } catch (NumberFormatException e) { + return false; + } + } + +} diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Oracle11Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Oracle11Dialect.java new file mode 100644 index 00000000..337bb456 --- /dev/null +++ b/src/main/java/jp/co/future/uroborosql/dialect/Oracle11Dialect.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2017-present, Future Corporation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package jp.co.future.uroborosql.dialect; + +import jp.co.future.uroborosql.connection.ConnectionSupplier; + +/** + * Oracle11用のDialect + * + * @author H.Sugimoto + */ +public class Oracle11Dialect extends AbstractDialect { + + /** + * コンストラクタ + */ + public Oracle11Dialect() { + super('\\', new char[] { '%', '_', '%', '_' }); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName() + */ + @Override + public String getDatabaseName() { + return "Oracle"; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#accept(jp.co.future.uroborosql.connection.ConnectionSupplier) + */ + @Override + public boolean accept(final ConnectionSupplier supplier) { + if (supplier == null) { + return false; + } + + String[] parts = supplier.getDatabaseName().split("-", 2); + String databaseName = parts[0]; + + if (!databaseName.startsWith(getDatabaseName())) { + return false; + } + + String databaseVersion = parts[1]; + + try { + int majorVersion = Integer.parseInt(databaseVersion.substring(0, databaseVersion.indexOf("."))); + return majorVersion == 11; + } catch (NumberFormatException e) { + return false; + } + } + +} diff --git a/src/main/java/jp/co/future/uroborosql/dialect/Oracle12Dialect.java b/src/main/java/jp/co/future/uroborosql/dialect/Oracle12Dialect.java new file mode 100644 index 00000000..1f6c504d --- /dev/null +++ b/src/main/java/jp/co/future/uroborosql/dialect/Oracle12Dialect.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2017-present, Future Corporation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package jp.co.future.uroborosql.dialect; + +import jp.co.future.uroborosql.connection.ConnectionSupplier; + +/** + * Oracle12(以降のバージョンも含む)用のDialect + * + * @author H.Sugimoto + */ +public class Oracle12Dialect extends AbstractDialect { + /** + * コンストラクタ + */ + public Oracle12Dialect() { + super('\\', new char[] { '%', '_', '%', '_' }); + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName() + */ + @Override + public String getDatabaseName() { + return "Oracle"; + } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#accept(jp.co.future.uroborosql.connection.ConnectionSupplier) + */ + @Override + public boolean accept(final ConnectionSupplier supplier) { + if (supplier == null) { + return false; + } + + String[] parts = supplier.getDatabaseName().split("-", 2); + String databaseName = parts[0]; + + if (!databaseName.startsWith(getDatabaseName())) { + return false; + } + + String databaseVersion = parts[1]; + + try { + int majorVersion = Integer.parseInt(databaseVersion.substring(0, databaseVersion.indexOf("."))); + return majorVersion >= 12; + } catch (NumberFormatException e) { + return false; + } + } +} diff --git a/src/main/java/jp/co/future/uroborosql/dialect/OracleDialect.java b/src/main/java/jp/co/future/uroborosql/dialect/OracleDialect.java deleted file mode 100644 index 9ed866f7..00000000 --- a/src/main/java/jp/co/future/uroborosql/dialect/OracleDialect.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2017-present, Future Corporation - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -package jp.co.future.uroborosql.dialect; - - -/** - * Oracle用のDialect - * - * @author H.Sugimoto - */ -public class OracleDialect extends AbstractDialect { - /** - * コンストラクタ - */ - public OracleDialect() { - super(); - } - - @Override - public String getDatabaseName() { - return "Oracle"; - } - -} diff --git a/src/main/java/jp/co/future/uroborosql/dialect/PostgresqlDialect.java b/src/main/java/jp/co/future/uroborosql/dialect/PostgresqlDialect.java index 390533e5..2c7b4c06 100644 --- a/src/main/java/jp/co/future/uroborosql/dialect/PostgresqlDialect.java +++ b/src/main/java/jp/co/future/uroborosql/dialect/PostgresqlDialect.java @@ -19,18 +19,43 @@ public PostgresqlDialect() { super(); } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#isRollbackToSavepointBeforeRetry() + */ @Override public boolean isRollbackToSavepointBeforeRetry() { return true; } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#getDatabaseName() + */ @Override public String getDatabaseName() { return "PostgreSQL"; } + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#supportsBulkInsert() + */ @Override public boolean supportsBulkInsert() { return true; } + + /** + * {@inheritDoc} + * + * @see jp.co.future.uroborosql.dialect.Dialect#supportsLimitClause() + */ + @Override + public boolean supportsLimitClause() { + return true; + } } diff --git a/src/main/java/jp/co/future/uroborosql/fluent/SqlEntityQuery.java b/src/main/java/jp/co/future/uroborosql/fluent/SqlEntityQuery.java index b683825b..4231c951 100644 --- a/src/main/java/jp/co/future/uroborosql/fluent/SqlEntityQuery.java +++ b/src/main/java/jp/co/future/uroborosql/fluent/SqlEntityQuery.java @@ -42,4 +42,207 @@ public interface SqlEntityQuery extends SqlFluent> { * @return 検索結果を順次取得するStream. */ Stream stream(); + + /** + * Where句に equal 条件を追加する + * @param col bind column name + * @param value 値 + * @return SqlEntityQuery + */ + SqlEntityQuery equal(String col, Object value); + + /** + * Where句に not equal 条件を追加する + * @param col bind column name + * @param value 値 + * @return SqlEntityQuery + */ + SqlEntityQuery notEqual(String col, Object value); + + /** + * Where句に greater than 条件を追加する + * @param col bind column name + * @param value 値 + * @return SqlEntityQuery + */ + SqlEntityQuery greaterThan(String col, Object value); + + /** + * Where句に less than 条件を追加する + * @param col bind column name + * @param value 値 + * @return SqlEntityQuery + */ + SqlEntityQuery lessThan(String col, Object value); + + /** + * Where句に greater equal 条件を追加する + * @param col bind column name + * @param value 値 + * @return SqlEntityQuery + */ + SqlEntityQuery greaterEqual(String col, Object value); + + /** + * Where句に less equal 条件を追加する + * @param col bind column name + * @param value 値 + * @return SqlEntityQuery + */ + SqlEntityQuery lessEqual(String col, Object value); + + /** + * Where句に in 条件を追加する + * @param col bind column name + * @param values 値の配列 + * @return SqlEntityQuery + */ + SqlEntityQuery in(String col, Object... values); + + /** + * Where句に in 条件を追加する + * @param col bind column name + * @param valueList 値の集合 + * @return SqlEntityQuery + */ + SqlEntityQuery in(String col, Iterable valueList); + + /** + * Where句に not in 条件を追加する + * @param col bind column name + * @param values 値の配列 + * @return SqlEntityQuery + */ + SqlEntityQuery notIn(String col, Object... values); + + /** + * Where句に not in 条件を追加する + * @param col bind column name + * @param valueList 値の集合 + * @return SqlEntityQuery + */ + SqlEntityQuery notIn(String col, Iterable valueList); + + /** + * Where句に like 条件を追加する。検索文字列はエスケープしない + * @param col bind column name + * @param searchValue 検索文字列 + * @return SqlEntityQuery + */ + SqlEntityQuery like(String col, CharSequence searchValue); + + /** + * Where句に前方一致条件を追加する。検索文字列は内部でエスケープされる。 + * @param col bind column name + * @param searchValue 検索文字列 + * @return SqlEntityQuery + */ + SqlEntityQuery startsWith(String col, CharSequence searchValue); + + /** + * Where句に後方一致条件を追加する。検索文字列は内部でエスケープされる。 + * @param col bind column name + * @param searchValue 検索文字列 + * @return SqlEntityQuery + */ + SqlEntityQuery endsWith(String col, CharSequence searchValue); + + /** + * Where句に 部分一致条件を追加する。検索文字列は内部でエスケープされる。 + * @param col bind column name + * @param searchValue 検索文字列 + * @return SqlEntityQuery + */ + SqlEntityQuery contains(String col, CharSequence searchValue); + + /** + * Where句に not like 条件を追加する + * @param col bind column name + * @param searchValue 検索文字列 + * @return SqlEntityQuery + */ + SqlEntityQuery notLike(String col, CharSequence searchValue); + + /** + * Where句に前方一致条件の否定を追加する。検索文字列は内部でエスケープされる。 + * @param col bind column name + * @param searchValue 検索文字列 + * @return SqlEntityQuery + */ + SqlEntityQuery notStartsWith(String col, CharSequence searchValue); + + /** + * Where句に後方一致条件の否定を追加する。検索文字列は内部でエスケープされる。 + * @param col bind column name + * @param searchValue 検索文字列 + * @return SqlEntityQuery + */ + SqlEntityQuery notEndsWith(String col, CharSequence searchValue); + + /** + * Where句に 部分一致条件の否定を追加する。検索文字列は内部でエスケープされる。 + * @param col bind column name + * @param searchValue 検索文字列 + * @return SqlEntityQuery + */ + SqlEntityQuery notContains(String col, CharSequence searchValue); + + /** + * Where句に between 条件を追加する + * @param col bind column name + * @param fromValue 開始値 + * @param toValue 終了値 + * @return SqlEntityQuery + */ + SqlEntityQuery between(String col, Object fromValue, Object toValue); + + /** + * Where句に is null 条件を追加する + * @param col bind column name + * @return SqlEntityQuery + */ + SqlEntityQuery isNull(String col); + + /** + * Where句に is not null 条件を追加する + * @param col bind column name + * @return SqlEntityQuery + */ + SqlEntityQuery isNotNull(String col); + + /** + * Where句に 素の文字列指定で 条件を追加する + * @param rawString Where句に出力する条件式 + * @return SqlEntityQuery + */ + SqlEntityQuery where(CharSequence rawString); + + /** + * ソート条件を指定(昇順) + * @param cols ソート対象カラム名の配列 + * @return SqlEntityQuery + */ + SqlEntityQuery orderByAsc(String... cols); + + /** + * ソート条件を指定(降順) + * @param cols ソート対象カラム名の配列 + * @return SqlEntityQuery + */ + SqlEntityQuery orderByDesc(String... cols); + + /** + * 検索結果の行数制限を指定する + * @param limit 取得する行数 + * @return SqlEntityQuery + */ + SqlEntityQuery limit(long limit); + + /** + * 検索結果の開始行を指定する + * @param offset 取得開始行 + * @return SqlEntityQuery + */ + SqlEntityQuery offset(long offset); + } diff --git a/src/main/java/jp/co/future/uroborosql/mapping/DefaultEntityHandler.java b/src/main/java/jp/co/future/uroborosql/mapping/DefaultEntityHandler.java index 7a744f58..8b747545 100644 --- a/src/main/java/jp/co/future/uroborosql/mapping/DefaultEntityHandler.java +++ b/src/main/java/jp/co/future/uroborosql/mapping/DefaultEntityHandler.java @@ -18,6 +18,8 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; + import jp.co.future.uroborosql.SqlAgent; import jp.co.future.uroborosql.connection.ConnectionManager; import jp.co.future.uroborosql.context.SqlContext; @@ -26,8 +28,6 @@ import jp.co.future.uroborosql.mapping.mapper.PropertyMapper; import jp.co.future.uroborosql.mapping.mapper.PropertyMapperManager; -import org.apache.commons.lang3.StringUtils; - /** * デフォルトORM処理クラス * @@ -63,13 +63,13 @@ public EntityHandler setEmptyStringEqualsNull(final boolean emptyStringE /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#createSelectContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class) + * @see jp.co.future.uroborosql.mapping.EntityHandler#createSelectContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class, boolean) */ @Override public SqlContext createSelectContext(final SqlAgent agent, final TableMetadata metadata, - final Class entityType) { + final Class entityType, final boolean addCondition) { return agent.contextWith(buildSelectSQL(metadata, entityType, agent.getSqlConfig().getSqlAgentFactory() - .getSqlIdKeyName())).setSqlId(createSqlId(metadata, entityType)); + .getSqlIdKeyName(), addCondition)).setSqlId(createSqlId(metadata, entityType)); } /** @@ -99,28 +99,27 @@ public SqlContext createInsertContext(final SqlAgent agent, final TableMetadata /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#createUpdateContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class) + * @see jp.co.future.uroborosql.mapping.EntityHandler#createUpdateContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class, boolean) */ @Override public SqlContext createUpdateContext(final SqlAgent agent, final TableMetadata metadata, - final Class entityType) { + final Class entityType, final boolean addCondition) { return agent.contextWith(buildUpdateSQL(metadata, entityType, agent.getSqlConfig().getSqlAgentFactory() - .getSqlIdKeyName())).setSqlId(createSqlId(metadata, entityType)); + .getSqlIdKeyName(), addCondition)).setSqlId(createSqlId(metadata, entityType)); } /** * {@inheritDoc} * - * @see jp.co.future.uroborosql.mapping.EntityHandler#createDeleteContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class) + * @see jp.co.future.uroborosql.mapping.EntityHandler#createDeleteContext(jp.co.future.uroborosql.SqlAgent, jp.co.future.uroborosql.mapping.TableMetadata, java.lang.Class, boolean) */ @Override public SqlContext createDeleteContext(final SqlAgent agent, final TableMetadata metadata, - final Class entityType) { + final Class entityType, final boolean addCondition) { return agent.contextWith(buildDeleteSQL(metadata, entityType, agent.getSqlConfig().getSqlAgentFactory() - .getSqlIdKeyName())).setSqlId(createSqlId(metadata, entityType)); + .getSqlIdKeyName(), addCondition)).setSqlId(createSqlId(metadata, entityType)); } - /** * {@inheritDoc} * @@ -247,8 +246,9 @@ public EntityHandler removePropertyMapper(final PropertyMapper proper * @return TableMetadata * @throws SQLException SQL例外 */ - protected TableMetadata createMetadata(final ConnectionManager connectionManager, final Class type) - throws SQLException { + protected TableMetadata createMetadata(final ConnectionManager connectionManager, + final Class type) + throws SQLException { Table table = getTable(type); return TableMetadata.createTableEntityMetadata(connectionManager, table); } @@ -269,17 +269,66 @@ protected Table getTable(final Class type) { * @param metadata エンティティメタ情報 * @param type エイティティタイプ * @param sqlIdKeyName SQL_IDキー名 + * @param addCondition 条件を追加するかどうか。追加する場合true * @return SELECT SQL */ protected String buildSelectSQL(final TableMetadata metadata, final Class type, + final String sqlIdKeyName, final boolean addCondition) { + final List columns = metadata.getColumns(); + + final StringBuilder sql = new StringBuilder(buildSelectClause(metadata, type, sqlIdKeyName)); + + if (addCondition) { + sql.append("/*BEGIN*/").append(System.lineSeparator()); + sql.append("WHERE").append(System.lineSeparator()); + + for (final TableMetadata.Column col : columns) { + final String camelColName = col.getCamelColumnName(); + final StringBuilder parts = new StringBuilder().append("\t").append("AND ") + .append(col.getColumnIdentifier()) + .append(" = ").append("/*").append(camelColName).append("*/''").append(System.lineSeparator()); + wrapIfComment(sql, parts, col); + } + sql.append("/*END*/").append(System.lineSeparator()); + + boolean firstFlag = true; + final List keys = metadata.getKeyColumns(); + if (!keys.isEmpty()) { + sql.append("ORDER BY").append(System.lineSeparator()); + firstFlag = true; + for (final TableMetadata.Column col : keys) { + sql.append("\t"); + if (firstFlag) { + sql.append(" "); + firstFlag = false; + } else { + sql.append(", "); + } + sql.append(col.getColumnIdentifier()).append(System.lineSeparator()); + } + } + } + + return sql.toString(); + } + + /** + * SELECT句生成 + * + * @param metadata エンティティメタ情報 + * @param type エイティティタイプ + * @param sqlIdKeyName SQL_IDキー名 + * @return SELECT句 + */ + protected String buildSelectClause(final TableMetadata metadata, final Class type, final String sqlIdKeyName) { - List columns = metadata.getColumns(); + final List columns = metadata.getColumns(); - StringBuilder sql = new StringBuilder("SELECT ").append("/* ").append(sqlIdKeyName).append(" */") + final StringBuilder sql = new StringBuilder("SELECT ").append("/* ").append(sqlIdKeyName).append(" */") .append(System.lineSeparator()); boolean firstFlag = true; - for (TableMetadata.Column col : columns) { + for (final TableMetadata.Column col : columns) { sql.append("\t"); if (firstFlag) { sql.append(" "); @@ -294,32 +343,6 @@ protected String buildSelectSQL(final TableMetadata metadata, final Class keys = metadata.getKeyColumns(); - if (!keys.isEmpty()) { - sql.append("ORDER BY").append(System.lineSeparator()); - firstFlag = true; - for (TableMetadata.Column col : keys) { - sql.append("\t"); - if (firstFlag) { - sql.append(" "); - firstFlag = false; - } else { - sql.append(", "); - } - sql.append(col.getColumnIdentifier()).append(System.lineSeparator()); - } - } return sql.toString(); } @@ -394,17 +417,19 @@ protected String buildBulkInsertSQL(final TableMetadata metadata, final Classtrue * @return UPDATE SQL */ protected String buildUpdateSQL(final TableMetadata metadata, final Class type, - final String sqlIdKeyName) { + final String sqlIdKeyName, final boolean addCondition) { StringBuilder sql = new StringBuilder("UPDATE ").append("/* ").append(sqlIdKeyName).append(" */") .append(" ").append(metadata.getTableIdentifier()).append(" SET ").append(System.lineSeparator()); List mappingColumnNames = Arrays.stream(MappingUtils.getMappingColumns(type, SqlStatement.UPDATE)) .map(c -> c.getName().toLowerCase()).collect(Collectors.toList()); - Optional versionMappingColumn = type == null ? Optional.empty() : MappingUtils + Optional versionMappingColumn = type == null ? Optional.empty() + : MappingUtils .getVersionMappingColumn(type); boolean firstFlag = true; @@ -443,42 +468,45 @@ protected String buildUpdateSQL(final TableMetadata metadata, final Class cols = !metadata.getKeyColumns().isEmpty() ? metadata.getKeyColumns() : Arrays - .asList(metadata.getColumns().get(0)); - firstFlag = true; - for (TableMetadata.Column col : cols) { - StringBuilder parts = new StringBuilder().append("\t"); - if (firstFlag) { - if (col.isNullable()) { + if (addCondition) { + sql.append("WHERE").append(System.lineSeparator()); + final List cols = !metadata.getKeyColumns().isEmpty() ? metadata.getKeyColumns() + : Arrays + .asList(metadata.getColumns().get(0)); + firstFlag = true; + for (final TableMetadata.Column col : cols) { + final StringBuilder parts = new StringBuilder().append("\t"); + if (firstFlag) { + if (col.isNullable()) { + parts.append("AND "); + } else { + parts.append(" "); + } + firstFlag = false; + } else { parts.append("AND "); + } + parts.append(col.getColumnIdentifier()).append(" = ").append("/*").append(col.getCamelColumnName()) + .append("*/''") + .append(System.lineSeparator()); + if (col.isNullable()) { + wrapIfComment(sql, parts, col); } else { - parts.append(" "); + sql.append(parts); } - firstFlag = false; - } else { - parts.append("AND "); - } - parts.append(col.getColumnIdentifier()).append(" = ").append("/*").append(col.getCamelColumnName()) - .append("*/''") - .append(System.lineSeparator()); - if (col.isNullable()) { - wrapIfComment(sql, parts, col); - } else { - sql.append(parts); } + final boolean first = firstFlag; + versionMappingColumn.ifPresent(mappingColumn -> { + sql.append("\t"); + if (first) { + sql.append(" "); + } else { + sql.append("AND "); + } + sql.append(mappingColumn.getName()).append(" = ").append("/*").append(mappingColumn.getCamelName()) + .append("*/''").append(System.lineSeparator()); + }); } - final boolean first = firstFlag; - versionMappingColumn.ifPresent(mappingColumn -> { - sql.append("\t"); - if (first) { - sql.append(" "); - } else { - sql.append("AND "); - } - sql.append(mappingColumn.getName()).append(" = ").append("/*").append(mappingColumn.getCamelName()) - .append("*/''").append(System.lineSeparator()); - }); return sql.toString(); } @@ -488,36 +516,40 @@ protected String buildUpdateSQL(final TableMetadata metadata, final Classtrue * @return DELETE SQL */ protected String buildDeleteSQL(final TableMetadata metadata, final Class type, - final String sqlIdKeyName) { + final String sqlIdKeyName, final boolean addCondition) { StringBuilder sql = new StringBuilder("DELETE ").append("/* ").append(sqlIdKeyName).append(" */") .append(" FROM ").append(metadata.getTableIdentifier()).append("").append(System.lineSeparator()); - boolean firstFlag = true; - sql.append("WHERE").append(System.lineSeparator()); + if (addCondition) { + boolean firstFlag = true; + sql.append("WHERE").append(System.lineSeparator()); - List cols = !metadata.getKeyColumns().isEmpty() ? metadata.getKeyColumns() : Arrays - .asList(metadata.getColumns().get(0)); - for (TableMetadata.Column col : cols) { - StringBuilder parts = new StringBuilder().append("\t"); - if (firstFlag) { - if (col.isNullable()) { + List cols = !metadata.getKeyColumns().isEmpty() ? metadata.getKeyColumns() + : Arrays + .asList(metadata.getColumns().get(0)); + for (TableMetadata.Column col : cols) { + StringBuilder parts = new StringBuilder().append("\t"); + if (firstFlag) { + if (col.isNullable()) { + parts.append("AND "); + } else { + parts.append(" "); + } + firstFlag = false; + } else { parts.append("AND "); + } + parts.append(col.getColumnIdentifier()).append(" = ").append("/*").append(col.getCamelColumnName()) + .append("*/''").append(System.lineSeparator()); + if (col.isNullable()) { + wrapIfComment(sql, parts, col); } else { - parts.append(" "); + sql.append(parts); } - firstFlag = false; - } else { - parts.append("AND "); - } - parts.append(col.getColumnIdentifier()).append(" = ").append("/*").append(col.getCamelColumnName()) - .append("*/''").append(System.lineSeparator()); - if (col.isNullable()) { - wrapIfComment(sql, parts, col); - } else { - sql.append(parts); } } return sql.toString(); @@ -613,8 +645,8 @@ private String createSqlId(final TableMetadata metadata, final Classtrue */ private boolean isStringType(final JDBCType type) { - return (JDBCType.CHAR.equals(type) || JDBCType.NCHAR.equals(type) || JDBCType.VARCHAR.equals(type) - || JDBCType.NVARCHAR.equals(type) || JDBCType.LONGNVARCHAR.equals(type)); + return JDBCType.CHAR.equals(type) || JDBCType.NCHAR.equals(type) || JDBCType.VARCHAR.equals(type) + || JDBCType.NVARCHAR.equals(type) || JDBCType.LONGNVARCHAR.equals(type); } /** @@ -632,7 +664,7 @@ private StringBuilder wrapIfComment(final StringBuilder original, final StringBu if (isStringType(col.getDataType())) { if (emptyStringEqualsNull) { original.append("/*IF SF.isNotEmpty(").append(camelColName).append(") */") - .append(System.lineSeparator()); + .append(System.lineSeparator()); } else { original.append("/*IF ").append(camelColName).append(" != null */").append(System.lineSeparator()); } diff --git a/src/main/java/jp/co/future/uroborosql/mapping/EntityHandler.java b/src/main/java/jp/co/future/uroborosql/mapping/EntityHandler.java index 0908720d..14e55d4b 100644 --- a/src/main/java/jp/co/future/uroborosql/mapping/EntityHandler.java +++ b/src/main/java/jp/co/future/uroborosql/mapping/EntityHandler.java @@ -45,9 +45,10 @@ TableMetadata getMetadata(ConnectionManager connectionManager, Classtrue * @return SELECT SQLコンテキスト */ - SqlContext createSelectContext(SqlAgent agent, TableMetadata metadata, Class entityType); + SqlContext createSelectContext(SqlAgent agent, TableMetadata metadata, Class entityType, boolean addCondition); /** * EntityからINSERT SQLコンテキストを生成します。 @@ -99,9 +100,10 @@ default int doInsert(final SqlAgent agent, final SqlContext context, final ENTIT * @param agent SqlAgent * @param metadata エンティティメタ情報 * @param entityType エンティティタイプ + * @param addCondition 条件を追加するかどうか。追加する場合true * @return UPDATE SQLコンテキスト */ - SqlContext createUpdateContext(SqlAgent agent, TableMetadata metadata, Class entityType); + SqlContext createUpdateContext(SqlAgent agent, TableMetadata metadata, Class entityType, boolean addCondition); /** * SqlContextのパラメーターににエンティティの値をセットします。 @@ -130,9 +132,10 @@ default int doUpdate(final SqlAgent agent, final SqlContext context, final ENTIT * @param agent SqlAgent * @param metadata エンティティメタ情報 * @param entityType エンティティタイプ + * @param addCondition 条件を追加するかどうか。追加する場合true * @return DELETE SQLコンテキスト */ - SqlContext createDeleteContext(SqlAgent agent, TableMetadata metadata, Class entityType); + SqlContext createDeleteContext(SqlAgent agent, TableMetadata metadata, Class entityType, boolean addCondition); /** * SqlContextのパラメーターににエンティティの値をセットします。 diff --git a/src/main/java/jp/co/future/uroborosql/parameter/Parameter.java b/src/main/java/jp/co/future/uroborosql/parameter/Parameter.java index 5072618c..50aa2799 100644 --- a/src/main/java/jp/co/future/uroborosql/parameter/Parameter.java +++ b/src/main/java/jp/co/future/uroborosql/parameter/Parameter.java @@ -7,6 +7,7 @@ package jp.co.future.uroborosql.parameter; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.sql.JDBCType; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -15,12 +16,13 @@ import java.util.Map; import java.util.Objects; -import jp.co.future.uroborosql.parameter.mapper.BindParameterMapperManager; - +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; +import jp.co.future.uroborosql.parameter.mapper.BindParameterMapperManager; + /** * パラメータオブジェクト。
* SQLへバインドするパラメータを保持する。
@@ -104,9 +106,21 @@ public Parameter createSubParameter(final String propertyName) { } } else { try { + // フィールドアクセスで値の取得を実施 Field field = value.getClass().getDeclaredField(propertyName); field.setAccessible(true); subValue = field.get(value); + } catch (NoSuchFieldException e) { + // メソッドアクセスで値の取得を実施 + try { + String prefix = boolean.class.equals(value.getClass()) ? "is" : "get"; + Method method = value.getClass() + .getMethod(prefix + StringUtils.capitalize(propertyName)); + subValue = method.invoke(value); + } catch (Exception e2) { + LOG.warn("Set subparameter value to NULL because property can not be accessed.[{}]", + subParameterName, e2); + } } catch (Exception e) { LOG.warn("Set subparameter value to NULL because property can not be accessed.[{}]", subParameterName, e); diff --git a/src/main/java/jp/co/future/uroborosql/store/NioSqlManagerImpl.java b/src/main/java/jp/co/future/uroborosql/store/NioSqlManagerImpl.java index 865079e4..16765bf8 100644 --- a/src/main/java/jp/co/future/uroborosql/store/NioSqlManagerImpl.java +++ b/src/main/java/jp/co/future/uroborosql/store/NioSqlManagerImpl.java @@ -38,13 +38,13 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; -import jp.co.future.uroborosql.dialect.Dialect; -import jp.co.future.uroborosql.exception.UroborosqlRuntimeException; - import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jp.co.future.uroborosql.dialect.Dialect; +import jp.co.future.uroborosql.exception.UroborosqlRuntimeException; + public class NioSqlManagerImpl implements SqlManager { /** ロガー */ private static final Logger log = LoggerFactory.getLogger(NioSqlManagerImpl.class); @@ -57,7 +57,7 @@ public class NioSqlManagerImpl implements SqlManager { /** 有効なDialectのSet */ private static final Set dialects = StreamSupport .stream(ServiceLoader.load(Dialect.class).spliterator(), false) - .map(Dialect::getDialectName).collect(Collectors.toSet()); + .map(Dialect::getDatabaseType).collect(Collectors.toSet()); /** SQLファイルをロードするルートパス */ private final String loadPath; @@ -81,10 +81,10 @@ public class NioSqlManagerImpl implements SqlManager { private ExecutorService es; /** sqlNameとそれに対するSqlInfoの紐付きを持つMap */ - private ConcurrentHashMap sqlInfos = new ConcurrentHashMap<>(); + private final ConcurrentHashMap sqlInfos = new ConcurrentHashMap<>(); /** WatchKeyに対するディレクトリPathを取得するためのMap */ - private ConcurrentHashMap watchDirs = new ConcurrentHashMap<>(); + private final ConcurrentHashMap watchDirs = new ConcurrentHashMap<>(); /** * コンストラクタ @@ -98,7 +98,7 @@ public NioSqlManagerImpl() { * * @param detectChanges SQLファイルの変更を検知するかどうか */ - public NioSqlManagerImpl(boolean detectChanges) { + public NioSqlManagerImpl(final boolean detectChanges) { this(null, null, null, detectChanges); } @@ -140,7 +140,8 @@ public NioSqlManagerImpl(final String loadPath, final String fileExtension, fina * @param charset SQLファイルエンコーディング * @param detectChanges SQLファイルの変更を検知するかどうか */ - public NioSqlManagerImpl(final String loadPath, final String fileExtension, final Charset charset, boolean detectChanges) { + public NioSqlManagerImpl(final String loadPath, final String fileExtension, final Charset charset, + final boolean detectChanges) { this.loadPath = loadPath != null ? loadPath : "sql"; this.fileExtension = fileExtension != null ? fileExtension : ".sql"; this.charset = charset != null ? charset : Charset.forName(System.getProperty("file.encoding")); @@ -467,7 +468,7 @@ private boolean validPath(final Path path) { String d = path.getName(count).toString().toLowerCase(); // loadPathの直下が現在のdialect以外と一致する場合は無効なパスと判定する - return !dialects.contains(d) || this.dialect.getDialectName().equals(d); + return !dialects.contains(d) || this.dialect.getDatabaseType().equals(d); } @@ -500,7 +501,7 @@ private void traverse(final Path path, final boolean watch, final boolean remove } else if (path.toString().endsWith(fileExtension)) { String sqlName = getSqlName(path); this.sqlInfos.compute(sqlName, - (k, v) -> (v == null) ? new SqlInfo(sqlName, path, dialect, charset) : v.computePath(path, remove)); + (k, v) -> v == null ? new SqlInfo(sqlName, path, dialect, charset) : v.computePath(path, remove)); } } @@ -516,7 +517,7 @@ public static class SqlInfo { /** Sqlファイルの文字コード */ private final Charset charset; /** sqlNameに対応するPathのList. ソートされて優先度が高いものから順に並んでいる. 適用されるのは先頭のPathになる. */ - private List pathList = new ArrayList<>(); + private final List pathList = new ArrayList<>(); /** SQLファイルの内容. nullの場合、getSqlBody()が呼び出された段階でロードして格納する. */ private String sqlBody; /** 適用されたPathの最終更新日時。SQLファイルが更新されたかどうかの判定に利用する */ @@ -560,7 +561,7 @@ private static FileTime getLastModifiedTime(final Path path) { */ private boolean hasDialect(final Path path) { for (Path p : path) { - if (this.dialect.getDialectName().equals(p.toString())) { + if (this.dialect.getDatabaseType().equals(p.toString())) { return true; } } diff --git a/src/main/resources/META-INF/services/jp.co.future.uroborosql.dialect.Dialect b/src/main/resources/META-INF/services/jp.co.future.uroborosql.dialect.Dialect index 7345e816..18ca28ec 100644 --- a/src/main/resources/META-INF/services/jp.co.future.uroborosql.dialect.Dialect +++ b/src/main/resources/META-INF/services/jp.co.future.uroborosql.dialect.Dialect @@ -1,4 +1,6 @@ -jp.co.future.uroborosql.dialect.OracleDialect +jp.co.future.uroborosql.dialect.Oracle12Dialect +jp.co.future.uroborosql.dialect.Oracle11Dialect +jp.co.future.uroborosql.dialect.Oracle10Dialect jp.co.future.uroborosql.dialect.MsSqlDialect jp.co.future.uroborosql.dialect.MySqlDialect jp.co.future.uroborosql.dialect.PostgresqlDialect diff --git a/src/test/java/jp/co/future/uroborosql/dialect/DefaultDialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/DefaultDialectTest.java new file mode 100644 index 00000000..386efc27 --- /dev/null +++ b/src/test/java/jp/co/future/uroborosql/dialect/DefaultDialectTest.java @@ -0,0 +1,67 @@ +package jp.co.future.uroborosql.dialect; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +public class DefaultDialectTest { + private Dialect dialect; + + @Before + public void setUp() throws Exception { + dialect = new DefaultDialect(); + } + + @Test + public void testGetDatabaseName() { + assertThat(dialect.getDatabaseName(), is("default")); + } + + @Test + public void testAccept() { + assertThat(dialect.accept(null), is(true)); + } + + @Test + public void testIsRemoveTerminator() { + assertThat(dialect.isRemoveTerminator(), is(true)); + } + + @Test + public void testIsRollbackToSavepointBeforeRetry() { + assertThat(dialect.isRollbackToSavepointBeforeRetry(), is(false)); + } + + @Test + public void testSupportsBulkInsert() { + assertThat(dialect.supportsBulkInsert(), is(false)); + } + + @Test + public void testSupportsLimitClause() { + assertThat(dialect.supportsBulkInsert(), is(false)); + } + + @Test + public void testEscapeLikePattern() { + assertThat(dialect.escapeLikePattern(""), is("")); + assertThat(dialect.escapeLikePattern("pattern"), is("pattern")); + assertThat(dialect.escapeLikePattern("%pattern"), is("$%pattern")); + assertThat(dialect.escapeLikePattern("_pattern"), is("$_pattern")); + assertThat(dialect.escapeLikePattern("pat%tern"), is("pat$%tern")); + assertThat(dialect.escapeLikePattern("pat_tern"), is("pat$_tern")); + assertThat(dialect.escapeLikePattern("pattern%"), is("pattern$%")); + assertThat(dialect.escapeLikePattern("pattern_"), is("pattern$_")); + assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern")); + assertThat(dialect.escapeLikePattern("pat%tern"), is("pat%tern")); + assertThat(dialect.escapeLikePattern("pat_tern"), is("pat_tern")); + } + + @Test + public void testGetDatabaseType() { + assertThat(dialect.getDatabaseType(), is("default")); + } + +} diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle10DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle10DialectTest.java new file mode 100644 index 00000000..80d4e77b --- /dev/null +++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle10DialectTest.java @@ -0,0 +1,116 @@ +package jp.co.future.uroborosql.dialect; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.sql.Connection; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +import org.junit.Test; + +import jp.co.future.uroborosql.connection.ConnectionSupplier; + +/** + * Oracle10Dialectの個別実装部分のテストケース + * + * @author H.Sugimoto + * + */ +public class Oracle10DialectTest { + + @Test + public void testAccept10() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-10.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, instanceOf(Oracle10Dialect.class)); + } + + @Test + public void testAcceptUnder10() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-9.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, instanceOf(Oracle10Dialect.class)); + } + + @Test + public void testAcceptOver10() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-11.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, not(instanceOf(Oracle10Dialect.class))); + } + + @Test + public void testEscapeLikePattern() { + Dialect dialect = new Oracle10Dialect(); + assertThat(dialect.escapeLikePattern(""), is("")); + assertThat(dialect.escapeLikePattern("pattern"), is("pattern")); + assertThat(dialect.escapeLikePattern("%pattern"), is("\\%pattern")); + assertThat(dialect.escapeLikePattern("_pattern"), is("\\_pattern")); + assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern")); + assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern")); + assertThat(dialect.escapeLikePattern("pattern%"), is("pattern\\%")); + assertThat(dialect.escapeLikePattern("pattern_"), is("pattern\\_")); + assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern")); + assertThat(dialect.escapeLikePattern("pat%tern"), is("pat%tern")); + assertThat(dialect.escapeLikePattern("pat_tern"), is("pat_tern")); + } + +} diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle11DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle11DialectTest.java new file mode 100644 index 00000000..a72bd46d --- /dev/null +++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle11DialectTest.java @@ -0,0 +1,118 @@ +package jp.co.future.uroborosql.dialect; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.*; + +import java.sql.Connection; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +import org.junit.Test; + +import jp.co.future.uroborosql.connection.ConnectionSupplier; + +/** + * Oracle10Dialectの個別実装部分のテストケース + * + * @author H.Sugimoto + * + */ +public class Oracle11DialectTest { + + @Test + public void testAccept11() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-11.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, instanceOf(Oracle11Dialect.class)); + } + + @Test + public void testAcceptUnder11() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-10.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, not(instanceOf(Oracle11Dialect.class))); + } + + @Test + public void testAcceptOver11() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-12.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, not(instanceOf(Oracle11Dialect.class))); + } + + @Test + public void testEscapeLikePattern() { + Dialect dialect = new Oracle11Dialect(); + assertThat(dialect.escapeLikePattern(""), is("")); + assertThat(dialect.escapeLikePattern("pattern"), is("pattern")); + assertThat(dialect.escapeLikePattern("%pattern"), is("\\%pattern")); + assertThat(dialect.escapeLikePattern("_pattern"), is("\\_pattern")); + assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern")); + assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern")); + assertThat(dialect.escapeLikePattern("pattern%"), is("pattern\\%")); + assertThat(dialect.escapeLikePattern("pattern_"), is("pattern\\_")); + assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern")); + assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern")); + assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern")); + } + +} diff --git a/src/test/java/jp/co/future/uroborosql/dialect/Oracle12DialectTest.java b/src/test/java/jp/co/future/uroborosql/dialect/Oracle12DialectTest.java new file mode 100644 index 00000000..88bf0e80 --- /dev/null +++ b/src/test/java/jp/co/future/uroborosql/dialect/Oracle12DialectTest.java @@ -0,0 +1,118 @@ +package jp.co.future.uroborosql.dialect; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.*; + +import java.sql.Connection; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +import org.junit.Test; + +import jp.co.future.uroborosql.connection.ConnectionSupplier; + +/** + * Oracle10Dialectの個別実装部分のテストケース + * + * @author H.Sugimoto + * + */ +public class Oracle12DialectTest { + + @Test + public void testAccept12() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-12.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, instanceOf(Oracle12Dialect.class)); + } + + @Test + public void testAcceptUnder12() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-11.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, not(instanceOf(Oracle12Dialect.class))); + } + + @Test + public void testAcceptOver12() { + ConnectionSupplier supplier = new ConnectionSupplier() { + + @Override + public Connection getConnection(final String alias) { + return null; + } + + @Override + public Connection getConnection() { + return null; + } + + @Override + public String getDatabaseName() { + return "Oracle-13.1"; + } + }; + + Dialect dialect = StreamSupport.stream(ServiceLoader.load(Dialect.class).spliterator(), false) + .filter(d -> d.accept(supplier)).findFirst().orElseGet(DefaultDialect::new); + + assertThat(dialect, instanceOf(Oracle12Dialect.class)); + } + + @Test + public void testEscapeLikePattern() { + Dialect dialect = new Oracle12Dialect(); + assertThat(dialect.escapeLikePattern(""), is("")); + assertThat(dialect.escapeLikePattern("pattern"), is("pattern")); + assertThat(dialect.escapeLikePattern("%pattern"), is("\\%pattern")); + assertThat(dialect.escapeLikePattern("_pattern"), is("\\_pattern")); + assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern")); + assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern")); + assertThat(dialect.escapeLikePattern("pattern%"), is("pattern\\%")); + assertThat(dialect.escapeLikePattern("pattern_"), is("pattern\\_")); + assertThat(dialect.escapeLikePattern("pat[]tern"), is("pat[]tern")); + assertThat(dialect.escapeLikePattern("pat%tern"), is("pat\\%tern")); + assertThat(dialect.escapeLikePattern("pat_tern"), is("pat\\_tern")); + } + +} diff --git a/src/test/java/jp/co/future/uroborosql/mapping/DefaultEntityHandlerTest.java b/src/test/java/jp/co/future/uroborosql/mapping/DefaultEntityHandlerTest.java index db16e664..6db06f3a 100644 --- a/src/test/java/jp/co/future/uroborosql/mapping/DefaultEntityHandlerTest.java +++ b/src/test/java/jp/co/future/uroborosql/mapping/DefaultEntityHandlerTest.java @@ -11,10 +11,15 @@ import java.sql.Statement; import java.time.LocalDate; import java.time.Month; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.stream.Stream; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + import jp.co.future.uroborosql.SqlAgent; import jp.co.future.uroborosql.UroboroSQL; import jp.co.future.uroborosql.config.SqlConfig; @@ -28,10 +33,6 @@ import jp.co.future.uroborosql.parameter.mapper.BindParameterMapper; import jp.co.future.uroborosql.parameter.mapper.BindParameterMapperManager; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - public class DefaultEntityHandlerTest { private static SqlConfig config; @@ -47,7 +48,8 @@ public static void setUpBeforeClass() throws Exception { // テーブル作成 try (Statement stmt = conn.createStatement()) { stmt.execute("drop table if exists test"); - stmt.execute("create table if not exists test( id NUMERIC(4),name VARCHAR(10),age NUMERIC(5),birthday DATE,memo VARCHAR(500),lock_version NUMERIC(4), primary key(id))"); + stmt.execute( + "create table if not exists test( id NUMERIC(4),name VARCHAR(10),age NUMERIC(5),birthday DATE,memo VARCHAR(500),lock_version NUMERIC(4), primary key(id))"); stmt.execute("comment on table test is 'test'"); stmt.execute("comment on column test.id is 'id'"); stmt.execute("comment on column test.name is 'name'"); @@ -56,13 +58,16 @@ public static void setUpBeforeClass() throws Exception { stmt.execute("comment on column test.memo is 'memo'"); stmt.execute("drop table if exists test_data_no_key"); - stmt.execute("create table if not exists test_data_no_key( id NUMERIC(4),name VARCHAR(10),age NUMERIC(5),birthday DATE,memo VARCHAR(500))"); + stmt.execute( + "create table if not exists test_data_no_key( id NUMERIC(4),name VARCHAR(10),age NUMERIC(5),birthday DATE,memo VARCHAR(500))"); stmt.execute("drop table if exists test_data_multi_key"); - stmt.execute("create table if not exists test_data_multi_key( id NUMERIC(4),key VARCHAR(10),name VARCHAR(10), primary key(id, key))"); + stmt.execute( + "create table if not exists test_data_multi_key( id NUMERIC(4),key VARCHAR(10),name VARCHAR(10), primary key(id, key))"); stmt.execute("drop table if exists test_data_lock_version"); - stmt.execute("create table if not exists test_data_lock_version( id NUMERIC(4), name VARCHAR(10), lock_version NUMERIC(10))"); + stmt.execute( + "create table if not exists test_data_lock_version( id NUMERIC(4), name VARCHAR(10), lock_version NUMERIC(10))"); } } @@ -226,6 +231,247 @@ public void testQuery3() throws Exception { } } + @Test + public void testQueryWithCondition() throws Exception { + + try (SqlAgent agent = config.agent()) { + agent.required(() -> { + TestEntity test1 = new TestEntity(1, "name1", 22, LocalDate.of(1990, Month.APRIL, 1), + Optional.of("memo")); + agent.insert(test1); + TestEntity test2 = new TestEntity(2, "name2", 21, LocalDate.of(1990, Month.MAY, 1), + Optional.of("memo2")); + agent.insert(test2); + TestEntity test3 = new TestEntity(3, "name3", 20, LocalDate.of(1990, Month.JUNE, 1), Optional.empty()); + agent.insert(test3); + + // Equal + List list = null; + list = agent.query(TestEntity.class).equal("id", 2).collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test2)); + + // Not Equal + list = agent.query(TestEntity.class).notEqual("id", 2).collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test3)); + + // Greater Than + list = agent.query(TestEntity.class).greaterThan("age", 21).collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test1)); + + // Greater Equal + list = agent.query(TestEntity.class).greaterEqual("age", 21).collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + + // Less Than + list = agent.query(TestEntity.class).lessThan("age", 21).collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test3)); + + // Greater Equal + list = agent.query(TestEntity.class).lessEqual("age", 21).collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test2)); + assertThat(list.get(1), is(test3)); + + // In (array) + list = agent.query(TestEntity.class).in("id", 1, 2).collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + + // In (list) + list = agent.query(TestEntity.class).in("id", Arrays.asList(2, 3)).collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test2)); + assertThat(list.get(1), is(test3)); + + // Not In (array) + list = agent.query(TestEntity.class).notIn("id", 1, 2).collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test3)); + + // Not In (list) + list = agent.query(TestEntity.class).notIn("id", Arrays.asList(2, 3)).collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test1)); + + // Like + list = agent.query(TestEntity.class).like("name", "name3").collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test3)); + + // Like with wildcards (_) + list = agent.query(TestEntity.class).like("name", "n_me_").collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test3)); + + // Like with wildcards (%) + list = agent.query(TestEntity.class).like("name", "name%").collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test3)); + + // startsWith + list = agent.query(TestEntity.class).startsWith("name", "name").collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test3)); + + // startsWith wildcards + list = agent.query(TestEntity.class).startsWith("name", "%ame").collect(); + assertThat(list.size(), is(0)); + + // endsWith + list = agent.query(TestEntity.class).endsWith("name", "3").collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test3)); + + // endsWith wildcards + list = agent.query(TestEntity.class).endsWith("name", "%3").collect(); + assertThat(list.size(), is(0)); + + // contains + list = agent.query(TestEntity.class).contains("name", "me").collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test3)); + + list = agent.query(TestEntity.class).contains("name", "%me_").collect(); + assertThat(list.size(), is(0)); + + // Not Like + list = agent.query(TestEntity.class).notLike("name", "name3").collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + + // Not Like with wildcards (_) + list = agent.query(TestEntity.class).notLike("name", "name_").collect(); + assertThat(list.size(), is(0)); + + // Not Like with wildcards (%) + list = agent.query(TestEntity.class).notLike("name", "name%").collect(); + assertThat(list.size(), is(0)); + + // notStartsWith + list = agent.query(TestEntity.class).notStartsWith("name", "name").collect(); + assertThat(list.size(), is(0)); + + // notStartsWith wildcards + list = agent.query(TestEntity.class).notStartsWith("name", "%name").collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test3)); + + // notEndsWith + list = agent.query(TestEntity.class).notEndsWith("name", "3").collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + + // notEndsWith wildcards + list = agent.query(TestEntity.class).notEndsWith("name", "%3").collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test3)); + + // notContains + list = agent.query(TestEntity.class).notContains("name", "2").collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test3)); + + // notContains wildcards + list = agent.query(TestEntity.class).notContains("name", "_2").collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test3)); + + // Between + list = agent.query(TestEntity.class) + .between("birthday", LocalDate.of(1990, Month.APRIL, 15), LocalDate.of(1990, Month.MAY, 15)) + .collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test2)); + list = agent.query(TestEntity.class) + .between("birthday", LocalDate.of(1990, Month.APRIL, 1), LocalDate.of(1990, Month.MAY, 1)) + .collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + + // is null + list = agent.query(TestEntity.class).isNull("memo").collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0), is(test3)); + + // is not null + list = agent.query(TestEntity.class).isNotNull("memo").collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + + // where + list = agent.query(TestEntity.class) + .where("BIRTHDAY < /*birthday1*/ or BIRTHDAY > /*birthday2*/") + .param("birthday1", LocalDate.of(1990, Month.APRIL, 15)) + .param("birthday2", LocalDate.of(1990, Month.MAY, 15)) + .collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test3)); + + // order by asc + list = agent.query(TestEntity.class) + .orderByAsc("age") + .collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test3)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test1)); + + // order by desc + list = agent.query(TestEntity.class) + .orderByDesc("birthday") + .collect(); + assertThat(list.size(), is(3)); + assertThat(list.get(0), is(test3)); + assertThat(list.get(1), is(test2)); + assertThat(list.get(2), is(test1)); + + // limit, offset + list = agent.query(TestEntity.class) + .limit(2) + .collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test1)); + assertThat(list.get(1), is(test2)); + + list = agent.query(TestEntity.class) + .limit(2) + .offset(1) + .collect(); + assertThat(list.size(), is(2)); + assertThat(list.get(0), is(test2)); + assertThat(list.get(1), is(test3)); + }); + } + } + @Test public void testUpdate1() throws Exception { @@ -419,11 +665,14 @@ public void testBatchInsert() throws Exception { try (SqlAgent agent = config.agent()) { agent.required(() -> { - TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, LocalDate.of(1990, Month.APRIL, 1), + TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, + LocalDate.of(1990, Month.APRIL, 1), "memo1"); - TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, LocalDate.of(1990, Month.APRIL, 2), + TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, + LocalDate.of(1990, Month.APRIL, 2), null); - TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, LocalDate.of(1990, Month.APRIL, 3), + TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, + LocalDate.of(1990, Month.APRIL, 3), "memo3"); int count = agent.inserts(Stream.of(test1, test2, test3), InsertsType.BATCH); @@ -445,14 +694,18 @@ public void testBatchInsert2() throws Exception { try (SqlAgent agent = config.agent()) { agent.required(() -> { - TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, LocalDate.of(1990, Month.APRIL, 1), + TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, + LocalDate.of(1990, Month.APRIL, 1), "memo1"); - TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, LocalDate.of(1990, Month.APRIL, 2), + TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, + LocalDate.of(1990, Month.APRIL, 2), null); - TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, LocalDate.of(1990, Month.APRIL, 3), + TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, + LocalDate.of(1990, Month.APRIL, 3), "memo3"); - int count = agent.inserts(TestEntityForInserts.class, Stream.of(test1, test2, test3), InsertsType.BATCH); + int count = agent.inserts(TestEntityForInserts.class, Stream.of(test1, test2, test3), + InsertsType.BATCH); assertThat(count, is(3)); TestEntityForInserts data = agent.find(TestEntityForInserts.class, 1).orElse(null); @@ -471,11 +724,14 @@ public void testBatchInsert3() throws Exception { try (SqlAgent agent = config.agent()) { agent.required(() -> { - TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, LocalDate.of(1990, Month.APRIL, 1), + TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, + LocalDate.of(1990, Month.APRIL, 1), "memo1"); - TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, LocalDate.of(1990, Month.APRIL, 2), + TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, + LocalDate.of(1990, Month.APRIL, 2), null); - TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, LocalDate.of(1990, Month.APRIL, 3), + TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, + LocalDate.of(1990, Month.APRIL, 3), "memo3"); int count = agent.inserts(Stream.of(test1, test2, test3), (ctx, cnt, r) -> cnt > 0, @@ -498,13 +754,17 @@ public void testBatchInsert4() throws Exception { try (SqlAgent agent = config.agent()) { agent.required(() -> { - TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, LocalDate.of(1990, Month.APRIL, 1), + TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, + LocalDate.of(1990, Month.APRIL, 1), "memo1"); - TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, LocalDate.of(1990, Month.APRIL, 2), + TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, + LocalDate.of(1990, Month.APRIL, 2), null); - TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, LocalDate.of(1990, Month.APRIL, 3), + TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, + LocalDate.of(1990, Month.APRIL, 3), "memo3"); - TestEntityForInserts test4 = new TestEntityForInserts(4, "name4", 23, LocalDate.of(1990, Month.APRIL, 4), + TestEntityForInserts test4 = new TestEntityForInserts(4, "name4", 23, + LocalDate.of(1990, Month.APRIL, 4), "memo4"); int count = agent.inserts(Stream.of(test1, test2, test3, test4), (ctx, cnt, r) -> cnt == 3, @@ -570,11 +830,14 @@ public void testBulkInsert() throws Exception { try (SqlAgent agent = config.agent()) { agent.required(() -> { - TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, LocalDate.of(1990, Month.APRIL, 1), + TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, + LocalDate.of(1990, Month.APRIL, 1), "memo1"); - TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, LocalDate.of(1990, Month.APRIL, 2), + TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, + LocalDate.of(1990, Month.APRIL, 2), null); - TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, LocalDate.of(1990, Month.APRIL, 3), + TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, + LocalDate.of(1990, Month.APRIL, 3), "memo3"); int count = agent.inserts(Stream.of(test1, test2, test3)); @@ -596,11 +859,14 @@ public void testBulkInsert2() throws Exception { try (SqlAgent agent = config.agent()) { agent.required(() -> { - TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, LocalDate.of(1990, Month.APRIL, 1), + TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, + LocalDate.of(1990, Month.APRIL, 1), "memo1"); - TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, LocalDate.of(1990, Month.APRIL, 2), + TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, + LocalDate.of(1990, Month.APRIL, 2), null); - TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, LocalDate.of(1990, Month.APRIL, 3), + TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, + LocalDate.of(1990, Month.APRIL, 3), "memo3"); int count = agent.inserts(TestEntityForInserts.class, Stream.of(test1, test2, test3)); @@ -622,11 +888,14 @@ public void testBulkInsert3() throws Exception { try (SqlAgent agent = config.agent()) { agent.required(() -> { - TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, LocalDate.of(1990, Month.APRIL, 1), + TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, + LocalDate.of(1990, Month.APRIL, 1), "memo1"); - TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, LocalDate.of(1990, Month.APRIL, 2), + TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, + LocalDate.of(1990, Month.APRIL, 2), null); - TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, LocalDate.of(1990, Month.APRIL, 3), + TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, + LocalDate.of(1990, Month.APRIL, 3), "memo3"); int count = agent.inserts(Stream.of(test1, test2, test3), (ctx, cnt, r) -> cnt > 0); @@ -648,13 +917,17 @@ public void testBulkInsert4() throws Exception { try (SqlAgent agent = config.agent()) { agent.required(() -> { - TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, LocalDate.of(1990, Month.APRIL, 1), + TestEntityForInserts test1 = new TestEntityForInserts(1, "name1", 20, + LocalDate.of(1990, Month.APRIL, 1), "memo1"); - TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, LocalDate.of(1990, Month.APRIL, 2), + TestEntityForInserts test2 = new TestEntityForInserts(2, "name2", 21, + LocalDate.of(1990, Month.APRIL, 2), null); - TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, LocalDate.of(1990, Month.APRIL, 3), + TestEntityForInserts test3 = new TestEntityForInserts(3, "name3", 22, + LocalDate.of(1990, Month.APRIL, 3), "memo3"); - TestEntityForInserts test4 = new TestEntityForInserts(4, "name4", 23, LocalDate.of(1990, Month.APRIL, 4), + TestEntityForInserts test4 = new TestEntityForInserts(4, "name4", 23, + LocalDate.of(1990, Month.APRIL, 4), "memo4"); int count = agent.inserts(Stream.of(test1, test2, test3, test4), (ctx, cnt, r) -> cnt == 3); @@ -765,7 +1038,7 @@ public void testCreateSelectContext() throws Exception { EntityHandler handler = config.getEntityHandler(); TableMetadata metadata = TableMetadata.createTableEntityMetadata(agent, MappingUtils.getTable(TestEntity.class)); - SqlContext ctx = handler.createSelectContext(agent, metadata, null); + SqlContext ctx = handler.createSelectContext(agent, metadata, null, true); String sql = ctx.getSql(); assertThat(sql, containsString("SF.isNotEmpty")); @@ -789,7 +1062,7 @@ public void testCreateSelectContextEmptyNotEqualsNull() throws Exception { handler.setEmptyStringEqualsNull(false); TableMetadata metadata = TableMetadata.createTableEntityMetadata(agent, MappingUtils.getTable(TestEntity.class)); - SqlContext ctx = handler.createSelectContext(agent, metadata, null); + SqlContext ctx = handler.createSelectContext(agent, metadata, null, true); String sql = ctx.getSql(); assertThat(sql, not(containsString("SF.isNotEmpty"))); @@ -814,7 +1087,7 @@ public void testCreateInsertContext() throws Exception { assertThat(sql, containsString("SF.isNotEmpty")); ctx.param("id", 1).param("name", "name1").param("age", 20) - .param("birthday", LocalDate.of(1990, Month.APRIL, 1)).param("memo", Optional.of("memo1")); + .param("birthday", LocalDate.of(1990, Month.APRIL, 1)).param("memo", Optional.of("memo1")); assertThat(agent.update(ctx), is(1)); } } @@ -832,7 +1105,7 @@ public void testCreateInsertContextEmptyNotEqualsNull() throws Exception { assertThat(sql, not(containsString("SF.isNotEmpty"))); ctx.param("id", 1).param("name", "name1").param("age", 20) - .param("birthday", LocalDate.of(1990, Month.APRIL, 1)).param("memo", Optional.of("memo1")); + .param("birthday", LocalDate.of(1990, Month.APRIL, 1)).param("memo", Optional.of("memo1")); assertThat(agent.update(ctx), is(1)); handler.setEmptyStringEqualsNull(true); @@ -851,7 +1124,7 @@ public void testCreateUpdateContext() throws Exception { EntityHandler handler = config.getEntityHandler(); TableMetadata metadata = TableMetadata.createTableEntityMetadata(agent, MappingUtils.getTable(TestEntity.class)); - SqlContext ctx = handler.createUpdateContext(agent, metadata, null); + SqlContext ctx = handler.createUpdateContext(agent, metadata, null, true); String sql = ctx.getSql(); assertThat(sql, containsString("SF.isNotEmpty")); @@ -875,7 +1148,7 @@ public void testCreateUpdateContextEmptyStringEqualsNull() throws Exception { handler.setEmptyStringEqualsNull(false); TableMetadata metadata = TableMetadata.createTableEntityMetadata(agent, MappingUtils.getTable(TestEntity.class)); - SqlContext ctx = handler.createUpdateContext(agent, metadata, null); + SqlContext ctx = handler.createUpdateContext(agent, metadata, null, true); String sql = ctx.getSql(); assertThat(sql, not(containsString("SF.isNotEmpty"))); @@ -900,7 +1173,7 @@ public void testCreateDeleteContext() throws Exception { EntityHandler handler = config.getEntityHandler(); TableMetadata metadata = TableMetadata.createTableEntityMetadata(agent, MappingUtils.getTable(TestEntity.class)); - SqlContext ctx = handler.createDeleteContext(agent, metadata, null); + SqlContext ctx = handler.createDeleteContext(agent, metadata, null, true); ctx.param("id", 1); assertThat(agent.update(ctx), is(1)); assertThat(agent.query(TestEntity.class).param("id", 1).first().orElse(null), is(nullValue())); @@ -950,7 +1223,7 @@ public Object toJdbc(final Name original, final Connection connection, @Override public Name getValue(final JavaType type, final ResultSet rs, final int columnIndex, final PropertyMapperManager mapperManager) - throws SQLException { + throws SQLException { String s = rs.getString(columnIndex); return s != null ? new Name(s.toUpperCase().replaceAll("^-", "").replaceAll("-$", "")) : null; } diff --git a/src/test/java/jp/co/future/uroborosql/parameter/ParameterTest.java b/src/test/java/jp/co/future/uroborosql/parameter/ParameterTest.java index 0814b013..c399d747 100644 --- a/src/test/java/jp/co/future/uroborosql/parameter/ParameterTest.java +++ b/src/test/java/jp/co/future/uroborosql/parameter/ParameterTest.java @@ -6,23 +6,28 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; import java.text.ParseException; import java.time.LocalDate; import java.time.Month; import java.util.Date; +import java.util.List; +import java.util.Map; import java.util.Optional; +import org.apache.commons.lang3.time.DateUtils; +import org.junit.Before; +import org.junit.Test; + import jp.co.future.uroborosql.SqlAgent; import jp.co.future.uroborosql.UroboroSQL; import jp.co.future.uroborosql.config.SqlConfig; import jp.co.future.uroborosql.context.SqlContext; +import jp.co.future.uroborosql.mapping.annotations.Table; import jp.co.future.uroborosql.parameter.mapper.BindParameterMapper; import jp.co.future.uroborosql.parameter.mapper.BindParameterMapperManager; -import org.apache.commons.lang3.time.DateUtils; -import org.junit.Before; -import org.junit.Test; - public class ParameterTest { private SqlConfig config; @@ -150,7 +155,133 @@ public void testSetInParameter_bytearray() throws SQLException { assertThat("更新件数が一致しません", agent.updateWith("INSERT INTO BYTE_ARRAY_TEST VALUES (/*id*/, /*data*/)").param("id", 1) - .param("data", "test".getBytes()).count(), is(1)); + .param("data", "test".getBytes()).count(), + is(1)); + } + } + + @Test + public void testSetParameter_subParameter() throws ParseException, SQLException { + + try (SqlAgent agent = config.agent()) { + agent.update("ddl/create_tables").count(); + + ColumnTypeTest bean = new ColumnTypeTest("test", 'A', 10, true, new Timestamp(System.currentTimeMillis()), + new Date(), Time.valueOf("10:20:30")); + agent.insert(bean); + + String sql = "select * from COLUMN_TYPE_TEST WHERE 1 = 1 /*IF bean.colVarchar != null*/ AND COL_VARCHAR = /*bean.colVarchar*//*END*//*IF bean.colBoolean != null*/ AND COL_BOOLEAN = /*bean.colBoolean*//*END*/"; + List> list = null; + + ColumnTypeChild child1 = new ColumnTypeChild("test", 'X', 0, null, null, null, null); + list = agent.queryWith(sql).param("bean", child1).collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0).get("COL_VARCHAR"), is("test")); + assertThat(list.get(0).get("COL_BOOLEAN"), is(true)); + + child1 = new ColumnTypeChild("test2", 'X', 0, null, null, null, null); + list = agent.queryWith(sql).param("bean", child1).collect(); + assertThat(list.size(), is(0)); + + ColumnTypeChild child2 = new ColumnTypeChild(null, 'X', 0, true, null, null, null); + list = agent.queryWith(sql).param("bean", child2).collect(); + assertThat(list.size(), is(1)); + assertThat(list.get(0).get("COL_VARCHAR"), is("test")); + assertThat(list.get(0).get("COL_BOOLEAN"), is(true)); + + child2 = new ColumnTypeChild(null, 'X', 0, false, null, null, null); + list = agent.queryWith(sql).param("bean", child2).collect(); + assertThat(list.size(), is(0)); + } + } + + @Table(name = "COLUMN_TYPE_TEST") + public static class ColumnTypeTest { + private String colVarchar; + private char colChar; + private int colNumeric; + private Boolean colBoolean; + private Timestamp colTimestamp; + private Date colDate; + private Time colTime; + + public ColumnTypeTest(final String colVarchar, final char colChar, final int colNumeric, + final Boolean colBoolean, + final Timestamp colTimestamp, final Date colDate, final Time colTime) { + super(); + this.colVarchar = colVarchar; + this.colChar = colChar; + this.colNumeric = colNumeric; + this.colBoolean = colBoolean; + this.colTimestamp = colTimestamp; + this.colDate = colDate; + this.colTime = colTime; + } + + public String getColVarchar() { + return colVarchar; + } + + public void setColVarchar(final String colVarchar) { + this.colVarchar = colVarchar; + } + + public char getColChar() { + return colChar; + } + + public void setColChar(final char colChar) { + this.colChar = colChar; } + + public int getColNumeric() { + return colNumeric; + } + + public void setColNumeric(final int colNumeric) { + this.colNumeric = colNumeric; + } + + public Boolean getColBoolean() { + return colBoolean; + } + + public void setColBoolean(final Boolean colBoolean) { + this.colBoolean = colBoolean; + } + + public Timestamp getColTimestamp() { + return colTimestamp; + } + + public void setColTimestamp(final Timestamp colTimestamp) { + this.colTimestamp = colTimestamp; + } + + public Date getColDate() { + return colDate; + } + + public void setColDate(final Date colDate) { + this.colDate = colDate; + } + + public Time getColTime() { + return colTime; + } + + public void setColTime(final Time colTime) { + this.colTime = colTime; + } + + } + + public static class ColumnTypeChild extends ColumnTypeTest { + public ColumnTypeChild(final String colVarchar, final char colChar, final int colNumeric, + final Boolean colBoolean, + final Timestamp colTimestamp, final Date colDate, final Time colTime) { + super(colVarchar, colChar, colNumeric, colBoolean, colTimestamp, colDate, colTime); + } + } } diff --git a/src/test/java/jp/co/future/uroborosql/store/NioSqlManagerTest.java b/src/test/java/jp/co/future/uroborosql/store/NioSqlManagerTest.java index 06a834ad..1dbf0791 100644 --- a/src/test/java/jp/co/future/uroborosql/store/NioSqlManagerTest.java +++ b/src/test/java/jp/co/future/uroborosql/store/NioSqlManagerTest.java @@ -13,7 +13,7 @@ import jp.co.future.uroborosql.dialect.Dialect; import jp.co.future.uroborosql.dialect.H2Dialect; -import jp.co.future.uroborosql.dialect.OracleDialect; +import jp.co.future.uroborosql.dialect.Oracle10Dialect; import jp.co.future.uroborosql.dialect.PostgresqlDialect; import jp.co.future.uroborosql.exception.UroborosqlRuntimeException; @@ -156,7 +156,7 @@ public void testGetSqlWithWatcher() throws Exception { Files.deleteIfExists(newFilePath); NioSqlManagerImpl manager = new NioSqlManagerImpl(true); - manager.setDialect(new OracleDialect()); + manager.setDialect(new Oracle10Dialect()); manager.initialize(); try { @@ -191,7 +191,7 @@ public void testGetSqlWithNoWatcher() throws Exception { Files.deleteIfExists(newFilePath); NioSqlManagerImpl manager = new NioSqlManagerImpl(); - manager.setDialect(new OracleDialect()); + manager.setDialect(new Oracle10Dialect()); manager.initialize(); try { @@ -224,7 +224,7 @@ public void testAddDialectSqlFolder() throws Exception { Files.deleteIfExists(dir); NioSqlManagerImpl manager = new NioSqlManagerImpl(true); - manager.setDialect(new OracleDialect()); + manager.setDialect(new Oracle10Dialect()); manager.initialize(); try { @@ -276,7 +276,7 @@ public void testAddDefaultFolderAndDialectFolder() throws Exception { Files.deleteIfExists(dialectDir); NioSqlManagerImpl manager = new NioSqlManagerImpl(true); - manager.setDialect(new OracleDialect()); + manager.setDialect(new Oracle10Dialect()); manager.initialize(); try { @@ -346,7 +346,7 @@ public void testAddDialectFolderAndDefaultFolder() throws Exception { Files.deleteIfExists(dialectDir); NioSqlManagerImpl manager = new NioSqlManagerImpl(true); - manager.setDialect(new OracleDialect()); + manager.setDialect(new Oracle10Dialect()); manager.initialize(); try {