This is an automated email from the ASF dual-hosted git repository.

doebele pushed a commit to branch version3
in repository https://gitbox.apache.org/repos/asf/empire-db.git


The following commit(s) were added to refs/heads/version3 by this push:
     new fa3d23e  EMPIREDB-362 queryRecordList initial
fa3d23e is described below

commit fa3d23ebf3b5bce6b132358c30f5705f602c3de3
Author: Rainer Döbele <[email protected]>
AuthorDate: Wed Jan 26 13:51:20 2022 +0100

    EMPIREDB-362 queryRecordList initial
---
 .../org/apache/empire/samples/db/SampleApp.java    |  13 +-
 .../org/apache/empire/data/list/DataListHead.java  |  46 +++----
 .../java/org/apache/empire/db/DBCommandExpr.java   |   2 +-
 .../main/java/org/apache/empire/db/DBQuery.java    |  23 ++++
 .../main/java/org/apache/empire/db/DBReader.java   |   2 +-
 .../main/java/org/apache/empire/db/DBRowSet.java   |  12 +-
 .../main/java/org/apache/empire/db/DBUtils.java    |  97 +++++++++++++++
 .../apache/empire/db/list/DBRecordListFactory.java |  21 ++++
 .../empire/db/list/DBRecordListFactoryImpl.java    | 133 +++++++++++++++++++++
 9 files changed, 322 insertions(+), 27 deletions(-)

diff --git 
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
 
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
index 0cb0f56..6ddf503 100644
--- 
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
+++ 
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
@@ -628,7 +628,7 @@ public class SampleApp
         cmd.orderBy(EMPLOYEE_FULLNAME);
         
         /*
-         * Test data list entry
+         * Test DataList
          * 
         List<DataListEntry> list = context.getUtils().queryDataList(cmd);
         for (DataListEntry dle : list)
@@ -639,6 +639,17 @@ public class SampleApp
             System.out.println(dle.toString());
         }
         */
+        
+        /*
+         * Test RecordList
+         */
+        List<DBRecord> list = context.getUtils().queryRecordList(cmd, new 
DBQuery(cmd, EMP.ID));
+        for (DBRecord record : list)
+        {
+            Object[] key = record.getKey();
+            boolean exists = record.isExists();
+            System.out.println(StringUtils.arrayToString(key, "|"));
+        }
 
         /*
          * Example for limitRows() and skipRows()
diff --git 
a/empire-db/src/main/java/org/apache/empire/data/list/DataListHead.java 
b/empire-db/src/main/java/org/apache/empire/data/list/DataListHead.java
index a8ec76a..3bfefef 100644
--- a/empire-db/src/main/java/org/apache/empire/data/list/DataListHead.java
+++ b/empire-db/src/main/java/org/apache/empire/data/list/DataListHead.java
@@ -72,29 +72,6 @@ public class DataListHead<T extends DataListEntry> 
implements Serializable
         this(findEntryConstructor(listEntryClass, DataListHead.class), 
columns);
     }
     
-    public ColumnExpr[] getColumns()
-    {
-        return columns; 
-    }
-
-    public int getColumnIndex(ColumnExpr column)
-    {
-        for (int i=0; i<columns.length; i++)
-            if (columns[i]==column)
-                return i; 
-        // Not found, try by name
-        return getColumnIndex(column.getName());
-    }
-    
-    public int getColumnIndex(String columnName)
-    {
-        for (int i=0; i<columns.length; i++)
-            if (columnName.equalsIgnoreCase(columns[i].getName()))
-                return i; 
-        // not found
-        return -1;
-    }
-    
     public T newEntry(int rownum, Object[] values)
     {   try
         {   // check
@@ -136,6 +113,29 @@ public class DataListHead<T extends DataListEntry> 
implements Serializable
         return newEntry(rownum, values);
     }
     
+    public ColumnExpr[] getColumns()
+    {
+        return columns; 
+    }
+
+    public int getColumnIndex(ColumnExpr column)
+    {
+        for (int i=0; i<columns.length; i++)
+            if (columns[i]==column)
+                return i; 
+        // Not found, try by name
+        return getColumnIndex(column.getName());
+    }
+    
+    public int getColumnIndex(String columnName)
+    {
+        for (int i=0; i<columns.length; i++)
+            if (columnName.equalsIgnoreCase(columns[i].getName()))
+                return i; 
+        // not found
+        return -1;
+    }
+    
     public String formatValue(int idx, Object value)
     {   // check empty
         if (ObjectUtils.isEmpty(value))
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java 
b/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
index 6665618..9d04599 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
@@ -306,7 +306,7 @@ public abstract class DBCommandExpr extends DBExpr
      * Returns the list of all select expressions as an array
      * Used internally only
      */
-    protected abstract DBColumnExpr[] getSelectExprList();
+    public abstract DBColumnExpr[] getSelectExprList();
     
     /**
      * returns a list of expressions for the SELECT part of the sql statement
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java 
b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
index 5480f39..6a9a6cb 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
@@ -339,6 +339,29 @@ public class DBQuery extends DBRowSet
     }
     
     /**
+     * Add rowset data
+     */
+    @Override
+    protected void initRecord(DBRecord rec, DBRecordData recData, Object 
rowSetData)
+    {
+        if (keyColumns!=null)
+        {   // check
+            if (rowSetData!=null && !(rowSetData instanceof Object[]) && 
((Object[])rowSetData).length!=keyColumns.length)
+                throw new InvalidArgumentException("rowSetData", rowSetData);
+            // create key if not already set
+            if (rowSetData==null)
+            {   // create key
+                Object[] recordKey = new Object[keyColumns.length];
+                for (int i=0; i<recordKey.length; i++)
+                    recordKey[i]=recData.getValue(keyColumns[i]);
+                rowSetData = recordKey;
+            }
+        }
+        // int
+        super.initRecord(rec, recData, rowSetData);
+    }
+    
+    /**
      * Returns an error, because it is not possible to add a record to a query.
      * 
      * @param rec the DBRecord object, contains all fields and the field 
properties
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBReader.java 
b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
index 206151e..aafc759 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBReader.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
@@ -657,7 +657,7 @@ public class DBReader extends DBRecordData implements 
DBContextAware, Closeable
     {
         // init Record
         DBRowSet rowset = rec.getRowSet();
-       rowset.initRecord(rec, this, null);
+       rowset.initRecord(rec, this);
     }
     
     /**
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java 
b/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
index bef4ede..2774ba1 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
@@ -558,7 +558,17 @@ public abstract class DBRowSet extends DBExpr implements 
Entity
      * The record may then be modified and updated.<BR>
      * At least all primary key columns must be supplied.<BR>
      * We strongly recommend to supply the value of the update timestamp 
column in order to detect concurrent changes.<BR>
-     * Fields for which no value is supplied with the recData paramter are set 
to NO_VALUE<BR>
+     */ 
+    public void initRecord(DBRecord rec, DBRecordData recData)
+    {
+        initRecord(rec, recData, null);
+    }
+    
+    /**
+     * Initializes a DBRecord for this rowset using the record data provided 
(i.e. from a DBReader)<BR>
+     * The record may then be modified and updated.<BR>
+     * At least all primary key columns must be supplied.<BR>
+     * We strongly recommend to supply the value of the update timestamp 
column in order to detect concurrent changes.<BR>
      * <P>
      * @param rec the record object
      * @param recData the record data from which to initialized the record
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBUtils.java 
b/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
index d999fbb..76a6fc7 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
@@ -18,6 +18,8 @@ import 
org.apache.empire.db.exceptions.ConstraintViolationException;
 import org.apache.empire.db.exceptions.QueryFailedException;
 import org.apache.empire.db.exceptions.QueryNoResultException;
 import org.apache.empire.db.exceptions.StatementFailedException;
+import org.apache.empire.db.list.DBRecordListFactory;
+import org.apache.empire.db.list.DBRecordListFactoryImpl;
 import org.apache.empire.dbms.DBMSFeature;
 import org.apache.empire.dbms.DBMSHandler;
 import org.apache.empire.exceptions.InternalException;
@@ -33,6 +35,8 @@ public class DBUtils implements DBContextAware
     
     // Threshold for long running queries in milliseconds
     protected static long longRunndingStmtThreshold = 30000;
+    // Default list capacity
+    protected static int  DEFAULT_LIST_CAPACITY  = 10;
     // Max-Rows for list queries
     protected static int  MAX_QUERY_ROWS  = 999;
     
@@ -692,6 +696,8 @@ public class DBUtils implements DBContextAware
             while (r.moveNext() && maxCount != 0)
             {   // Create bean an init
                 T entry = listHead.newEntry(++rownum, r);
+                if (entry==null)
+                    continue;
                 // add entry
                 list.add(entry);
                 // Decrease count
@@ -760,5 +766,96 @@ public class DBUtils implements DBContextAware
     {
         return (T)queryDataEntry(cmd, DataListEntry.class);
     }
+
+    /**
+     * Crates a default DBRecordListFactory for a DBRecord class
+     * The DBRecord class must provide the following constructor
+     *      DBRecord(DBContext context, DBRowSet rowset)
+     * @param recordClass the recordClass for which to create the list head 
+     * @return
+     */
+    protected <T extends DBRecord> DBRecordListFactory<T> 
createDefaultRecordListFactory(DBContext context, DBRowSet rowset, Class<T> 
recordClass) 
+    {
+        return new DBRecordListFactoryImpl<T>(recordClass, context, rowset);
+    }
+    
+    /**
+     * Executes a query and returns a list of DBRecord items
+     * @param sqlCmd the SQL-Command for the query
+     * @param listHead the HeadInfo to be used for each list item
+     * @param first the number of records to skip from the beginning of the 
result
+     * @param pageSize the maximum number of item to return
+     * @return the list 
+     */
+    public <T extends DBRecord> List<T> queryRecordList(DBCommand cmd, 
DBRecordListFactory<T> factory, int first, int pageSize)
+    {
+        List<T> list = null;
+        DBReader r = new DBReader(context);
+        try
+        {   // prepare
+            factory.prepareQuery(cmd);
+            // check pageSize
+            if (pageSize==0)
+            {   log.warn("PageSize must not be 0. Setting to -1 for all 
records!");
+                pageSize = -1;
+            }
+            // set range
+            DBMSHandler dbms = cmd.getDatabase().getDbms();
+            if (pageSize>0 && dbms.isSupported(DBMSFeature.QUERY_LIMIT_ROWS))
+            {   // let the database limit the rows
+                if (first>0 && dbms.isSupported(DBMSFeature.QUERY_SKIP_ROWS))
+                {   // let the database skip the rows
+                    cmd.skipRows(first);
+                    // no need to skip rows ourself
+                    first = 0;
+                }
+                cmd.limitRows(first+pageSize);
+            }
+            // Runquery
+            r.open(cmd);
+            if (first>0) 
+            {   // skip rows
+                r.skipRows(first);
+            }
+            // Create a list of data entries
+            int maxCount = (pageSize>=0) ? pageSize : MAX_QUERY_ROWS;
+            list = factory.newList((pageSize>=0) ? pageSize : 
DEFAULT_LIST_CAPACITY);
+            // add data
+            int rownum = 0;
+            while (r.moveNext() && maxCount != 0)
+            {   // Create bean an init
+                T entry = factory.newRecord(++rownum, r);
+                if (entry==null)
+                    continue;
+                // add entry
+                list.add(entry);
+                // Decrease count
+                if (maxCount > 0)
+                    maxCount--;
+            }
+            // check
+            if (rownum==MAX_QUERY_ROWS)
+            {
+                
log.warn("********************************************************");
+                log.warn("Query Result was limited to {} by MAX_QUERY_ROWS", 
rownum);
+                
log.warn("********************************************************");
+            }
+            return list;
+        }
+        finally
+        {   // close reader
+            r.close();
+            // complete
+            if (list!=null)
+                factory.completeQuery(list);
+        }
+    }
+
+    public final <T extends DBRecord> List<T> queryRecordList(DBCommand cmd, 
DBRowSet rowset)
+    {
+        @SuppressWarnings("unchecked")
+        DBRecordListFactory<T> factory = 
(DBRecordListFactory<T>)createDefaultRecordListFactory(context, rowset, 
DBRecord.class);
+        return queryRecordList(cmd, factory, 0, -1);
+    }
     
 }
diff --git 
a/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactory.java 
b/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactory.java
new file mode 100644
index 0000000..731fa01
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactory.java
@@ -0,0 +1,21 @@
+/*
+ * ESTEAM Software GmbH, 26.01.2022
+ */
+package org.apache.empire.db.list;
+
+import java.util.List;
+
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordData;
+
+public interface DBRecordListFactory<T extends DBRecord>
+{
+    void prepareQuery(DBCommand cmd);
+    
+    List<T> newList(int capacity);
+
+    T newRecord(int rownum, DBRecordData dataRow);
+    
+    void completeQuery(List<T> list);
+}
diff --git 
a/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactoryImpl.java
 
b/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactoryImpl.java
new file mode 100644
index 0000000..b76befd
--- /dev/null
+++ 
b/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactoryImpl.java
@@ -0,0 +1,133 @@
+/*
+ * ESTEAM Software GmbH, 26.01.2022
+ */
+package org.apache.empire.db.list;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBContext;
+import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordData;
+import org.apache.empire.db.DBRowSet;
+import org.apache.empire.exceptions.InternalException;
+import org.apache.empire.exceptions.InvalidArgumentException;
+import org.apache.empire.exceptions.NotSupportedException;
+import org.apache.empire.exceptions.UnsupportedTypeException;
+
+/**
+ * DBRecordListFactory
+ * @author rainer
+ */
+public class DBRecordListFactoryImpl<T extends DBRecord> implements 
DBRecordListFactory<T>
+{
+    /**
+     * findEntryConstructor
+     * @param recordClass
+     * @param listHeadClass
+     * @return the constructor
+     */
+    @SuppressWarnings("unchecked")
+    protected static <T extends DBRecord> Constructor<T> 
findEntryConstructor(Class<?> recordClass, Class<? extends DBContext> 
contextClass, Class<? extends DBRowSet> rowsetClass)
+    {
+        /*
+        Constructor<?> constructor = 
ClassUtils.findMatchingAccessibleConstructor(recordClass, new Class<?>[] { 
listHeadClass, int.class, Object[].class });
+        if (constructor==null)
+            throw new UnsupportedTypeException(recordClass);
+        return constructor;
+        */
+        try
+        {   // Find the constructor
+            return 
(Constructor<T>)recordClass.getDeclaredConstructor(contextClass, rowsetClass);
+        }
+        catch (NoSuchMethodException e)
+        {
+            throw new UnsupportedTypeException(recordClass);
+        }
+        catch (SecurityException e)
+        {
+            throw new UnsupportedTypeException(recordClass);
+        }
+    }
+    
+    protected final Constructor<T> constructor;
+    protected final DBContext context;
+    protected final DBRowSet rowset;
+
+    /**
+     * Constructs a DataListHead based on an DataListEntry constructor
+     * @param constructor the DataListEntry constructor
+     * @param columns the list entry columns
+     */
+    public DBRecordListFactoryImpl(Constructor<T> constructor, DBContext 
context, DBRowSet rowset) 
+    {
+        this.constructor = constructor;
+        this.context = context;
+        this.rowset = rowset;
+    }
+    
+    public DBRecordListFactoryImpl(Class<T> recordClass, DBContext context, 
DBRowSet rowset) 
+    {
+        this(findEntryConstructor(recordClass, DBContext.class, 
DBRowSet.class), context, rowset);
+    }
+    
+    @Override
+    public void prepareQuery(DBCommand cmd)
+    {
+        if (cmd.hasSelectExpr())
+        {   // Already has select expressions. 
+            // Check against Rowset
+            return;
+        }
+        // otherwise select
+        cmd.select(rowset.getColumns());
+    }
+    
+    @Override
+    public List<T> newList(int capacity)
+    {
+        return new ArrayList<T>(capacity);        
+    }
+    
+    @Override
+    public T newRecord(int rownum, DBRecordData dataRow)
+    {   try
+        {   // check
+            if (dataRow==null)
+                throw new InvalidArgumentException("data", dataRow);
+            // must override newEntry if no recordClass is provided
+            if (constructor==null)
+                throw new NotSupportedException(this, "newEntry");
+            // create item
+            T record = constructor.newInstance(context, rowset);
+            rowset.initRecord(record, dataRow);
+            return record;
+        }
+        catch (InstantiationException e)
+        {
+            throw new InternalException(e);
+        }
+        catch (IllegalAccessException e)
+        {
+            throw new InternalException(e);
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new InternalException(e);
+        }
+        catch (InvocationTargetException e)
+        {
+            throw new InternalException(e);
+        }
+    }
+    
+    @Override
+    public void completeQuery(List<T> list)
+    {
+        
+    }
+    
+}

Reply via email to