From 16e64af5c4054acb88b2b04506e92e87ac90d21b Mon Sep 17 00:00:00 2001 From: teo_sarca Date: Mon, 2 Jun 2008 11:04:14 +0000 Subject: [PATCH] FR [ 1981760 ] Improve Query class --- base/src/org/compiere/model/POIterator.java | 11 +- base/src/org/compiere/model/Query.java | 177 +++++++++++------- .../test/functional/FunctionalTestSuite.java | 1 + extend/src/test/functional/QueryTest.java | 128 +++++++++++++ 4 files changed, 245 insertions(+), 72 deletions(-) create mode 100644 extend/src/test/functional/QueryTest.java diff --git a/base/src/org/compiere/model/POIterator.java b/base/src/org/compiere/model/POIterator.java index a117097488..3cfc4eaf92 100644 --- a/base/src/org/compiere/model/POIterator.java +++ b/base/src/org/compiere/model/POIterator.java @@ -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 implements Iterator { 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 "); diff --git a/base/src/org/compiere/model/Query.java b/base/src/org/compiere/model/Query.java index 20c2fa7461..051efac3eb 100644 --- a/base/src/org/compiere/model/Query.java +++ b/base/src/org/compiere/model/Query.java @@ -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 List list() throws DBException { List list = new ArrayList(); - - 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 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 Iterator 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 idList = new ArrayList(); 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 POResultSet 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(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(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(); + } + } diff --git a/extend/src/test/functional/FunctionalTestSuite.java b/extend/src/test/functional/FunctionalTestSuite.java index 8f7c8a7ae3..d077ad5d75 100644 --- a/extend/src/test/functional/FunctionalTestSuite.java +++ b/extend/src/test/functional/FunctionalTestSuite.java @@ -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; } diff --git a/extend/src/test/functional/QueryTest.java b/extend/src/test/functional/QueryTest.java new file mode 100644 index 0000000000..b3b40358b7 --- /dev/null +++ b/extend/src/test/functional/QueryTest.java @@ -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 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 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 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()); + } +}