com.j256.ormlite.stmt.StatementBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ormlite-core Show documentation
Show all versions of ormlite-core Show documentation
Lightweight Object Relational Model (ORM) for persisting objects to SQL databases.
package com.j256.ormlite.stmt;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.db.DatabaseType;
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.logger.Logger;
import com.j256.ormlite.logger.LoggerFactory;
import com.j256.ormlite.stmt.mapped.MappedPreparedStmt;
import com.j256.ormlite.table.TableInfo;
/**
* Assists in building of SQL statements for a particular table in a particular database.
*
* @param
* The class that the code will be operating on.
* @param
* The class of the ID column associated with the class. The T class does not require an ID field. The class
* needs an ID parameter however so you can use Void or Object to satisfy the compiler.
* @author graywatson
*/
public abstract class StatementBuilder {
private static Logger logger = LoggerFactory.getLogger(StatementBuilder.class);
protected final TableInfo tableInfo;
protected final String tableName;
protected final DatabaseType databaseType;
protected final Dao dao;
protected StatementType type;
protected boolean addTableName;
protected Where where = null;
// NOTE: anything added here should be added to the clear() method below
public StatementBuilder(DatabaseType databaseType, TableInfo tableInfo, Dao dao, StatementType type) {
this.databaseType = databaseType;
this.tableInfo = tableInfo;
this.tableName = tableInfo.getTableName();
this.dao = dao;
this.type = type;
if (!type.isOkForStatementBuilder()) {
throw new IllegalStateException("Building a statement from a " + type + " statement is not allowed");
}
}
/**
* Creates and returns a new {@link Where} object for this QueryBulder that can be used to add WHERE clauses to the
* SQL statement. Only one {@link Where} object can be associated with a QueryBuilder at a time and calling this
* method again creates a new {@link Where} object and resets the where information for this QueryBuilder.
*/
public Where where() {
where = new Where(tableInfo, this, databaseType);
return where;
}
/**
* Set the {@link Where} object on the query. This allows someone to use the same Where object on multiple queries.
*/
public void setWhere(Where where) {
this.where = where;
}
/**
* Prepare our statement for the subclasses.
*
* @param limit
* Limit for queries. Can be null if none.
*/
protected MappedPreparedStmt prepareStatement(Long limit, boolean cacheStore) throws SQLException {
List argList = new ArrayList();
String statement = buildStatementString(argList);
ArgumentHolder[] selectArgs = argList.toArray(new ArgumentHolder[argList.size()]);
FieldType[] resultFieldTypes = getResultFieldTypes();
FieldType[] argFieldTypes = new FieldType[argList.size()];
for (int selectC = 0; selectC < selectArgs.length; selectC++) {
argFieldTypes[selectC] = selectArgs[selectC].getFieldType();
}
if (!type.isOkForStatementBuilder()) {
throw new IllegalStateException("Building a statement from a " + type + " statement is not allowed");
}
return new MappedPreparedStmt(dao, tableInfo, statement, argFieldTypes, resultFieldTypes, selectArgs,
(databaseType.isLimitSqlSupported() ? null : limit), type, cacheStore);
}
/**
* Build and return a string version of the query. If you change the where or make other calls you will need to
* re-call this method to re-prepare the query for execution.
*/
public String prepareStatementString() throws SQLException {
List argList = new ArrayList();
return buildStatementString(argList);
}
/**
* Build and return all of the information about the prepared statement. See {@link StatementInfo} for more details.
*/
public StatementInfo prepareStatementInfo() throws SQLException {
List argList = new ArrayList();
String statement = buildStatementString(argList);
return new StatementInfo(statement, argList);
}
/**
* Clear out all of the statement settings so we can reuse the builder.
*/
public void reset() {
where = null;
}
protected String buildStatementString(List argList) throws SQLException {
StringBuilder sb = new StringBuilder(128);
appendStatementString(sb, argList);
String statement = sb.toString();
logger.debug("built statement {}", statement);
return statement;
}
/**
* Internal method to build a query while tracking various arguments. Users should use the
* {@link #prepareStatementString()} method instead.
*
*
* This needs to be protected because of (WARNING: DO NOT MAKE A JAVADOC LINK) InternalQueryBuilder (WARNING: DO NOT
* MAKE A JAVADOC LINK).
*
*/
protected void appendStatementString(StringBuilder sb, List argList) throws SQLException {
appendStatementStart(sb, argList);
appendWhereStatement(sb, argList, WhereOperation.FIRST);
appendStatementEnd(sb, argList);
}
/**
* Append the start of our statement string to the StringBuilder.
*/
protected abstract void appendStatementStart(StringBuilder sb, List argList) throws SQLException;
/**
* Append the WHERE part of the statement to the StringBuilder.
*/
protected boolean appendWhereStatement(StringBuilder sb, List argList, WhereOperation operation)
throws SQLException {
if (where == null) {
return operation == WhereOperation.FIRST;
}
operation.appendBefore(sb);
where.appendSql((addTableName ? getTableName() : null), sb, argList);
operation.appendAfter(sb);
return false;
}
/**
* Append the end of our statement string to the StringBuilder.
*/
protected abstract void appendStatementEnd(StringBuilder sb, List argList) throws SQLException;
/**
* Return true if we need to prepend table-name to columns.
*/
protected boolean shouldPrependTableNameToColumns() {
return false;
}
/**
* Get the result array from our statement after the {@link #appendStatementStart(StringBuilder, List)} was called.
* This will be null except for the QueryBuilder.
*/
protected FieldType[] getResultFieldTypes() {
return null;
}
/**
* Verify the columnName is valid and return its FieldType.
*
* @throws IllegalArgumentException
* if the column name is not valid.
*/
protected FieldType verifyColumnName(String columnName) {
return tableInfo.getFieldTypeByColumnName(columnName);
}
protected String getTableName() {
return tableName;
}
/**
* Return the type of the statement.
*/
StatementType getType() {
return type;
}
/**
* Types of statements that we are building.
*/
public static enum StatementType {
/** SQL statement in the form of SELECT ... */
SELECT(true, true, false, false),
/** SQL statement in the form of SELECT COUNT(*)... or something */
SELECT_LONG(true, true, false, false),
/** SQL statement in the form of SELECT... with aggregate functions or something */
SELECT_RAW(true, true, false, false),
/** SQL statement in the form of UPDATE ... */
UPDATE(true, false, true, false),
/** SQL statement in the form of DELETE ... */
DELETE(true, false, true, false),
/**
* SQL statement in the form of CREATE TABLE, ALTER TABLE, or something returning the number of rows affected
*/
EXECUTE(false, false, false, true),
// end
;
private final boolean okForStatementBuilder;
private final boolean okForQuery;
private final boolean okForUpdate;
private final boolean okForExecute;
private StatementType(boolean okForStatementBuilder, boolean okForQuery, boolean okForUpdate,
boolean okForExecute) {
this.okForStatementBuilder = okForStatementBuilder;
this.okForQuery = okForQuery;
this.okForUpdate = okForUpdate;
this.okForExecute = okForExecute;
}
public boolean isOkForStatementBuilder() {
return okForStatementBuilder;
}
public boolean isOkForQuery() {
return okForQuery;
}
public boolean isOkForUpdate() {
return okForUpdate;
}
public boolean isOkForExecute() {
return okForExecute;
}
}
/**
* Class which wraps information about a statement including the arguments and the generated SQL statement string.
*/
public static class StatementInfo {
private final String statement;
private final List argList;
StatementInfo(String statement, List argList) {
this.argList = argList;
this.statement = statement;
}
public String getStatement() {
return statement;
}
public List getArgList() {
return argList;
}
}
/**
* Enum which defines which type of where operation we are appending.
*/
protected enum WhereOperation {
FIRST("WHERE ", null),
AND("AND (", ") "),
OR("OR (", ") "),
// end
;
private final String before;
private final String after;
private WhereOperation(String before, String after) {
this.before = before;
this.after = after;
}
/**
* Append the necessary operators before the where statement.
*/
public void appendBefore(StringBuilder sb) {
if (before != null) {
sb.append(before);
}
}
/**
* Append the necessary operators after the where statement.
*/
public void appendAfter(StringBuilder sb) {
if (after != null) {
sb.append(after);
}
}
}
}