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

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/master by this push:
     new 5c1af5aebe CAUSEWAY-3404: some quality of life improvements for 
DataTable
5c1af5aebe is described below

commit 5c1af5aebe82244c50d4e49048a54dc676f12c56
Author: Andi Huber <[email protected]>
AuthorDate: Thu Feb 1 11:53:54 2024 +0100

    CAUSEWAY-3404: some quality of life improvements for DataTable
---
 .../apache/causeway/commons/collections/Can.java   |   4 +
 .../core/metamodel/tabular/simple/DataTable.java   | 122 +++++++++++++++++++--
 2 files changed, 116 insertions(+), 10 deletions(-)

diff --git 
a/commons/src/main/java/org/apache/causeway/commons/collections/Can.java 
b/commons/src/main/java/org/apache/causeway/commons/collections/Can.java
index 27b7b6adc7..da1080ac9e 100644
--- a/commons/src/main/java/org/apache/causeway/commons/collections/Can.java
+++ b/commons/src/main/java/org/apache/causeway/commons/collections/Can.java
@@ -249,6 +249,10 @@ extends ImmutableCollection<T>, Comparable<Can<T>>, 
Serializable {
         if(iterable==null) {
             return empty();
         }
+        // Can implements Iterable, hence there is a potential shortcut, 
assuming un-modifaiablitity.
+        if(iterable instanceof Can) {
+            return (Can<T>)iterable;
+        }
 
         val nonNullElements = new ArrayList<T>();
         iterable.forEach(element->{
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/simple/DataTable.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/simple/DataTable.java
index 0f657d387e..8cf1dd177d 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/simple/DataTable.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/simple/DataTable.java
@@ -21,15 +21,23 @@ package org.apache.causeway.core.metamodel.tabular.simple;
 import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
+import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 import org.springframework.lang.Nullable;
 
+import org.apache.causeway.applib.query.Query;
 import org.apache.causeway.applib.services.bookmark.Bookmark;
 import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.commons.internal.assertions._Assert;
+import org.apache.causeway.commons.internal.base._NullSafe;
 import org.apache.causeway.commons.internal.base._Strings;
+import org.apache.causeway.commons.internal.functions._Predicates;
+import org.apache.causeway.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
+import org.apache.causeway.core.metamodel.objectmanager.ObjectBulkLoader;
+import org.apache.causeway.core.metamodel.objectmanager.ObjectManager;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.spec.feature.MixedIn;
 import org.apache.causeway.core.metamodel.spec.feature.ObjectAssociation;
@@ -55,7 +63,7 @@ public class DataTable implements Serializable {
 
     /**
      * Returns an empty {@link DataTable} for given domain object type.
-     * It can be populated later on using {@link 
DataTable#setDataElements(Can)}.
+     * It can be populated later on using {@link 
DataTable#setDataElements(Iterable)}.
      */
     public static DataTable forDomainType(final Class<?> domainType) {
         val elementType = 
MetaModelContext.instanceElseFail().specForTypeElseFail(domainType);
@@ -64,7 +72,7 @@ public class DataTable implements Serializable {
 
     /**
      * Returns an empty {@link DataTable} for given domain object type.
-     * It can be populated later on using {@link 
DataTable#setDataElements(Can)}.
+     * It can be populated later on using {@link 
DataTable#setDataElements(Iterable)}.
      */
     public DataTable(
             final @NonNull ObjectSpecification elementType) {
@@ -79,7 +87,7 @@ public class DataTable implements Serializable {
 
     /**
      * Returns an empty {@link DataTable} for given domain object type.
-     * It can be populated later on using {@link 
DataTable#setDataElements(Can)}.
+     * It can be populated later on using {@link 
DataTable#setDataElements(Iterable)}.
      */
     public DataTable(
             final @NonNull ObjectSpecification elementType,
@@ -104,13 +112,6 @@ public class DataTable implements Serializable {
         setDataElements(dataElements);
     }
 
-    // -- POPULATE
-
-    public void setDataElements(final Can<ManagedObject> dataElements) {
-        this.dataRows = dataElements
-                .map(domainObject->new DataRow(this, domainObject));
-    }
-
     /**
      * Unique within application scope, can act as an id.
      */
@@ -130,6 +131,101 @@ public class DataTable implements Serializable {
             .map(DataRow::getRowElement);
     }
 
+    // -- CONCATENATION (ADD ROWS)
+
+    /**
+     * Adds all data-elements from the other table to this table.
+     */
+    public DataTable addDataElementsFrom(final @Nullable DataTable otherTable) 
{
+        if(otherTable==null) return this;
+        { // sanity check
+            val thisType = otherTable.getElementType().getCorrespondingClass();
+            val otherType = this.getElementType().getCorrespondingClass();
+            _Assert.assertEquals(thisType, otherType, ()->
+                    String.format("Other tables's element-type %s must match 
the this table's element-type %s.",
+                            otherType,
+                            thisType));
+        }
+        if(otherTable.dataRows.isNotEmpty()) {
+            this.dataRows = this.dataRows.addAll(otherTable.dataRows);
+        }
+        return this;
+    }
+
+    // -- POPULATE
+
+    /**
+     * Sets the data-elements of this table, which make up the rows of this 
table.
+     */
+    public DataTable setDataElements(final @Nullable Iterable<ManagedObject> 
dataElements) {
+        this.dataRows = Can.ofIterable(dataElements)
+                .map(domainObject->new DataRow(this, domainObject));
+        return this;
+    }
+    /**
+     * Sets the data-elements of this table from given pojos, that are adapted 
to {@link ManagedObject}(s).
+     * @see #setDataElements(Iterable)
+     */
+    public void setDataElementPojos(final @Nullable Iterable<?> 
dataElementPojos) {
+        var dataElements = _NullSafe.stream(dataElementPojos)
+                .map(objectManager()::adapt)
+                .collect(Can.toCan());
+        setDataElements(dataElements);
+    }
+
+    /**
+     * Populates this table from the underlying (default) persistence layer.
+     * @see #setDataElements(Iterable)
+     */
+    public DataTable populateEntities() {
+        val query = Query.allInstances(elementType.getCorrespondingClass());
+        return populateEntities(query);
+    }
+
+    /**
+     * Populates this table from the underlying (default) persistence layer,
+     * using given {@link Query} to refine the result.
+     * @see #setDataElements(Iterable)
+     */
+    public DataTable populateEntities(final Query<?> query) {
+        { // sanity check
+            val requestType = query.getResultType();
+            val resultType = getElementType().getCorrespondingClass();
+            _Assert.assertEquals(requestType, resultType, ()->
+                    String.format("Query's result-type %s must match the 
table's element-type %s.",
+                            requestType,
+                            resultType));
+        }
+        val queryRequest = ObjectBulkLoader.Request.of(getElementType(), 
query);
+        val allMatching = 
getElementType().getObjectManager().queryObjects(queryRequest);
+        return setDataElements(allMatching);
+    }
+
+    // -- TRAVERSAL
+
+    public static interface CellVisitor {
+        default void onRowEnter(final DataRow row) {};
+        default void onRowLeave(final DataRow row) {};
+        void onCell(DataColumn column, Can<ManagedObject> cellValues);
+    }
+
+    public DataTable visit(final CellVisitor visitor) {
+        return visit(visitor, _Predicates.alwaysTrue());
+    }
+    public DataTable visit(final CellVisitor visitor, final 
Predicate<DataColumn> columnFilter) {
+        var columnsOfInterest = getDataColumns().filter(columnFilter);
+        if(columnsOfInterest.isNotEmpty()) {
+            getDataRows().forEach(row->{
+                visitor.onRowEnter(row);
+                columnsOfInterest.forEach(col->{
+                    visitor.onCell(col, row.getCellElements(col, 
InteractionInitiatedBy.PASS_THROUGH));
+                });
+                visitor.onRowLeave(row);
+            });
+        }
+        return this;
+    }
+
     // -- SERIALIZATION PROXY
 
     private Object writeReplace() {
@@ -165,4 +261,10 @@ public class DataTable implements Serializable {
         }
     }
 
+    // -- HELPER
+
+    private ObjectManager objectManager() {
+        return getElementType().getObjectManager();
+    }
+
 }

Reply via email to