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-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package jodd.db.oom;

import jodd.db.DbQuery;
import jodd.db.DbSession;
import jodd.db.DbUtil;
import jodd.db.oom.mapper.DefaultResultSetMapper;
import jodd.db.oom.mapper.ResultSetMapper;
import jodd.db.oom.sqlgen.ParameterValue;
import jodd.db.type.SqlType;
import jodd.util.StringUtil;
import jodd.log.Logger;
import jodd.log.LoggerFactory;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
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; } if (hints == null) { 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 != SqlType.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 = SqlType.DB_SQLTYPE_NOT_AVAILABLE; if (log.isWarnEnabled()) { log.warn("Column SQL type not available: " + ded.toString() + '.' + dec.getColumnName()); } } } catch (SQLException sex) { dec.dbSqlType = SqlType.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 resolveRowResults(Object[] row) { row = hintResolver.join(row, hints); return row.length == 1 ? row[0] : row; } // ---------------------------------------------------------------- result set protected boolean cacheEntities = dbOomManager.isCacheEntitiesInResultSet(); /** * Defines if entities should be cached in {@link ResultSetMapper}. * Overrides default value in {@link DbOomManager}. */ public DbOomQuery cacheEntities(boolean cacheEntities) { this.cacheEntities = cacheEntities; return this; } /** * Executes the query and returns {@link #createResultSetMapper(java.sql.ResultSet) builded ResultSet mapper}. */ protected ResultSetMapper executeAndBuildResultSetMapper() { ResultSet resultSet = execute(); return createResultSetMapper(resultSet); } /** * Factory for result sets mapper. */ protected ResultSetMapper createResultSetMapper(ResultSet resultSet) { Map columnAliases = sqlgen != null ? sqlgen.getColumnData() : null; return new DefaultResultSetMapper(resultSet, columnAliases, cacheEntities, this); } // ---------------------------------------------------------------- db list protected boolean entityAwareMode = dbOomManager.isEntityAwareMode(); /** * Defines entity-aware mode for entities tracking in result collection. * @see DbOomManager#setEntityAwareMode(boolean) */ public DbOomQuery entityAwareMode(boolean entityAware) { if (entityAware) { this.cacheEntities = true; } this.entityAwareMode = entityAware; return this; } // ---------------------------------------------------------------- iterator public Iterator iterate(Class... types) { return iterate(types, autoClose); } public Iterator iterate() { return iterate(null, autoClose); } protected Iterator iterate(Class[] types, boolean close) { return new DbListIterator<>(this, types, close); } // ---------------------------------------------------------------- list public List list(Class... types) { return list(types, -1, autoClose); } public List list() { return list(null, -1, autoClose); } public List list(int max, Class... types) { return list(types, max, autoClose); } public List list(int max) { return list(null, max, autoClose); } /** * Iterates result set, maps rows to classes and populates resulting array list. * @param types mapping types * @param max max number of rows to collect, -1 for all * @param close true if query is closed at the end, otherwise false. * @return list of mapped entities or array of 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(); } Object previousElement = null; while (rsm.next()) { Object[] objects = rsm.parseObjects(types); Object row = resolveRowResults(objects); int size = result.size(); T newElement = (T) row; if (entityAwareMode && size > 0) { if (previousElement != null && newElement != null) { boolean equals; if (newElement.getClass().isArray()) { equals = Arrays.equals((Object[]) previousElement, (Object[]) newElement); } else { equals = previousElement.equals(newElement); } if (equals) { continue; } } } if (size == max) { break; } result.add(newElement); previousElement = newElement; } close(rsm, close); return result; } // ---------------------------------------------------------------- set public Set listSet(Class... types) { return listSet(types, -1, autoClose); } public Set listSet() { return listSet(null, -1, autoClose); } public Set listSet(int max, Class... types) { return listSet(types, max, autoClose); } public Set listSet(int max) { return listSet(null, max, autoClose); } @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(); } Object previousElement = null; while (rsm.next()) { Object[] objects = rsm.parseObjects(types); Object row = resolveRowResults(objects); int size = result.size(); T newElement = (T) row; if (entityAwareMode && size > 0) { if (previousElement != null && newElement != null) { boolean equals; if (newElement.getClass().isArray()) { equals = Arrays.equals((Object[]) previousElement, (Object[]) newElement); } else { equals = previousElement.equals(newElement); } if (equals) { continue; } } } if (size == max) { break; } result.add(newElement); previousElement = newElement; } close(rsm, close); return result; } // ---------------------------------------------------------------- find public T find(Class... types) { return find(types, autoClose, null); } public T find() { return find(null, autoClose, null); } protected T find(Class[] types, boolean close, ResultSet resultSet) { if (resultSet == null) { resultSet = execute(); } ResultSetMapper rsm = createResultSetMapper(resultSet); Iterator iterator = new DbListIterator<>(this, types, rsm, false); T result = null; if (iterator.hasNext()) { result = iterator.next(); } close(rsm, close); return result; } // ---------------------------------------------------------------- generated columns /** * Finds generated key column of given type. */ public T findGeneratedKey(Class type) { return find(new Class[] {type}, false, getGeneratedColumns()); } /** * Finds generated columns. */ public Object findGeneratedColumns(Class... types) { return find(types, false, getGeneratedColumns()); } // ---------------------------------------------------------------- util /** * {@inheritDoc} */ @Override public DbOomQuery autoClose() { super.autoClose(); return this; } /** * Closes results set or whole query. */ protected void close(ResultSetMapper rsm, boolean closeQuery) { if (closeQuery) { close(); } else { closeResultSet(rsm.getResultSet()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy