
jodd.db.oom.DbOomQuery Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jodd-db Show documentation
Show all versions of jodd-db Show documentation
Jodd DB is efficient and thin database facade; DbOom is convenient database object mapper.
// Copyright (c) 2003-2012, Jodd Team (jodd.org). All Rights Reserved.
package jodd.db.oom;
import jodd.db.DbQuery;
import jodd.db.DbSession;
import jodd.db.DbUtil;
import jodd.db.oom.mapper.ResultSetMapper;
import jodd.db.oom.sqlgen.ParameterValue;
import jodd.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
import static jodd.db.oom.DbOomUtil.initialCollectionSize;
/**
* A simple ORM extension for {@link DbQuery}.
*
* OOM extension may map results to objects in two ways:
*
* - auto mode - when result set is mapped to provided types, and
* - mapped mode - requires explicit mapping definitions.
*
*/
public class DbOomQuery extends DbQuery {
private static final Logger log = LoggerFactory.getLogger(DbOomQuery.class);
// ---------------------------------------------------------------- default ctors
public DbOomQuery(Connection conn, String sqlString) {
super(conn, sqlString);
}
public static DbOomQuery query(Connection conn, String sqlString) {
return new DbOomQuery(conn, sqlString);
}
public DbOomQuery(DbSession session, String sqlString) {
super(session, sqlString);
}
public static DbOomQuery query(DbSession session, String sqlString) {
return new DbOomQuery(session, sqlString);
}
public DbOomQuery(String sqlString) {
super(sqlString);
}
public static DbOomQuery query(String sqlString) {
return new DbOomQuery(sqlString);
}
// ---------------------------------------------------------------- sqlgen ctors
protected DbSqlGenerator sqlgen;
public DbOomQuery(Connection conn, DbSqlGenerator sqlgen) {
super(conn, sqlgen.generateQuery());
this.sqlgen = sqlgen;
}
public static DbOomQuery query(Connection conn, DbSqlGenerator sqlgen) {
return new DbOomQuery(conn, sqlgen);
}
public DbOomQuery(DbSession session, DbSqlGenerator sqlgen) {
super(session, sqlgen.generateQuery());
this.sqlgen = sqlgen;
}
public static DbOomQuery query(DbSession session, DbSqlGenerator sqlgen) {
return new DbOomQuery(session, sqlgen);
}
public DbOomQuery(DbSqlGenerator sqlgen) {
super(sqlgen.generateQuery());
this.sqlgen = sqlgen;
}
public static DbOomQuery query(DbSqlGenerator sqlgen) {
return new DbOomQuery(sqlgen);
}
// ---------------------------------------------------------------- initialization
protected DbOomManager dbOomManager = DbOomManager.getInstance();
/**
* Returns used ORM manager.
*/
public DbOomManager getManager() {
return dbOomManager;
}
/**
* Prepares the query after initialization. Besides default work, it checks if sql generator
* is used, and if so, generator hints and query parameters will be used for this query.
* Note regarding hints: since hints can be added manually, generators hints will be ignored
* if there exists some manually set hints.
*/
@Override
protected void prepareQuery() {
super.prepareQuery();
if (sqlgen == null) {
return;
}
String[] joinHints = sqlgen.getJoinHints();
if (joinHints != null) {
withHints(joinHints);
}
// insert parameters
Map parameters = sqlgen.getQueryParameters();
if (parameters == null) {
return;
}
for (Map.Entry entry : parameters.entrySet()) {
String paramName = entry.getKey();
ParameterValue param = entry.getValue();
DbEntityColumnDescriptor dec = param.getColumnDescriptor();
if (dec == null) {
setObject(paramName, param.getValue());
} else {
resolveColumnDbSqlType(connection, dec);
setObject(paramName, param.getValue(), dec.getSqlTypeClass(), dec.getDbSqlType());
}
}
}
/**
* Resolves column db sql type and populates it in column descriptor if missing.
*/
protected void resolveColumnDbSqlType(Connection connection, DbEntityColumnDescriptor dec) {
if (dec.dbSqlType != DbEntityColumnDescriptor.DB_SQLTYPE_UNKNOWN) {
return;
}
ResultSet rs = null;
DbEntityDescriptor ded = dec.getDbEntityDescriptor();
try {
DatabaseMetaData dmd = connection.getMetaData();
rs = dmd.getColumns(null, ded.getSchemaName(), ded.getTableName(), dec.getColumnName());
if (rs.next()) {
dec.dbSqlType = rs.getInt("DATA_TYPE");
} else {
dec.dbSqlType = DbEntityColumnDescriptor.DB_SQLTYPE_NOT_AVAILABLE;
if (log.isWarnEnabled()) {
log.warn("Column SQL type not available: " + ded.toString() + '.' + dec.getColumnName());
}
}
} catch (SQLException sex) {
dec.dbSqlType = DbEntityColumnDescriptor.DB_SQLTYPE_NOT_AVAILABLE;
if (log.isWarnEnabled()) {
log.warn("Column SQL type not resolved: " + ded.toString() + '.' + dec.getColumnName(), sex);
}
} finally {
DbUtil.close(rs);
}
}
// ---------------------------------------------------------------- join hints
protected String[] hints;
protected JoinHintResolver hintResolver = dbOomManager.getHintResolver();
/**
* Specifies hints for the query. Provided string is
* split on ',' separator.
*/
public DbOomQuery withHints(String hint) {
this.hints = StringUtil.splitc(hint, ',');
return this;
}
/**
* Specifies multiple hints for the query.
*/
public DbOomQuery withHints(String... hints) {
this.hints = hints;
return this;
}
/**
* Prepares a row (array of rows mapped object) using hints.
* Returns either single object or objects array.
*/
protected Object resolveRowHints(Object[] row) {
row = hintResolver.join(row, hints);
return row.length == 1 ? row[0] : row;
}
// ---------------------------------------------------------------- result set
/**
* Executes the query and returns {@link #createResultSetMapper(java.sql.ResultSet) builded ResultSet mapper}.
*/
protected ResultSetMapper executeAndBuildResultSetMapper() {
return createResultSetMapper(execute());
}
/**
* Factory for result sets mapper.
*/
protected ResultSetMapper createResultSetMapper(ResultSet resultSet) {
return dbOomManager.createResultSetMapper(resultSet, sqlgen != null ? sqlgen.getColumnData() : null);
}
// ---------------------------------------------------------------- iterator
public Iterator iterateOne(Class type) {
return iterateOne(type, false);
}
public Iterator iterateOneAndClose(Class type) {
return iterateOne(type, true);
}
public Iterator iterateOne() {
return iterateOne(null, false);
}
public Iterator iterateOneAndClose() {
return iterateOne(null, true);
}
protected Iterator iterateOne(Class type, boolean close) {
return new DbListOneIterator(this, type, close);
}
public Iterator iterate(Class... types) {
return iterate(types, false);
}
public Iterator iterateAndClose(Class... types) {
return iterate(types, true);
}
public Iterator iterate() {
return iterate(null, false);
}
public Iterator iterateAndClose() {
return iterate(null, true);
}
protected Iterator iterate(Class[] types, boolean close) {
return new DbListIterator(this, types, close);
}
// ---------------------------------------------------------------- list
public List listOne(Class type) {
return listOne(type, 0, false);
}
public List listOneAndClose(Class type) {
return listOne(type, 0, true);
}
public List listOne() {
return listOne(null, 0, false);
}
public List listOneAndClose() {
return listOne(null, 0, true);
}
public List listOne(int max, Class type) {
return listOne(type, max, false);
}
public List listOneAndClose(int max, Class type) {
return listOne(type, max, true);
}
public List listOne(int max) {
return listOne(null, max, false);
}
public List listOneAndClose(int max) {
return listOne(null, max, true);
}
/**
* Iterates results set, maps rows to just one class and populates the array list.
* @param type target type
* @param max max number of rows to collect, 0
for all
* @param close true
if query is closed at the end, otherwise false
* @return list of mapped entities
*/
@SuppressWarnings({"unchecked"})
protected List listOne(Class type, int max, boolean close) {
List result = new ArrayList(initialCollectionSize(max));
ResultSetMapper rsm = executeAndBuildResultSetMapper();
Class[] types = (type == null ? rsm.resolveTables() : new Class[]{type});
while (rsm.next()) {
result.add((T) rsm.parseOneObject(types));
max--;
if (max == 0) {
break;
}
}
close(rsm, close);
return result;
}
public List list(Class... types) {
return list(types, 0, false);
}
public List listAndClose(Class... types) {
return list(types, 0, true);
}
public List list() {
return list(null, 0, false);
}
public List listAndClose() {
return list(null, 0, true);
}
public List list(int max, Class... types) {
return list(types, max, false);
}
public List listAndClose(int max, Class... types) {
return list(types, max, true);
}
public List list(int max) {
return list(null, max, false);
}
public List listAndClose(int max) {
return list(null, max, true);
}
/**
* Iterates result set, maps rows to classes and populates the array list.
* @param types mapping types
* @param max max number of rows to collect, 0
for all
* @param close true
if query is closed at the end, otherwise false
* @return list of mapped entities
*/
@SuppressWarnings({"unchecked"})
protected List list(Class[] types, int max, boolean close) {
List result = new ArrayList(initialCollectionSize(max));
ResultSetMapper rsm = executeAndBuildResultSetMapper();
if (types == null) {
types = rsm.resolveTables();
}
while (rsm.next()) {
Object[] objects = rsm.parseObjects(types);
Object row = resolveRowHints(objects);
result.add((T) row);
max--;
if (max == 0) {
break;
}
}
close(rsm, close);
return result;
}
// ---------------------------------------------------------------- set
public Set listSetOne(Class type) {
return listSetOne(type, 0, false);
}
public Set listSetOneAndClose(Class type) {
return listSetOne(type, 0, true);
}
public Set listSetOne() {
return listSetOne(null, 0, false);
}
public Set listSetOneAndClose() {
return listSetOne(null, 0, true);
}
public Set listSetOne(int max, Class type) {
return listSetOne(type, max, false);
}
public Set listSetOneAndClose(int max, Class type) {
return listSetOne(type, max, true);
}
public Set listSetOne(int max) {
return listSetOne(null, max, false);
}
public Set listSetOneAndClose(int max) {
return listSetOne(null, max, true);
}
@SuppressWarnings({"unchecked"})
protected Set listSetOne(Class type, int max, boolean close) {
Set result = new LinkedHashSet(initialCollectionSize(max));
ResultSetMapper rsm = executeAndBuildResultSetMapper();
Class[] types = (type == null ? rsm.resolveTables() : new Class[]{type});
while (rsm.next()) {
result.add((T) rsm.parseOneObject(types));
max--;
if (max == 0) {
break;
}
}
close(rsm, close);
return result;
}
public Set listSet(Class... types) {
return listSet(types, 0, false);
}
public Set listSetAndClose(Class... types) {
return listSet(types, 0, true);
}
public Set listSet() {
return listSet(null, 0, false);
}
public Set listSetAndClose() {
return listSet(null, 0, true);
}
public Set listSet(int max, Class... types) {
return listSet(types, max, false);
}
public Set listSetAndClose(int max, Class... types) {
return listSet(types, max, true);
}
public Set listSet(int max) {
return listSet(null, max, false);
}
public Set listSetAndClose(int max) {
return listSet(null, max, true);
}
@SuppressWarnings({"unchecked"})
protected Set listSet(Class[] types, int max, boolean close) {
Set result = new LinkedHashSet(initialCollectionSize(max));
ResultSetMapper rsm = executeAndBuildResultSetMapper();
if (types == null) {
types = rsm.resolveTables();
}
while (rsm.next()) {
Object[] objects = rsm.parseObjects(types);
Object row = resolveRowHints(objects);
result.add((T) row);
max--;
if (max == 0) {
break;
}
}
close(rsm, close);
return result;
}
// ---------------------------------------------------------------- find
@SuppressWarnings({"unchecked"})
public T findOne(Class type) {
return findOne(type, false, null);
}
public T findOneAndClose(Class type) {
return findOne(type, true, null);
}
public Object findOne() {
return findOne(null, false, null);
}
public Object findOneAndClose() {
return findOne(null, true, null);
}
@SuppressWarnings({"unchecked"})
protected T findOne(Class type, boolean close, ResultSet resultSet) {
if (resultSet == null) {
resultSet = execute();
}
ResultSetMapper rsm = createResultSetMapper(resultSet);
if (rsm.next() == false) {
return null;
}
Class[] types = (type == null ? rsm.resolveTables() : new Class[]{type});
Object result = rsm.parseOneObject(types);
close(rsm, close);
return (T) result;
}
public Object find(Class... types) {
return find(types, false, null);
}
public Object findAndClose(Class... types) {
return find(types, true, null);
}
public Object find() {
return find(null, false, null);
}
public Object findAndClose() {
return find(null, true, null);
}
protected Object find(Class[] types, boolean close, ResultSet resultSet) {
if (resultSet == null) {
resultSet = execute();
}
ResultSetMapper rsm = createResultSetMapper(resultSet);
if (rsm.next() == false) {
return null;
}
if (types == null) {
types = rsm.resolveTables();
}
Object[] objects = rsm.parseObjects(types);
Object result = resolveRowHints(objects);
close(rsm, close);
return result;
}
// ---------------------------------------------------------------- generated columns
public T findGeneratedKey(Class type) {
return findOne(type, false, getGeneratedColumns());
}
public Object findGeneratedColumns(Class... types) {
return find(types, false, getGeneratedColumns());
}
// ---------------------------------------------------------------- util
/**
* Closes results set or whole query.
*/
protected void close(ResultSetMapper rsm, boolean closeQuery) {
if (closeQuery == true) {
close();
} else {
closeResultSet(rsm.getResultSet());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy