diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractCreateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractCreateQuery.java index 7c5d3a0cb..1bbc8c60e 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractCreateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractCreateQuery.java @@ -17,19 +17,30 @@ import org.seasar.doma.jdbc.Sql; +/** + * An abstract base class for queries that create database resources. + * + *

This class provides a skeletal implementation of the {@link CreateQuery} interface, reducing + * the effort required to implement resource creation queries. + * + * @param the type of the resource to be created + */ public abstract class AbstractCreateQuery extends AbstractQuery implements CreateQuery { + /** {@inheritDoc} */ @Override public int getQueryTimeout() { return -1; } + /** {@inheritDoc} */ @Override public Sql getSql() { return null; } + /** {@inheritDoc} */ @Override public void complete() {} } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractQuery.java index 0d740eb96..b335e8a0f 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractQuery.java @@ -21,79 +21,129 @@ import org.seasar.doma.jdbc.CommentContext; import org.seasar.doma.jdbc.Config; +/** + * The base abstract class for all query implementations. + * + *

This class provides common functionality for all query types. + */ public abstract class AbstractQuery implements Query { + /** The class name of the caller. */ protected String callerClassName; + /** The method name of the caller. */ protected String callerMethodName; + /** The configuration. */ protected Config config; + /** The method that defines the query. */ protected Method method; + /** The query timeout in seconds. */ protected int queryTimeout; + /** The message to be included in SQL comments. */ protected String message; + /** The context for SQL comments. */ private CommentContext commentContext; + /** Creates a new instance. */ protected AbstractQuery() {} + /** {@inheritDoc} */ @Override public String getClassName() { return callerClassName; } + /** + * Sets the class name of the caller. + * + * @param callerClassName the class name + */ public void setCallerClassName(String callerClassName) { this.callerClassName = callerClassName; } + /** {@inheritDoc} */ @Override public String getMethodName() { return callerMethodName; } + /** + * Sets the method name of the caller. + * + * @param callerMethodName the method name + */ public void setCallerMethodName(String callerMethodName) { this.callerMethodName = callerMethodName; } + /** {@inheritDoc} */ @Override public Config getConfig() { return config; } + /** + * Sets the configuration. + * + * @param config the configuration + */ public void setConfig(Config config) { this.config = config; } + /** {@inheritDoc} */ @Override public Method getMethod() { return method; } + /** + * Sets the method that defines the query. + * + * @param method the method + */ public void setMethod(Method method) { this.method = method; } + /** {@inheritDoc} */ @Override public int getQueryTimeout() { return queryTimeout; } + /** + * Sets the query timeout in seconds. + * + * @param queryTimeout the query timeout + */ public void setQueryTimeout(int queryTimeout) { this.queryTimeout = queryTimeout; } + /** + * Sets the message to be included in SQL comments. + * + * @param message the message + */ public void setMessage(String message) { this.message = message; } + /** {@inheritDoc} */ @Override public void prepare() { assertNotNull(callerClassName, callerMethodName, config); commentContext = new CommentContext(callerClassName, callerMethodName, config, method, message); } + /** {@inheritDoc} */ @Override public String comment(String sql) { assertNotNull(sql, config, commentContext); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractSelectQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractSelectQuery.java index 6556ffa39..d7687ad05 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractSelectQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AbstractSelectQuery.java @@ -51,34 +51,57 @@ import org.seasar.doma.message.Message; import org.seasar.doma.wrapper.PrimitiveLongWrapper; +/** + * The base abstract class for all select query implementations. + * + *

This class provides common functionality for queries that select data from a database. + */ public abstract class AbstractSelectQuery extends AbstractQuery implements SelectQuery { + /** The parameters for the query. */ protected final Map parameters = new HashMap<>(); + /** The select options. */ protected SelectOptions options = SelectOptions.get(); + /** Whether the query is expected to return at least one result. */ protected boolean resultEnsured; + /** Whether the result mapping is ensured. */ protected boolean resultMappingEnsured; + /** The fetch type for this query. */ protected FetchType fetchType; + /** The fetch size for this query. */ protected int fetchSize; + /** The maximum number of rows to be returned. */ protected int maxRows; + /** The entity type for this query. */ protected EntityType entityType; + /** The prepared SQL for this query. */ protected PreparedSql sql; + /** The SQL log type for this query. */ protected SqlLogType sqlLogType; + /** Whether the result should be processed as a stream. */ protected boolean resultStream; + /** The aggregate strategy type for this query. */ protected AggregateStrategyType aggregateStrategyType; + /** Creates a new instance. */ protected AbstractSelectQuery() {} + /** + * {@inheritDoc} + * + *

This implementation prepares options and SQL. + */ @Override public void prepare() { super.prepare(); @@ -87,6 +110,12 @@ public void prepare() { assertNotNull(sql); } + /** + * Prepares the options for this query. + * + *

This method sets default values for fetch size, max rows, and query timeout if they are not + * already set. + */ protected void prepareOptions() { if (fetchSize <= 0) { fetchSize = config.getFetchSize(); @@ -99,8 +128,19 @@ protected void prepareOptions() { } } + /** + * Prepares the SQL for this query. + * + *

This method must be implemented by subclasses to build the SQL statement. + */ protected abstract void prepareSql(); + /** + * Builds the SQL for this query using the provided SQL builder. + * + * @param sqlBuilder the function to build the SQL + * @deprecated This method is scheduled for removal in a future version + */ @Deprecated(forRemoval = true) protected void buildSql( BiFunction>, PreparedSql> sqlBuilder) { @@ -108,11 +148,23 @@ protected void buildSql( sql = sqlBuilder.apply(evaluator, this::expandColumns); } + /** + * Creates an expression evaluator for evaluating SQL expressions. + * + * @return the expression evaluator + */ protected ExpressionEvaluator createExpressionEvaluator() { return new ExpressionEvaluator( parameters, config.getDialect().getExpressionFunctions(), config.getClassHelper()); } + /** + * Expands the columns for the entity type. + * + * @param node the expand node + * @return the list of expanded column names + * @throws JdbcException if the entity type is null + */ protected List expandColumns(ExpandNode node) { if (entityType == null) { SqlLocation location = node.getLocation(); @@ -130,6 +182,15 @@ protected List expandColumns(ExpandNode node) { .collect(Collectors.toList()); } + /** + * Expands the columns for the aggregate strategy type with the specified aliases. + * + * @param node the expand node + * @param aliasCsv the comma-separated list of aliases + * @return the list of expanded column names with aliases + * @throws JdbcException if the entity type is null + * @throws DomaException if an alias is not defined in the aggregate strategy type + */ protected List expandAggregateColumns(ExpandNode node, String aliasCsv) { if (entityType == null) { SqlLocation location = node.getLocation(); @@ -176,10 +237,23 @@ protected List expandAggregateColumns(ExpandNode node, String aliasCsv) .toList(); } + /** + * Populates values for the specified node in the SQL context. + * + * @param node the populate node + * @param context the SQL context + * @throws UnsupportedOperationException always thrown as this method is not supported in this + * class + */ protected void populateValues(PopulateNode node, SqlContext context) { throw new UnsupportedOperationException(); } + /** + * Executes a count query using the specified SQL node. The result is set to the select options. + * + * @param sqlNode the SQL node for the count query + */ protected void executeCount(SqlNode sqlNode) { CountQuery query = new CountQuery(); query.setCallerClassName(callerClassName); @@ -202,102 +276,181 @@ protected void executeCount(SqlNode sqlNode) { SelectOptionsAccessor.setCountSize(options, count); } + /** {@inheritDoc} */ @Override public SelectOptions getOptions() { return options; } + /** + * Sets the select options. + * + * @param options the select options + */ public void setOptions(SelectOptions options) { this.options = options; } + /** + * Adds a parameter to this query. + * + * @param name the parameter name + * @param type the parameter type + * @param value the parameter value + */ public void addParameter(String name, Class type, Object value) { assertNotNull(name, type); parameters.put(name, new Value(type, value)); } + /** + * Adds multiple parameters to this query. + * + * @param parameters the parameters to add + */ public void addParameters(Map parameters) { this.parameters.putAll(parameters); } + /** Clears all parameters from this query. */ public void clearParameters() { this.parameters.clear(); } + /** {@inheritDoc} */ @Override public boolean isResultEnsured() { return resultEnsured; } + /** + * Sets whether the query is expected to return at least one result. + * + * @param resultEnsured {@code true} if the query is expected to return at least one result + */ public void setResultEnsured(boolean resultEnsured) { this.resultEnsured = resultEnsured; } + /** {@inheritDoc} */ @Override public boolean isResultMappingEnsured() { return resultMappingEnsured; } + /** + * Sets whether the result mapping is ensured. + * + * @param resultMappingEnsured {@code true} if the result mapping is ensured + */ public void setResultMappingEnsured(boolean resultMappingEnsured) { this.resultMappingEnsured = resultMappingEnsured; } + /** {@inheritDoc} */ @Override public FetchType getFetchType() { return fetchType; } + /** + * Sets the fetch type for this query. + * + * @param fetchType the fetch type + */ public void setFetchType(FetchType fetchType) { this.fetchType = fetchType; } + /** {@inheritDoc} */ @Override public int getFetchSize() { return fetchSize; } + /** + * Sets the fetch size for this query. + * + * @param fetchSize the fetch size + */ public void setFetchSize(int fetchSize) { this.fetchSize = fetchSize; } + /** {@inheritDoc} */ @Override public int getMaxRows() { return maxRows; } + /** + * Sets the maximum number of rows to be returned. + * + * @param maxRows the maximum number of rows + */ public void setMaxRows(int maxRows) { this.maxRows = maxRows; } + /** {@inheritDoc} */ + @Override public SqlLogType getSqlLogType() { return sqlLogType; } + /** + * Sets the SQL log type for this query. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** {@inheritDoc} */ + @Override public boolean isResultStream() { return resultStream; } + /** + * Sets whether the result should be processed as a stream. + * + * @param resultStream {@code true} if the result should be processed as a stream + */ public void setResultStream(boolean resultStream) { this.resultStream = resultStream; } + /** + * Sets the aggregate strategy type for this query. + * + * @param aggregateStrategyType the aggregate strategy type + */ public void setAggregateStrategyType(AggregateStrategyType aggregateStrategyType) { this.aggregateStrategyType = aggregateStrategyType; } + /** + * Sets the entity type for this query. + * + * @param entityType the entity type + */ public void setEntityType(EntityType entityType) { this.entityType = entityType; } + /** {@inheritDoc} */ @Override public PreparedSql getSql() { return sql; } + /** + * Returns a string representation of this query. + * + * @return the string representation of the SQL, or null if the SQL is not prepared + */ @Override public String toString() { return sql != null ? sql.toString() : null; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ArrayCreateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ArrayCreateQuery.java index a3ef78ae5..3f63c0863 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ArrayCreateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ArrayCreateQuery.java @@ -21,34 +21,74 @@ import java.sql.Connection; import java.sql.SQLException; +/** + * A query implementation for creating a SQL array. + * + *

This class extends {@link AbstractCreateQuery} to provide functionality for creating SQL + * arrays in a database. It handles the creation of JDBC {@link Array} objects by specifying the SQL + * type name and array elements. + */ public class ArrayCreateQuery extends AbstractCreateQuery { + /** The SQL type name of the array. */ protected String typeName; + /** The array elements. */ protected Object[] elements; + /** + * Prepares this query for execution. This method must be called before {@link + * #create(Connection)}. + */ @Override public void prepare() { super.prepare(); assertNotNull(typeName, elements); } + /** + * Returns the SQL type name of the array. + * + * @return the SQL type name + */ public String getTypeName() { return typeName; } + /** + * Sets the SQL type name of the array. + * + * @param typeName the SQL type name + */ public void setTypeName(String typeName) { this.typeName = typeName; } + /** + * Returns the array elements. + * + * @return the array elements + */ public Object[] getElements() { return elements; } + /** + * Sets the array elements. + * + * @param elements the array elements + */ public void setElements(Object[] elements) { this.elements = elements; } + /** + * Creates a SQL array. + * + * @param connection the JDBC connection + * @return the created SQL array + * @throws SQLException if a database access error occurs + */ @Override public Array create(Connection connection) throws SQLException { return connection.createArrayOf(typeName, elements); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchDeleteQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchDeleteQuery.java index 050f8f6bb..a466cb11a 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchDeleteQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchDeleteQuery.java @@ -32,17 +32,39 @@ import org.seasar.doma.jdbc.entity.EntityType; import org.seasar.doma.jdbc.entity.Property; +/** + * An auto batch delete query that is executed against an entity class. + * + *

This class implements {@link BatchDeleteQuery} to provide batch DELETE operations for + * entities. It handles version checking for optimistic locking and supports tenant ID-based + * isolation. + * + * @param the entity type + */ public class AutoBatchDeleteQuery extends AutoBatchModifyQuery implements BatchDeleteQuery { + /** Whether to ignore the version property for optimistic locking. */ protected boolean versionIgnored; + /** Whether to suppress optimistic lock exceptions. */ protected boolean optimisticLockExceptionSuppressed; + /** + * Constructs an instance. + * + * @param entityType the entity type + */ public AutoBatchDeleteQuery(EntityType entityType) { super(entityType); } + /** + * Prepares this query for execution. + * + *

This method validates the state of this instance, prepares SQL statements for all entities, + * and ensures that the number of SQL statements matches the number of entities. + */ @Override public void prepare() { super.prepare(); @@ -70,6 +92,12 @@ public void prepare() { assertEquals(size, sqls.size()); } + /** + * Executes pre-delete processing for the current entity. + * + *

This method creates a context for pre-delete operations and calls the entity type's + * preDelete method. If a new entity is returned by the context, it replaces the current entity. + */ protected void preDelete() { AutoBatchPreDeleteContext context = new AutoBatchPreDeleteContext<>(entityType, method, config); @@ -79,6 +107,12 @@ protected void preDelete() { } } + /** + * Prepares optimistic locking settings for this query. + * + *

This method sets the optimistic lock check flag based on the version property type and the + * configuration settings for version handling and exception suppression. + */ protected void prepareOptimisticLock() { if (versionPropertyType != null && !versionIgnored) { if (!optimisticLockExceptionSuppressed) { @@ -87,6 +121,13 @@ protected void prepareOptimisticLock() { } } + /** + * Prepares the SQL statement for the current entity. + * + *

This method builds a DELETE SQL statement with appropriate WHERE clauses for ID properties, + * version property (for optimistic locking), and tenant ID property (for multi-tenancy). The + * completed SQL statement is added to the list of SQL statements to be executed. + */ protected void prepareSql() { Naming naming = config.getNaming(); Dialect dialect = config.getDialect(); @@ -139,6 +180,12 @@ protected void prepareSql() { sqls.add(sql); } + /** + * Completes this query after execution. + * + *

This method performs post-processing for all entities after the batch delete operation has + * been executed. It calls the postDelete method for each entity. + */ @Override public void complete() { for (ListIterator it = entities.listIterator(); it.hasNext(); ) { @@ -148,6 +195,12 @@ public void complete() { } } + /** + * Executes post-delete processing for the current entity. + * + *

This method creates a context for post-delete operations and calls the entity type's + * postDelete method. If a new entity is returned by the context, it replaces the current entity. + */ protected void postDelete() { AutoBatchPostDeleteContext context = new AutoBatchPostDeleteContext<>(entityType, method, config); @@ -157,23 +210,58 @@ protected void postDelete() { } } + /** + * Sets whether to ignore the version property for optimistic locking. + * + * @param versionIgnored true to ignore the version property, false otherwise + */ public void setVersionIgnored(boolean versionIgnored) { this.versionIgnored = versionIgnored; } + /** + * Sets whether to suppress optimistic lock exceptions. + * + * @param optimisticLockExceptionSuppressed true to suppress optimistic lock exceptions, false + * otherwise + */ public void setOptimisticLockExceptionSuppressed(boolean optimisticLockExceptionSuppressed) { this.optimisticLockExceptionSuppressed = optimisticLockExceptionSuppressed; } + /** + * The context class for pre-delete processing in batch operations. + * + * @param the entity type + */ protected static class AutoBatchPreDeleteContext extends AbstractPreDeleteContext { + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public AutoBatchPreDeleteContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } } + /** + * The context class for post-delete processing in batch operations. + * + * @param the entity type + */ protected static class AutoBatchPostDeleteContext extends AbstractPostDeleteContext { + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public AutoBatchPostDeleteContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchInsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchInsertQuery.java index 9116bc6c4..ddde51b5b 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchInsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchInsertQuery.java @@ -44,37 +44,78 @@ import org.seasar.doma.jdbc.id.IdGenerationConfig; import org.seasar.doma.message.Message; +/** + * An auto batch insert query that is executed against an entity class. + * + *

This class implements {@link BatchInsertQuery} to provide batch INSERT operations for + * entities. It handles ID generation, version initialization, and supports various duplicate key + * handling strategies. + * + * @param the entity type + */ public class AutoBatchInsertQuery extends AutoBatchModifyQuery implements BatchInsertQuery { + /** The property type for the generated ID. */ protected GeneratedIdPropertyType generatedIdPropertyType; + /** The configuration for ID generation. */ protected IdGenerationConfig idGenerationConfig; + /** Whether batch operations are supported. */ protected boolean batchSupported = true; + /** Whether to ignore auto-generated keys. */ protected boolean generatedKeysIgnored = false; + /** The strategy for handling duplicate keys. */ protected DuplicateKeyType duplicateKeyType = DuplicateKeyType.EXCEPTION; + /** The names of columns that may cause duplicate key violations. */ protected String[] duplicateKeyNames = EMPTY_STRINGS; + /** + * Constructs an instance. + * + * @param entityType the entity type + */ public AutoBatchInsertQuery(EntityType entityType) { super(entityType); } + /** + * Sets whether to ignore auto-generated keys. + * + * @param generatedKeysIgnored whether to ignore auto-generated keys + */ public void setGeneratedKeysIgnored(boolean generatedKeysIgnored) { this.generatedKeysIgnored = generatedKeysIgnored; } + /** + * Sets the strategy for handling duplicate keys. + * + * @param duplicateKeyType the strategy for handling duplicate keys + */ public void setDuplicateKeyType(DuplicateKeyType duplicateKeyType) { this.duplicateKeyType = duplicateKeyType; } + /** + * Sets the names of columns that may cause duplicate key violations. + * + * @param duplicateKeyNames the names of columns that may cause duplicate key violations + */ public void setDuplicateKeyNames(String... duplicateKeyNames) { this.duplicateKeyNames = duplicateKeyNames; } + /** + * Prepares this query for execution. + * + *

This method processes all entities in the batch, applying pre-insert hooks, preparing ID and + * version values, and generating SQL statements for each entity. + */ @Override public void prepare() { super.prepare(); @@ -106,6 +147,12 @@ public void prepare() { assertEquals(entities.size(), sqls.size()); } + /** + * Executes pre-insert hooks on the current entity. + * + *

This method creates a context for pre-insert processing and applies entity-specific + * pre-insert logic to the current entity. + */ protected void preInsert() { AutoBatchPreInsertContext context = new AutoBatchPreInsertContext<>(entityType, method, config, duplicateKeyType); @@ -115,6 +162,12 @@ protected void preInsert() { } } + /** + * Prepares ID and version property types for this query. + * + *

This method initializes the generated ID property type and configures ID generation + * settings, including whether batch operations and auto-generated keys are supported. + */ @Override protected void prepareIdAndVersionPropertyTypes() { super.prepareIdAndVersionPropertyTypes(); @@ -132,6 +185,13 @@ protected void prepareIdAndVersionPropertyTypes() { } } + /** + * Prepares the target property types for this query. + * + *

This method determines which entity properties should be included in the INSERT statement + * based on their insertability, ID status, and other criteria. It also validates that + * non-generated ID properties have non-null values. + */ protected void prepareTargetPropertyTypes() { targetPropertyTypes = new ArrayList<>(entityType.getEntityPropertyTypes().size()); for (EntityPropertyType propertyType : entityType.getEntityPropertyTypes()) { @@ -160,6 +220,12 @@ protected void prepareTargetPropertyTypes() { } } + /** + * Prepares the ID value for the current entity. + * + *

If a generated ID property type is configured, this method applies pre-insert ID generation + * logic to the current entity. + */ protected void prepareIdValue() { if (generatedIdPropertyType != null && idGenerationConfig != null) { currentEntity = @@ -167,12 +233,24 @@ protected void prepareIdValue() { } } + /** + * Prepares the version value for the current entity. + * + *

If a version property type is configured, this method initializes the version value to 1 for + * the current entity. + */ protected void prepareVersionValue() { if (versionPropertyType != null) { currentEntity = versionPropertyType.setIfNecessary(entityType, currentEntity, 1); } } + /** + * Prepares the SQL statement for the current entity. + * + *

This method builds the appropriate SQL statement (INSERT or UPSERT) based on the duplicate + * key handling strategy and dialect capabilities. + */ protected void prepareSql() { Naming naming = config.getNaming(); Dialect dialect = config.getDialect(); @@ -235,11 +313,25 @@ private void assembleUpsertSql(PreparedSqlBuilder builder, Naming naming, Dialec upsertAssembler.assemble(); } + /** + * Determines whether batch operations are supported for this query. + * + * @return true if batch operations are supported, false otherwise + */ @Override public boolean isBatchSupported() { return batchSupported; } + /** + * Generates an ID for the entity at the specified index using auto-generated keys. + * + *

This method retrieves the auto-generated key from the statement and updates the entity with + * the generated ID value. + * + * @param statement the statement that executed the insert + * @param index the index of the entity in the batch + */ @Override public void generateId(Statement statement, int index) { if (isAutoGeneratedKeysSupported()) { @@ -255,6 +347,17 @@ public void generateId(Statement statement, int index) { } } + /** + * Generates IDs for a range of entities using auto-generated keys. + * + *

This method retrieves auto-generated keys from the statement and updates the specified range + * of entities with the generated ID values. + * + * @param statement the statement that executed the batch insert + * @param position the starting position in the entities list + * @param size the number of entities to process + * @throws DomaIllegalArgumentException if the position and size parameters are invalid + */ @Override public void generateIds(Statement statement, int position, int size) { if (isAutoGeneratedKeysSupported() && isBatchSupported()) { @@ -281,6 +384,12 @@ public void generateIds(Statement statement, int position, int size) { } } + /** + * Completes the batch insert operation. + * + *

This method applies post-insert hooks to all entities in the batch after the database + * operation has been executed. + */ @Override public void complete() { for (ListIterator it = entities.listIterator(); it.hasNext(); ) { @@ -290,6 +399,12 @@ public void complete() { } } + /** + * Executes post-insert hooks on the current entity. + * + *

This method creates a context for post-insert processing and applies entity-specific + * post-insert logic to the current entity. + */ protected void postInsert() { AutoBatchPostInsertContext context = new AutoBatchPostInsertContext<>(entityType, method, config, duplicateKeyType); @@ -299,16 +414,48 @@ protected void postInsert() { } } + /** + * The context class for pre-insert batch processing. + * + *

This context is used during the pre-insert phase of batch insert operations to provide + * entity-specific processing. + * + * @param the entity type + */ protected static class AutoBatchPreInsertContext extends AbstractPreInsertContext { + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + * @param duplicateKeyType the strategy for handling duplicate keys + */ public AutoBatchPreInsertContext( EntityType entityType, Method method, Config config, DuplicateKeyType duplicateKeyType) { super(entityType, method, config, duplicateKeyType); } } + /** + * The context class for post-insert batch processing. + * + *

This context is used during the post-insert phase of batch insert operations to provide + * entity-specific processing after database operations have been executed. + * + * @param the entity type + */ protected static class AutoBatchPostInsertContext extends AbstractPostInsertContext { + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + * @param duplicateKeyType the strategy for handling duplicate keys + */ public AutoBatchPostInsertContext( EntityType entityType, Method method, Config config, DuplicateKeyType duplicateKeyType) { super(entityType, method, config, duplicateKeyType); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchModifyQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchModifyQuery.java index e7eaf940a..fef5ad7a2 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchModifyQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchModifyQuery.java @@ -30,42 +30,68 @@ import org.seasar.doma.jdbc.entity.VersionPropertyType; import org.seasar.doma.message.Message; +/** + * An abstract base class for auto batch modification queries. + * + *

This class provides common functionality for batch operations that modify entities in the + * database, such as batch insert, update, and delete operations. It manages entity properties, + * optimistic locking, and SQL generation for batch operations. + * + * @param the entity type + */ public abstract class AutoBatchModifyQuery extends AbstractQuery implements BatchModifyQuery { + /** Empty string array constant. */ protected static final String[] EMPTY_STRINGS = new String[] {}; + /** The property types targeted by this query. */ protected List> targetPropertyTypes; + /** The ID property types of the entity. */ protected List> idPropertyTypes; + /** The names of properties to be included in the query. */ protected String[] includedPropertyNames = EMPTY_STRINGS; + /** The names of properties to be excluded from the query. */ protected String[] excludedPropertyNames = EMPTY_STRINGS; + /** The entity type. */ protected final EntityType entityType; + /** The version property type for optimistic locking. */ protected VersionPropertyType versionPropertyType; + /** The tenant ID property type for multi-tenancy. */ protected TenantIdPropertyType tenantIdPropertyType; + /** Whether optimistic lock checking is required. */ protected boolean optimisticLockCheckRequired; + /** Whether auto-generated keys are supported. */ protected boolean autoGeneratedKeysSupported; + /** Whether this query is executable. */ protected boolean executable; + /** The cause of SQL execution skip if the query is not executable. */ protected SqlExecutionSkipCause sqlExecutionSkipCause = SqlExecutionSkipCause.BATCH_TARGET_NONEXISTENT; + /** The list of SQL statements to be executed in batch. */ protected List sqls; + /** The list of entities to be processed. */ protected List entities; + /** The current entity being processed. */ protected ENTITY currentEntity; + /** The batch size. */ protected int batchSize; + /** The SQL log type. */ protected SqlLogType sqlLogType; public AutoBatchModifyQuery(EntityType entityType) { @@ -73,18 +99,38 @@ public AutoBatchModifyQuery(EntityType entityType) { this.entityType = entityType; } + /** + * Prepares the ID, version, and tenant ID property types from the entity type. + * + *

This method initializes the property types that are used for identifying entities and + * handling optimistic locking and multi-tenancy. + */ protected void prepareIdAndVersionPropertyTypes() { idPropertyTypes = entityType.getIdPropertyTypes(); versionPropertyType = entityType.getVersionPropertyType(); tenantIdPropertyType = entityType.getTenantIdPropertyType(); } + /** + * Validates that the entity has at least one ID property. + * + *

This method throws a {@link JdbcException} if the entity doesn't have any ID properties, as + * batch operations require entities to be identifiable. + * + * @throws JdbcException if the entity doesn't have any ID properties + */ protected void validateIdExistent() { if (idPropertyTypes.isEmpty()) { throw new JdbcException(Message.DOMA2022, entityType.getName()); } } + /** + * Prepares the query options. + * + *

This method initializes the query timeout and batch size from the configuration if they + * haven't been explicitly set or if they have invalid values. + */ protected void prepareOptions() { if (queryTimeout <= 0) { queryTimeout = config.getQueryTimeout(); @@ -94,6 +140,16 @@ protected void prepareOptions() { } } + /** + * Determines if a property should be included in the query based on its name. + * + *

This method checks if the property name is in the included properties list and not in the + * excluded properties list. If no included properties are specified, all properties except those + * explicitly excluded are considered targets. + * + * @param name the property name to check + * @return {@code true} if the property should be included, {@code false} otherwise + */ protected boolean isTargetPropertyName(String name) { if (includedPropertyNames.length > 0) { for (String includedName : includedPropertyNames) { @@ -119,6 +175,15 @@ protected boolean isTargetPropertyName(String name) { return true; } + /** + * Sets the entities to be processed by this batch query. + * + *

This method initializes the internal list of entities and prepares the SQL statements list + * with the same size as the entities list. + * + * @param entities the entities to be processed + * @throws NullPointerException if {@code entities} is {@code null} + */ public void setEntities(Iterable entities) { assertNotNull(entities); if (entities instanceof Collection) { @@ -132,66 +197,146 @@ public void setEntities(Iterable entities) { this.sqls = new ArrayList<>(this.entities.size()); } + /** + * Returns the list of entities to be processed by this batch query. + * + * @return the list of entities + */ public List getEntities() { return entities; } + /** + * Sets the batch size for this query. + * + *

The batch size determines how many entities are processed in a single batch operation. + * + * @param batchSize the batch size + */ public void setBatchSize(int batchSize) { this.batchSize = batchSize; } + /** + * Sets the names of properties to be included in the query. + * + *

If this is set, only the specified properties will be included in the query, unless they are + * also in the excluded properties list. + * + * @param includedPropertyNames the names of properties to include + */ public void setIncludedPropertyNames(String... includedPropertyNames) { this.includedPropertyNames = includedPropertyNames; } + /** + * Sets the names of properties to be excluded from the query. + * + *

If this is set, the specified properties will be excluded from the query, even if they are + * in the included properties list. + * + * @param excludedPropertyNames the names of properties to exclude + */ public void setExcludedPropertyNames(String... excludedPropertyNames) { this.excludedPropertyNames = excludedPropertyNames; } + /** + * Sets the SQL log type for this query. + * + *

The SQL log type determines how SQL statements are logged. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** + * Returns the first SQL statement in the batch. + * + * @return the first SQL statement + */ @Override public PreparedSql getSql() { return sqls.get(0); } + /** + * Returns all SQL statements in the batch. + * + * @return the list of SQL statements + */ @Override public List getSqls() { return sqls; } + /** + * Indicates whether optimistic lock checking is required. + * + * @return {@code true} if optimistic lock checking is required, {@code false} otherwise + */ @Override public boolean isOptimisticLockCheckRequired() { return optimisticLockCheckRequired; } + /** + * Indicates whether auto-generated keys are supported. + * + * @return {@code true} if auto-generated keys are supported, {@code false} otherwise + */ @Override public boolean isAutoGeneratedKeysSupported() { return autoGeneratedKeysSupported; } + /** + * Indicates whether this query is executable. + * + * @return {@code true} if this query is executable, {@code false} otherwise + */ @Override public boolean isExecutable() { return executable; } + /** + * Returns the cause of SQL execution skip if the query is not executable. + * + * @return the cause of SQL execution skip, or {@code null} if the query is executable + */ @Override public SqlExecutionSkipCause getSqlExecutionSkipCause() { return sqlExecutionSkipCause; } + /** + * Returns the batch size for this query. + * + * @return the batch size + */ @Override public int getBatchSize() { return batchSize; } + /** + * Returns the SQL log type for this query. + * + * @return the SQL log type + */ @Override public SqlLogType getSqlLogType() { return sqlLogType; } + /** + * Returns a string representation of this query. + * + * @return a string representation of this query + */ @Override public String toString() { return sqls.toString(); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchUpdateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchUpdateQuery.java index 8e33eb379..c9b499db9 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchUpdateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoBatchUpdateQuery.java @@ -32,19 +32,37 @@ import org.seasar.doma.jdbc.entity.EntityType; import org.seasar.doma.jdbc.entity.Property; +/** + * An auto batch update query that is executed against an entity class. + * + *

This class implements {@link BatchUpdateQuery} to provide batch UPDATE operations for + * entities. It handles version checking for optimistic locking and supports tenant ID-based + * isolation. + * + * @param the entity type + */ public class AutoBatchUpdateQuery extends AutoBatchModifyQuery implements BatchUpdateQuery { + /** Whether to ignore the version property for optimistic locking. */ protected boolean versionIgnored; + /** Whether to suppress optimistic lock exceptions. */ protected boolean optimisticLockExceptionSuppressed; + /** Helper for batch update queries. */ protected BatchUpdateQueryHelper helper; public AutoBatchUpdateQuery(EntityType entityType) { super(entityType); } + /** + * Prepares this query for execution. + * + *

This method initializes the query by setting up the helper, preparing the entities, and + * generating SQL statements for each entity in the batch. + */ @Override public void prepare() { super.prepare(); @@ -72,6 +90,12 @@ public void prepare() { assertEquals(entities.size(), sqls.size()); } + /** + * Sets up the batch update query helper. + * + *

This method initializes the helper with the configuration, entity type, included and + * excluded property names, and optimistic locking settings. + */ protected void setupHelper() { helper = new BatchUpdateQueryHelper<>( @@ -83,6 +107,12 @@ protected void setupHelper() { optimisticLockExceptionSuppressed); } + /** + * Executes pre-update processing for the current entity. + * + *

This method calls the entity type's preUpdate method with the current entity and updates the + * current entity if a new entity is returned from the context. + */ protected void preUpdate() { AutoBatchPreUpdateContext context = new AutoBatchPreUpdateContext<>(entityType, method, config); @@ -92,6 +122,12 @@ protected void preUpdate() { } } + /** + * Prepares optimistic locking settings for this query. + * + *

This method sets the optimistic lock check flag based on the version property type and the + * version ignored and optimistic lock exception suppressed flags. + */ protected void prepareOptimisticLock() { if (versionPropertyType != null && !versionIgnored) { if (!optimisticLockExceptionSuppressed) { @@ -100,6 +136,12 @@ protected void prepareOptimisticLock() { } } + /** + * Prepares the target property types for this query. + * + *

This method gets the target property types from the helper and sets the executable flag to + * true if there are any target properties to update. + */ protected void prepareTargetPropertyTypes() { targetPropertyTypes = helper.getTargetPropertyTypes(); if (!targetPropertyTypes.isEmpty()) { @@ -108,6 +150,13 @@ protected void prepareTargetPropertyTypes() { } } + /** + * Prepares the SQL statement for the current entity. + * + *

This method builds an UPDATE SQL statement with the appropriate SET clause for the target + * properties and WHERE clause for the ID properties, version property, and tenant ID property as + * needed. + */ protected void prepareSql() { Naming naming = config.getNaming(); Dialect dialect = config.getDialect(); @@ -162,6 +211,12 @@ protected void prepareSql() { sqls.add(sql); } + /** + * Increments the version property values of all entities. + * + *

This method is called after successful execution of the batch update to increment the + * version values for optimistic locking. + */ @Override public void incrementVersions() { if (versionPropertyType != null && !versionIgnored) { @@ -172,6 +227,12 @@ public void incrementVersions() { } } + /** + * Completes this query by performing post-update processing for all entities. + * + *

This method is called after the batch update has been executed to perform any necessary + * post-processing on the entities. + */ @Override public void complete() { for (ListIterator it = entities.listIterator(); it.hasNext(); ) { @@ -181,6 +242,13 @@ public void complete() { } } + /** + * Executes post-update processing for the current entity. + * + *

This method calls the entity type's postUpdate method with the current entity, updates the + * current entity if a new entity is returned from the context, and saves the current states of + * the entity. + */ protected void postUpdate() { AutoBatchPostUpdateContext context = new AutoBatchPostUpdateContext<>(entityType, method, config); @@ -191,25 +259,71 @@ protected void postUpdate() { entityType.saveCurrentStates(currentEntity); } + /** + * Sets whether to ignore the version property for optimistic locking. + * + *

If set to {@code true}, the version property will not be used for optimistic locking in the + * WHERE clause of the UPDATE statement, and the version will not be incremented. + * + * @param versionIgnored whether to ignore the version property + */ public void setVersionIgnored(boolean versionIgnored) { this.versionIgnored |= versionIgnored; } + /** + * Sets whether to suppress optimistic lock exceptions. + * + *

If set to {@code true}, optimistic lock exceptions will not be thrown even if the version + * check fails during the update operation. + * + * @param optimisticLockExceptionSuppressed whether to suppress optimistic lock exceptions + */ public void setOptimisticLockExceptionSuppressed(boolean optimisticLockExceptionSuppressed) { this.optimisticLockExceptionSuppressed = optimisticLockExceptionSuppressed; } + /** + * A context class for pre-update processing in batch update operations. + * + *

This class provides context information for the pre-update phase of batch update operations. + * + * @param the entity type + */ protected static class AutoBatchPreUpdateContext extends AbstractPreUpdateContext { + /** + * Constructs a new instance. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public AutoBatchPreUpdateContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } + /** + * Indicates whether the entity has been changed. + * + *

This method always returns {@code true} for batch update operations. + * + * @return {@code true} + */ @Override public boolean isEntityChanged() { return true; } + /** + * Indicates whether the specified property has been changed. + * + *

This method always returns {@code true} for batch update operations. + * + * @param propertyName the property name + * @return {@code true} + * @throws IllegalArgumentException if the property is not defined in the entity + */ @Override public boolean isPropertyChanged(String propertyName) { validatePropertyDefined(propertyName); @@ -217,12 +331,36 @@ public boolean isPropertyChanged(String propertyName) { } } + /** + * A context class for post-update processing in batch update operations. + * + *

This class provides context information for the post-update phase of batch update + * operations. + * + * @param the entity type + */ protected static class AutoBatchPostUpdateContext extends AbstractPostUpdateContext { + /** + * Constructs a new instance. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public AutoBatchPostUpdateContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } + /** + * Indicates whether the specified property has been changed. + * + *

This method always returns {@code true} for batch update operations. + * + * @param propertyName the property name + * @return {@code true} + * @throws IllegalArgumentException if the property is not defined in the entity + */ @Override public boolean isPropertyChanged(String propertyName) { validatePropertyDefined(propertyName); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoDeleteQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoDeleteQuery.java index 4494360d4..6b3d43b8d 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoDeleteQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoDeleteQuery.java @@ -27,16 +27,38 @@ import org.seasar.doma.jdbc.dialect.Dialect; import org.seasar.doma.jdbc.entity.EntityType; +/** + * An auto delete query that is executed against an entity class. + * + *

This class implements {@link DeleteQuery} to provide DELETE operations for entities. It + * handles version checking for optimistic locking and supports tenant ID-based isolation. + * + * @param the entity type + */ public class AutoDeleteQuery extends AutoModifyQuery implements DeleteQuery { + /** Whether to ignore the version property for optimistic locking. */ protected boolean versionIgnored; + /** Whether to suppress optimistic lock exceptions. */ protected boolean optimisticLockExceptionSuppressed; + /** + * Creates a new instance with the specified entity type. + * + * @param entityType the entity type + */ public AutoDeleteQuery(EntityType entityType) { super(entityType); } + /** + * {@inheritDoc} + * + *

This implementation prepares the query for execution by performing pre-delete operations, + * preparing special property types, validating ID existence, preparing options and optimistic + * locking, and building the SQL statement. + */ @Override public void prepare() { super.prepare(); @@ -51,6 +73,10 @@ public void prepare() { assertNotNull(sql); } + /** + * Performs pre-delete operations on the entity. This method is called before the entity is + * deleted from the database. + */ protected void preDelete() { AutoPreDeleteContext context = new AutoPreDeleteContext<>(entityType, method, config, returning); @@ -60,6 +86,10 @@ protected void preDelete() { } } + /** + * Prepares optimistic locking for this query. If a version property exists and is not ignored, + * optimistic lock checking will be enabled unless it is explicitly suppressed. + */ protected void prepareOptimisticLock() { if (versionPropertyType != null && !versionIgnored) { if (!optimisticLockExceptionSuppressed) { @@ -68,6 +98,10 @@ protected void prepareOptimisticLock() { } } + /** + * Prepares the SQL statement for this query. This method builds a DELETE statement using the + * entity type and its properties. + */ protected void prepareSql() { Dialect dialect = config.getDialect(); PreparedSqlBuilder builder = new PreparedSqlBuilder(config, SqlKind.DELETE, sqlLogType); @@ -88,11 +122,20 @@ protected void prepareSql() { sql = builder.build(this::comment); } + /** + * {@inheritDoc} + * + *

This implementation performs post-delete operations on the entity. + */ @Override public void complete() { postDelete(); } + /** + * Performs post-delete operations on the entity. This method is called after the entity is + * deleted from the database. + */ protected void postDelete() { AutoPostDeleteContext context = new AutoPostDeleteContext<>(entityType, method, config, returning); @@ -102,18 +145,42 @@ protected void postDelete() { } } + /** + * Sets whether to ignore the version property for optimistic locking. + * + * @param versionIgnored {@code true} to ignore the version property + */ public void setVersionIgnored(boolean versionIgnored) { this.versionIgnored = versionIgnored; } + /** + * Sets whether to suppress optimistic lock exceptions. + * + * @param optimisticLockExceptionSuppressed {@code true} to suppress optimistic lock exceptions + */ public void setOptimisticLockExceptionSuppressed(boolean optimisticLockExceptionSuppressed) { this.optimisticLockExceptionSuppressed = optimisticLockExceptionSuppressed; } + /** + * Context class for pre-delete operations. + * + * @param the entity type + */ protected static class AutoPreDeleteContext extends AbstractPreDeleteContext { + /** The properties to be returned from the DELETE operation. */ private final ReturningProperties returningProperties; + /** + * Creates a new context for pre-delete operations. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + * @param returningProperties the properties to be returned + */ public AutoPreDeleteContext( EntityType entityType, Method method, @@ -123,16 +190,35 @@ public AutoPreDeleteContext( this.returningProperties = Objects.requireNonNull(returningProperties); } + /** + * {@inheritDoc} + * + * @return the properties to be returned from the DELETE operation + */ @Override public ReturningProperties getReturningProperties() { return returningProperties; } } + /** + * Context class for post-delete operations. + * + * @param the entity type + */ protected static class AutoPostDeleteContext extends AbstractPostDeleteContext { + /** The properties to be returned from the DELETE operation. */ private final ReturningProperties returningProperties; + /** + * Creates a new context for post-delete operations. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + * @param returningProperties the properties to be returned + */ public AutoPostDeleteContext( EntityType entityType, Method method, @@ -142,6 +228,11 @@ public AutoPostDeleteContext( this.returningProperties = Objects.requireNonNull(returningProperties); } + /** + * {@inheritDoc} + * + * @return the properties to be returned from the DELETE operation + */ @Override public ReturningProperties getReturningProperties() { return returningProperties; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoFunctionQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoFunctionQuery.java index 48f21f6e0..9859877d8 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoFunctionQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoFunctionQuery.java @@ -21,10 +21,20 @@ import org.seasar.doma.jdbc.ResultParameter; import org.seasar.doma.jdbc.SqlKind; +/** + * An auto function query that calls a database function. + * + *

This class implements {@link FunctionQuery} to provide functionality for calling database + * functions. It handles parameter binding and result retrieval. + * + * @param the type of the function result + */ public class AutoFunctionQuery extends AutoModuleQuery implements FunctionQuery { + /** The parameter that will hold the function result. */ protected ResultParameter resultParameter; + /** {@inheritDoc} */ @Override public void prepare() { super.prepare(); @@ -35,6 +45,11 @@ public void prepare() { assertNotNull(sql); } + /** + * Prepares the SQL for this function query. + * + *

This method builds the callable SQL statement for the function call. + */ protected void prepareSql() { CallableSqlBuilder builder = new CallableSqlBuilder( @@ -42,14 +57,25 @@ protected void prepareSql() { sql = builder.build(this::comment); } + /** + * Sets the function name. + * + * @param functionName the function name + */ public void setFunctionName(String functionName) { setModuleName(functionName); } + /** + * Sets the result parameter. + * + * @param parameter the result parameter + */ public void setResultParameter(ResultParameter parameter) { this.resultParameter = parameter; } + /** {@inheritDoc} */ @Override public RESULT getResult() { return resultParameter.getResult(); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoInsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoInsertQuery.java index 5b9183c16..cab5d956d 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoInsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoInsertQuery.java @@ -40,22 +40,79 @@ import org.seasar.doma.jdbc.id.IdGenerationConfig; import org.seasar.doma.message.Message; +/** + * A query implementation for automatically inserting an entity into a database table. + * + *

This class provides functionality to generate and execute SQL INSERT statements based on + * entity definitions. It handles various insert scenarios including: + * + *

+ * + *

The query execution process includes: + * + *

    + *
  1. Pre-insert entity processing + *
  2. SQL statement preparation + *
  3. Statement execution + *
  4. Generated ID retrieval (if applicable) + *
  5. Post-insert entity processing + *
+ * + * @param the entity type + */ public class AutoInsertQuery extends AutoModifyQuery implements InsertQuery { + /** Indicates whether null properties should be excluded from the INSERT statement. */ protected boolean nullExcluded; + /** The property type for the generated ID, if the entity has one. */ protected GeneratedIdPropertyType generatedIdPropertyType; + /** Configuration for ID generation, used when the entity has a generated ID property. */ protected IdGenerationConfig idGenerationConfig; + /** + * The strategy for handling duplicate key violations. Default is {@link + * DuplicateKeyType#EXCEPTION}, which throws an exception on duplicate key. + */ protected DuplicateKeyType duplicateKeyType = DuplicateKeyType.EXCEPTION; + /** + * The names of properties that form the unique key for duplicate key handling. Used when {@link + * #duplicateKeyType} is not {@link DuplicateKeyType#EXCEPTION}. + */ protected String[] duplicateKeyNames = EMPTY_STRINGS; + /** + * Constructs an instance. + * + * @param entityType the entity type + */ public AutoInsertQuery(EntityType entityType) { super(entityType); } + /** + * Prepares this query for execution. + * + *

This method performs the following operations: + * + *

    + *
  1. Validates that required components are not null + *
  2. Executes pre-insert entity processing + *
  3. Prepares special property types (ID, version, etc.) + *
  4. Prepares query options + *
  5. Determines target properties for the INSERT statement + *
  6. Prepares ID and version values + *
  7. Builds the SQL statement + *
+ */ @Override public void prepare() { super.prepare(); @@ -71,6 +128,12 @@ public void prepare() { assertNotNull(sql); } + /** + * Executes pre-insert entity processing. + * + *

This method creates a pre-insert context and calls the entity's preInsert method, allowing + * entity listeners to modify the entity before insertion. + */ protected void preInsert() { AutoPreInsertContext context = new AutoPreInsertContext<>(entityType, method, config, duplicateKeyType, returning); @@ -80,6 +143,12 @@ protected void preInsert() { } } + /** + * Prepares special property types for this query. + * + *

This method initializes the generated ID property type and its configuration, and determines + * if auto-generated keys are supported for this query. + */ @Override protected void prepareSpecialPropertyTypes() { super.prepareSpecialPropertyTypes(); @@ -92,6 +161,22 @@ protected void prepareSpecialPropertyTypes() { } } + /** + * Prepares the target property types for the INSERT statement. + * + *

This method determines which entity properties should be included in the INSERT statement + * based on the following rules: + * + *

    + *
  • Properties must be insertable + *
  • ID properties are included if they are not auto-generated or if they have a value + *
  • Version properties are always included + *
  • If nullExcluded is true, null-valued properties are excluded + *
  • Properties must match the include/exclude name filters if specified + *
+ * + *

This method throws a JdbcException if a non-generated ID property has a null value. + */ protected void prepareTargetPropertyType() { targetPropertyTypes = new ArrayList<>(entityType.getEntityPropertyTypes().size()); for (EntityPropertyType propertyType : entityType.getEntityPropertyTypes()) { @@ -127,18 +212,41 @@ protected void prepareTargetPropertyType() { } } + /** + * Prepares the ID value for the entity before insertion. + * + *

If the entity has a generated ID property, this method calls its preInsert method to + * generate or prepare the ID value before the INSERT operation. + */ protected void prepareIdValue() { if (generatedIdPropertyType != null && idGenerationConfig != null) { entity = generatedIdPropertyType.preInsert(entityType, entity, idGenerationConfig); } } + /** + * Prepares the version value for the entity before insertion. + * + *

If the entity has a version property, this method initializes it to 1 for optimistic + * locking. + */ protected void prepareVersionValue() { if (versionPropertyType != null) { entity = versionPropertyType.setIfNecessary(entityType, entity, 1); } } + /** + * Prepares the SQL statement for this query. + * + *

This method builds either a standard INSERT statement or an UPSERT statement based on the + * duplicate key handling strategy. It uses the dialect-specific SQL assemblers to generate the + * appropriate SQL syntax. + * + *

If the duplicate key type is EXCEPTION, a standard INSERT statement is generated. Otherwise, + * an UPSERT statement is generated, unless the dialect supports MERGE statements and an identity + * key is included in the duplicate keys, in which case it falls back to a standard INSERT. + */ protected void prepareSql() { Naming naming = config.getNaming(); Dialect dialect = config.getDialect(); @@ -158,6 +266,16 @@ protected void prepareSql() { sql = builder.build(this::comment); } + /** + * Assembles a standard INSERT SQL statement. + * + *

This method creates an INSERT assembler context and uses the dialect-specific INSERT + * assembler to generate the SQL statement. + * + * @param builder the SQL builder + * @param naming the naming convention + * @param dialect the database dialect + */ private void assembleInsertSql(PreparedSqlBuilder builder, Naming naming, Dialect dialect) { InsertAssemblerContext context = InsertAssemblerContextBuilder.build( @@ -166,6 +284,17 @@ private void assembleInsertSql(PreparedSqlBuilder builder, Naming naming, Dialec insertAssembler.assemble(); } + /** + * Assembles an UPSERT SQL statement. + * + *

This method creates an UPSERT assembler context and uses the dialect-specific UPSERT + * assembler to generate the SQL statement. The UPSERT statement handles duplicate key scenarios + * according to the specified duplicate key type. + * + * @param builder the SQL builder + * @param naming the naming convention + * @param dialect the database dialect + */ private void assembleUpsertSql(PreparedSqlBuilder builder, Naming naming, Dialect dialect) { List> duplicateKeys = Arrays.stream(this.duplicateKeyNames) @@ -189,6 +318,15 @@ private void assembleUpsertSql(PreparedSqlBuilder builder, Naming naming, Dialec upsertAssembler.assemble(); } + /** + * Generates an ID for the inserted entity. + * + *

This method is called after executing the INSERT statement to retrieve and set + * auto-generated keys for the entity. It's only executed if auto-generated keys are supported for + * this query. + * + * @param statement the statement used for the INSERT operation + */ @Override public void generateId(Statement statement) { if (isAutoGeneratedKeysSupported()) { @@ -202,11 +340,23 @@ public void generateId(Statement statement) { } } + /** + * Completes this query by executing post-insert processing. + * + *

This method is called after the INSERT statement has been executed and any generated IDs + * have been retrieved. + */ @Override public void complete() { postInsert(); } + /** + * Executes post-insert entity processing. + * + *

This method creates a post-insert context and calls the entity's postInsert method, allowing + * entity listeners to modify the entity after insertion. + */ protected void postInsert() { AutoPostInsertContext context = new AutoPostInsertContext<>(entityType, method, config, duplicateKeyType, returning); @@ -216,22 +366,55 @@ protected void postInsert() { } } + /** + * Sets whether null properties should be excluded from the INSERT statement. + * + * @param nullExcluded true to exclude null properties, false otherwise + */ public void setNullExcluded(boolean nullExcluded) { this.nullExcluded = nullExcluded; } + /** + * Sets the strategy for handling duplicate key violations. + * + * @param duplicateKeyType the duplicate key handling strategy + */ public void setDuplicateKeyType(DuplicateKeyType duplicateKeyType) { this.duplicateKeyType = duplicateKeyType; } + /** + * Sets the names of properties that form the unique key for duplicate key handling. + * + * @param duplicateKeyNames the property names that form the unique key + */ public void setDuplicateKeyNames(String... duplicateKeyNames) { this.duplicateKeyNames = duplicateKeyNames; } + /** + * A context class for pre-insert entity processing. + * + *

This class extends AbstractPreInsertContext to add support for returning properties. It's + * used to pass information to entity listeners during the pre-insert phase. + * + * @param the entity type + */ protected static class AutoPreInsertContext extends AbstractPreInsertContext { + /** The properties to be returned from the INSERT statement. */ private final ReturningProperties returningProperties; + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method that triggered this context + * @param config the configuration + * @param duplicateKeyType the duplicate key handling strategy + * @param returningProperties the properties to be returned + */ public AutoPreInsertContext( EntityType entityType, Method method, @@ -242,16 +425,39 @@ public AutoPreInsertContext( this.returningProperties = Objects.requireNonNull(returningProperties); } + /** + * Returns the properties to be returned from the INSERT statement. + * + * @return the returning properties + */ @Override public ReturningProperties getReturningProperties() { return returningProperties; } } + /** + * A context class for post-insert entity processing. + * + *

This class extends AbstractPostInsertContext to add support for returning properties. It's + * used to pass information to entity listeners during the post-insert phase. + * + * @param the entity type + */ protected static class AutoPostInsertContext extends AbstractPostInsertContext { + /** The properties to be returned from the INSERT statement. */ private final ReturningProperties returningProperties; + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method that triggered this context + * @param config the configuration + * @param duplicateKeyType the duplicate key handling strategy + * @param returningProperties the properties to be returned + */ public AutoPostInsertContext( EntityType entityType, Method method, @@ -262,6 +468,11 @@ public AutoPostInsertContext( this.returningProperties = Objects.requireNonNull(returningProperties); } + /** + * Returns the properties to be returned from the INSERT statement. + * + * @return the returning properties + */ @Override public ReturningProperties getReturningProperties() { return returningProperties; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoModifyQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoModifyQuery.java index d7fb5d399..f9e5ff0b0 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoModifyQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoModifyQuery.java @@ -27,45 +27,96 @@ import org.seasar.doma.jdbc.entity.VersionPropertyType; import org.seasar.doma.message.Message; +/** + * An abstract base class for queries that automatically modify entities in a database. + * + *

This class provides common functionality for entity-based modification operations such as + * INSERT, UPDATE, and DELETE. It handles: + * + *

    + *
  • Entity property filtering (inclusion/exclusion) + *
  • ID property management + *
  • Version property handling for optimistic locking + *
  • Tenant ID property handling for multi-tenancy + *
  • SQL generation and execution control + *
+ * + *

Subclasses implement specific modification operations by extending this class and providing + * operation-specific logic. + * + * @param the entity type + */ public abstract class AutoModifyQuery extends AbstractQuery implements ModifyQuery { + /** An empty string array used as default for property name filters. */ protected static final String[] EMPTY_STRINGS = new String[] {}; + /** Names of properties to be included in the modification operation. */ protected String[] includedPropertyNames = EMPTY_STRINGS; + /** Names of properties to be excluded from the modification operation. */ protected String[] excludedPropertyNames = EMPTY_STRINGS; + /** The entity type metadata. */ protected final EntityType entityType; + /** The entity instance to be modified. */ protected ENTITY entity; + /** The prepared SQL for this query. */ protected PreparedSql sql; + /** The property types targeted by this modification operation. */ protected List> targetPropertyTypes; + /** The ID property types of the entity. */ protected List> idPropertyTypes; + /** The version property type for optimistic locking, if the entity has one. */ protected VersionPropertyType versionPropertyType; + /** The tenant ID property type for multi-tenancy, if the entity has one. */ protected TenantIdPropertyType tenantIdPropertyType; + /** Indicates whether optimistic lock checking is required for this query. */ protected boolean optimisticLockCheckRequired; + /** Indicates whether auto-generated keys are supported for this query. */ protected boolean autoGeneratedKeysSupported; + /** Indicates whether this query is executable. */ protected boolean executable; + /** The cause if SQL execution should be skipped. */ protected SqlExecutionSkipCause sqlExecutionSkipCause = SqlExecutionSkipCause.STATE_UNCHANGED; + /** The SQL log type for this query. */ protected SqlLogType sqlLogType; + /** The properties to be returned from the modification operation. */ protected ReturningProperties returning = ReturningProperties.NONE; + /** + * Constructs an instance. + * + * @param entityType the entity type metadata + */ protected AutoModifyQuery(EntityType entityType) { AssertionUtil.assertNotNull(entityType); this.entityType = entityType; } + /** + * Prepares this query for execution. + * + *

This method performs basic preparation steps and validates that the dialect supports + * returning properties if they are specified. + * + *

Subclasses should override this method to perform additional preparation steps, but must + * call {@code super.prepare()} first. + * + * @throws JdbcException if returning properties are specified but not supported by the dialect + */ @Override public void prepare() { super.prepare(); @@ -74,24 +125,60 @@ public void prepare() { } } + /** + * Prepares special property types for this query. + * + *

This method initializes the ID, version, and tenant ID property types from the entity type + * metadata. + */ protected void prepareSpecialPropertyTypes() { idPropertyTypes = entityType.getIdPropertyTypes(); versionPropertyType = entityType.getVersionPropertyType(); tenantIdPropertyType = entityType.getTenantIdPropertyType(); } + /** + * Validates that the entity has at least one ID property. + * + *

This method is typically called by operations that require an ID property, such as UPDATE + * and DELETE. + * + * @throws JdbcException if the entity has no ID properties + */ protected void validateIdExistent() { if (idPropertyTypes.isEmpty()) { throw new JdbcException(Message.DOMA2022, entityType.getName()); } } + /** + * Prepares query options. + * + *

This method sets the query timeout from the configuration if it's not already set. + */ protected void prepareOptions() { if (queryTimeout <= 0) { queryTimeout = config.getQueryTimeout(); } } + /** + * Determines whether a property should be included in the modification operation. + * + *

This method applies the include and exclude filters to determine if a property should be + * targeted by the operation. The rules are: + * + *

    + *
  1. If includedPropertyNames is not empty, only properties in that list are included, unless + * they are also in excludedPropertyNames + *
  2. If includedPropertyNames is empty but excludedPropertyNames is not, all properties except + * those in excludedPropertyNames are included + *
  3. If both lists are empty, all properties are included + *
+ * + * @param name the property name to check + * @return true if the property should be included, false otherwise + */ protected boolean isTargetPropertyName(String name) { if (includedPropertyNames.length > 0) { for (String includedName : includedPropertyNames) { @@ -117,60 +204,111 @@ protected boolean isTargetPropertyName(String name) { return true; } + /** + * Sets the entity instance to be modified. + * + * @param entity the entity instance + */ public void setEntity(ENTITY entity) { this.entity = entity; } + /** + * Returns the entity instance to be modified. + * + * @return the entity instance + */ public ENTITY getEntity() { return entity; } + /** + * Sets the names of properties to be included in the modification operation. + * + *

If this is set, only the specified properties will be included in the operation, unless they + * are also in the excluded property names. + * + * @param includedPropertyNames the property names to include + */ public void setIncludedPropertyNames(String... includedPropertyNames) { this.includedPropertyNames = includedPropertyNames; } + /** + * Sets the names of properties to be excluded from the modification operation. + * + *

If this is set, the specified properties will be excluded from the operation. + * + * @param excludedPropertyNames the property names to exclude + */ public void setExcludedPropertyNames(String... excludedPropertyNames) { this.excludedPropertyNames = excludedPropertyNames; } + /** + * Sets the SQL log type for this query. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** + * Sets the properties to be returned from the modification operation. + * + *

This is used for database systems that support returning clause in modification statements. + * + * @param returning the returning properties + */ public void setReturning(ReturningProperties returning) { this.returning = returning; } + /** {@inheritDoc} */ @Override public PreparedSql getSql() { return sql; } + /** {@inheritDoc} */ @Override public boolean isOptimisticLockCheckRequired() { return optimisticLockCheckRequired; } + /** {@inheritDoc} */ @Override public boolean isExecutable() { return executable; } + /** {@inheritDoc} */ @Override public SqlExecutionSkipCause getSqlExecutionSkipCause() { return sqlExecutionSkipCause; } + /** {@inheritDoc} */ @Override public boolean isAutoGeneratedKeysSupported() { return autoGeneratedKeysSupported; } + /** {@inheritDoc} */ @Override public SqlLogType getSqlLogType() { return sqlLogType; } + /** + * Returns a string representation of this query. + * + *

This method returns the string representation of the SQL statement if it has been prepared, + * or null otherwise. + * + * @return the string representation + */ @Override public String toString() { return sql != null ? sql.toString() : null; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoModuleQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoModuleQuery.java index e7b7d8dce..433a4635a 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoModuleQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoModuleQuery.java @@ -23,24 +23,44 @@ import org.seasar.doma.jdbc.SqlLogType; import org.seasar.doma.jdbc.SqlParameter; +/** + * An abstract base class for queries that call database modules. + * + *

This class provides common functionality for queries that call database stored procedures and + * functions. It handles parameter binding, module name qualification, and SQL generation. + */ public abstract class AutoModuleQuery extends AbstractQuery implements ModuleQuery { + /** The callable SQL for this module query. */ protected CallableSql sql; + /** The catalog name of the module. */ protected String catalogName; + /** The schema name of the module. */ protected String schemaName; + /** The name of the module. */ protected String moduleName; + /** The qualified name of the module. */ protected String qualifiedName; + /** Whether quotes are required for identifiers. */ protected boolean isQuoteRequired; + /** The parameters for the module call. */ protected final List parameters = new ArrayList<>(); + /** The SQL log type for this module query. */ protected SqlLogType sqlLogType; + /** + * Prepares the qualified name of the module. + * + *

This method builds the fully qualified name of the module using catalog, schema, and module + * names, applying quotes if required. + */ protected void prepareQualifiedName() { Function mapper = isQuoteRequired ? config.getDialect()::applyQuote : Function.identity(); @@ -48,49 +68,88 @@ protected void prepareQualifiedName() { DatabaseObjectUtil.getQualifiedName(mapper, catalogName, schemaName, moduleName); } + /** + * Prepares the options for this module query. + * + *

This method sets default values for query timeout if not already set. + */ protected void prepareOptions() { if (queryTimeout <= 0) { queryTimeout = config.getQueryTimeout(); } } + /** {@inheritDoc} */ @Override public void complete() {} + /** + * Sets the catalog name of the module. + * + * @param catalogName the catalog name + */ public void setCatalogName(String catalogName) { this.catalogName = catalogName; } + /** + * Sets the schema name of the module. + * + * @param schemaName the schema name + */ public void setSchemaName(String schemaName) { this.schemaName = schemaName; } + /** + * Sets the name of the module. + * + * @param moduleName the module name + */ protected void setModuleName(String moduleName) { this.moduleName = moduleName; } + /** + * Sets whether quotes are required for identifiers. + * + * @param isQuoteRequired {@code true} if quotes are required + */ public void setQuoteRequired(boolean isQuoteRequired) { this.isQuoteRequired = isQuoteRequired; } + /** + * Sets the SQL log type for this module query. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** + * Adds a parameter to this module query. + * + * @param parameter the parameter to add + */ public void addParameter(SqlParameter parameter) { parameters.add(parameter); } + /** {@inheritDoc} */ @Override public String getQualifiedName() { return qualifiedName; } + /** {@inheritDoc} */ @Override public CallableSql getSql() { return sql; } + /** {@inheritDoc} */ @Override public SqlLogType getSqlLogType() { return sqlLogType; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoMultiInsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoMultiInsertQuery.java index c9a0e1c91..437dcac95 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoMultiInsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoMultiInsertQuery.java @@ -42,21 +42,80 @@ import org.seasar.doma.jdbc.id.IdGenerationConfig; import org.seasar.doma.message.Message; +/** + * A query implementation for automatically inserting multiple entities into a database table. + * + *

This class provides functionality to generate and execute SQL multi-row INSERT statements + * based on entity definitions. It handles various insert scenarios including: + * + *

    + *
  • Batch inserts with multiple entities in a single statement + *
  • Inserts with generated ID values (sequence-based only for multiple rows) + *
  • Inserts with version number initialization + *
  • Handling of duplicate key scenarios (exception or update) + *
+ * + *

The query execution process includes: + * + *

    + *
  1. Pre-insert entity processing for each entity + *
  2. SQL statement preparation for multiple rows + *
  3. Statement execution + *
  4. Generated ID retrieval (if applicable) + *
  5. Post-insert entity processing for each entity + *
+ * + * @param the entity type + */ public class AutoMultiInsertQuery extends AutoModifyQuery implements InsertQuery { + /** The list of entities to be inserted. */ protected List entities; + + /** The property type for the generated ID, if the entity has one. */ protected GeneratedIdPropertyType generatedIdPropertyType; + /** Configuration for ID generation, used when the entity has a generated ID property. */ protected IdGenerationConfig idGenerationConfig; + /** + * The strategy for handling duplicate key violations. Default is {@link + * DuplicateKeyType#EXCEPTION}, which throws an exception on duplicate key. + */ protected DuplicateKeyType duplicateKeyType = DuplicateKeyType.EXCEPTION; + /** + * The names of properties that form the unique key for duplicate key handling. Used when {@link + * #duplicateKeyType} is not {@link DuplicateKeyType#EXCEPTION}. + */ protected String[] duplicateKeyNames = EMPTY_STRINGS; + /** + * Constructs an instance. + * + * @param entityType the entity type + */ public AutoMultiInsertQuery(EntityType entityType) { super(entityType); } + /** + * Prepares this query for execution. + * + *

This method performs the following operations: + * + *

    + *
  1. Validates that required components are not null + *
  2. Checks if the dialect supports multi-row INSERT statements + *
  3. Skips execution if the entity list is empty + *
  4. Executes pre-insert entity processing for each entity + *
  5. Prepares special property types (ID, version, etc.) + *
  6. Prepares query options + *
  7. Determines target properties for the INSERT statement + *
  8. Prepares ID and version values + *
  9. Builds the SQL statement + *
+ */ @Override public void prepare() { super.prepare(); @@ -84,6 +143,12 @@ public void prepare() { assertNotNull(sql); } + /** + * Executes pre-insert entity processing for each entity. + * + *

This method creates a pre-insert context for each entity and calls the entity's preInsert + * method, allowing entity listeners to modify the entities before insertion. + */ protected void preInsert() { ListIterator iterator = entities.listIterator(); while (iterator.hasNext()) { @@ -98,6 +163,15 @@ protected void preInsert() { } } + /** + * Prepares special property types for this query. + * + *

This method initializes the generated ID property type and its configuration, and determines + * if auto-generated keys are supported for this query. + * + *

It also checks if the dialect supports auto-increment when inserting multiple rows, and + * throws an exception if not supported with IDENTITY generation type. + */ @Override protected void prepareSpecialPropertyTypes() { super.prepareSpecialPropertyTypes(); @@ -116,6 +190,21 @@ protected void prepareSpecialPropertyTypes() { } } + /** + * Prepares the target property types for the INSERT statement. + * + *

This method determines which entity properties should be included in the INSERT statement + * based on the following rules: + * + *

    + *
  • Properties must be insertable + *
  • ID properties are included if they are not auto-generated or if they have a value + *
  • Version properties are always included + *
  • Properties must match the include/exclude name filters if specified + *
+ * + *

This method throws a JdbcException if a non-generated ID property has a null value. + */ protected void prepareTargetPropertyType() { targetPropertyTypes = new ArrayList<>(entityType.getEntityPropertyTypes().size()); for (EntityPropertyType propertyType : entityType.getEntityPropertyTypes()) { @@ -146,6 +235,12 @@ protected void prepareTargetPropertyType() { } } + /** + * Prepares the ID values for the entities before insertion. + * + *

If the entities have a generated ID property, this method calls its preInsert method to + * generate or prepare the ID values before the INSERT operation. + */ protected void prepareIdValue() { if (generatedIdPropertyType != null && idGenerationConfig != null) { List newEntities = @@ -156,6 +251,12 @@ protected void prepareIdValue() { } } + /** + * Prepares the version values for the entities before insertion. + * + *

If the entities have a version property, this method initializes it to 1 for optimistic + * locking. + */ protected void prepareVersionValue() { if (versionPropertyType != null) { ListIterator iterator = entities.listIterator(); @@ -167,6 +268,17 @@ protected void prepareVersionValue() { } } + /** + * Prepares the SQL statement for this query. + * + *

This method builds either a standard multi-row INSERT statement or an UPSERT statement based + * on the duplicate key handling strategy. It uses the dialect-specific SQL assemblers to generate + * the appropriate SQL syntax. + * + *

If the duplicate key type is EXCEPTION, a standard INSERT statement is generated. Otherwise, + * an UPSERT statement is generated, unless the dialect supports MERGE statements and an identity + * key is included in the duplicate keys, in which case it falls back to a standard INSERT. + */ protected void prepareSql() { Naming naming = config.getNaming(); Dialect dialect = config.getDialect(); @@ -186,6 +298,16 @@ protected void prepareSql() { sql = builder.build(this::comment); } + /** + * Assembles a standard multi-row INSERT SQL statement. + * + *

This method creates a multi-insert assembler context and uses the dialect-specific + * multi-insert assembler to generate the SQL statement. + * + * @param builder the SQL builder + * @param naming the naming convention + * @param dialect the database dialect + */ private void assembleInsertSql(PreparedSqlBuilder builder, Naming naming, Dialect dialect) { MultiInsertAssemblerContext context = MultiInsertAssemblerContextBuilder.buildFromEntityList( @@ -194,6 +316,17 @@ private void assembleInsertSql(PreparedSqlBuilder builder, Naming naming, Dialec assembler.assemble(); } + /** + * Assembles an UPSERT SQL statement for multiple entities. + * + *

This method creates an UPSERT assembler context and uses the dialect-specific UPSERT + * assembler to generate the SQL statement. The UPSERT statement handles duplicate key scenarios + * according to the specified duplicate key type. + * + * @param builder the SQL builder + * @param naming the naming convention + * @param dialect the database dialect + */ private void assembleUpsertSql(PreparedSqlBuilder builder, Naming naming, Dialect dialect) { List> duplicateKeys = Arrays.stream(this.duplicateKeyNames) @@ -217,6 +350,15 @@ private void assembleUpsertSql(PreparedSqlBuilder builder, Naming naming, Dialec assembler.assemble(); } + /** + * Generates IDs for the inserted entities. + * + *

This method is called after executing the INSERT statement to retrieve and set + * auto-generated keys for the entities. It's only executed if auto-generated keys are supported + * for this query. + * + * @param statement the statement used for the INSERT operation + */ @Override public void generateId(Statement statement) { if (isAutoGeneratedKeysSupported()) { @@ -228,11 +370,23 @@ public void generateId(Statement statement) { } } + /** + * Completes this query by executing post-insert processing. + * + *

This method is called after the INSERT statement has been executed and any generated IDs + * have been retrieved. + */ @Override public void complete() { postInsert(); } + /** + * Executes post-insert entity processing for each entity. + * + *

This method creates a post-insert context for each entity and calls the entity's postInsert + * method, allowing entity listeners to modify the entities after insertion. + */ protected void postInsert() { ListIterator iterator = entities.listIterator(); while (iterator.hasNext()) { @@ -247,18 +401,46 @@ protected void postInsert() { } } + /** + * Sets the strategy for handling duplicate key violations. + * + * @param duplicateKeyType the duplicate key handling strategy + */ public void setDuplicateKeyType(DuplicateKeyType duplicateKeyType) { this.duplicateKeyType = duplicateKeyType; } + /** + * Sets the names of properties that form the unique key for duplicate key handling. + * + * @param duplicateKeyNames the property names that form the unique key + */ public void setDuplicateKeyNames(String... duplicateKeyNames) { this.duplicateKeyNames = duplicateKeyNames; } + /** + * A context class for pre-insert entity processing. + * + *

This class extends AbstractPreInsertContext to add support for returning properties. It's + * used to pass information to entity listeners during the pre-insert phase. + * + * @param the entity type + */ protected static class AutoPreInsertContext extends AbstractPreInsertContext { + /** The properties to be returned from the INSERT statement. */ private final ReturningProperties returningProperties; + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method that triggered this context + * @param config the configuration + * @param duplicateKeyType the duplicate key handling strategy + * @param returningProperties the properties to be returned + */ public AutoPreInsertContext( EntityType entityType, Method method, @@ -269,16 +451,39 @@ public AutoPreInsertContext( this.returningProperties = Objects.requireNonNull(returningProperties); } + /** + * Returns the properties to be returned from the INSERT statement. + * + * @return the returning properties + */ @Override public ReturningProperties getReturningProperties() { return returningProperties; } } + /** + * A context class for post-insert entity processing. + * + *

This class extends AbstractPostInsertContext to add support for returning properties. It's + * used to pass information to entity listeners during the post-insert phase. + * + * @param the entity type + */ protected static class AutoPostInsertContext extends AbstractPostInsertContext { + /** The properties to be returned from the INSERT statement. */ private final ReturningProperties returningProperties; + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method that triggered this context + * @param config the configuration + * @param duplicateKeyType the duplicate key handling strategy + * @param returningProperties the properties to be returned + */ public AutoPostInsertContext( EntityType entityType, Method method, @@ -289,27 +494,54 @@ public AutoPostInsertContext( this.returningProperties = Objects.requireNonNull(returningProperties); } + /** + * Returns the properties to be returned from the INSERT statement. + * + * @return the returning properties + */ @Override public ReturningProperties getReturningProperties() { return returningProperties; } } + /** + * Sets the list of entities to be inserted. + * + * @param entities the list of entities + */ public void setEntities(List entities) { if (entities != null) { this.entities = new ArrayList<>(entities); } } + /** + * Returns the list of entities to be inserted. + * + * @return the list of entities + */ public List getEntities() { return this.entities; } + /** + * This method is not supported for multi-insert queries. Use {@link #setEntities(List)} instead. + * + * @param entity the entity + * @throws UnsupportedOperationException always thrown + */ @Override public void setEntity(ENTITY entity) { throw new UnsupportedOperationException("Use the setEntities method instead."); } + /** + * This method is not supported for multi-insert queries. Use {@link #getEntities()} instead. + * + * @return never returns + * @throws UnsupportedOperationException always thrown + */ @Override public ENTITY getEntity() { throw new UnsupportedOperationException("Use the getEntities method instead."); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoProcedureQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoProcedureQuery.java index 065446f5e..7ba59b622 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoProcedureQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoProcedureQuery.java @@ -20,8 +20,15 @@ import org.seasar.doma.internal.jdbc.sql.CallableSqlBuilder; import org.seasar.doma.jdbc.SqlKind; +/** + * An auto procedure query that calls a database stored procedure. + * + *

This class implements {@link ProcedureQuery} to provide functionality for calling database + * stored procedures. It handles parameter binding and SQL generation. + */ public class AutoProcedureQuery extends AutoModuleQuery implements ProcedureQuery { + /** {@inheritDoc} */ @Override public void prepare() { super.prepare(); @@ -32,12 +39,22 @@ public void prepare() { assertNotNull(sql); } + /** + * Prepares the SQL for this procedure query. + * + *

This method builds the callable SQL statement for the procedure call. + */ protected void prepareSql() { CallableSqlBuilder builder = new CallableSqlBuilder(config, SqlKind.PROCEDURE, qualifiedName, parameters, sqlLogType); sql = builder.build(this::comment); } + /** + * Sets the procedure name. + * + * @param procedureName the procedure name + */ public void setProcedureName(String procedureName) { setModuleName(procedureName); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoUpdateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoUpdateQuery.java index ac8afdd45..6a8c6cfe9 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoUpdateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/AutoUpdateQuery.java @@ -30,22 +30,49 @@ import org.seasar.doma.jdbc.entity.EntityPropertyType; import org.seasar.doma.jdbc.entity.EntityType; +/** + * A query implementation for automatically updating an entity. + * + *

This class handles the automatic generation of SQL UPDATE statements based on entity + * definitions and configuration settings. It provides support for optimistic concurrency control + * through version properties, and allows customization of which properties are included in the + * update operation. + * + * @param the entity type + */ public class AutoUpdateQuery extends AutoModifyQuery implements UpdateQuery { + /** Indicates whether null properties should be excluded from the UPDATE statement. */ protected boolean nullExcluded; + /** Indicates whether the version property should be ignored for optimistic locking. */ protected boolean versionIgnored; + /** Indicates whether optimistic lock exceptions should be suppressed. */ protected boolean optimisticLockExceptionSuppressed; + /** Indicates whether unchanged properties should be included in the UPDATE statement. */ protected boolean unchangedPropertyIncluded; + /** Helper for building the update query. */ protected UpdateQueryHelper helper; + /** + * Constructs an instance. + * + * @param entityType the entity type + */ public AutoUpdateQuery(EntityType entityType) { super(entityType); } + /** + * {@inheritDoc} + * + *

This method prepares the query for execution by setting up the helper, calling pre-update + * hooks, preparing property types, validating entity IDs, setting up optimistic locking, and + * generating the SQL statement. + */ @Override public void prepare() { super.prepare(); @@ -61,6 +88,13 @@ public void prepare() { assertNotNull(sql); } + /** + * Sets up the helper for this query. + * + *

This method initializes the {@link UpdateQueryHelper} with the current configuration and + * settings for property inclusion/exclusion, null handling, version handling, optimistic lock + * exception handling, and unchanged property handling. + */ protected void setupHelper() { helper = new UpdateQueryHelper<>( @@ -74,6 +108,13 @@ protected void setupHelper() { unchangedPropertyIncluded); } + /** + * Executes pre-update processing for the entity. + * + *

This method calls the entity's pre-update hooks with the appropriate context, allowing the + * entity to perform any necessary operations before the update is executed. If the pre-update + * hook returns a new entity instance, it will replace the current one. + */ protected void preUpdate() { List> targetPropertyTypes = helper.getTargetPropertyTypes(entity); AutoPreUpdateContext context = @@ -84,6 +125,13 @@ protected void preUpdate() { } } + /** + * Prepares optimistic locking for this query. + * + *

This method sets up optimistic concurrency control based on the version property and + * configuration settings. If version checking is enabled and not suppressed, the query will be + * configured to check for optimistic lock violations. + */ protected void prepareOptimisticLock() { if (!versionIgnored && versionPropertyType != null) { if (!optimisticLockExceptionSuppressed) { @@ -92,6 +140,13 @@ protected void prepareOptimisticLock() { } } + /** + * Prepares the target property types for this query. + * + *

This method determines which entity properties will be included in the UPDATE statement + * based on the configuration and entity definition. If there are properties to update, the query + * is marked as executable. + */ protected void prepareTargetPropertyTypes() { targetPropertyTypes = helper.getTargetPropertyTypes(entity); if (!targetPropertyTypes.isEmpty()) { @@ -100,6 +155,13 @@ protected void prepareTargetPropertyTypes() { } } + /** + * Prepares the SQL statement for this query. + * + *

This method builds the SQL UPDATE statement using the dialect-specific assembler and the + * configured property types. It creates a context with all necessary information for the + * assembler to generate the appropriate SQL for the current database dialect. + */ protected void prepareSql() { Dialect dialect = config.getDialect(); PreparedSqlBuilder builder = new PreparedSqlBuilder(config, SqlKind.UPDATE, sqlLogType); @@ -124,6 +186,13 @@ protected void prepareSql() { sql = builder.build(this::comment); } + /** + * {@inheritDoc} + * + *

This method increments the version number of the entity if optimistic concurrency control is + * enabled. The version property is used to detect concurrent modifications and prevent lost + * updates. + */ @Override public void incrementVersion() { if (!versionIgnored && versionPropertyType != null) { @@ -131,11 +200,24 @@ public void incrementVersion() { } } + /** + * {@inheritDoc} + * + *

This method completes the query execution by performing post-update processing. + */ @Override public void complete() { postUpdate(); } + /** + * Executes post-update processing for the entity. + * + *

This method calls the entity's post-update hooks with the appropriate context, allowing the + * entity to perform any necessary operations after the update is executed. If the post-update + * hook returns a new entity instance, it will replace the current one. Finally, the current state + * of the entity is saved to track future changes. + */ protected void postUpdate() { List> targetPropertyTypes = helper.getTargetPropertyTypes(entity); if (!versionIgnored && versionPropertyType != null) { @@ -150,27 +232,71 @@ protected void postUpdate() { entityType.saveCurrentStates(entity); } + /** + * Sets whether null properties should be excluded from the UPDATE statement. + * + * @param nullExcluded true to exclude null properties, false otherwise + */ public void setNullExcluded(boolean nullExcluded) { this.nullExcluded = nullExcluded; } + /** + * Sets whether the version property should be ignored for optimistic locking. + * + *

This method uses a bitwise OR operation to combine the current setting with the new value, + * ensuring that once version checking is ignored, it remains ignored. + * + * @param versionIgnored true to ignore the version property, false otherwise + */ public void setVersionIgnored(boolean versionIgnored) { this.versionIgnored |= versionIgnored; } + /** + * Sets whether optimistic lock exceptions should be suppressed. + * + * @param optimisticLockExceptionSuppressed true to suppress optimistic lock exceptions, false + * otherwise + */ public void setOptimisticLockExceptionSuppressed(boolean optimisticLockExceptionSuppressed) { this.optimisticLockExceptionSuppressed = optimisticLockExceptionSuppressed; } + /** + * Sets whether unchanged properties should be included in the UPDATE statement. + * + * @param unchangedPropertyIncluded true to include unchanged properties, false otherwise + */ public void setUnchangedPropertyIncluded(Boolean unchangedPropertyIncluded) { this.unchangedPropertyIncluded = unchangedPropertyIncluded; } + /** + * A context class for pre-update processing. + * + *

This class provides context information for entity pre-update hooks, including which + * properties are being changed and which properties should be returned. + * + * @param the entity type + */ protected static class AutoPreUpdateContext extends AbstractPreUpdateContext { + /** The properties to be returned from the update operation. */ private final ReturningProperties returningProperties; + + /** The names of properties that are being changed in this update. */ protected final Set changedPropertyNames; + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method that triggered the update + * @param config the configuration + * @param targetPropertyTypes the property types targeted for update + * @param returningProperties the properties to be returned + */ public AutoPreUpdateContext( EntityType entityType, Method method, @@ -186,28 +312,60 @@ public AutoPreUpdateContext( } } + /** + * {@inheritDoc} + * + *

The entity is considered changed if there are any properties being updated. + */ @Override public boolean isEntityChanged() { return !changedPropertyNames.isEmpty(); } + /** + * {@inheritDoc} + * + *

A property is considered changed if it is included in the set of properties targeted for + * update. + */ @Override public boolean isPropertyChanged(String propertyName) { validatePropertyDefined(propertyName); return changedPropertyNames.contains(propertyName); } + /** {@inheritDoc} */ @Override public ReturningProperties getReturningProperties() { return returningProperties; } } + /** + * A context class for post-update processing. + * + *

This class provides context information for entity post-update hooks, including which + * properties were changed and which properties should be returned. + * + * @param the entity type + */ protected static class AutoPostUpdateContext extends AbstractPostUpdateContext { + /** The properties to be returned from the update operation. */ private final ReturningProperties returningProperties; + + /** The names of properties that were changed in this update. */ protected final Set changedPropertyNames; + /** + * Constructs an instance. + * + * @param entityType the entity type + * @param method the method that triggered the update + * @param config the configuration + * @param targetPropertyTypes the property types that were updated + * @param returningProperties the properties to be returned + */ public AutoPostUpdateContext( EntityType entityType, Method method, @@ -223,12 +381,19 @@ public AutoPostUpdateContext( } } + /** + * {@inheritDoc} + * + *

A property is considered changed if it was included in the set of properties that were + * updated. + */ @Override public boolean isPropertyChanged(String propertyName) { validatePropertyDefined(propertyName); return changedPropertyNames.contains(propertyName); } + /** {@inheritDoc} */ @Override public ReturningProperties getReturningProperties() { return returningProperties; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchDeleteQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchDeleteQuery.java index 8d8e144e1..ea262ab67 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchDeleteQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchDeleteQuery.java @@ -15,4 +15,14 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for batch DELETE queries. + * + *

This interface represents a query that performs batch DELETE operations. It extends {@link + * BatchModifyQuery} to inherit common batch data modification functionality while specializing for + * DELETE operations. + * + *

Implementations of this interface handle the execution of multiple DELETE statements as a + * single batch operation for improved performance. + */ public interface BatchDeleteQuery extends BatchModifyQuery {} diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchInsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchInsertQuery.java index de1b705ba..1b6957c40 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchInsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchInsertQuery.java @@ -17,10 +17,38 @@ import java.sql.Statement; +/** + * An interface for batch INSERT queries. + * + *

This interface represents a query that performs batch INSERT operations. It extends {@link + * BatchModifyQuery} to inherit common batch data modification functionality while specializing for + * INSERT operations. + * + *

Implementations of this interface handle the execution of multiple INSERT statements as a + * single batch operation for improved performance, and provide methods for generating IDs for + * inserted rows. + */ public interface BatchInsertQuery extends BatchModifyQuery { + /** + * Determines if batch operations are supported for this query. + * + *

Some database operations or configurations may not support batch processing. This method + * allows implementations to indicate whether batch operations can be used. + * + * @return true if batch operations are supported, false otherwise + */ boolean isBatchSupported(); + /** + * Generates an ID for a single inserted row in the batch. + * + *

This method is called after executing the batch to generate IDs for rows that use + * auto-generated keys or sequences. + * + * @param statement the statement used for the batch operation + * @param index the index of the element in the batch + */ void generateId(Statement statement, int index); /** diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchModifyQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchModifyQuery.java index 46c5855d0..fcd286df2 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchModifyQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchModifyQuery.java @@ -20,23 +20,71 @@ import org.seasar.doma.jdbc.SqlExecutionSkipCause; import org.seasar.doma.jdbc.SqlLogType; +/** + * A query that performs batch operations to modify data in a database. + * + *

This interface defines operations specific to batch data modification statements such as batch + * INSERT, UPDATE, and DELETE. + */ public interface BatchModifyQuery extends Query { + /** + * Returns the list of prepared SQL statements for this batch query. + * + * @return the list of prepared SQL statements + */ List getSqls(); + /** + * Returns a representative prepared SQL statement for this batch query. + * + *

This method is typically used for logging purposes. + * + * @return a representative prepared SQL statement + */ @Override PreparedSql getSql(); + /** + * Returns whether optimistic lock checking is required for this batch query. + * + * @return {@code true} if optimistic lock checking is required + */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") boolean isOptimisticLockCheckRequired(); + /** + * Returns whether auto-generated keys are supported for this batch query. + * + * @return {@code true} if auto-generated keys are supported + */ boolean isAutoGeneratedKeysSupported(); + /** + * Returns whether this batch query is executable. + * + * @return {@code true} if this batch query is executable + */ boolean isExecutable(); + /** + * Returns the cause if SQL execution should be skipped. + * + * @return the cause of SQL execution skip, or {@code null} if execution should not be skipped + */ SqlExecutionSkipCause getSqlExecutionSkipCause(); + /** + * Returns the batch size for this query. + * + * @return the batch size + */ int getBatchSize(); + /** + * Returns the SQL log type for this batch query. + * + * @return the SQL log type + */ SqlLogType getSqlLogType(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchUpdateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchUpdateQuery.java index 449e3b91f..19083eb9e 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchUpdateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchUpdateQuery.java @@ -15,7 +15,25 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for batch UPDATE queries. + * + *

This interface represents a query that performs batch UPDATE operations. It extends {@link + * BatchModifyQuery} to inherit common batch data modification functionality while specializing for + * UPDATE operations. + * + *

Implementations of this interface handle the execution of multiple UPDATE statements as a + * single batch operation for improved performance, and provide methods for handling optimistic + * concurrency control through version numbers. + */ public interface BatchUpdateQuery extends BatchModifyQuery { + /** + * Increments the version numbers for all entities in the batch. + * + *

This method is called after executing the batch to update the version numbers in the entity + * objects, ensuring they match the values in the database after the update. This is important for + * optimistic concurrency control. + */ void incrementVersions(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchUpdateQueryHelper.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchUpdateQueryHelper.java index b8344ad1e..bffff9708 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchUpdateQueryHelper.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BatchUpdateQueryHelper.java @@ -25,20 +25,42 @@ import org.seasar.doma.jdbc.entity.EntityType; import org.seasar.doma.jdbc.entity.Property; +/** + * A helper class for batch update queries. This class provides utility methods for handling entity + * properties in batch update operations. + * + * @param the entity type + */ public class BatchUpdateQueryHelper { + /** The configuration. */ protected final Config config; + /** The entity type. */ protected final EntityType entityType; + /** Whether the version property is ignored. */ protected final boolean versionIgnored; + /** Whether the optimistic lock exception is suppressed. */ protected final boolean optimisticLockExceptionSuppressed; + /** The included property names. */ protected final String[] includedPropertyNames; + /** The excluded property names. */ protected final String[] excludedPropertyNames; + /** + * Constructs a new {@code BatchUpdateQueryHelper}. + * + * @param config the configuration + * @param entityType the entity type + * @param includedPropertyNames the included property names + * @param excludedPropertyNames the excluded property names + * @param versionIgnored whether the version property is ignored + * @param optimisticLockExceptionSuppressed whether the optimistic lock exception is suppressed + */ public BatchUpdateQueryHelper( Config config, EntityType entityType, @@ -54,6 +76,12 @@ public BatchUpdateQueryHelper( this.excludedPropertyNames = excludedPropertyNames; } + /** + * Returns the target property types for the update operation. This method filters the entity + * property types based on various criteria. + * + * @return the list of target property types + */ public List> getTargetPropertyTypes() { List> targetPropertyTypes = new ArrayList<>(entityType.getEntityPropertyTypes().size()); @@ -79,6 +107,13 @@ public BatchUpdateQueryHelper( return targetPropertyTypes; } + /** + * Determines if the property name is a target for the update operation. This method checks if the + * property name is included and not excluded. + * + * @param name the property name + * @return true if the property name is a target, false otherwise + */ protected boolean isTargetPropertyName(String name) { if (includedPropertyNames.length > 0) { for (String includedName : includedPropertyNames) { @@ -104,6 +139,15 @@ protected boolean isTargetPropertyName(String name) { return true; } + /** + * Populates the SQL context with values from the entity. This method appends SQL for setting + * column values in the update statement. + * + * @param entity the entity + * @param targetPropertyTypes the target property types + * @param versionPropertyType the version property type + * @param context the SQL context + */ public void populateValues( E entity, List> targetPropertyTypes, diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BlobCreateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BlobCreateQuery.java index b68fdbdde..075145e82 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/BlobCreateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/BlobCreateQuery.java @@ -19,8 +19,15 @@ import java.sql.Connection; import java.sql.SQLException; +/** + * A query that creates a BLOB (Binary Large Object) in the database. + * + *

This class extends {@link AbstractCreateQuery} to provide functionality for creating BLOB + * objects. It uses the JDBC connection's createBlob method to create a new empty BLOB instance. + */ public class BlobCreateQuery extends AbstractCreateQuery { + /** {@inheritDoc} */ @Override public Blob create(Connection connection) throws SQLException { return connection.createBlob(); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ClobCreateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ClobCreateQuery.java index b510ae94b..85290ac4b 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ClobCreateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ClobCreateQuery.java @@ -19,8 +19,15 @@ import java.sql.Connection; import java.sql.SQLException; +/** + * A query that creates a CLOB (Character Large Object) in the database. + * + *

This class extends {@link AbstractCreateQuery} to provide functionality for creating CLOB + * objects. It uses the JDBC connection's createClob method to create a new empty CLOB instance. + */ public class ClobCreateQuery extends AbstractCreateQuery { + /** {@inheritDoc} */ @Override public Clob create(Connection connection) throws SQLException { return connection.createClob(); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/CountQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/CountQuery.java index f10fa9c13..f77f675f9 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/CountQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/CountQuery.java @@ -23,31 +23,44 @@ import org.seasar.doma.jdbc.SqlKind; import org.seasar.doma.jdbc.SqlNode; +/** + * A query that counts the number of rows that would be returned by a SELECT statement. + * + *

This class extends {@link AbstractSelectQuery} to provide functionality for transforming a + * SELECT query into a COUNT query. It uses the database dialect to transform the SQL node for + * counting. + */ public class CountQuery extends AbstractSelectQuery { + /** The SQL node representing the original SELECT query. */ protected SqlNode sqlNode; + /** {@inheritDoc} */ @Override public boolean isResultEnsured() { return true; } + /** {@inheritDoc} */ @Override public boolean isResultMappingEnsured() { return false; } + /** {@inheritDoc} */ @Override public FetchType getFetchType() { return FetchType.LAZY; } + /** {@inheritDoc} */ @Override public void prepare() { super.prepare(); assertNotNull(sqlNode); } + /** {@inheritDoc} */ @Override protected void prepareSql() { SqlNode transformedSqlNode = config.getDialect().transformSelectSqlNodeForGettingCount(sqlNode); @@ -65,11 +78,17 @@ protected void prepareSql() { sql = sqlBuilder.build(transformedSqlNode, this::comment); } + /** {@inheritDoc} */ @Override public void complete() { // do nothing } + /** + * Sets the SQL node representing the original SELECT query. + * + * @param sqlNode the SQL node + */ public void setSqlNode(SqlNode sqlNode) { this.sqlNode = sqlNode; } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/CreateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/CreateQuery.java index c0010286d..aa45f243e 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/CreateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/CreateQuery.java @@ -18,7 +18,21 @@ import java.sql.Connection; import java.sql.SQLException; +/** + * A query that creates a database resource. + * + *

This interface is used to create JDBC resources such as BLOB, CLOB, Array, etc. + * + * @param the type of the resource to be created + */ public interface CreateQuery extends Query { + /** + * Creates a database resource using the given connection. + * + * @param connection the JDBC connection + * @return the created resource + * @throws SQLException if a database access error occurs + */ RESULT create(Connection connection) throws SQLException; } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteAssembler.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteAssembler.java index b5119c478..2351b03a7 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteAssembler.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteAssembler.java @@ -15,6 +15,19 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for assembling DELETE queries. + * + *

This interface is responsible for generating the SQL for DELETE operations. Implementations of + * this interface handle the construction of DELETE statements, including the WHERE clause and any + * other necessary SQL components. + */ public interface DeleteAssembler { + /** + * Assembles the DELETE query. + * + *

This method generates the SQL for the DELETE operation, including the table name, WHERE + * clause, and any other required SQL components. + */ void assemble(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteAssemblerContext.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteAssemblerContext.java index e0e19d75c..55e74a789 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteAssemblerContext.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteAssemblerContext.java @@ -31,17 +31,50 @@ * @param the entity type */ public class DeleteAssemblerContext { + /** The SQL builder used to construct the DELETE statement. */ public final PreparedSqlBuilder buf; + + /** The entity type that represents the table to delete from. */ public final EntityType entityType; + + /** The naming convention used for converting Java names to database names. */ public final Naming naming; + + /** The dialect that defines database-specific behaviors. */ public final Dialect dialect; + + /** The list of property types that represent the primary key. */ public final List> idPropertyTypes; + + /** The property type that represents the version column for optimistic locking. */ public final VersionPropertyType versionPropertyType; + + /** The property type that represents the tenant ID column for multi-tenancy. */ public final TenantIdPropertyType tenantIdPropertyType; + + /** Whether to ignore the version property for optimistic locking. */ public boolean versionIgnored; + + /** The entity instance to be deleted. */ public final ENTITY entity; + + /** The properties to be returned from the DELETE operation. */ public ReturningProperties returning; + /** + * Creates a new context for assembling DELETE statements. + * + * @param buf the SQL builder + * @param entityType the entity type + * @param naming the naming convention + * @param dialect the SQL dialect + * @param idPropertyTypes the list of ID property types + * @param versionPropertyType the version property type + * @param tenantIdPropertyType the tenant ID property type + * @param versionIgnored whether to ignore the version property + * @param entity the entity instance + * @param returning the properties to be returned + */ DeleteAssemblerContext( PreparedSqlBuilder buf, EntityType entityType, diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteQuery.java index 5825563a7..148d43fa4 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/DeleteQuery.java @@ -15,4 +15,14 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for DELETE queries. + * + *

This interface represents a query that performs DELETE operations. It extends {@link + * ModifyQuery} to inherit common data modification functionality while specializing for DELETE + * operations. + * + *

Implementations of this interface handle the execution of DELETE statements, including the + * construction of the WHERE clause and handling of optimistic concurrency control. + */ public interface DeleteQuery extends ModifyQuery {} diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/DuplicateKeyType.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/DuplicateKeyType.java index 5835ad3c3..55469bddc 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/DuplicateKeyType.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/DuplicateKeyType.java @@ -15,10 +15,35 @@ */ package org.seasar.doma.jdbc.query; -/** Retrieves the type of the duplicate key when inserting a new entity. */ +/** + * Specifies how to handle duplicate key violations during insert operations. + * + *

This enum defines the behavior when an insert operation would violate a unique constraint in + * the database. + */ public enum DuplicateKeyType { + /** + * Updates the existing row when a duplicate key is encountered. + * + *

This option causes the database to perform an update on the existing row instead of + * inserting a new row when a duplicate key is detected. + */ UPDATE, + + /** + * Ignores the insert operation when a duplicate key is encountered. + * + *

This option causes the database to silently ignore the insert operation without raising an + * error when a duplicate key is detected. + */ IGNORE, + + /** + * Throws an exception when a duplicate key is encountered. + * + *

This option causes the database to raise an error when a duplicate key is detected, which is + * the default behavior for most databases. + */ EXCEPTION, ; } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/FunctionQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/FunctionQuery.java index 1c4aafebf..12b07a549 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/FunctionQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/FunctionQuery.java @@ -15,7 +15,27 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for database function queries. + * + *

This interface represents a query that calls a database function. It extends {@link + * ModuleQuery} to inherit common database module functionality while specializing for function + * calls that return a result. + * + *

Implementations of this interface handle the execution of database function calls, including + * parameter binding and result retrieval. + * + * @param the type of the function result + */ public interface FunctionQuery extends ModuleQuery { + /** + * Returns the result of the function call. + * + *

This method is called after executing the function to retrieve the result value. The result + * type depends on the function's return type and the Java type mapping. + * + * @return the function result + */ RESULT getResult(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertAssembler.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertAssembler.java index 9e08bd53f..51b66b724 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertAssembler.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertAssembler.java @@ -15,6 +15,19 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for assembling INSERT queries. + * + *

This interface is responsible for generating the SQL for INSERT operations. Implementations of + * this interface handle the construction of INSERT statements, including the column list, values + * clause, and any other necessary SQL components. + */ public interface InsertAssembler { + /** + * Assembles the INSERT query. + * + *

This method generates the SQL for the INSERT operation, including the table name, column + * list, values clause, and any other required SQL components. + */ void assemble(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertQuery.java index fc91a821f..850650fde 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertQuery.java @@ -17,7 +17,27 @@ import java.sql.Statement; +/** + * An interface for INSERT queries. + * + *

This interface represents a query that performs INSERT operations. It extends {@link + * ModifyQuery} to inherit common data modification functionality while specializing for INSERT + * operations. + * + *

Implementations of this interface handle the execution of INSERT statements, including the + * construction of the column list, values clause, and generation of auto-generated keys or sequence + * values. + */ public interface InsertQuery extends ModifyQuery { + /** + * Generates an ID for the inserted row. + * + *

This method is called after executing the INSERT statement to retrieve and set + * auto-generated keys or sequence values for the entity. It's typically used for primary key + * generation strategies like identity columns or sequences. + * + * @param statement the statement used for the INSERT operation + */ void generateId(Statement statement); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertRow.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertRow.java index 214742052..97eb8b69b 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertRow.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/InsertRow.java @@ -19,13 +19,26 @@ import java.util.List; import java.util.Objects; +/** + * Represents a row to be inserted in an INSERT statement. + * + *

This class holds a list of values for a single row in a batch or multi-row insert operation. + * It implements {@link Iterable} to allow iteration over the values in the row. + */ public class InsertRow implements Iterable { + /** The values for this insert row. */ private final List values; + /** + * Constructs a new {@code InsertRow} with the specified values. + * + * @param values the values for this insert row + */ public InsertRow(List values) { this.values = Objects.requireNonNull(values); } + /** {@inheritDoc} */ @Override public Iterator iterator() { return values.iterator(); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ModifyQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ModifyQuery.java index a027ed0ed..04aed0717 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ModifyQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ModifyQuery.java @@ -19,18 +19,54 @@ import org.seasar.doma.jdbc.SqlExecutionSkipCause; import org.seasar.doma.jdbc.SqlLogType; +/** + * A query that modifies data in a database. + * + *

This interface defines operations specific to data modification statements such as INSERT, + * UPDATE, and DELETE. + */ public interface ModifyQuery extends Query { + /** + * Returns the prepared SQL for this modification query. + * + * @return the prepared SQL + */ @Override PreparedSql getSql(); + /** + * Returns whether optimistic lock checking is required for this query. + * + * @return {@code true} if optimistic lock checking is required + */ boolean isOptimisticLockCheckRequired(); + /** + * Returns whether auto-generated keys are supported for this query. + * + * @return {@code true} if auto-generated keys are supported + */ boolean isAutoGeneratedKeysSupported(); + /** + * Returns whether this query is executable. + * + * @return {@code true} if this query is executable + */ boolean isExecutable(); + /** + * Returns the cause if SQL execution should be skipped. + * + * @return the cause of SQL execution skip, or {@code null} if execution should not be skipped + */ SqlExecutionSkipCause getSqlExecutionSkipCause(); + /** + * Returns the SQL log type for this query. + * + * @return the SQL log type + */ SqlLogType getSqlLogType(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ModuleQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ModuleQuery.java index 17f9b745e..611433889 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ModuleQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ModuleQuery.java @@ -18,12 +18,32 @@ import org.seasar.doma.jdbc.CallableSql; import org.seasar.doma.jdbc.SqlLogType; +/** + * A query that calls a database module such as a stored procedure or function. + * + *

This interface defines operations specific to database module calls. + */ public interface ModuleQuery extends Query { + /** + * Returns the callable SQL for this module query. + * + * @return the callable SQL + */ @Override CallableSql getSql(); + /** + * Returns the qualified name of the database module. + * + * @return the qualified name + */ String getQualifiedName(); + /** + * Returns the SQL log type for this module query. + * + * @return the SQL log type + */ SqlLogType getSqlLogType(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/MultiInsertAssemblerContext.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/MultiInsertAssemblerContext.java index b4453b04f..d7e782521 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/MultiInsertAssemblerContext.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/MultiInsertAssemblerContext.java @@ -47,6 +47,7 @@ public class MultiInsertAssemblerContext { * @param dialect the SQL dialect * @param insertPropertyTypes the property types that are targets for the insert * @param entities the entities + * @param returning the properties to be returned after insert execution */ MultiInsertAssemblerContext( PreparedSqlBuilder buf, diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/NClobCreateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/NClobCreateQuery.java index 05cfbe8a6..42f52509f 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/NClobCreateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/NClobCreateQuery.java @@ -19,8 +19,16 @@ import java.sql.NClob; import java.sql.SQLException; +/** + * A query that creates an NCLOB (National Character Large Object) in the database. + * + *

This class extends {@link AbstractCreateQuery} to provide functionality for creating NCLOB + * objects. It uses the JDBC connection's createNClob method to create a new empty NCLOB instance + * that can store Unicode character data. + */ public class NClobCreateQuery extends AbstractCreateQuery { + /** {@inheritDoc} */ @Override public NClob create(Connection connection) throws SQLException { return connection.createNClob(); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ProcedureQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ProcedureQuery.java index c1c67b3ae..141c85074 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ProcedureQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ProcedureQuery.java @@ -15,4 +15,16 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for database stored procedure queries. + * + *

This interface represents a query that calls a database stored procedure. It extends {@link + * ModuleQuery} to inherit common database module functionality while specializing for procedure + * calls that don't return a result. + * + *

Implementations of this interface handle the execution of database procedure calls, including + * parameter binding and handling of OUT and INOUT parameters. Unlike {@link FunctionQuery}, + * procedures typically don't return a value directly, but may modify OUT parameters or perform + * database operations. + */ public interface ProcedureQuery extends ModuleQuery {} diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/Query.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/Query.java index 214eafe0c..e0accb6e2 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/Query.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/Query.java @@ -19,23 +19,68 @@ import org.seasar.doma.jdbc.Config; import org.seasar.doma.jdbc.Sql; +/** + * The base interface for all query types. + * + *

This interface defines the common operations for all database queries in Doma. + */ public interface Query { + /** + * Returns the SQL object that represents the query. + * + * @return the SQL object + */ Sql getSql(); + /** + * Returns the class name where the query is defined. + * + * @return the class name + */ String getClassName(); + /** + * Returns the method name where the query is defined. + * + * @return the method name + */ String getMethodName(); + /** + * Returns the method object where the query is defined. + * + * @return the method object + */ Method getMethod(); + /** + * Returns the configuration for this query. + * + * @return the configuration + */ Config getConfig(); + /** + * Returns the query timeout in seconds. + * + * @return the query timeout + */ int getQueryTimeout(); + /** Prepares this query for execution. This method must be called before the query is executed. */ void prepare(); + /** + * Completes this query after execution. This method must be called after the query is executed. + */ void complete(); + /** + * Adds a comment to the SQL statement. + * + * @param sql the SQL statement + * @return the SQL statement with the comment + */ String comment(String sql); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryOperand.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryOperand.java index 95ce45354..bcd550042 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryOperand.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryOperand.java @@ -19,53 +19,117 @@ import org.seasar.doma.jdbc.InParameter; import org.seasar.doma.jdbc.entity.EntityPropertyType; +/** + * An interface representing an operand in a database query. + * + *

This interface provides a way to represent different types of operands that can be used in + * database queries, such as parameters and property references. It follows the visitor pattern to + * allow operations on these operands without modifying their structure. + */ public interface QueryOperand { + /** + * Returns the entity property type associated with this operand. + * + * @return the entity property type + */ EntityPropertyType getEntityPropertyType(); + /** + * Accepts a visitor to perform operations on this operand. + * + * @param visitor the visitor to accept + */ void accept(QueryOperand.Visitor visitor); + /** + * A parameter operand that contains both a property type and an input parameter. + * + *

This class represents a parameter value that will be bound to a query. + */ final class Param implements QueryOperand { + /** The entity property type. */ public final EntityPropertyType propertyType; + + /** The input parameter to be bound to the query. */ public final InParameter inParameter; + /** + * Constructs a new parameter operand. + * + * @param propertyType the entity property type + * @param inParameter the input parameter + * @throws NullPointerException if either parameter is null + */ public Param(EntityPropertyType propertyType, InParameter inParameter) { this.propertyType = Objects.requireNonNull(propertyType); this.inParameter = Objects.requireNonNull(inParameter); } + /** {@inheritDoc} */ @Override public EntityPropertyType getEntityPropertyType() { return propertyType; } + /** {@inheritDoc} */ @Override public void accept(Visitor visitor) { visitor.visit(this); } } + /** + * A property operand that references an entity property. + * + *

This class represents a reference to an entity property in a query. + */ final class Prop implements QueryOperand { + /** The entity property type. */ public final EntityPropertyType propertyType; + /** + * Constructs a new property operand. + * + * @param propertyType the entity property type + * @throws NullPointerException if the property type is null + */ public Prop(EntityPropertyType propertyType) { this.propertyType = Objects.requireNonNull(propertyType); } + /** {@inheritDoc} */ @Override public EntityPropertyType getEntityPropertyType() { return propertyType; } + /** {@inheritDoc} */ @Override public void accept(Visitor visitor) { visitor.visit(this); } } + /** + * A visitor interface for {@link QueryOperand} implementations. + * + *

This interface follows the visitor pattern to allow operations on different types of query + * operands without modifying their structure. + */ interface Visitor { + /** + * Visits a parameter operand. + * + * @param param the parameter operand to visit + */ void visit(QueryOperand.Param param); + /** + * Visits a property operand. + * + * @param prop the property operand to visit + */ void visit(QueryOperand.Prop prop); } } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryOperandPair.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryOperandPair.java index 2058b10dc..d2265ed1c 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryOperandPair.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryOperandPair.java @@ -17,19 +17,46 @@ import java.util.Objects; +/** + * Represents a pair of query operands. + * + *

This class is used to associate two operands together, typically for operations that require + * comparing or mapping values between them, such as in UPDATE statements where columns are set to + * new values. + */ public class QueryOperandPair { + /** The left operand in the pair. */ private final QueryOperand left; + + /** The right operand in the pair. */ private final QueryOperand right; + /** + * Constructs a new {@code QueryOperandPair} with the specified operands. + * + * @param left the left operand + * @param right the right operand + * @throws NullPointerException if either operand is null + */ public QueryOperandPair(QueryOperand left, QueryOperand right) { this.left = Objects.requireNonNull(left); this.right = Objects.requireNonNull(right); } + /** + * Returns the left operand. + * + * @return the left operand + */ public QueryOperand getLeft() { return left; } + /** + * Returns the right operand. + * + * @return the right operand + */ public QueryOperand getRight() { return right; } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryUtil.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryUtil.java index 05ae05958..8eebf6f2e 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryUtil.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/QueryUtil.java @@ -19,8 +19,24 @@ import org.seasar.doma.GenerationType; import org.seasar.doma.jdbc.entity.GeneratedIdPropertyType; +/** + * Utility class for query operations. + * + *

This class provides utility methods for query processing and validation. + */ final class QueryUtil { + /** + * Determines if an identity key is included in the duplicate keys. + * + *

This method checks whether a generated identity property is part of the specified duplicate + * key names. If no duplicate key names are specified, it assumes the identity key is included. + * + * @param generatedIdPropertyType the generated ID property type + * @param duplicateKeyNames the names of columns that may cause duplicate key violations + * @return {@code true} if the identity key is included in the duplicate keys, {@code false} + * otherwise + */ static boolean isIdentityKeyIncludedInDuplicateKeys( GeneratedIdPropertyType generatedIdPropertyType, String[] duplicateKeyNames) { if (generatedIdPropertyType == null) { diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ReturningProperties.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ReturningProperties.java index 54561986d..b3fe071a4 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ReturningProperties.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ReturningProperties.java @@ -21,7 +21,23 @@ import org.seasar.doma.jdbc.entity.EntityPropertyType; import org.seasar.doma.jdbc.entity.EntityType; -/** Represents returning properties. */ +/** + * An interface that represents properties to be returned from database operations. + * + *

This interface is used to specify which entity properties should be returned from database + * operations that support returning clauses, such as INSERT, UPDATE, or DELETE with RETURNING. It + * provides a way to select specific properties or all properties to be included in the returning + * clause. + * + *

The interface includes predefined instances for common cases: + * + *

    + *
  • {@link #NONE} - represents no properties to be returned + *
  • {@link #ALL} - represents all properties to be returned + *
+ * + *

Custom implementations can be created to return specific subsets of properties. + */ public interface ReturningProperties { /** A predefined instance of {@link ReturningProperties} that represents no properties. */ diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ReturningPropertyNames.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ReturningPropertyNames.java index 5211eb365..1e85801a9 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ReturningPropertyNames.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ReturningPropertyNames.java @@ -20,16 +20,33 @@ import org.seasar.doma.jdbc.entity.EntityPropertyType; import org.seasar.doma.jdbc.entity.EntityType; +/** + * A class that resolves property names to entity property types for returning clauses. + * + *

This class implements {@link ReturningProperties} to provide a way to specify which entity + * properties should be returned from database operations using property names. It supports + * including specific properties and excluding others. + */ public class ReturningPropertyNames implements ReturningProperties { + /** The names of properties to include in the returning clause. */ private final List includedNames; + + /** The names of properties to exclude from the returning clause. */ private final List excludedNames; + /** + * Constructs a new {@code ReturningPropertyNames} with the specified included and excluded names. + * + * @param includedNames the names of properties to include + * @param excludedNames the names of properties to exclude + */ private ReturningPropertyNames(List includedNames, List excludedNames) { this.includedNames = Objects.requireNonNull(includedNames); this.excludedNames = Objects.requireNonNull(excludedNames); } + /** {@inheritDoc} */ @Override public List> resolve(EntityType entityType) { Objects.requireNonNull(entityType); @@ -40,17 +57,37 @@ private ReturningPropertyNames(List includedNames, List excluded .toList(); } + /** + * Extracts the included property types from the entity type. + * + * @param entityType the entity type + * @return the list of included property types + */ private List> extractIncludedPropertyTypes( EntityType entityType) { var list = includedNames.stream().map(entityType::getEntityPropertyType).toList(); return list.isEmpty() ? entityType.getEntityPropertyTypes() : list; } + /** + * Extracts the excluded property types from the entity type. + * + * @param entityType the entity type + * @return the list of excluded property types + */ private List> extractExcludedPropertyTypes( EntityType entityType) { return excludedNames.stream().map(entityType::getEntityPropertyType).toList(); } + /** + * Creates a new {@code ReturningProperties} instance with the specified included and excluded + * names. + * + * @param includedNames the names of properties to include + * @param excludedNames the names of properties to exclude + * @return a new {@code ReturningProperties} instance + */ public static ReturningProperties of(List includedNames, List excludedNames) { if (includedNames.isEmpty() && excludedNames.isEmpty()) { return ALL; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SQLXMLCreateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SQLXMLCreateQuery.java index ee8550dbb..6e1de59a5 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SQLXMLCreateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SQLXMLCreateQuery.java @@ -19,8 +19,16 @@ import java.sql.SQLException; import java.sql.SQLXML; +/** + * A query that creates a SQLXML object in the database. + * + *

This class extends {@link AbstractCreateQuery} to provide functionality for creating SQLXML + * objects. It uses the JDBC connection's createSQLXML method to create a new empty SQLXML instance + * that can store XML data. + */ public class SQLXMLCreateQuery extends AbstractCreateQuery { + /** {@inheritDoc} */ @Override public SQLXML create(Connection connection) throws SQLException { return connection.createSQLXML(); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ScriptQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ScriptQuery.java index 0b19de5cf..48b341b5e 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/ScriptQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/ScriptQuery.java @@ -20,17 +20,52 @@ import java.util.function.Supplier; import org.seasar.doma.jdbc.SqlLogType; +/** + * A query that executes SQL scripts. + * + *

This interface defines operations for executing SQL scripts from files or other sources. + */ public interface ScriptQuery extends Query { + /** + * Returns the URL of the script file. + * + * @return the URL of the script file + */ URL getScriptFileUrl(); + /** + * Returns a supplier that provides a reader for the script content. + * + * @return the reader supplier + */ Supplier getReaderSupplier(); + /** + * Returns the path of the script file. + * + * @return the script file path + */ String getScriptFilePath(); + /** + * Returns the delimiter that separates SQL statements in the script. + * + * @return the block delimiter + */ String getBlockDelimiter(); + /** + * Returns whether execution should halt on error. + * + * @return {@code true} if execution should halt on error + */ boolean getHaltOnError(); + /** + * Returns the SQL log type for this script query. + * + * @return the SQL log type + */ SqlLogType getSqlLogType(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SelectQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SelectQuery.java index 85a59d9fc..cd152a31e 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SelectQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SelectQuery.java @@ -20,24 +20,74 @@ import org.seasar.doma.jdbc.SelectOptions; import org.seasar.doma.jdbc.SqlLogType; +/** + * A query for selecting data from a database. + * + *

This interface defines operations specific to SELECT statements. + */ public interface SelectQuery extends Query { + /** + * Returns the prepared SQL for this select query. + * + * @return the prepared SQL + */ @Override PreparedSql getSql(); + /** + * Returns the options for this select query. + * + * @return the select options + */ SelectOptions getOptions(); + /** + * Returns whether the query is expected to return at least one result. + * + * @return {@code true} if the query is expected to return at least one result + */ boolean isResultEnsured(); + /** + * Returns whether the result mapping is ensured. + * + * @return {@code true} if the result mapping is ensured + */ boolean isResultMappingEnsured(); + /** + * Returns the fetch type for this query. + * + * @return the fetch type + */ FetchType getFetchType(); + /** + * Returns the fetch size for this query. + * + * @return the fetch size + */ int getFetchSize(); + /** + * Returns the maximum number of rows to be returned. + * + * @return the maximum number of rows + */ int getMaxRows(); + /** + * Returns the SQL log type for this query. + * + * @return the SQL log type + */ SqlLogType getSqlLogType(); + /** + * Returns whether the result should be processed as a stream. + * + * @return {@code true} if the result should be processed as a stream + */ boolean isResultStream(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchDeleteQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchDeleteQuery.java index 330401fff..47c5dd37b 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchDeleteQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchDeleteQuery.java @@ -18,10 +18,22 @@ import org.seasar.doma.jdbc.SqlKind; /** + * A query that performs batch delete operations using SQL statements. + * + *

This class extends {@link SqlBatchModifyQuery} to provide functionality for executing batch + * DELETE statements. It initializes the SQL kind to {@link SqlKind#DELETE} to indicate that this + * query performs DELETE operations. + * * @author bakenezumi */ public class SqlBatchDeleteQuery extends SqlBatchModifyQuery implements BatchDeleteQuery { + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#DELETE} to indicate that it + * performs DELETE operations. + */ public SqlBatchDeleteQuery() { super(SqlKind.DELETE); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchInsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchInsertQuery.java index 2947cb3c3..bf85ca12a 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchInsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchInsertQuery.java @@ -19,17 +19,39 @@ import org.seasar.doma.jdbc.SqlKind; /** + * A query that performs batch insert operations using SQL statements. + * + *

This class extends {@link SqlBatchModifyQuery} to provide functionality for executing batch + * INSERT statements. It initializes the SQL kind to {@link SqlKind#INSERT} to indicate that this + * query performs INSERT operations. + * * @author bakenezumi */ public class SqlBatchInsertQuery extends SqlBatchModifyQuery implements BatchInsertQuery { + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#INSERT} to indicate that it + * performs INSERT operations. + */ public SqlBatchInsertQuery() { super(SqlKind.INSERT); } + /** + * {@inheritDoc} + * + *

This implementation does nothing because this query does not support auto-generated keys. + */ @Override public void generateId(Statement statement, int index) {} + /** + * {@inheritDoc} + * + *

This implementation always returns true because SQL batch queries are always supported. + */ @Override public boolean isBatchSupported() { return true; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchModifyQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchModifyQuery.java index 0d12aec1b..d6f8727d2 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchModifyQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchModifyQuery.java @@ -33,31 +33,56 @@ import org.seasar.doma.jdbc.SqlNode; /** + * An abstract base class for SQL-based batch modification queries. + * + *

This class provides common functionality for executing batch operations using SQL statements. + * It handles SQL node processing, parameter binding, and batch execution for INSERT, UPDATE, and + * DELETE operations. + * * @author bakenezumi */ public abstract class SqlBatchModifyQuery extends AbstractQuery implements BatchModifyQuery { + /** The SQL kind (INSERT, UPDATE, or DELETE). */ protected final SqlKind kind; + /** The SQL node representing the SQL statement. */ protected SqlNode sqlNode; + /** The parameters for the SQL statement, mapped by name. */ protected final Map> parameters = new LinkedHashMap<>(); + /** The prepared SQL statements for the batch. */ protected List sqls; + /** Whether optimistic lock checking is required for this query. */ protected boolean optimisticLockCheckRequired; + /** The batch size for this query. */ protected int batchSize = -1; + /** The SQL log type for this query. */ protected SqlLogType sqlLogType; + /** The size of the parameter lists. */ protected int parameterSize = -1; + /** + * Constructs a new instance with the specified SQL kind. + * + * @param kind the SQL kind + */ protected SqlBatchModifyQuery(SqlKind kind) { assertNotNull(kind); this.kind = kind; } + /** + * {@inheritDoc} + * + *

This implementation prepares the SQL statements for the batch operation by setting options + * and building SQL statements. + */ @Override public void prepare() { super.prepare(); @@ -67,6 +92,12 @@ public void prepare() { assertNotNull(sqls); } + /** + * Prepares the query options. + * + *

This method sets the query timeout and batch size from the configuration if they're not + * already set. + */ protected void prepareOptions() { if (queryTimeout <= 0) { queryTimeout = config.getQueryTimeout(); @@ -76,6 +107,11 @@ protected void prepareOptions() { } } + /** + * Prepares the SQL statements for the batch. + * + *

This method creates a SQL statement for each set of parameter values in the batch. + */ protected void prepareSql() { sqls = new ArrayList<>(); IntStream.rangeClosed(0, parameterSize - 1) @@ -98,13 +134,32 @@ protected void prepareSql() { }); } + /** + * {@inheritDoc} + * + *

This implementation does nothing because no post-processing is required. + */ @Override public void complete() {} + /** + * Sets the SQL node for this query. + * + * @param sqlNode the SQL node + */ public void setSqlNode(SqlNode sqlNode) { this.sqlNode = sqlNode; } + /** + * Adds a parameter to this query. + * + *

This method adds a named parameter with a list of values for batch processing. + * + * @param name the parameter name + * @param type the parameter type + * @param values the parameter values + */ public void addParameter(String name, Class type, List values) { assertNotNull(name, type); assertNotNull(values); @@ -120,58 +175,115 @@ public void addParameter(String name, Class type, List values) { parameters.put(name, valueList); } + /** Clears all parameters from this query. */ public void clearParameters() { parameters.clear(); } + /** + * Sets the batch size for this query. + * + * @param batchSize the batch size + */ public void setBatchSize(int batchSize) { this.batchSize = batchSize; } + /** + * Sets the SQL log type for this query. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** + * {@inheritDoc} + * + *

This implementation returns the first SQL statement in the batch. + */ @Override public PreparedSql getSql() { return sqls.get(0); } + /** + * {@inheritDoc} + * + *

This implementation returns all SQL statements in the batch. + */ @Override public List getSqls() { return sqls; } + /** + * {@inheritDoc} + * + *

This implementation returns whether optimistic lock checking is required for this query. + */ @Override public boolean isOptimisticLockCheckRequired() { return optimisticLockCheckRequired; } + /** + * {@inheritDoc} + * + *

This implementation always returns true because SQL batch queries are always executable. + */ @Override public boolean isExecutable() { return true; } + /** + * {@inheritDoc} + * + *

This implementation always returns null because SQL batch queries are always executable. + */ @Override public SqlExecutionSkipCause getSqlExecutionSkipCause() { return null; } + /** + * {@inheritDoc} + * + *

This implementation always returns false because SQL batch queries do not support + * auto-generated keys. + */ @Override public boolean isAutoGeneratedKeysSupported() { return false; } + /** + * {@inheritDoc} + * + *

This implementation returns the batch size for this query. + */ @Override public int getBatchSize() { return batchSize; } + /** + * {@inheritDoc} + * + *

This implementation returns the SQL log type for this query. + */ @Override public SqlLogType getSqlLogType() { return sqlLogType; } + /** + * {@inheritDoc} + * + *

This implementation returns the string representation of the SQL statements. + */ @Override public String toString() { return sqls != null ? sqls.toString() : null; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchUpdateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchUpdateQuery.java index 4f146d04b..84a9dca87 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchUpdateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlBatchUpdateQuery.java @@ -18,14 +18,31 @@ import org.seasar.doma.jdbc.SqlKind; /** + * A query that performs batch update operations using SQL statements. + * + *

This class extends {@link SqlBatchModifyQuery} to provide functionality for executing batch + * UPDATE statements. It initializes the SQL kind to {@link SqlKind#UPDATE} to indicate that this + * query performs UPDATE operations. + * * @author bakenezumi */ public class SqlBatchUpdateQuery extends SqlBatchModifyQuery implements BatchUpdateQuery { + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#UPDATE} to indicate that it + * performs UPDATE operations. + */ public SqlBatchUpdateQuery() { super(SqlKind.UPDATE); } + /** + * {@inheritDoc} + * + *

This implementation does nothing because this query does not support version incrementation. + */ @Override public void incrementVersions() {} } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlDeleteQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlDeleteQuery.java index bd2b4ce9e..cd387b664 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlDeleteQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlDeleteQuery.java @@ -17,8 +17,21 @@ import org.seasar.doma.jdbc.SqlKind; +/** + * A query that executes a SQL DELETE statement. + * + *

This class extends {@link SqlModifyQuery} to provide functionality for executing DELETE + * statements. It sets the SQL kind to {@link SqlKind#DELETE} to indicate that this query performs a + * DELETE operation. + */ public class SqlDeleteQuery extends SqlModifyQuery implements DeleteQuery { + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#DELETE} to indicate that it + * performs a DELETE operation. + */ public SqlDeleteQuery() { super(SqlKind.DELETE); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchDeleteQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchDeleteQuery.java index cca74fff7..eb2fc4a8e 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchDeleteQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchDeleteQuery.java @@ -27,19 +27,42 @@ import org.seasar.doma.jdbc.entity.EntityType; import org.seasar.doma.jdbc.entity.VersionPropertyType; +/** + * A query that performs batch delete operations using an external SQL file. + * + *

This class extends {@link SqlFileBatchModifyQuery} to provide functionality for executing + * batch DELETE statements defined in external SQL files. It handles entity lifecycle callbacks, + * optimistic locking, and SQL file execution for multiple entities. + * + * @param the type of elements in the batch + */ public class SqlFileBatchDeleteQuery extends SqlFileBatchModifyQuery implements BatchDeleteQuery { + /** The entity handler for this query. */ protected EntityHandler entityHandler; + /** Whether to ignore the version property for optimistic locking. */ protected boolean versionIgnored; + /** Whether to suppress optimistic lock exceptions. */ protected boolean optimisticLockExceptionSuppressed; + /** + * Constructs a new instance with the specified element class. + * + * @param elementClass the class of elements in the batch + */ public SqlFileBatchDeleteQuery(Class elementClass) { super(elementClass, SqlKind.BATCH_DELETE); } + /** + * {@inheritDoc} + * + *

This implementation prepares the SQL statements for each entity in the batch, executing + * pre-delete callbacks and optimistic lock preparation. + */ @Override public void prepare() { super.prepare(); @@ -65,18 +88,34 @@ public void prepare() { assertEquals(size, sqls.size()); } + /** + * Executes pre-delete entity lifecycle callbacks. + * + *

This method delegates to the entity handler if one is available. + */ protected void preDelete() { if (entityHandler != null) { entityHandler.preDelete(); } } + /** + * Prepares optimistic locking for this query. + * + *

This method delegates to the entity handler if one is available. + */ protected void prepareOptimisticLock() { if (entityHandler != null) { entityHandler.prepareOptimisticLock(); } } + /** + * {@inheritDoc} + * + *

This implementation executes post-delete entity lifecycle callbacks for each entity in the + * batch. + */ @Override public void complete() { if (entityHandler != null) { @@ -88,31 +127,59 @@ public void complete() { } } + /** + * {@inheritDoc} + * + *

This implementation creates an entity handler for the specified entity type. + */ @Override public void setEntityType(EntityType entityType) { entityHandler = new EntityHandler(entityType); } + /** + * Sets whether to ignore the version property for optimistic locking. + * + * @param versionIgnored whether to ignore the version property + */ public void setVersionIgnored(boolean versionIgnored) { this.versionIgnored = versionIgnored; } + /** + * Sets whether to suppress optimistic lock exceptions. + * + * @param optimisticLockExceptionSuppressed whether to suppress optimistic lock exceptions + */ public void setOptimisticLockExceptionSuppressed(boolean optimisticLockExceptionSuppressed) { this.optimisticLockExceptionSuppressed = optimisticLockExceptionSuppressed; } + /** A handler for entity lifecycle callbacks and optimistic locking. */ protected class EntityHandler { + /** The entity type. */ protected final EntityType entityType; + /** The version property type for optimistic locking. */ protected final VersionPropertyType versionPropertyType; + /** + * Constructs a new instance with the specified entity type. + * + * @param entityType the entity type + */ protected EntityHandler(EntityType entityType) { assertNotNull(entityType); this.entityType = entityType; this.versionPropertyType = entityType.getVersionPropertyType(); } + /** + * Executes pre-delete entity lifecycle callbacks. + * + *

This method creates a pre-delete context and calls the entity type's preDelete method. + */ protected void preDelete() { SqlFileBatchPreDeleteContext context = new SqlFileBatchPreDeleteContext<>(entityType, method, config); @@ -122,6 +189,11 @@ protected void preDelete() { } } + /** + * Executes post-delete entity lifecycle callbacks. + * + *

This method creates a post-delete context and calls the entity type's postDelete method. + */ protected void postDelete() { SqlFileBatchPostDeleteContext context = new SqlFileBatchPostDeleteContext<>(entityType, method, config); @@ -131,6 +203,12 @@ protected void postDelete() { } } + /** + * Prepares optimistic locking for this query. + * + *

This method sets the optimistic lock check flag based on the version property and + * configuration. + */ protected void prepareOptimisticLock() { if (versionPropertyType != null && !versionIgnored) { if (!optimisticLockExceptionSuppressed) { @@ -140,15 +218,39 @@ protected void prepareOptimisticLock() { } } + /** + * A context for pre-delete entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFileBatchPreDeleteContext extends AbstractPreDeleteContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFileBatchPreDeleteContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } } + /** + * A context for post-delete entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFileBatchPostDeleteContext extends AbstractPostDeleteContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFileBatchPostDeleteContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchInsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchInsertQuery.java index 6ddf069fe..5a203b534 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchInsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchInsertQuery.java @@ -27,15 +27,36 @@ import org.seasar.doma.jdbc.SqlKind; import org.seasar.doma.jdbc.entity.EntityType; +/** + * A query that performs batch insert operations using an external SQL file. + * + *

This class extends {@link SqlFileBatchModifyQuery} to provide functionality for executing + * batch INSERT statements defined in external SQL files. It handles entity lifecycle callbacks and + * SQL file execution for multiple entities. + * + * @param the type of elements in the batch + */ public class SqlFileBatchInsertQuery extends SqlFileBatchModifyQuery implements BatchInsertQuery { + /** The entity handler for this query. */ protected EntityHandler entityHandler; + /** + * Constructs a new instance with the specified element class. + * + * @param elementClass the class of elements in the batch + */ public SqlFileBatchInsertQuery(Class elementClass) { super(elementClass, SqlKind.BATCH_INSERT); } + /** + * {@inheritDoc} + * + *

This implementation prepares the SQL statements for each entity in the batch, executing + * pre-insert callbacks. + */ @Override public void prepare() { super.prepare(); @@ -60,15 +81,31 @@ public void prepare() { assertEquals(size, sqls.size()); } + /** + * Executes pre-insert entity lifecycle callbacks. + * + *

This method delegates to the entity handler if one is available. + */ protected void preInsert() { if (entityHandler != null) { entityHandler.preInsert(); } } + /** + * {@inheritDoc} + * + *

This implementation does nothing because this query does not support auto-generated keys. + */ @Override public void generateId(Statement statement, int index) {} + /** + * {@inheritDoc} + * + *

This implementation executes post-insert entity lifecycle callbacks for each entity in the + * batch. + */ @Override public void complete() { if (entityHandler != null) { @@ -80,25 +117,43 @@ public void complete() { } } + /** + * {@inheritDoc} + * + *

This implementation creates an entity handler for the specified entity type. + */ @Override public void setEntityType(EntityType entityType) { entityHandler = new EntityHandler(entityType); } + /** {@inheritDoc} */ @Override public boolean isBatchSupported() { return true; } + /** A handler for entity lifecycle callbacks. */ protected class EntityHandler { + /** The entity type. */ protected final EntityType entityType; + /** + * Constructs a new instance with the specified entity type. + * + * @param entityType the entity type + */ protected EntityHandler(EntityType entityType) { assertNotNull(entityType); this.entityType = entityType; } + /** + * Executes pre-insert entity lifecycle callbacks. + * + *

This method creates a pre-insert context and calls the entity type's preInsert method. + */ protected void preInsert() { SqlFileBatchPreInsertContext context = new SqlFileBatchPreInsertContext<>(entityType, method, config); @@ -108,6 +163,11 @@ protected void preInsert() { } } + /** + * Executes post-insert entity lifecycle callbacks. + * + *

This method creates a post-insert context and calls the entity type's postInsert method. + */ protected void postInsert() { SqlFileBatchPostInsertContext context = new SqlFileBatchPostInsertContext<>(entityType, method, config); @@ -118,15 +178,39 @@ protected void postInsert() { } } + /** + * A context for pre-insert entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFileBatchPreInsertContext extends AbstractPreInsertContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFileBatchPreInsertContext(EntityType entityType, Method method, Config config) { super(entityType, method, config, DuplicateKeyType.EXCEPTION); } } + /** + * A context for post-insert entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFileBatchPostInsertContext extends AbstractPostInsertContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFileBatchPostInsertContext(EntityType entityType, Method method, Config config) { super(entityType, method, config, DuplicateKeyType.EXCEPTION); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchModifyQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchModifyQuery.java index 4772f1ad6..cf834d6ff 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchModifyQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchModifyQuery.java @@ -35,58 +35,105 @@ import org.seasar.doma.jdbc.SqlLogType; import org.seasar.doma.jdbc.entity.EntityType; +/** + * An abstract base class for SQL file-based batch modification queries. + * + *

This class provides common functionality for executing batch operations using SQL files. It + * handles SQL file loading, parameter binding, and batch execution for INSERT, UPDATE, and DELETE + * operations. + * + * @param the type of elements in the batch + */ public abstract class SqlFileBatchModifyQuery extends AbstractQuery implements BatchModifyQuery { + /** Empty string array used as default for property name arrays. */ protected static final String[] EMPTY_STRINGS = new String[] {}; + /** The class of elements in the batch. */ protected final Class elementClass; + /** The SQL kind (INSERT, UPDATE, or DELETE). */ protected final SqlKind kind; + /** The path to the SQL file. */ protected String sqlFilePath; + /** The parameter name used in the SQL file. */ protected String parameterName; + /** The SQL file. */ protected SqlFile sqlFile; + /** Whether optimistic lock checking is required for this query. */ protected boolean optimisticLockCheckRequired; + /** Whether this query is executable. */ protected boolean executable; + /** The cause for skipping SQL execution, if applicable. */ protected SqlExecutionSkipCause sqlExecutionSkipCause = SqlExecutionSkipCause.BATCH_TARGET_NONEXISTENT; + /** The batch size for this query. */ protected int batchSize; + /** The SQL log type for this query. */ protected SqlLogType sqlLogType; + /** The property names to be included in the operation. */ protected String[] includedPropertyNames = EMPTY_STRINGS; + /** The property names to be excluded from the operation. */ protected String[] excludedPropertyNames = EMPTY_STRINGS; + /** The elements to be processed in the batch. */ protected List elements; + /** The current element being processed. */ protected ELEMENT currentEntity; + /** The prepared SQL statements for the batch. */ protected List sqls; + /** + * Constructs a new instance with the specified element class and SQL kind. + * + * @param elementClass the class of elements in the batch + * @param kind the SQL kind + */ protected SqlFileBatchModifyQuery(Class elementClass, SqlKind kind) { assertNotNull(elementClass, kind); this.elementClass = elementClass; this.kind = kind; } + /** + * {@inheritDoc} + * + *

This implementation validates that required components are not null. + */ @Override public void prepare() { super.prepare(); assertNotNull(method, sqlFilePath, parameterName, elements, sqls); } + /** + * Prepares the SQL file for this query. + * + *

This method loads the SQL file from the repository using the configured dialect. + */ protected void prepareSqlFile() { sqlFile = config.getSqlFileRepository().getSqlFile(method, sqlFilePath, config.getDialect()); } + /** + * Prepares the query options. + * + *

This method sets the query timeout and batch size from the configuration if they're not + * already set. + */ protected void prepareOptions() { if (queryTimeout <= 0) { queryTimeout = config.getQueryTimeout(); @@ -96,6 +143,12 @@ protected void prepareOptions() { } } + /** + * Prepares the SQL statement for the current entity. + * + *

This method creates an expression evaluator and SQL builder to generate the SQL statement + * for the current entity, then adds it to the list of SQL statements for the batch. + */ protected void prepareSql() { Value value = new Value(elementClass, currentEntity); ExpressionEvaluator evaluator = @@ -116,22 +169,57 @@ protected void prepareSql() { sqls.add(sql); } + /** + * Expands columns in the SQL statement. + * + *

This method is called when an expand node is encountered in the SQL file. + * + * @param node the expand node + * @return the expanded column list + * @throws UnsupportedOperationException if this operation is not supported by the implementing + * class + */ protected List expandColumns(ExpandNode node) { throw new UnsupportedOperationException(); } + /** + * Populates values in the SQL context. + * + *

This method is called when a populate node is encountered in the SQL file. + * + * @param node the populate node + * @param context the SQL context + * @throws UnsupportedOperationException if this operation is not supported by the implementing + * class + */ protected void populateValues(PopulateNode node, SqlContext context) { throw new UnsupportedOperationException(); } + /** + * Sets the path to the SQL file. + * + * @param sqlFilePath the SQL file path + */ public void setSqlFilePath(String sqlFilePath) { this.sqlFilePath = sqlFilePath; } + /** + * Sets the parameter name used in the SQL file. + * + * @param parameterName the parameter name + */ public void setParameterName(String parameterName) { this.parameterName = parameterName; } + /** + * Sets the elements to be processed in the batch. + * + * @param elements the elements + */ public void setElements(Iterable elements) { assertNotNull(elements); if (elements instanceof Collection) { @@ -145,73 +233,113 @@ public void setElements(Iterable elements) { this.sqls = new ArrayList<>(this.elements.size()); } + /** + * Returns the elements to be processed in the batch. + * + * @return the elements + */ public List getEntities() { return elements; } + /** + * Sets the batch size for this query. + * + * @param batchSize the batch size + */ public void setBatchSize(int batchSize) { this.batchSize = batchSize; } + /** + * Sets the SQL log type for this query. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** + * Sets the property names to be included in the operation. + * + * @param includedPropertyNames the property names to be included + */ public void setIncludedPropertyNames(String... includedPropertyNames) { this.includedPropertyNames = includedPropertyNames; } + /** + * Sets the property names to be excluded from the operation. + * + * @param excludedPropertyNames the property names to be excluded + */ public void setExcludedPropertyNames(String... excludedPropertyNames) { this.excludedPropertyNames = excludedPropertyNames; } + /** + * Sets the entity type for this query. + * + * @param entityType the entity type + */ public abstract void setEntityType(EntityType entityType); + /** {@inheritDoc} */ @Override public PreparedSql getSql() { return sqls.get(0); } + /** {@inheritDoc} */ @Override public List getSqls() { return sqls; } + /** {@inheritDoc} */ @Override public Config getConfig() { return config; } + /** {@inheritDoc} */ @Override public boolean isOptimisticLockCheckRequired() { return optimisticLockCheckRequired; } + /** {@inheritDoc} */ @Override public boolean isAutoGeneratedKeysSupported() { return false; } + /** {@inheritDoc} */ @Override public boolean isExecutable() { return executable; } + /** {@inheritDoc} */ @Override public SqlExecutionSkipCause getSqlExecutionSkipCause() { return sqlExecutionSkipCause; } + /** {@inheritDoc} */ @Override public int getBatchSize() { return batchSize; } + /** {@inheritDoc} */ @Override public SqlLogType getSqlLogType() { return sqlLogType; } + /** {@inheritDoc} */ @Override public String toString() { return sqls.toString(); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchUpdateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchUpdateQuery.java index 4fa105eb2..72e4bed05 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchUpdateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileBatchUpdateQuery.java @@ -31,19 +31,42 @@ import org.seasar.doma.jdbc.entity.EntityType; import org.seasar.doma.jdbc.entity.VersionPropertyType; +/** + * A query that performs batch update operations using an external SQL file. + * + *

This class extends {@link SqlFileBatchModifyQuery} to provide functionality for executing + * batch UPDATE statements defined in external SQL files. It handles entity lifecycle callbacks, + * optimistic locking, version incrementation, and SQL file execution for multiple entities. + * + * @param the type of elements in the batch + */ public class SqlFileBatchUpdateQuery extends SqlFileBatchModifyQuery implements BatchUpdateQuery { + /** The entity handler for this query. */ protected EntityHandler entityHandler; + /** Whether to ignore the version property for optimistic locking. */ protected boolean versionIgnored; + /** Whether to suppress optimistic lock exceptions. */ protected boolean optimisticLockExceptionSuppressed; + /** + * Constructs a new instance with the specified element class. + * + * @param elementClass the class of elements in the batch + */ public SqlFileBatchUpdateQuery(Class elementClass) { super(elementClass, SqlKind.BATCH_UPDATE); } + /** + * {@inheritDoc} + * + *

This implementation prepares the SQL statements for each entity in the batch, executing + * pre-update callbacks, optimistic lock preparation, and target property type preparation. + */ @Override public void prepare() { super.prepare(); @@ -71,24 +94,46 @@ public void prepare() { assertEquals(size, sqls.size()); } + /** + * Initializes the entity handler. + * + *

This method delegates to the entity handler if one is available. + */ protected void initEntityHandler() { if (entityHandler != null) { entityHandler.init(); } } + /** + * Executes pre-update entity lifecycle callbacks. + * + *

This method delegates to the entity handler if one is available. + */ protected void preUpdate() { if (entityHandler != null) { entityHandler.preUpdate(); } } + /** + * Prepares the target property types for this query. + * + *

This method delegates to the entity handler if one is available. + */ protected void prepareTargetPropertyTypes() { if (entityHandler != null) { entityHandler.prepareTargetPropertyTypes(); } } + /** + * {@inheritDoc} + * + *

This implementation delegates to the entity handler to populate values in the SQL context. + * + * @throws UnsupportedOperationException if the entity handler is not available + */ @Override protected void populateValues(PopulateNode node, SqlContext context) { if (entityHandler == null) { @@ -97,12 +142,23 @@ protected void populateValues(PopulateNode node, SqlContext context) { entityHandler.populateValues(context); } + /** + * Prepares optimistic locking for this query. + * + *

This method delegates to the entity handler if one is available. + */ protected void prepareOptimisticLock() { if (entityHandler != null) { entityHandler.prepareOptimisticLock(); } } + /** + * {@inheritDoc} + * + *

This implementation delegates to the entity handler to increment version values for + * optimistic locking. + */ @Override public void incrementVersions() { if (entityHandler != null) { @@ -110,6 +166,12 @@ public void incrementVersions() { } } + /** + * {@inheritDoc} + * + *

This implementation executes post-update entity lifecycle callbacks for each entity in the + * batch. + */ @Override public void complete() { if (entityHandler != null) { @@ -121,39 +183,74 @@ public void complete() { } } + /** + * {@inheritDoc} + * + *

This implementation creates an entity handler for the specified entity type. + */ @Override public void setEntityType(EntityType entityType) { entityHandler = new EntityHandler(entityType); } + /** + * Sets whether to include the version property in the update. + * + * @param versionIncluded whether to include the version property + */ public void setVersionIncluded(boolean versionIncluded) { this.versionIgnored |= versionIncluded; } + /** + * Sets whether to ignore the version property for optimistic locking. + * + * @param versionIgnored whether to ignore the version property + */ public void setVersionIgnored(boolean versionIgnored) { this.versionIgnored |= versionIgnored; } + /** + * Sets whether to suppress optimistic lock exceptions. + * + * @param optimisticLockExceptionSuppressed whether to suppress optimistic lock exceptions + */ public void setOptimisticLockExceptionSuppressed(boolean optimisticLockExceptionSuppressed) { this.optimisticLockExceptionSuppressed = optimisticLockExceptionSuppressed; } + /** A handler for entity lifecycle callbacks, optimistic locking, and value population. */ protected class EntityHandler { + /** The entity type. */ protected final EntityType entityType; + /** The version property type for optimistic locking. */ protected final VersionPropertyType versionPropertyType; + /** The property types to be included in the update. */ protected List> targetPropertyTypes; + /** The helper for batch update operations. */ protected BatchUpdateQueryHelper helper; + /** + * Constructs a new instance with the specified entity type. + * + * @param entityType the entity type + */ protected EntityHandler(EntityType entityType) { assertNotNull(entityType); this.entityType = entityType; this.versionPropertyType = entityType.getVersionPropertyType(); } + /** + * Initializes this handler. + * + *

This method creates a batch update query helper with the configured properties. + */ protected void init() { helper = new BatchUpdateQueryHelper<>( @@ -165,6 +262,11 @@ protected void init() { optimisticLockExceptionSuppressed); } + /** + * Executes pre-update entity lifecycle callbacks. + * + *

This method creates a pre-update context and calls the entity type's preUpdate method. + */ protected void preUpdate() { SqlFileBatchPreUpdateContext context = new SqlFileBatchPreUpdateContext<>(entityType, method, config); @@ -174,10 +276,21 @@ protected void preUpdate() { } } + /** + * Prepares the target property types for this query. + * + *

This method retrieves the target property types from the helper. + */ protected void prepareTargetPropertyTypes() { targetPropertyTypes = helper.getTargetPropertyTypes(); } + /** + * Executes post-update entity lifecycle callbacks. + * + *

This method creates a post-update context, calls the entity type's postUpdate method, and + * saves the current state of the entity. + */ protected void postUpdate() { SqlFileBatchPostUpdateContext context = new SqlFileBatchPostUpdateContext<>(entityType, method, config); @@ -188,6 +301,12 @@ protected void postUpdate() { entityType.saveCurrentStates(currentEntity); } + /** + * Prepares optimistic locking for this query. + * + *

This method sets the optimistic lock check flag based on the version property and + * configuration. + */ protected void prepareOptimisticLock() { if (versionPropertyType != null && !versionIgnored) { if (!optimisticLockExceptionSuppressed) { @@ -196,6 +315,12 @@ protected void prepareOptimisticLock() { } } + /** + * Increments version values for optimistic locking. + * + *

This method increments the version property value for each entity in the batch if + * optimistic locking is enabled. + */ protected void incrementVersions() { if (versionPropertyType != null && !versionIgnored) { for (ListIterator it = elements.listIterator(); it.hasNext(); ) { @@ -205,22 +330,51 @@ protected void incrementVersions() { } } + /** + * Populates values in the SQL context. + * + *

This method delegates to the helper to populate values for the current entity. + * + * @param context the SQL context + */ protected void populateValues(SqlContext context) { helper.populateValues(currentEntity, targetPropertyTypes, versionPropertyType, context); } } + /** + * A context for pre-update entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFileBatchPreUpdateContext extends AbstractPreUpdateContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFileBatchPreUpdateContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } + /** + * {@inheritDoc} + * + *

This implementation always returns true for batch operations. + */ @Override public boolean isEntityChanged() { return true; } + /** + * {@inheritDoc} + * + *

This implementation always returns true for batch operations. + */ @Override public boolean isPropertyChanged(String propertyName) { validatePropertyDefined(propertyName); @@ -228,12 +382,29 @@ public boolean isPropertyChanged(String propertyName) { } } + /** + * A context for post-update entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFileBatchPostUpdateContext extends AbstractPostUpdateContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFileBatchPostUpdateContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } + /** + * {@inheritDoc} + * + *

This implementation always returns true for batch operations. + */ @Override public boolean isPropertyChanged(String propertyName) { validatePropertyDefined(propertyName); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileDeleteQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileDeleteQuery.java index 1eb6cc1af..524897c36 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileDeleteQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileDeleteQuery.java @@ -25,18 +25,40 @@ import org.seasar.doma.jdbc.entity.EntityType; import org.seasar.doma.jdbc.entity.VersionPropertyType; +/** + * A query that deletes data from a database using an external SQL file. + * + *

This class extends {@link SqlFileModifyQuery} to provide functionality for executing DELETE + * statements defined in external SQL files. It handles entity lifecycle callbacks, optimistic + * locking, and SQL file execution. + */ public class SqlFileDeleteQuery extends SqlFileModifyQuery implements DeleteQuery { + /** The entity handler for this query. */ protected EntityHandler entityHandler; + /** Whether to ignore the version property for optimistic locking. */ protected boolean versionIgnored; + /** Whether to suppress optimistic lock exceptions. */ protected boolean optimisticLockExceptionSuppressed; + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#DELETE} to indicate that it + * performs a DELETE operation. + */ public SqlFileDeleteQuery() { super(SqlKind.DELETE); } + /** + * {@inheritDoc} + * + *

This implementation prepares the SQL statement by processing the SQL file and handling + * entity lifecycle callbacks and optimistic locking. + */ @Override public void prepare() { super.prepare(); @@ -49,23 +71,43 @@ public void prepare() { assertNotNull(sql); } + /** + * Executes pre-delete entity lifecycle callbacks. + * + *

This method delegates to the entity handler if one is available. + */ protected void preDelete() { if (entityHandler != null) { entityHandler.preDelete(); } } + /** + * Prepares optimistic locking for this query. + * + *

This method delegates to the entity handler if one is available. + */ protected void prepareOptimisticLock() { if (entityHandler != null) { entityHandler.prepareOptimisticLock(); } } + /** + * Prepares the executable state for this query. + * + *

This method sets the query as executable and clears any skip cause. + */ protected void prepareExecutable() { executable = true; sqlExecutionSkipCause = null; } + /** + * {@inheritDoc} + * + *

This implementation executes post-delete entity lifecycle callbacks. + */ @Override public void complete() { if (entityHandler != null) { @@ -73,19 +115,41 @@ public void complete() { } } + /** + * {@inheritDoc} + * + *

This implementation creates an entity handler for the specified entity. + */ @Override public void setEntityAndEntityType(String name, E entity, EntityType entityType) { entityHandler = new EntityHandler<>(name, entity, entityType); } + /** + * Sets whether to ignore the version property for optimistic locking. + * + * @param versionIgnored whether to ignore the version property + */ public void setVersionIgnored(boolean versionIgnored) { this.versionIgnored = versionIgnored; } + /** + * Sets whether to suppress optimistic lock exceptions. + * + * @param optimisticLockExceptionSuppressed whether to suppress optimistic lock exceptions + */ public void setOptimisticLockExceptionSuppressed(boolean optimisticLockExceptionSuppressed) { this.optimisticLockExceptionSuppressed = optimisticLockExceptionSuppressed; } + /** + * Returns the entity associated with this query. + * + * @param the entity type + * @param entityType the entity class + * @return the entity, or null if no entity is associated with this query + */ @SuppressWarnings("unchecked") public E getEntity(Class entityType) { if (entityHandler != null) { @@ -94,16 +158,32 @@ public E getEntity(Class entityType) { return null; } + /** + * A handler for entity lifecycle callbacks and optimistic locking. + * + * @param the entity type + */ protected class EntityHandler { + /** The parameter name for the entity. */ protected final String name; + /** The entity being deleted. */ protected E entity; + /** The entity type. */ protected final EntityType entityType; + /** The version property type for optimistic locking. */ protected final VersionPropertyType versionPropertyType; + /** + * Constructs a new instance with the specified entity information. + * + * @param name the parameter name for the entity + * @param entity the entity being deleted + * @param entityType the entity type + */ protected EntityHandler(String name, E entity, EntityType entityType) { assertNotNull(name, entity, entityType); this.name = name; @@ -112,6 +192,11 @@ protected EntityHandler(String name, E entity, EntityType entityType) { this.versionPropertyType = entityType.getVersionPropertyType(); } + /** + * Executes pre-delete entity lifecycle callbacks. + * + *

This method creates a pre-delete context and calls the entity type's preDelete method. + */ protected void preDelete() { SqlFilePreDeleteContext context = new SqlFilePreDeleteContext<>(entityType, method, config); @@ -122,6 +207,11 @@ protected void preDelete() { } } + /** + * Executes post-delete entity lifecycle callbacks. + * + *

This method creates a post-delete context and calls the entity type's postDelete method. + */ protected void postDelete() { SqlFilePostDeleteContext context = new SqlFilePostDeleteContext<>(entityType, method, config); @@ -131,6 +221,12 @@ protected void postDelete() { } } + /** + * Prepares optimistic locking for this query. + * + *

This method sets the optimistic lock check flag based on the version property and + * configuration. + */ protected void prepareOptimisticLock() { if (versionPropertyType != null && !versionIgnored) { if (!optimisticLockExceptionSuppressed) { @@ -140,15 +236,39 @@ protected void prepareOptimisticLock() { } } + /** + * A context for pre-delete entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFilePreDeleteContext extends AbstractPreDeleteContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFilePreDeleteContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } } + /** + * A context for post-delete entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFilePostDeleteContext extends AbstractPostDeleteContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFilePostDeleteContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileInsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileInsertQuery.java index be95f1ee9..008399ede 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileInsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileInsertQuery.java @@ -25,16 +25,37 @@ import org.seasar.doma.jdbc.SqlKind; import org.seasar.doma.jdbc.entity.EntityType; +/** + * A query that inserts data into a database using an external SQL file. + * + *

This class extends {@link SqlFileModifyQuery} to provide functionality for executing INSERT + * statements defined in external SQL files. It handles entity lifecycle callbacks and SQL file + * execution. + */ public class SqlFileInsertQuery extends SqlFileModifyQuery implements InsertQuery { + /** Whether to exclude null properties from the insert operation. */ protected boolean nullExcluded; + /** The entity handler for this query. */ protected EntityHandler entityHandler; + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#INSERT} to indicate that it + * performs an INSERT operation. + */ public SqlFileInsertQuery() { super(SqlKind.INSERT); } + /** + * {@inheritDoc} + * + *

This implementation prepares the SQL statement by processing the SQL file and handling + * entity lifecycle callbacks. + */ @Override public void prepare() { super.prepare(); @@ -46,20 +67,42 @@ public void prepare() { assertNotNull(sql); } + /** + * Executes pre-insert entity lifecycle callbacks. + * + *

This method delegates to the entity handler if one is available. + */ protected void preInsert() { if (entityHandler != null) { entityHandler.preInsert(); } } + /** + * Prepares the executable state for this query. + * + *

This method sets the query as executable and clears any skip cause. + */ protected void prepareExecutable() { executable = true; sqlExecutionSkipCause = null; } + /** + * {@inheritDoc} + * + *

This implementation does nothing because this query does not support auto-generated keys. + */ @Override public void generateId(Statement statement) {} + /** + * Returns the entity associated with this query. + * + * @param the entity type + * @param entityType the entity class + * @return the entity, or null if no entity is associated with this query + */ @SuppressWarnings("unchecked") public E getEntity(Class entityType) { if (entityHandler != null) { @@ -68,6 +111,11 @@ public E getEntity(Class entityType) { return null; } + /** + * {@inheritDoc} + * + *

This implementation executes post-insert entity lifecycle callbacks. + */ @Override public void complete() { if (entityHandler != null) { @@ -75,23 +123,48 @@ public void complete() { } } + /** + * {@inheritDoc} + * + *

This implementation creates an entity handler for the specified entity. + */ @Override public void setEntityAndEntityType(String name, E entity, EntityType entityType) { entityHandler = new EntityHandler<>(name, entity, entityType); } + /** + * Sets whether to exclude null properties from the insert operation. + * + * @param nullExcluded whether to exclude null properties + */ public void setNullExcluded(boolean nullExcluded) { this.nullExcluded = nullExcluded; } + /** + * A handler for entity lifecycle callbacks. + * + * @param the entity type + */ protected class EntityHandler { + /** The parameter name for the entity. */ protected final String name; + /** The entity being inserted. */ protected E entity; + /** The entity type. */ protected final EntityType entityType; + /** + * Constructs a new instance with the specified entity information. + * + * @param name the parameter name for the entity + * @param entity the entity being inserted + * @param entityType the entity type + */ protected EntityHandler(String name, E entity, EntityType entityType) { assertNotNull(name, entity, entityType); this.name = name; @@ -99,6 +172,11 @@ protected EntityHandler(String name, E entity, EntityType entityType) { this.entityType = entityType; } + /** + * Executes pre-insert entity lifecycle callbacks. + * + *

This method creates a pre-insert context and calls the entity type's preInsert method. + */ protected void preInsert() { SqlFilePreInsertContext context = new SqlFilePreInsertContext<>(entityType, method, config); @@ -109,6 +187,11 @@ protected void preInsert() { } } + /** + * Executes post-insert entity lifecycle callbacks. + * + *

This method creates a post-insert context and calls the entity type's postInsert method. + */ protected void postInsert() { SqlFilePostInsertContext context = new SqlFilePostInsertContext<>(entityType, method, config); @@ -119,15 +202,39 @@ protected void postInsert() { } } + /** + * A context for pre-insert entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFilePreInsertContext extends AbstractPreInsertContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFilePreInsertContext(EntityType entityType, Method method, Config config) { super(entityType, method, config, DuplicateKeyType.EXCEPTION); } } + /** + * A context for post-insert entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFilePostInsertContext extends AbstractPostInsertContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFilePostInsertContext(EntityType entityType, Method method, Config config) { super(entityType, method, config, DuplicateKeyType.EXCEPTION); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileModifyQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileModifyQuery.java index 2b6eaa18c..72762b1ca 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileModifyQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileModifyQuery.java @@ -33,41 +33,74 @@ import org.seasar.doma.jdbc.SqlLogType; import org.seasar.doma.jdbc.entity.EntityType; +/** + * An abstract base class for SQL file-based data modification queries. + * + *

This class provides common functionality for SQL file-based INSERT, UPDATE, and DELETE + * operations. It handles SQL file loading, parameter binding, and SQL statement preparation. + */ public abstract class SqlFileModifyQuery extends AbstractQuery implements ModifyQuery { + /** Empty string array used as default for property name arrays. */ protected static final String[] EMPTY_STRINGS = new String[] {}; + /** The SQL kind (INSERT, UPDATE, or DELETE). */ protected final SqlKind kind; + /** The path to the SQL file. */ protected String sqlFilePath; + /** The parameters to be bound to the SQL statement. */ protected final Map parameters = new LinkedHashMap<>(); + /** The prepared SQL statement. */ protected PreparedSql sql; + /** Whether optimistic lock checking is required for this query. */ protected boolean optimisticLockCheckRequired; + /** The SQL log type for this query. */ protected SqlLogType sqlLogType; + /** The property names to be included in the operation. */ protected String[] includedPropertyNames = EMPTY_STRINGS; + /** The property names to be excluded from the operation. */ protected String[] excludedPropertyNames = EMPTY_STRINGS; + /** Whether this query is executable. */ protected boolean executable; + /** The cause for skipping SQL execution, if applicable. */ protected SqlExecutionSkipCause sqlExecutionSkipCause = SqlExecutionSkipCause.STATE_UNCHANGED; + /** + * Constructs a new instance with the specified SQL kind. + * + * @param kind the SQL kind + */ protected SqlFileModifyQuery(SqlKind kind) { assertNotNull(kind); this.kind = kind; } + /** + * Prepares the query options. + * + *

This method sets the query timeout from the configuration if it's not already set. + */ protected void prepareOptions() { if (queryTimeout <= 0) { queryTimeout = config.getQueryTimeout(); } } + /** + * Prepares the SQL statement. + * + *

This method loads the SQL file, evaluates expressions, and builds the prepared SQL + * statement. + */ protected void prepareSql() { SqlFile sqlFile = config.getSqlFileRepository().getSqlFile(method, sqlFilePath, config.getDialect()); @@ -86,71 +119,142 @@ protected void prepareSql() { sql = sqlBuilder.build(sqlFile.getSqlNode(), this::comment); } + /** + * Expands columns in the SQL statement. + * + *

This method is called when an expand node is encountered in the SQL file. + * + * @param node the expand node + * @return the expanded column list + * @throws UnsupportedOperationException if this operation is not supported by the implementing + * class + */ protected List expandColumns(ExpandNode node) { throw new UnsupportedOperationException(); } + /** + * Populates values in the SQL context. + * + *

This method is called when a populate node is encountered in the SQL file. + * + * @param node the populate node + * @param context the SQL context + * @throws UnsupportedOperationException if this operation is not supported by the implementing + * class + */ protected void populateValues(PopulateNode node, SqlContext context) { throw new UnsupportedOperationException(); } + /** + * Sets the path to the SQL file. + * + * @param sqlFilePath the SQL file path + */ public void setSqlFilePath(String sqlFilePath) { this.sqlFilePath = sqlFilePath; } + /** + * Adds a parameter to this query. + * + * @param name the parameter name + * @param type the parameter type + * @param value the parameter value + */ public void addParameter(String name, Class type, Object value) { assertNotNull(name, type); addParameterInternal(name, type, value); } + /** + * Adds a parameter to this query without null checks. + * + *

This method is used internally when null checks have already been performed. + * + * @param name the parameter name + * @param type the parameter type + * @param value the parameter value + */ public void addParameterInternal(String name, Class type, Object value) { parameters.put(name, new Value(type, value)); } + /** + * Sets the SQL log type for this query. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** + * Sets the property names to be included in the operation. + * + * @param includedPropertyNames the property names to be included + */ public void setIncludedPropertyNames(String... includedPropertyNames) { this.includedPropertyNames = includedPropertyNames; } + /** + * Sets the property names to be excluded from the operation. + * + * @param excludedPropertyNames the property names to be excluded + */ public void setExcludedPropertyNames(String... excludedPropertyNames) { this.excludedPropertyNames = excludedPropertyNames; } + /** {@inheritDoc} */ @Override public PreparedSql getSql() { return sql; } + /** {@inheritDoc} */ @Override public boolean isOptimisticLockCheckRequired() { return optimisticLockCheckRequired; } + /** {@inheritDoc} */ @Override public boolean isExecutable() { return executable; } + /** {@inheritDoc} */ @Override public SqlExecutionSkipCause getSqlExecutionSkipCause() { return sqlExecutionSkipCause; } + /** {@inheritDoc} */ @Override public boolean isAutoGeneratedKeysSupported() { return false; } + /** {@inheritDoc} */ @Override public SqlLogType getSqlLogType() { return sqlLogType; } + /** + * Sets the entity and entity type for this query. + * + * @param the entity type + * @param name the parameter name for the entity + * @param entity the entity + * @param entityType the entity type + */ public abstract void setEntityAndEntityType(String name, E entity, EntityType entityType); + /** {@inheritDoc} */ @Override public String toString() { return sql != null ? sql.toString() : null; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileScriptQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileScriptQuery.java index ce9112a8b..404f2eed2 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileScriptQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileScriptQuery.java @@ -34,36 +34,69 @@ import org.seasar.doma.jdbc.Sql; import org.seasar.doma.jdbc.SqlLogType; +/** + * A query that executes a SQL script file. + * + *

This class extends {@link AbstractQuery} to provide functionality for executing SQL script + * files. It handles script file loading, block delimiter detection, and script execution. + */ public class SqlFileScriptQuery extends AbstractQuery implements ScriptQuery { + /** The path to the script file. */ protected String scriptFilePath; + /** The delimiter that separates SQL statements in the script. */ protected String blockDelimiter; + /** Whether to halt execution when an error occurs. */ protected boolean haltOnError; + /** The URL of the script file. */ protected URL scriptFileUrl; + /** The SQL annotation if the script is defined inline. */ protected org.seasar.doma.Sql sqlAnnotation; + /** The SQL log type for this script query. */ protected SqlLogType sqlLogType; + /** + * Sets the path to the script file. + * + * @param scriptFilePath the script file path + */ public void setScriptFilePath(String scriptFilePath) { this.scriptFilePath = scriptFilePath; } + /** + * Sets the delimiter that separates SQL statements in the script. + * + * @param blockDelimiter the block delimiter + */ public void setBlockDelimiter(String blockDelimiter) { this.blockDelimiter = blockDelimiter; } + /** + * Sets whether to halt execution when an error occurs. + * + * @param haltOnError whether to halt on error + */ public void setHaltOnError(boolean haltOnError) { this.haltOnError = haltOnError; } + /** + * Sets the SQL log type for this script query. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** {@inheritDoc} */ @Override public void prepare() { super.prepare(); @@ -91,30 +124,40 @@ public void prepare() { } } + /** {@inheritDoc} */ @Override public void complete() {} + /** {@inheritDoc} */ @Override public int getQueryTimeout() { return -1; } + /** {@inheritDoc} */ @Override public Sql getSql() { assertUnreachable(); return null; } + /** {@inheritDoc} */ @Override public String getScriptFilePath() { return scriptFilePath; } + /** {@inheritDoc} */ @Override public URL getScriptFileUrl() { return scriptFileUrl; } + /** + * Returns a supplier that provides a reader for the script content. + * + * @return the reader supplier + */ public Supplier getReaderSupplier() { if (sqlAnnotation == null) { return () -> { @@ -129,16 +172,23 @@ public Supplier getReaderSupplier() { return () -> new StringReader(sqlAnnotation.value()); } + /** {@inheritDoc} */ @Override public String getBlockDelimiter() { return blockDelimiter; } + /** {@inheritDoc} */ @Override public boolean getHaltOnError() { return haltOnError; } + /** + * Returns the SQL log type for this script query. + * + * @return the SQL log type + */ public SqlLogType getSqlLogType() { return sqlLogType; } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileSelectQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileSelectQuery.java index 3aaf4e15e..c78f3de17 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileSelectQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileSelectQuery.java @@ -24,18 +24,34 @@ import org.seasar.doma.jdbc.SqlKind; import org.seasar.doma.jdbc.SqlNode; +/** + * A query that selects data from a database using an external SQL file. + * + *

This class extends {@link AbstractSelectQuery} to provide functionality for executing SELECT + * statements defined in external SQL files. It handles SQL file loading, transformation, and + * execution. + */ public class SqlFileSelectQuery extends AbstractSelectQuery { + /** The path to the SQL file. */ protected String sqlFilePath; + /** The SQL file containing the SELECT statement. */ protected SqlFile sqlFile; + /** {@inheritDoc} */ @Override public void prepare() { super.prepare(); assertNotNull(sqlFilePath); } + /** + * Prepares the SQL for this query. + * + *

This method loads the SQL file, transforms the SQL node using the dialect, and builds the + * prepared SQL statement. + */ protected void prepareSql() { sqlFile = config.getSqlFileRepository().getSqlFile(method, sqlFilePath, config.getDialect()); SqlNode transformedSqlNode = @@ -54,6 +70,7 @@ protected void prepareSql() { sql = sqlBuilder.build(transformedSqlNode, this::comment); } + /** {@inheritDoc} */ @Override public void complete() { if (SelectOptionsAccessor.isCount(options)) { @@ -61,6 +78,11 @@ public void complete() { } } + /** + * Sets the path to the SQL file. + * + * @param sqlFilePath the SQL file path + */ public void setSqlFilePath(String sqlFilePath) { this.sqlFilePath = sqlFilePath; } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileUpdateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileUpdateQuery.java index 91b71d5ce..971b656db 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileUpdateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlFileUpdateQuery.java @@ -29,22 +29,46 @@ import org.seasar.doma.jdbc.entity.EntityType; import org.seasar.doma.jdbc.entity.VersionPropertyType; +/** + * A query that updates data in a database using an external SQL file. + * + *

This class extends {@link SqlFileModifyQuery} to provide functionality for executing UPDATE + * statements defined in external SQL files. It handles entity lifecycle callbacks, optimistic + * locking, and SQL file execution. + */ public class SqlFileUpdateQuery extends SqlFileModifyQuery implements UpdateQuery { + /** The entity handler for this query. */ protected EntityHandler entityHandler; + /** Whether to exclude null properties from the update operation. */ protected boolean nullExcluded; + /** Whether to ignore the version property for optimistic locking. */ protected boolean versionIgnored; + /** Whether to suppress optimistic lock exceptions. */ protected boolean optimisticLockExceptionSuppressed; + /** Whether to include properties that haven't changed in the update operation. */ protected boolean unchangedPropertyIncluded; + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#UPDATE} to indicate that it + * performs an UPDATE operation. + */ public SqlFileUpdateQuery() { super(SqlKind.UPDATE); } + /** + * {@inheritDoc} + * + *

This implementation prepares the SQL statement by processing the SQL file and handling + * entity lifecycle callbacks and optimistic locking. + */ @Override public void prepare() { super.prepare(); @@ -59,24 +83,45 @@ public void prepare() { assertNotNull(sql); } + /** + * Initializes the entity handler. + * + *

This method delegates to the entity handler if one is available. + */ protected void initEntityHandler() { if (entityHandler != null) { entityHandler.init(); } } + /** + * Executes pre-update entity lifecycle callbacks. + * + *

This method delegates to the entity handler if one is available. + */ protected void preUpdate() { if (entityHandler != null) { entityHandler.preUpdate(); } } + /** + * Prepares the target property types for this query. + * + *

This method delegates to the entity handler if one is available. + */ protected void prepareTargetPropertyTypes() { if (entityHandler != null) { entityHandler.prepareTargetPropertyTypes(); } } + /** + * Prepares the executable state for this query. + * + *

This method sets the query as executable if there is no entity handler or if the entity + * handler has target property types. + */ protected void prepareExecutable() { if (entityHandler == null || entityHandler.hasTargetPropertyTypes()) { executable = true; @@ -84,6 +129,13 @@ protected void prepareExecutable() { } } + /** + * {@inheritDoc} + * + *

This implementation delegates to the entity handler to populate values in the SQL context. + * + * @throws UnsupportedOperationException if no entity handler is available + */ @Override protected void populateValues(PopulateNode node, SqlContext context) { if (entityHandler == null) { @@ -92,12 +144,22 @@ protected void populateValues(PopulateNode node, SqlContext context) { entityHandler.populateValues(context); } + /** + * Prepares optimistic locking for this query. + * + *

This method delegates to the entity handler if one is available. + */ protected void prepareOptimisticLock() { if (entityHandler != null) { entityHandler.prepareOptimisticLock(); } } + /** + * {@inheritDoc} + * + *

This implementation delegates to the entity handler to increment the version property. + */ @Override public void incrementVersion() { if (entityHandler != null) { @@ -105,6 +167,13 @@ public void incrementVersion() { } } + /** + * Returns the entity associated with this query. + * + * @param the entity type + * @param entityType the entity class + * @return the entity, or null if no entity is associated with this query + */ @SuppressWarnings("unchecked") public E getEntity(Class entityType) { if (entityHandler != null) { @@ -113,6 +182,11 @@ public E getEntity(Class entityType) { return null; } + /** + * {@inheritDoc} + * + *

This implementation executes post-update entity lifecycle callbacks. + */ @Override public void complete() { if (entityHandler != null) { @@ -120,41 +194,84 @@ public void complete() { } } + /** + * {@inheritDoc} + * + *

This implementation creates an entity handler for the specified entity. + */ @Override public void setEntityAndEntityType(String name, E entity, EntityType entityType) { entityHandler = new EntityHandler<>(name, entity, entityType); } + /** + * Sets whether to exclude null properties from the update operation. + * + * @param nullExcluded whether to exclude null properties + */ public void setNullExcluded(boolean nullExcluded) { this.nullExcluded = nullExcluded; } + /** + * Sets whether to ignore the version property for optimistic locking. + * + * @param versionIgnored whether to ignore the version property + */ public void setVersionIgnored(boolean versionIgnored) { this.versionIgnored |= versionIgnored; } + /** + * Sets whether to suppress optimistic lock exceptions. + * + * @param optimisticLockExceptionSuppressed whether to suppress optimistic lock exceptions + */ public void setOptimisticLockExceptionSuppressed(boolean optimisticLockExceptionSuppressed) { this.optimisticLockExceptionSuppressed = optimisticLockExceptionSuppressed; } + /** + * Sets whether to include properties that haven't changed in the update operation. + * + * @param unchangedPropertyIncluded whether to include unchanged properties + */ public void setUnchangedPropertyIncluded(Boolean unchangedPropertyIncluded) { this.unchangedPropertyIncluded = unchangedPropertyIncluded; } + /** + * A handler for entity lifecycle callbacks and optimistic locking. + * + * @param the entity type + */ protected class EntityHandler { + /** The parameter name for the entity. */ protected final String name; + /** The entity being updated. */ protected E entity; + /** The entity type. */ protected final EntityType entityType; + /** The version property type for optimistic locking. */ protected final VersionPropertyType versionPropertyType; + /** The property types to be updated. */ protected List> targetPropertyTypes; + /** The helper for update operations. */ protected UpdateQueryHelper helper; + /** + * Constructs a new instance with the specified entity information. + * + * @param name the parameter name for the entity + * @param entity the entity being updated + * @param entityType the entity type + */ protected EntityHandler(String name, E entity, EntityType entityType) { assertNotNull(name, entity, entityType); this.name = name; @@ -163,6 +280,11 @@ protected EntityHandler(String name, E entity, EntityType entityType) { this.versionPropertyType = entityType.getVersionPropertyType(); } + /** + * Initializes the update query helper. + * + *

This method creates a helper with the current configuration and entity information. + */ protected void init() { helper = new UpdateQueryHelper<>( @@ -176,6 +298,11 @@ protected void init() { unchangedPropertyIncluded); } + /** + * Executes pre-update entity lifecycle callbacks. + * + *

This method creates a pre-update context and calls the entity type's preUpdate method. + */ protected void preUpdate() { SqlFilePreUpdateContext context = new SqlFilePreUpdateContext<>(entityType, method, config); @@ -186,14 +313,29 @@ protected void preUpdate() { } } + /** + * Prepares the target property types for this query. + * + *

This method uses the helper to determine which properties should be updated. + */ protected void prepareTargetPropertyTypes() { targetPropertyTypes = helper.getTargetPropertyTypes(entity); } + /** + * Returns whether this handler has target property types. + * + * @return {@code true} if this handler has target property types, {@code false} otherwise + */ protected boolean hasTargetPropertyTypes() { return targetPropertyTypes != null && !targetPropertyTypes.isEmpty(); } + /** + * Executes post-update entity lifecycle callbacks. + * + *

This method creates a post-update context and calls the entity type's postUpdate method. + */ protected void postUpdate() { SqlFilePostUpdateContext context = new SqlFilePostUpdateContext<>(entityType, method, config); @@ -204,6 +346,12 @@ protected void postUpdate() { entityType.saveCurrentStates(entity); } + /** + * Prepares optimistic locking for this query. + * + *

This method sets the optimistic lock check flag based on the version property and + * configuration. + */ protected void prepareOptimisticLock() { if (versionPropertyType != null && !versionIgnored) { if (!optimisticLockExceptionSuppressed) { @@ -212,28 +360,65 @@ protected void prepareOptimisticLock() { } } + /** + * Increments the version property for optimistic locking. + * + *

This method increments the version property if one exists and version checking is not + * ignored. + */ protected void incrementVersion() { if (versionPropertyType != null && !versionIgnored) { entity = versionPropertyType.increment(entityType, entity); } } + /** + * Populates values in the SQL context. + * + *

This method uses the helper to populate values for the target properties. + * + * @param context the SQL context + */ protected void populateValues(SqlContext context) { helper.populateValues(entity, targetPropertyTypes, versionPropertyType, context); } } + /** + * A context for pre-update entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFilePreUpdateContext extends AbstractPreUpdateContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFilePreUpdateContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } + /** + * {@inheritDoc} + * + *

This implementation always returns {@code true} because SQL file-based updates always + * consider the entity changed. + */ @Override public boolean isEntityChanged() { return true; } + /** + * {@inheritDoc} + * + *

This implementation always returns {@code true} because SQL file-based updates always + * consider properties changed. + */ @Override public boolean isPropertyChanged(String propertyName) { validatePropertyDefined(propertyName); @@ -241,12 +426,30 @@ public boolean isPropertyChanged(String propertyName) { } } + /** + * A context for post-update entity lifecycle callbacks. + * + * @param the entity type + */ protected static class SqlFilePostUpdateContext extends AbstractPostUpdateContext { + /** + * Constructs a new instance with the specified entity information. + * + * @param entityType the entity type + * @param method the method + * @param config the configuration + */ public SqlFilePostUpdateContext(EntityType entityType, Method method, Config config) { super(entityType, method, config); } + /** + * {@inheritDoc} + * + *

This implementation always returns {@code true} because SQL file-based updates always + * consider properties changed. + */ @Override public boolean isPropertyChanged(String propertyName) { validatePropertyDefined(propertyName); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlInsertQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlInsertQuery.java index 7f0acd11f..cb9b19fff 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlInsertQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlInsertQuery.java @@ -18,12 +18,30 @@ import java.sql.Statement; import org.seasar.doma.jdbc.SqlKind; +/** + * A query that executes a SQL INSERT statement. + * + *

This class extends {@link SqlModifyQuery} to provide functionality for executing INSERT + * statements. It sets the SQL kind to {@link SqlKind#INSERT} to indicate that this query performs + * an INSERT operation. + */ public class SqlInsertQuery extends SqlModifyQuery implements InsertQuery { + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#INSERT} to indicate that it + * performs an INSERT operation. + */ public SqlInsertQuery() { super(SqlKind.INSERT); } + /** + * {@inheritDoc} + * + *

This implementation does nothing because this query does not support auto-generated keys. + */ @Override public void generateId(Statement statement) {} } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlModifyQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlModifyQuery.java index 07442b6fc..ded79d64c 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlModifyQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlModifyQuery.java @@ -28,25 +28,48 @@ import org.seasar.doma.jdbc.SqlLogType; import org.seasar.doma.jdbc.SqlNode; +/** + * An abstract base class for SQL-based data modification queries. + * + *

This class provides common functionality for SQL-based INSERT, UPDATE, and DELETE operations. + * It handles SQL node processing, parameter binding, and SQL statement preparation. + */ public abstract class SqlModifyQuery extends AbstractQuery implements ModifyQuery { + /** The SQL kind (INSERT, UPDATE, or DELETE). */ protected final SqlKind kind; + /** The SQL node representing the query. */ protected SqlNode sqlNode; + /** The parameters to be bound to the SQL statement. */ protected final Map parameters = new LinkedHashMap<>(); + /** The prepared SQL statement. */ protected PreparedSql sql; + /** Whether optimistic lock checking is required for this query. */ protected boolean optimisticLockCheckRequired; + /** The SQL log type for this query. */ protected SqlLogType sqlLogType; + /** + * Constructs a new instance with the specified SQL kind. + * + * @param kind the SQL kind + */ protected SqlModifyQuery(SqlKind kind) { assertNotNull(kind); this.kind = kind; } + /** + * {@inheritDoc} + * + *

This implementation prepares the SQL statement by processing the SQL node and binding + * parameters. + */ @Override public void prepare() { super.prepare(); @@ -56,12 +79,22 @@ public void prepare() { assertNotNull(sql); } + /** + * Prepares the query options. + * + *

This method sets the query timeout from the configuration if it's not already set. + */ protected void prepareOptions() { if (queryTimeout <= 0) { queryTimeout = config.getQueryTimeout(); } } + /** + * Prepares the SQL statement. + * + *

This method evaluates expressions in the SQL node and builds the prepared SQL statement. + */ protected void prepareSql() { ExpressionEvaluator evaluator = new ExpressionEvaluator( @@ -71,56 +104,82 @@ protected void prepareSql() { sql = sqlBuilder.build(sqlNode, this::comment); } + /** {@inheritDoc} */ @Override public void complete() {} + /** + * Sets the SQL node for this query. + * + * @param sqlNode the SQL node + */ public void setSqlNode(SqlNode sqlNode) { this.sqlNode = sqlNode; } + /** + * Adds a parameter to this query. + * + * @param name the parameter name + * @param type the parameter type + * @param value the parameter value + */ public void addParameter(String name, Class type, Object value) { assertNotNull(name, type); parameters.put(name, new Value(type, value)); } + /** Clears all parameters from this query. */ public void clearParameters() { parameters.clear(); } + /** + * Sets the SQL log type for this query. + * + * @param sqlLogType the SQL log type + */ public void setSqlLogType(SqlLogType sqlLogType) { this.sqlLogType = sqlLogType; } + /** {@inheritDoc} */ @Override public PreparedSql getSql() { return sql; } + /** {@inheritDoc} */ @Override public boolean isOptimisticLockCheckRequired() { return optimisticLockCheckRequired; } + /** {@inheritDoc} */ @Override public boolean isExecutable() { return true; } + /** {@inheritDoc} */ @Override public SqlExecutionSkipCause getSqlExecutionSkipCause() { return null; } + /** {@inheritDoc} */ @Override public boolean isAutoGeneratedKeysSupported() { return false; } + /** {@inheritDoc} */ @Override public SqlLogType getSqlLogType() { return sqlLogType; } + /** {@inheritDoc} */ @Override public String toString() { return sql != null ? sql.toString() : null; diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlProcessorQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlProcessorQuery.java index 402ca463f..c69f7f3cd 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlProcessorQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlProcessorQuery.java @@ -27,25 +27,46 @@ import org.seasar.doma.jdbc.SqlKind; import org.seasar.doma.jdbc.SqlLogType; +/** + * A query that processes SQL files. This class is responsible for loading SQL files and building + * prepared SQL statements with parameter binding. + */ public class SqlProcessorQuery extends AbstractQuery { + /** The parameters to be bound to the SQL. */ protected final Map parameters = new HashMap<>(); + /** The path to the SQL file. */ protected String sqlFilePath; + /** The SQL file. */ protected SqlFile sqlFile; + /** The prepared SQL statement. */ protected PreparedSql sql; + /** + * Sets the path to the SQL file. + * + * @param sqlFilePath the SQL file path + */ public void setSqlFilePath(String sqlFilePath) { this.sqlFilePath = sqlFilePath; } + /** + * Adds a parameter to be bound to the SQL. + * + * @param name the parameter name + * @param type the parameter type + * @param value the parameter value + */ public void addParameter(String name, Class type, Object value) { assertNotNull(name, type); parameters.put(name, new Value(type, value)); } + /** Prepares this query for execution. This method must be called before {@link #getSql()}. */ @Override public void prepare() { super.prepare(); @@ -53,6 +74,7 @@ public void prepare() { prepareSql(); } + /** Prepares the SQL statement by loading the SQL file and building the prepared SQL. */ protected void prepareSql() { sqlFile = config.getSqlFileRepository().getSqlFile(method, sqlFilePath, config.getDialect()); ExpressionEvaluator evaluator = @@ -64,11 +86,17 @@ protected void prepareSql() { sql = sqlBuilder.build(sqlFile.getSqlNode(), this::comment); } + /** + * Returns the prepared SQL statement. + * + * @return the prepared SQL statement + */ @Override public PreparedSql getSql() { return sql; } + /** Completes this query. This method is called after the query execution. */ @Override public void complete() {} } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlSelectQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlSelectQuery.java index 21121e953..ea40f371b 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlSelectQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlSelectQuery.java @@ -23,16 +23,35 @@ import org.seasar.doma.jdbc.SqlKind; import org.seasar.doma.jdbc.SqlNode; +/** + * A query that executes a SQL SELECT statement. + * + *

This class extends {@link AbstractSelectQuery} to provide functionality for executing SELECT + * statements. It handles SQL node transformation, expression evaluation, and SQL statement + * preparation. + */ public class SqlSelectQuery extends AbstractSelectQuery { + /** The SQL node representing the query. */ protected SqlNode sqlNode; + /** + * {@inheritDoc} + * + *

This implementation validates that the SQL node is not null. + */ @Override public void prepare() { super.prepare(); assertNotNull(sqlNode); } + /** + * Prepares the SQL statement. + * + *

This method transforms the SQL node using the dialect, evaluates expressions, and builds the + * prepared SQL statement. + */ protected void prepareSql() { SqlNode transformedSqlNode = config.getDialect().transformSelectSqlNode(sqlNode, options); ExpressionEvaluator evaluator = createExpressionEvaluator(); @@ -49,6 +68,11 @@ protected void prepareSql() { sql = sqlBuilder.build(transformedSqlNode, this::comment); } + /** + * {@inheritDoc} + * + *

This implementation executes a count query if the select options indicate a count operation. + */ @Override public void complete() { if (SelectOptionsAccessor.isCount(options)) { @@ -56,6 +80,11 @@ public void complete() { } } + /** + * Sets the SQL node for this query. + * + * @param sqlNode the SQL node + */ public void setSqlNode(SqlNode sqlNode) { this.sqlNode = sqlNode; } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlUpdateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlUpdateQuery.java index 00c4b02f0..cf8cf4000 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlUpdateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/SqlUpdateQuery.java @@ -17,12 +17,30 @@ import org.seasar.doma.jdbc.SqlKind; +/** + * A query that executes a SQL UPDATE statement. + * + *

This class extends {@link SqlModifyQuery} to provide functionality for executing UPDATE + * statements. It sets the SQL kind to {@link SqlKind#UPDATE} to indicate that this query performs + * an UPDATE operation. + */ public class SqlUpdateQuery extends SqlModifyQuery implements UpdateQuery { + /** + * Constructs a new instance. + * + *

This constructor initializes the query with {@link SqlKind#UPDATE} to indicate that it + * performs an UPDATE operation. + */ public SqlUpdateQuery() { super(SqlKind.UPDATE); } + /** + * {@inheritDoc} + * + *

This implementation does nothing because this query does not support version incrementation. + */ @Override public void incrementVersion() {} } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpdateAssembler.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpdateAssembler.java index 1de86527d..ba5dd1668 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpdateAssembler.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpdateAssembler.java @@ -15,6 +15,19 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for assembling UPDATE queries. + * + *

This interface is responsible for generating the SQL for UPDATE operations. Implementations of + * this interface handle the construction of UPDATE statements, including the SET clause, WHERE + * clause, and any other necessary SQL components. + */ public interface UpdateAssembler { + /** + * Assembles the UPDATE query. + * + *

This method generates the SQL for the UPDATE operation, including the table name, SET + * clause, WHERE clause, and any other required SQL components. + */ void assemble(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpdateQuery.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpdateQuery.java index ad73df3ad..700340d0d 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpdateQuery.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpdateQuery.java @@ -15,7 +15,25 @@ */ package org.seasar.doma.jdbc.query; +/** + * An interface for UPDATE queries. + * + *

This interface represents a query that performs UPDATE operations. It extends {@link + * ModifyQuery} to inherit common data modification functionality while specializing for UPDATE + * operations. + * + *

Implementations of this interface handle the execution of UPDATE statements, including the + * construction of the SET clause, WHERE clause, and handling of optimistic concurrency control + * through version numbers. + */ public interface UpdateQuery extends ModifyQuery { + /** + * Increments the version number for the entity being updated. + * + *

This method is called after executing the UPDATE statement to update the version number in + * the entity object, ensuring it matches the value in the database after the update. This is + * important for optimistic concurrency control. + */ void incrementVersion(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssembler.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssembler.java index 5b3b83737..573c23d87 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssembler.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssembler.java @@ -15,7 +15,22 @@ */ package org.seasar.doma.jdbc.query; -/** Assemble the upsert query interface. Implement this interface for each dialect. */ +/** + * An interface for assembling upsert queries. + * + *

Upsert is a database operation that inserts a row if it doesn't exist, or updates it if it + * does. This interface is implemented for each database dialect to handle dialect-specific upsert + * syntax. + * + *

Implementations of this interface are responsible for generating the SQL for upsert + * operations, including handling the specific syntax required by different database systems. + */ public interface UpsertAssembler { + /** + * Assembles the upsert query. + * + *

This method generates the SQL for the upsert operation according to the specific database + * dialect's syntax requirements. + */ void assemble(); } diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssemblerContext.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssemblerContext.java index ad93ef260..f880390c8 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssemblerContext.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssemblerContext.java @@ -71,7 +71,7 @@ public class UpsertAssemblerContext { * @param insertRows the insert rows * @param setValues the set clause property-value pair list(optional).Required in case of * duplicateKeyType.UPDATE - * @param returning whether returning values is required + * @param returning the properties to be returned after update execution */ UpsertAssemblerContext( PreparedSqlBuilder buf, diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssemblerSupport.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssemblerSupport.java index 1cabd3ec7..edc886904 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssemblerSupport.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/UpsertAssemblerSupport.java @@ -24,15 +24,37 @@ import org.seasar.doma.jdbc.entity.EntityPropertyType; import org.seasar.doma.jdbc.entity.EntityType; +/** + * Support class for assembling UPSERT SQL statements. Provides utilities for handling table and + * column names with different formatting options. + */ public class UpsertAssemblerSupport { + /** The naming convention used for converting Java names to database names. */ private final Naming naming; + + /** The dialect that defines database-specific behaviors. */ private final Dialect dialect; + + /** Constants for table aliases used in UPSERT statements. */ private final UpsertAliasConstants aliasConstants; + /** + * Creates a new instance with default alias constants. + * + * @param naming the naming convention + * @param dialect the SQL dialect + */ public UpsertAssemblerSupport(Naming naming, Dialect dialect) { this(naming, dialect, new DefaultUpsertAliasConstants()); } + /** + * Creates a new instance with the specified alias constants. + * + * @param naming the naming convention + * @param dialect the SQL dialect + * @param aliasConstants the constants for table aliases + */ public UpsertAssemblerSupport( Naming naming, Dialect dialect, UpsertAliasConstants aliasConstants) { this.naming = Objects.requireNonNull(naming); @@ -40,37 +62,76 @@ public UpsertAssemblerSupport( this.aliasConstants = Objects.requireNonNull(aliasConstants); } + /** Enum representing different ways to format table names in SQL statements. */ public enum TableNameType { + /** Use only the table name. */ NAME, + /** Use only the alias. */ ALIAS, + /** Use "as alias" format. */ AS_ALIAS, + /** Use "name alias" format. */ NAME_ALIAS, + /** Use "name as alias" format. */ NAME_AS_ALIAS, } + /** Enum representing different ways to format column names in SQL statements. */ public enum ColumnNameType { + /** Use only the column name. */ NAME, + /** Use "alias.name" format. */ NAME_ALIAS, } + /** Default implementation of UpsertAliasConstants that provides standard alias names. */ public static class DefaultUpsertAliasConstants implements UpsertAliasConstants { + /** + * {@inheritDoc} + * + * @return "target" as the default target alias + */ @Override public String getTargetAlias() { return "target"; } + /** + * {@inheritDoc} + * + * @return "excluded" as the default excluded alias + */ @Override public String getExcludedAlias() { return "excluded"; } } + /** Interface defining constants for table aliases used in UPSERT statements. */ public interface UpsertAliasConstants { + /** + * Gets the alias for the target table. + * + * @return the target table alias + */ String getTargetAlias(); + /** + * Gets the alias for the excluded table. + * + * @return the excluded table alias + */ String getExcludedAlias(); } + /** + * Formats a table name based on the specified entity type and table name type. + * + * @param entityType the entity type + * @param tableNameType the table name formatting type + * @return the formatted table name + * @throws IllegalArgumentException if the table name type is unknown + */ public String targetTable(EntityType entityType, TableNameType tableNameType) { switch (tableNameType) { case NAME: @@ -92,6 +153,15 @@ public String targetTable(EntityType entityType, TableNameType tableNameType) } } + /** + * Formats a table name based on the specified entity property types and table name type. + * + * @param entityPropertyTypes the entity property types + * @param tableNameType the table name formatting type + * @return the formatted table name + * @throws UnsupportedOperationException if the table name type is NAME or NAME_ALIAS + * @throws IllegalArgumentException if the table name type is unknown + */ public String targetTable( List> entityPropertyTypes, TableNameType tableNameType) { switch (tableNameType) { @@ -107,6 +177,15 @@ public String targetTable( } } + /** + * Formats a property name for the target table based on the specified property type and column + * name type. + * + * @param propertyType the entity property type + * @param columnNameType the column name formatting type + * @return the formatted property name + * @throws IllegalArgumentException if the column name type is unknown + */ public String targetProp(EntityPropertyType propertyType, ColumnNameType columnNameType) { switch (columnNameType) { case NAME: @@ -120,10 +199,24 @@ public String targetProp(EntityPropertyType propertyType, ColumnNameType c } } + /** + * Gets the alias for the excluded table. + * + * @return the excluded table alias + */ public String excludeAlias() { return aliasConstants.getExcludedAlias(); } + /** + * Formats a property name for the excluded table based on the specified property type and column + * name type. + * + * @param propertyType the entity property type + * @param columnNameType the column name formatting type + * @return the formatted property name + * @throws IllegalArgumentException if the column name type is unknown + */ public String excludeProp(EntityPropertyType propertyType, ColumnNameType columnNameType) { switch (columnNameType) { case NAME: @@ -137,10 +230,23 @@ public String excludeProp(EntityPropertyType propertyType, ColumnNameType } } + /** + * Gets the column name for the specified property type. + * + * @param propertyType the entity property type + * @return the column name + */ public String prop(EntityPropertyType propertyType) { return propertyType.getColumnName(naming::apply, dialect::applyQuote); } + /** + * Gets the input parameter for the specified property type from the values map. + * + * @param propertyType the entity property type + * @param values the map of property types to input parameters + * @return the input parameter for the property type, or null if not found + */ public InParameter param( EntityPropertyType propertyType, Map, InParameter> values) { return values.get(propertyType); diff --git a/doma-core/src/main/java/org/seasar/doma/jdbc/query/package-info.java b/doma-core/src/main/java/org/seasar/doma/jdbc/query/package-info.java index 89d41e7fc..6095f69b7 100644 --- a/doma-core/src/main/java/org/seasar/doma/jdbc/query/package-info.java +++ b/doma-core/src/main/java/org/seasar/doma/jdbc/query/package-info.java @@ -13,5 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** Provides query objects that build SQL statements. */ +/** + * Provides query objects that build and execute SQL statements. + * + *

This package contains interfaces and classes that represent various types of database queries, + * such as SELECT, INSERT, UPDATE, DELETE, batch operations, and stored procedure/function calls. + * These query objects are responsible for building SQL statements, binding parameters, and + * executing the statements against a database. + * + *

The main interfaces in this package include: + * + *

    + *
  • {@link org.seasar.doma.jdbc.query.Query} - The base interface for all query types + *
  • {@link org.seasar.doma.jdbc.query.SelectQuery} - For SELECT operations + *
  • {@link org.seasar.doma.jdbc.query.ModifyQuery} - For data modification operations + *
  • {@link org.seasar.doma.jdbc.query.InsertQuery} - For INSERT operations + *
  • {@link org.seasar.doma.jdbc.query.UpdateQuery} - For UPDATE operations + *
  • {@link org.seasar.doma.jdbc.query.DeleteQuery} - For DELETE operations + *
  • {@link org.seasar.doma.jdbc.query.BatchModifyQuery} - For batch operations + *
  • {@link org.seasar.doma.jdbc.query.CreateQuery} - For creating database resources + *
  • {@link org.seasar.doma.jdbc.query.ModuleQuery} - For calling database modules + *
+ * + *

The implementation classes in this package provide concrete functionality for these + * interfaces, handling SQL generation, parameter binding, and execution according to the specific + * requirements of each query type. + */ package org.seasar.doma.jdbc.query;