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

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit bfd1a0b50cc407c5bf5d5cb6d84d900c453daafa
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sun Jul 26 17:58:06 2026 +0300

    CAY-2985 DataDomain init and structure cleanup
---
 .../java/org/apache/cayenne/access/DataDomain.java |  21 +-
 .../configuration/runtime/CoreModuleExtender.java  |  13 ++
 .../configuration/runtime/DataDomainProvider.java  |  45 ++--
 .../cayenne/DataContextMaxIdQualifierIT.java       | 244 ++++++++++++---------
 4 files changed, 181 insertions(+), 142 deletions(-)

diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java 
b/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
index 0ff8754d5..3ced1dab4 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
@@ -71,8 +71,8 @@ public class DataDomain implements DataChannel {
     protected final QueryCache queryCache;
 
     protected final EntityResolver entityResolver;
+    protected final int maxIdQualifierSize;
 
-    protected int maxIdQualifierSize;
     protected List<DataChannelQueryFilter> queryFilters;
     protected List<DataChannelSyncFilter> syncFilters;
     protected Map<String, DataNode> nodes;
@@ -85,14 +85,17 @@ public class DataDomain implements DataChannel {
 
     public DataDomain(
             String name,
+
             TransactionManager transactionManager,
             TransactionFactory transactionFactory,
             DataDomainFlushActionFactory flushActionFactory,
             AdhocObjectFactory objectFactory,
             EventManager eventManager,
-            EntitySorter entitySorter,
             QueryCache queryCache,
-            EntityResolver entityResolver
+            int maxIdQualifierSize,
+
+            EntityResolver entityResolver,
+            EntitySorter entitySorter
     ) {
 
         this.name = name;
@@ -104,6 +107,7 @@ public class DataDomain implements DataChannel {
         this.entitySorter = entitySorter;
         this.queryCache = queryCache;
         this.entityResolver = entityResolver;
+        this.maxIdQualifierSize = maxIdQualifierSize;
 
         this.queryFilters = new CopyOnWriteArrayList<>();
         this.syncFilters = new CopyOnWriteArrayList<>();
@@ -588,9 +592,7 @@ public class DataDomain implements DataChannel {
      * and DISJOINT_BY_ID prefetches and is intended to address database
      * limitations on the size of SQL statements as well as to cap memory use 
in
      * Cayenne when generating such queries. The default is 10000. It can be
-     * changed either by calling {@link #setMaxIdQualifierSize(int)} or 
changing
-     * the value for property
-     * {@link Constants#MAX_ID_QUALIFIER_SIZE_PROPERTY}.
+     * changed by setting the {@link Constants#MAX_ID_QUALIFIER_SIZE_PROPERTY} 
property.
      *
      * @since 3.1
      */
@@ -598,13 +600,6 @@ public class DataDomain implements DataChannel {
         return maxIdQualifierSize;
     }
 
-    /**
-     * @since 3.1
-     */
-    public void setMaxIdQualifierSize(int maxIdQualifierSize) {
-        this.maxIdQualifierSize = maxIdQualifierSize;
-    }
-
     TransactionManager getTransactionManager() {
         return transactionManager;
     }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/CoreModuleExtender.java
 
b/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/CoreModuleExtender.java
index 811f0876e..20d9bc9ef 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/CoreModuleExtender.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/CoreModuleExtender.java
@@ -134,6 +134,19 @@ public class CoreModuleExtender {
         return this;
     }
 
+    /**
+     * Sets the maximum number of object IDs to match in a single query for 
queries that select objects based on a
+     * collection of ObjectIds, such as paginated queries and DISJOINT_BY_ID 
prefetches. Zero or negative value means
+     * no limit.
+     *
+     * @param size max number of IDs per generated query
+     * @since 5.0
+     */
+    public CoreModuleExtender maxIdQualifierSize(int size) {
+        contributeProperties().put(Constants.MAX_ID_QUALIFIER_SIZE_PROPERTY, 
Integer.toString(size));
+        return this;
+    }
+
     /**
      * Adds a custom project location.
      */
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/DataDomainProvider.java
 
b/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/DataDomainProvider.java
index 31f4b4d0f..8ce33a81c 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/DataDomainProvider.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/DataDomainProvider.java
@@ -158,18 +158,18 @@ public class DataDomainProvider implements 
Provider<DataDomain> {
                 flushActionFactory,
                 objectFactory,
                 eventManager,
-                entitySorter,
                 new NestedQueryCache(queryCache),
-                entityResolver);
-
-        
domain.setMaxIdQualifierSize(runtimeProperties.getInt(Constants.MAX_ID_QUALIFIER_SIZE_PROPERTY,
 -1));
+                
runtimeProperties.getInt(Constants.MAX_ID_QUALIFIER_SIZE_PROPERTY, -1),
+                entityResolver,
+                entitySorter
+        );
 
         Map<String, String> properties = descriptor.getProperties();
 
         boolean sharedCache = 
"true".equals(properties.getOrDefault(SHARED_CACHE_ENABLED_PROPERTY, 
SHARED_CACHE_ENABLED_DEFAULT));
         if (sharedCache) {
             DataRowStore cache = 
injector.getInstance(DataRowStoreFactory.class).createDataRowStore(descriptor.getName());
-            // TODO: setSharedSnapshotCache mutates cache internally; also 
DataDomain.setName() does
+            // TODO: setSharedSnapshotCache mutates cache internally
             domain.setSharedSnapshotCache(cache);
         }
 
@@ -180,23 +180,9 @@ public class DataDomainProvider implements 
Provider<DataDomain> {
             addDataNode(domain, nodeDescriptor);
         }
 
-        // init default node
-        DataNode defaultNode = null;
-
-        if (descriptor.getDefaultNodeName() != null) {
-            defaultNode = domain.getDataNode(descriptor.getDefaultNodeName());
-        }
-
-        if (defaultNode == null) {
-            Collection<DataNode> allNodes = domain.getDataNodes();
-            if (allNodes.size() == 1) {
-                defaultNode = allNodes.iterator().next();
-            }
-        }
-
+        DataNode defaultNode = resolveDefaultNode(domain, descriptor);
         if (defaultNode != null) {
             LOGGER.info("setting DataNode '{}' as default, used by all 
unlinked DataMaps", defaultNode.getName());
-
             domain.setDefaultNode(defaultNode);
         }
 
@@ -215,6 +201,25 @@ public class DataDomainProvider implements 
Provider<DataDomain> {
         return domain;
     }
 
+    /**
+     * Returns a DataNode to use for DataMaps not linked to any node, either 
the one named in the descriptor, or the
+     * only node of the domain. Returns null if neither applies.
+     *
+     * @since 5.0
+     */
+    protected DataNode resolveDefaultNode(DataDomain domain, 
DataChannelDescriptor descriptor) {
+
+        if (descriptor.getDefaultNodeName() != null) {
+            DataNode namedNode = 
domain.getDataNode(descriptor.getDefaultNodeName());
+            if (namedNode != null) {
+                return namedNode;
+            }
+        }
+
+        Collection<DataNode> allNodes = domain.getDataNodes();
+        return allNodes.size() == 1 ? allNodes.iterator().next() : null;
+    }
+
     protected EntityResolver createEntityResolver(DataChannelDescriptor 
descriptor) {
 
         EntityResolver entityResolver = new EntityResolver();
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/DataContextMaxIdQualifierIT.java 
b/cayenne/src/test/java/org/apache/cayenne/DataContextMaxIdQualifierIT.java
index b80eb668f..c8523641b 100644
--- a/cayenne/src/test/java/org/apache/cayenne/DataContextMaxIdQualifierIT.java
+++ b/cayenne/src/test/java/org/apache/cayenne/DataContextMaxIdQualifierIT.java
@@ -18,17 +18,16 @@
  ****************************************************************/
 package org.apache.cayenne;
 
-import org.apache.cayenne.access.DataContext;
+import org.apache.cayenne.configuration.runtime.CoreModule;
 import org.apache.cayenne.query.ObjectSelect;
-import org.apache.cayenne.runtime.CayenneRuntime;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.unit.CayenneProjects;
 import org.apache.cayenne.unit.CayenneTestsEnv;
-import org.junit.jupiter.api.extension.RegisterExtension;
-import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 import java.sql.SQLException;
 import java.sql.Types;
@@ -37,161 +36,188 @@ import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
+/**
+ * "maxIdQualifierSize" is immutable and comes from the runtime properties, so 
each size under test needs its own
+ * stack.
+ */
 public class DataContextMaxIdQualifierIT {
 
-    @RegisterExtension
-    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.TESTMAP_PROJECT);
-
-    protected DataContext context;
-    protected CayenneRuntime runtime;
-    
-    private TableHelper tArtist;
-    private TableHelper tPainting;
-
-    @BeforeEach
-    public void setUp() throws Exception {
-        context = env.context();
-        runtime = env.runtime();
-        tArtist = env.table("ARTIST", "ARTIST_ID", "ARTIST_NAME");
-
-        tPainting = env.table("PAINTING").setColumns("PAINTING_ID", 
"ARTIST_ID", "PAINTING_TITLE").setColumnTypes(Types.INTEGER, Types.BIGINT,
-                Types.VARCHAR);
+    private static CayenneTestsEnv envWithMaxIdQualifierSize(int size) {
+        return CayenneTestsEnv.forProject(CayenneProjects.TESTMAP_PROJECT)
+                .withExtraModules(b -> 
CoreModule.extend(b).maxIdQualifierSize(size));
     }
 
-    private void insertData() throws SQLException {
-        
+    private static void insert100ArtistsWithAPaintingEach(CayenneTestsEnv env) 
throws SQLException {
+        TableHelper tArtist = artistTable(env);
+        TableHelper tPainting = paintingTable(env);
+
         for (int i = 1; i <= 100; i++) {
             tArtist.insert(i, "AA" + i);
             tPainting.insert(i, i, "P" + i);
         }
     }
 
-    private void insertData_OneBag_100Boxes() throws SQLException {
-        tArtist.insert(1, "AA1");
+    private static void insertOneArtistWith100Paintings(CayenneTestsEnv env) 
throws SQLException {
+        artistTable(env).insert(1, "AA1");
 
+        TableHelper tPainting = paintingTable(env);
         for (int i = 1; i <= 100; i++) {
             tPainting.insert(i, 1, "P" + i);
         }
     }
 
-    @Test
-    public void disjointByIdPrefetch() throws Exception {
-        insertData();
-        runtime.getDataDomain().setMaxIdQualifierSize(10);
-
-        int queriesCount = env.runWithQueryCounter(() ->
-                ObjectSelect.query(Artist.class)
-                        .prefetch(Artist.PAINTING_ARRAY.disjointById())
-                        .select(context));
-
-        assertEquals(11, queriesCount);
+    private static TableHelper artistTable(CayenneTestsEnv env) {
+        return env.table("ARTIST", "ARTIST_ID", "ARTIST_NAME");
     }
 
-    @Test
-    public void disjointByIdPrefetch_Zero() throws Exception {
-        insertData();
-        runtime.getDataDomain().setMaxIdQualifierSize(0);
+    private static TableHelper paintingTable(CayenneTestsEnv env) {
+        return env.table("PAINTING")
+                .setColumns("PAINTING_ID", "ARTIST_ID", "PAINTING_TITLE")
+                .setColumnTypes(Types.INTEGER, Types.BIGINT, Types.VARCHAR);
+    }
 
-        int queriesCount = env.runWithQueryCounter(() ->
-                ObjectSelect.query(Artist.class)
-                        .prefetch(Artist.PAINTING_ARRAY.disjointById())
-                        .select(context));
+    @Nested
+    public class Size10 {
 
-        assertEquals(2, queriesCount);
-    }
+        @RegisterExtension
+        final CayenneTestsEnv env = envWithMaxIdQualifierSize(10);
 
-    @Test
-    public void disjointByIdPrefetch_Negative() throws Exception {
-        insertData();
-        runtime.getDataDomain().setMaxIdQualifierSize(-1);
+        @Test
+        public void disjointByIdPrefetch() throws Exception {
+            insert100ArtistsWithAPaintingEach(env);
 
-        int queriesCount = env.runWithQueryCounter(() ->
-                ObjectSelect.query(Artist.class)
-                        .prefetch(Artist.PAINTING_ARRAY.disjointById())
-                        .select(context));
+            int queriesCount = env.runWithQueryCounter(() ->
+                    ObjectSelect.query(Artist.class)
+                            .prefetch(Artist.PAINTING_ARRAY.disjointById())
+                            .select(env.context()));
 
-        assertEquals(2, queriesCount);
+            assertEquals(11, queriesCount);
+        }
     }
 
-    @Test
-    public void incrementalFaultList_Lower() throws Exception {
-        insertData_OneBag_100Boxes();
+    @Nested
+    public class Size5 {
 
-        runtime.getDataDomain().setMaxIdQualifierSize(5);
+        @RegisterExtension
+        final CayenneTestsEnv env = envWithMaxIdQualifierSize(5);
 
-        ObjectSelect<Painting> query = 
ObjectSelect.query(Painting.class).pageSize(10);
+        @Test
+        public void incrementalFaultList() throws Exception {
+            insertOneArtistWith100Paintings(env);
 
-        int queriesCount = env.runWithQueryCounter(() -> {
-            List<Painting> boxes = query.select(context);
-            for (Painting box : boxes) {
-                box.getToArtist();
-            }
-        });
+            ObjectSelect<Painting> query = 
ObjectSelect.query(Painting.class).pageSize(10);
 
-        assertEquals(21, queriesCount);
+            int queriesCount = env.runWithQueryCounter(() -> {
+                List<Painting> paintings = query.select(env.context());
+                for (Painting painting : paintings) {
+                    painting.getToArtist();
+                }
+            });
 
-        queriesCount = env.runWithQueryCounter(() -> {
-            List<Painting> boxes = query.select(context);
-            List<Painting> tempList = new ArrayList<>(boxes);
-        });
+            assertEquals(21, queriesCount);
 
-        assertEquals(21, queriesCount);
+            queriesCount = env.runWithQueryCounter(() -> {
+                List<Painting> paintings = query.select(env.context());
+                List<Painting> tempList = new ArrayList<>(paintings);
+            });
+
+            assertEquals(21, queriesCount);
+        }
     }
 
-    @Test
-    public void incrementalFaultList_Higher() throws Exception {
-        insertData_OneBag_100Boxes();
+    @Nested
+    public class Size101 {
+
+        @RegisterExtension
+        final CayenneTestsEnv env = envWithMaxIdQualifierSize(101);
 
-        runtime.getDataDomain().setMaxIdQualifierSize(101);
+        @Test
+        public void incrementalFaultList() throws Exception {
+            insertOneArtistWith100Paintings(env);
 
-        ObjectSelect<Painting> query = 
ObjectSelect.query(Painting.class).pageSize(10);
+            ObjectSelect<Painting> query = 
ObjectSelect.query(Painting.class).pageSize(10);
 
-        int queriesCount = env.runWithQueryCounter(() -> {
-            final List<Painting> boxes = query.select(context);
-            for (Painting box : boxes) {
-                box.getToArtist();
-            }
-        });
+            int queriesCount = env.runWithQueryCounter(() -> {
+                List<Painting> paintings = query.select(env.context());
+                for (Painting painting : paintings) {
+                    painting.getToArtist();
+                }
+            });
 
-        assertEquals(11, queriesCount);
+            assertEquals(11, queriesCount);
 
-        queriesCount = env.runWithQueryCounter(() -> {
-             List<Painting> boxes = query.select(context);
-            List<Painting> tempList = new ArrayList<>(boxes);
-        });
+            queriesCount = env.runWithQueryCounter(() -> {
+                List<Painting> paintings = query.select(env.context());
+                List<Painting> tempList = new ArrayList<>(paintings);
+            });
 
-        assertEquals(2, queriesCount);
+            assertEquals(2, queriesCount);
+        }
     }
 
-    @Test
-    public void incrementalFaultList_Zero() throws Exception {
-        insertData_OneBag_100Boxes();
+    @Nested
+    public class SizeZero {
+
+        @RegisterExtension
+        final CayenneTestsEnv env = envWithMaxIdQualifierSize(0);
 
-        runtime.getDataDomain().setMaxIdQualifierSize(0);
+        @Test
+        public void disjointByIdPrefetch() throws Exception {
+            insert100ArtistsWithAPaintingEach(env);
 
-        ObjectSelect<Painting> query = 
ObjectSelect.query(Painting.class).pageSize(10);
+            int queriesCount = env.runWithQueryCounter(() ->
+                    ObjectSelect.query(Artist.class)
+                            .prefetch(Artist.PAINTING_ARRAY.disjointById())
+                            .select(env.context()));
+
+            assertEquals(2, queriesCount);
+        }
 
-        int queriesCount = env.runWithQueryCounter(() -> {
-            final List<Painting> boxes = query.select(context);
-            List<Painting> tempList = new ArrayList<>(boxes);
-        });
+        @Test
+        public void incrementalFaultList() throws Exception {
+            insertOneArtistWith100Paintings(env);
 
-        assertEquals(2, queriesCount);
+            ObjectSelect<Painting> query = 
ObjectSelect.query(Painting.class).pageSize(10);
+
+            int queriesCount = env.runWithQueryCounter(() -> {
+                List<Painting> paintings = query.select(env.context());
+                List<Painting> tempList = new ArrayList<>(paintings);
+            });
+
+            assertEquals(2, queriesCount);
+        }
     }
 
-    @Test
-    public void incrementalFaultList_Negative() throws Exception {
-        insertData_OneBag_100Boxes();
+    @Nested
+    public class SizeNegative {
 
-        runtime.getDataDomain().setMaxIdQualifierSize(-1);
+        @RegisterExtension
+        final CayenneTestsEnv env = envWithMaxIdQualifierSize(-1);
 
-        ObjectSelect<Painting> query = 
ObjectSelect.query(Painting.class).pageSize(10);
+        @Test
+        public void disjointByIdPrefetch() throws Exception {
+            insert100ArtistsWithAPaintingEach(env);
 
-        int queriesCount = env.runWithQueryCounter(() -> {
-            final List<Painting> boxes = query.select(context);
-            List<Painting> tempList = new ArrayList<>(boxes);
-        });
+            int queriesCount = env.runWithQueryCounter(() ->
+                    ObjectSelect.query(Artist.class)
+                            .prefetch(Artist.PAINTING_ARRAY.disjointById())
+                            .select(env.context()));
 
-        assertEquals(2, queriesCount);
+            assertEquals(2, queriesCount);
+        }
+
+        @Test
+        public void incrementalFaultList() throws Exception {
+            insertOneArtistWith100Paintings(env);
+
+            ObjectSelect<Painting> query = 
ObjectSelect.query(Painting.class).pageSize(10);
+
+            int queriesCount = env.runWithQueryCounter(() -> {
+                List<Painting> paintings = query.select(env.context());
+                List<Painting> tempList = new ArrayList<>(paintings);
+            });
+
+            assertEquals(2, queriesCount);
+        }
     }
 }

Reply via email to