FR [ 1981760 ] Improve Query class

This commit is contained in:
teo_sarca 2008-06-02 11:04:14 +00:00
parent 8168ac255b
commit 16e64af5c4
4 changed files with 245 additions and 72 deletions

View File

@ -20,8 +20,6 @@ package org.compiere.model;
import java.util.Iterator;
import java.util.List;
import org.compiere.util.Env;
/**
*
* Iterator implementation to fetch PO one at a time using a prefetch ID list.
@ -89,15 +87,12 @@ public class POIterator<T extends PO> implements Iterator<T> {
public T get(int index) {
if (index <= (idList.size() - 1)) {
Object[] ids = idList.get(index);
if (ids.length == 1 && ids[0] instanceof Integer) {
return (T) table.getPO((Integer)ids[0], trxName);
if (ids.length == 1 && (ids[0] instanceof Number)) {
return (T) table.getPO( ((Number)ids[0]).intValue(), trxName);
} else {
if (keyWhereClause == null) {
String[] keys = table.getKeyColumns();
POInfo info = POInfo.getPOInfo(Env.getCtx(), table.getAD_Table_ID(), trxName);
if (info == null) return null;
StringBuffer sqlBuffer = info.buildSelect();
sqlBuffer.append(" WHERE ");
StringBuffer sqlBuffer = new StringBuffer();
for (int i = 0; i < keys.length; i++) {
if (i > 0)
sqlBuffer.append(" AND ");

View File

@ -22,8 +22,8 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import org.compiere.util.CLogger;
@ -60,6 +60,12 @@ public class Query {
this.trxName = trxName;
}
public Query(String tableName, String whereClause, String trxName) {
this(MTable.get(Env.getCtx(), tableName), whereClause, trxName);
if (this.table == null)
throw new IllegalArgumentException("Table Name Not Found - "+tableName);
}
/**
* Set query parameters
* @param parameters
@ -108,33 +114,14 @@ public class Query {
*/
public <T extends PO> List<T> list() throws DBException {
List<T> list = new ArrayList<T>();
POInfo info = POInfo.getPOInfo(Env.getCtx(), table.getAD_Table_ID(), trxName);
if (info == null) return null;
StringBuffer sqlBuffer = info.buildSelect();
if (whereClause != null && whereClause.trim().length() > 0)
sqlBuffer.append(" WHERE ").append(whereClause);
if (orderBy != null && orderBy.trim().length() > 0)
sqlBuffer.append(" Order By ").append(orderBy);
String sql = sqlBuffer.toString();
if (applyAccessFilter) {
MRole role = MRole.getDefault();
sql = role.addAccessSQL(sql, table.getTableName(), true, false);
}
String sql = buildSQL(null);
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement (sql, trxName);
if (parameters != null && parameters.length > 0)
{
for (int i = 0; i < parameters.length; i++)
{
pstmt.setObject(i+1, parameters[i]);
}
}
rs = pstmt.executeQuery ();
rs = createResultSet(pstmt);
while (rs.next ())
{
T po = (T)table.getPO(rs, trxName);
@ -152,12 +139,69 @@ public class Query {
return list;
}
/**
* Return first PO that match query criteria
* @return PO
* @throws DBException
*/
public <T extends PO> T first() throws DBException {
T po = null;
String sql = buildSQL(null);
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement (sql, trxName);
rs = createResultSet(pstmt);
if (rs.next ())
{
po = (T)table.getPO(rs, trxName);
}
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
throw new DBException(e);
} finally {
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
return po;
}
/**
* Count items that match query criteria
* @return count
* @throws DBException
*/
public int count() throws DBException
{
int count = -1;
String sql = buildSQL(new StringBuffer("SELECT COUNT(*) FROM ").append(table.getTableName()));
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = DB.prepareStatement(sql, this.trxName);
rs = createResultSet(pstmt);
rs.next();
count = rs.getInt(1);
}
catch (SQLException e) {
throw new DBException(e);
}
finally {
DB.close(rs, pstmt);
}
return count;
}
/**
* Return an Iterator implementation to fetch one PO at a time. The implementation first retrieve
* all IDS that match the query criteria and issue sql query to fetch the PO when caller want to
* fetch the next PO. This minimize memory usage but it is slower than the list method.
* @return Iterator
* @throws SQLException
* @throws DBException
*/
public <T extends PO> Iterator<T> iterate() throws DBException {
String[] keys = table.getKeyColumns();
@ -168,29 +212,15 @@ public class Query {
sqlBuffer.append(keys[i]);
}
sqlBuffer.append(" FROM ").append(table.getTableName());
if (whereClause != null && whereClause.trim().length() > 0)
sqlBuffer.append(" WHERE ").append(whereClause);
if (orderBy != null && orderBy.trim().length() > 0)
sqlBuffer.append(" Order By ").append(orderBy);
String sql = sqlBuffer.toString();
if (applyAccessFilter) {
MRole role = MRole.getDefault();
sql = role.addAccessSQL(sql, table.getTableName(), true, false);
}
String sql = buildSQL(sqlBuffer);
PreparedStatement pstmt = null;
ResultSet rs = null;
List<Object[]> idList = new ArrayList<Object[]>();
try
{
pstmt = DB.prepareStatement (sql, trxName);
if (parameters != null && parameters.length > 0)
{
for (int i = 0; i < parameters.length; i++)
{
pstmt.setObject(i+1, parameters[i]);
}
}
rs = pstmt.executeQuery ();
rs = createResultSet(pstmt);
while (rs.next ())
{
Object[] ids = new Object[keys.length];
@ -215,12 +245,37 @@ public class Query {
* Return a simple wrapper over a jdbc resultset. It is the caller responsibility to
* call the close method to release the underlying database resources.
* @return POResultSet
* @throws SQLException
* @throws DBException
*/
public <T extends PO> POResultSet<T> scroll() throws DBException {
POInfo info = POInfo.getPOInfo(Env.getCtx(), table.getAD_Table_ID(), trxName);
if (info == null) return null;
StringBuffer sqlBuffer = info.buildSelect();
String sql = buildSQL(null);
PreparedStatement pstmt = null;
try
{
pstmt = DB.prepareStatement (sql, trxName);
ResultSet rs = createResultSet(pstmt);
return new POResultSet<T>(table, pstmt, rs, trxName);
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
throw new DBException(e);
}
}
/**
* Build SQL Clause
* @param selectClause optional; if null the select clause will be build according to POInfo
* @return final SQL
*/
private final String buildSQL(StringBuffer selectClause) {
if (selectClause == null) {
POInfo info = POInfo.getPOInfo(Env.getCtx(), table.getAD_Table_ID(), trxName);
if (info == null)
throw new IllegalStateException("No POInfo found for AD_Table_ID="+table.getAD_Table_ID());
selectClause = info.buildSelect();
}
StringBuffer sqlBuffer = new StringBuffer(selectClause);
if (whereClause != null && whereClause.trim().length() > 0)
sqlBuffer.append(" WHERE ").append(whereClause);
if (orderBy != null && orderBy.trim().length() > 0)
@ -230,25 +285,19 @@ public class Query {
MRole role = MRole.getDefault();
sql = role.addAccessSQL(sql, table.getTableName(), true, false);
}
PreparedStatement pstmt = null;
try
{
pstmt = DB.prepareStatement (sql, trxName);
if (parameters != null && parameters.length > 0)
{
for (int i = 0; i < parameters.length; i++)
{
pstmt.setObject(i+1, parameters[i]);
}
}
ResultSet rs = pstmt.executeQuery ();
return new POResultSet<T>(table, pstmt, rs, trxName);
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
throw new DBException(e);
}
return sql;
}
private final ResultSet createResultSet (PreparedStatement pstmt) throws SQLException
{
if (parameters != null && parameters.length > 0)
{
for (int i = 0; i < parameters.length; i++)
{
pstmt.setObject(i+1, parameters[i]);
}
}
return pstmt.executeQuery();
}
}

View File

@ -17,6 +17,7 @@ public class FunctionalTestSuite {
suite.addTestSuite(POTest.class);
suite.addTestSuite(MStorageTest.class);
suite.addTestSuite(MSysConfigTest.class);
suite.addTestSuite(QueryTest.class);
//$JUnit-END$
return suite;
}

View File

@ -0,0 +1,128 @@
/**
*
*/
package test.functional;
import java.util.Iterator;
import java.util.List;
import org.compiere.model.MTable;
import org.compiere.model.POResultSet;
import org.compiere.model.Query;
import org.compiere.util.DBException;
import test.AdempiereTestCase;
/**
* Test {@link org.compiere.model.Query} class
* @author Teo Sarca, SC ARHIPAC SERVICE SRL
*/
public class QueryTest extends AdempiereTestCase {
public void testQuery_NoTable() throws Exception {
boolean exThrowed = false;
try {
new Query("NO_TABLE_DEFINED", null, getTrxName());
}
catch (RuntimeException e) {
exThrowed = true;
}
assertTrue("No Error Was Throwed", exThrowed);
}
public void testList() throws Exception {
List<MTable> list = new Query("AD_Table", "TableName IN (?,?)", getTrxName())
.setParameters(new Object[]{"C_Invoice", "M_InOut"})
.setOrderBy("TableName")
.list();
assertEquals("Invalid list size", 2, list.size());
assertEquals("Invalid object 1", list.get(0).getTableName(), "C_Invoice");
assertEquals("Invalid object 2", list.get(1).getTableName(), "M_InOut");
}
public void testScroll() throws Exception {
POResultSet<MTable> rs = null;
try {
rs = new Query("AD_Table", "TableName IN (?,?)", getTrxName())
.setParameters(new Object[]{"C_Invoice", "M_InOut"})
.setOrderBy("TableName")
.scroll();
int i = 0;
for(MTable t = rs.next(); t != null; t = rs.next()) {
if (i == 0) {
assertEquals("Invalid object "+i, "C_Invoice", t.getTableName());
}
else if (i == 1) {
assertEquals("Invalid object "+i, "M_InOut", t.getTableName());
}
else {
assertFalse("More objects retrived than expected", true);
}
i++;
}
}
finally {
if (rs != null)
rs.close();
rs = null;
}
}
public void testIterate() throws Exception {
Iterator<MTable> it = new Query("AD_Table", "TableName IN (?,?)", getTrxName())
.setParameters(new Object[]{"C_Invoice", "M_InOut"})
.setOrderBy("TableName")
.iterate();
int i = 0;
while(it.hasNext()) {
MTable t = it.next();
if (i == 0) {
assertEquals("Invalid object "+i, "C_Invoice", t.getTableName());
}
else if (i == 1) {
assertEquals("Invalid object "+i, "M_InOut", t.getTableName());
}
else {
assertFalse("More objects retrived than expected", true);
}
i++;
}
}
public void testCount() throws Exception {
int count = new Query("AD_Table", "TableName IN (?,?)", getTrxName())
.setParameters(new Object[]{"C_Invoice", "M_InOut"})
.setOrderBy("TableName")
.count();
assertEquals("Invalid count", 2, count);
}
public void testCount_BadSQL() throws Exception {
boolean exThrowed = false;
try {
new Query("AD_Table", "TableName IN (?,?) AND BAD_SQL", getTrxName())
.setParameters(new Object[]{"C_Invoice", "M_InOut"})
.setOrderBy("TableName")
.count();
}
catch (DBException e) {
exThrowed = true;
}
assertTrue("No Error Was Throwed", exThrowed);
}
public void testCount_NoValues() throws Exception {
int count = new Query("AD_Table", "1=2", getTrxName()).count();
assertEquals("Counter should be ZERO", 0, count);
}
public void testFirst() throws Exception {
MTable t = new Query("AD_Table", "TableName IN (?,?)", getTrxName())
.setParameters(new Object[]{"C_Invoice", "M_InOut"})
.setOrderBy("TableName")
.first();
assertEquals("Invalid object", "C_Invoice", t.getTableName());
}
}