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

jodd.db.oom.DbOomQuery Maven / Gradle / Ivy

Go to download

Jodd DB is efficient and thin database facade; DbOom is convenient database object mapper.

There is a newer version: 6.0.0
Show newest version
// 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()); } } }