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)
+ {
+
+ }
+
+}