FR [ 1981760 ] Improve Query class
This commit is contained in:
parent
8168ac255b
commit
16e64af5c4
|
@ -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 ");
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue