All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.j256.ormlite.stmt.QueryBuilder Maven / Gradle / Ivy

package com.j256.ormlite.stmt;

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.MappedPreparedQuery;
import com.j256.ormlite.stmt.query.OrderBy;
import com.j256.ormlite.table.TableInfo;

/**
 * Assists in building SQL query (select) statements for a particular table in a particular database. Uses the
 * {@link DatabaseType} to get per-database SQL statements. By default the resulting queries will return objects with
 * all columns -- doing the equivalent of 'select * from table'. See {@link #columns(Iterable)} or
 * {@link #columns(String...)} to return partial column lists.
 * 
 * 

* Here is a good tutorial of SQL commands. *

* * @param T * The class that the code will be operating on. * @param ID * 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 class QueryBuilder { private static Logger logger = LoggerFactory.getLogger(QueryBuilder.class); private TableInfo tableInfo; private DatabaseType databaseType; private final FieldType idField; private boolean distinct = false; private boolean selectIdColumn = true; private List columnList = null; private final List orderByList = new ArrayList(); private final List groupByList = new ArrayList(); private Where where = null; private Integer limit = null; /** * Provides statements for various SQL operations. * * @param databaseType * Database type. * @param tableInfo * Information about the table/class that is being handled. */ public QueryBuilder(DatabaseType databaseType, TableInfo tableInfo) { this.databaseType = databaseType; this.tableInfo = tableInfo; this.idField = tableInfo.getIdField(); } /** * Add columns to be returned by the query. If no column...() method called then all columns are returned by * default. */ public QueryBuilder columns(String... columns) { if (columnList == null) { columnList = new ArrayList(); } for (String column : columns) { addColumnToList(column); } return this; } /** * Add columns to be returned by the query. If no column...() method called then all columns are returned by * default. */ public QueryBuilder columns(Iterable columns) { if (columnList == null) { columnList = new ArrayList(); } for (String column : columns) { addColumnToList(column); } return this; } /** * Add "GROUP BY" clauses to the SQL query statement. * * NOTE: Use of this means that the resulting objects may not have a valid ID column value so cannot be deleted or * updated. */ public QueryBuilder groupBy(String columnName) { verifyColumnName(columnName); groupByList.add(columnName); selectIdColumn = false; return this; } /** * Add "ORDER BY" clauses to the SQL query statement. */ public QueryBuilder orderBy(String columnName, boolean ascending) { verifyColumnName(columnName); orderByList.add(new OrderBy(columnName, ascending)); return this; } /** * Add "DISTINCT" clause to the SQL query statement. * * NOTE: Use of this means that the resulting objects may not have a valid ID column value so cannot be deleted or * updated. */ public QueryBuilder distinct() { distinct = true; selectIdColumn = false; return this; } /** * Limit the output to maxRows maximum number of rows. Set to null for no limit (the default). This is implemented * at the database level either through a LIMIT SQL query addition or a JDBC setMaxRows method call. */ public QueryBuilder limit(Integer maxRows) { limit = maxRows; return this; } /** * Returns a {@link Where} object that should be used to add SQL where clauses to the statement. This will also * reset the where object so you can use the same query builder with a different where statement. */ public Where where() { where = new Where(tableInfo); 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; } /** * Build and return a {@link PreparedQuery} object which then can be used by {@link Dao#query(PreparedQuery)} and * {@link Dao#iterator(PreparedQuery)} methods. 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 PreparedQuery prepareQuery() { List argFieldTypeList = new ArrayList(); List resultFieldTypeList = new ArrayList(); List selectArgList = new ArrayList(); String statement = buildSelectString(argFieldTypeList, resultFieldTypeList, selectArgList); return new MappedPreparedQuery(tableInfo, statement, argFieldTypeList, resultFieldTypeList, selectArgList, (databaseType.isLimitSqlSupported() ? null : limit)); } /** * 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. * *

* This is mostly used for debugging or logging cases. The dao classes us the {@link #prepareQuery} method. *

*/ public String prepareQueryString() { List argFieldTypeList = new ArrayList(); List resultFieldTypeList = new ArrayList(); List selectArgList = new ArrayList(); return buildSelectString(argFieldTypeList, resultFieldTypeList, selectArgList); } /** * Internal method to build a query while tracking various arguments. Users should use the {@link #prepareQuery()} * method instead. */ private String buildSelectString(List argFieldTypeList, List resultFieldTypeList, List selectArgList) { StringBuilder sb = new StringBuilder(); sb.append("SELECT "); if (databaseType.isLimitAfterSelect()) { appendLimit(sb); } if (distinct) { sb.append("DISTINCT "); } appendColumns(sb, resultFieldTypeList); sb.append("FROM "); databaseType.appendEscapedEntityName(sb, tableInfo.getTableName()); sb.append(' '); if (where != null) { sb.append("WHERE "); where.appendSql(databaseType, sb, selectArgList); } for (SelectArg selectArg : selectArgList) { FieldType fieldType = tableInfo.nameToFieldType(selectArg.getColumnName()); argFieldTypeList.add(fieldType); } // 'group by' comes before 'order by' appendGroupBys(sb); appendOrderBys(sb); if (!databaseType.isLimitAfterSelect()) { appendLimit(sb); } String statement = sb.toString(); logger.debug("built statement {}", statement); return statement; } private void addColumnToList(String column) { verifyColumnName(column); columnList.add(column); } private void verifyColumnName(String columnName) { if (tableInfo.nameToFieldType(columnName) == null) { throw new IllegalArgumentException("Unknown column-name " + columnName); } } private void appendColumns(StringBuilder sb, List fieldTypeList) { // if no columns were specified then * is the default if (columnList == null) { sb.append("* "); // add all of the field types for (FieldType fieldType : tableInfo.getFieldTypes()) { fieldTypeList.add(fieldType); } return; } boolean first = true; boolean hasId = false; for (String columnName : columnList) { if (first) { first = false; } else { sb.append(','); } FieldType fieldType = tableInfo.nameToFieldType(columnName); appendFieldColumnName(sb, fieldType, fieldTypeList); if (fieldType == idField) { hasId = true; } } // we have to add the idField even if it isn't in the columnNameSet if (!hasId && selectIdColumn) { if (!first) { sb.append(','); } appendFieldColumnName(sb, idField, fieldTypeList); } sb.append(' '); } private void appendFieldColumnName(StringBuilder sb, FieldType fieldType, List fieldTypeList) { databaseType.appendEscapedEntityName(sb, fieldType.getDbColumnName()); if (fieldTypeList != null) { fieldTypeList.add(fieldType); } } private void appendGroupBys(StringBuilder sb) { if (groupByList.size() == 0) { return; } sb.append("GROUP BY "); boolean first = true; for (String columnName : groupByList) { if (first) { first = false; } else { sb.append(','); } databaseType.appendEscapedEntityName(sb, columnName); } sb.append(' '); } private void appendOrderBys(StringBuilder sb) { if (orderByList.size() == 0) { return; } sb.append("ORDER BY "); boolean first = true; for (OrderBy orderBy : orderByList) { if (first) { first = false; } else { sb.append(','); } String columnName = orderBy.getColumnName(); verifyColumnName(columnName); databaseType.appendEscapedEntityName(sb, columnName); if (orderBy.isAscending()) { // sb.append(" ASC"); } else { sb.append(" DESC"); } } sb.append(' '); } private void appendLimit(StringBuilder sb) { if (limit != null && databaseType.isLimitSqlSupported()) { databaseType.appendLimitValue(sb, limit); } } /* * Inner class used to hide from the user the {@link QueryBuilder#buildSelectString} method. The buildQuery method * is needed for mapped mapped statements such as {@link MappedQueryForId} but I didn't want the dao user to access * it directly. * * That I had to do this probably means that I have a bad type hierarchy or package layout but I don't see a better * way to do it right now. */ public static class InternalQueryBuilder extends QueryBuilder { public InternalQueryBuilder(DatabaseType databaseType, TableInfo tableInfo) { super(databaseType, tableInfo); } /** * Internal method to build a query while tracking various arguments. Users should use the * {@link QueryBuilder#prepareQuery()} method instead. */ public String buildSelectString(List argFieldTypeList, List resultFieldTypeList, List selectArgList) { return super.buildSelectString(argFieldTypeList, resultFieldTypeList, selectArgList); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy