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

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


The following commit(s) were added to refs/heads/master by this push:
     new b59a97fb99 fix(admin): batch proxy selector discovery lookups (#7234)
b59a97fb99 is described below

commit b59a97fb99d9297aba3c63a46035ad5b0e0ca986
Author: Liming Deng <[email protected]>
AuthorDate: Thu Oct 1 11:59:16 2026 +0800

    fix(admin): batch proxy selector discovery lookups (#7234)
---
 .../admin/mapper/DiscoveryHandlerMapper.java       |   8 ++
 .../shenyu/admin/mapper/DiscoveryMapper.java       |   8 ++
 .../shenyu/admin/mapper/DiscoveryRelMapper.java    |   8 ++
 .../admin/mapper/DiscoveryUpstreamMapper.java      |   8 ++
 .../service/impl/ProxySelectorServiceImpl.java     |  35 ++++++-
 .../resources/mappers/discovery-handler-sqlmap.xml |  14 +++
 .../resources/mappers/discovery-rel-sqlmap.xml     |  14 +++
 .../main/resources/mappers/discovery-sqlmap.xml    |  14 +++
 .../mappers/discovery-upstream-sqlmap.xml          |  14 +++
 .../admin/mapper/DiscoveryHandlerMapperTest.java   |   9 ++
 .../shenyu/admin/mapper/DiscoveryMapperTest.java   |  14 +++
 .../admin/mapper/DiscoveryUpstreamMapperTest.java  |   7 ++
 .../admin/service/ProxySelectorServiceTest.java    | 115 +++++++++++++++++++++
 13 files changed, 264 insertions(+), 4 deletions(-)

diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryHandlerMapper.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryHandlerMapper.java
index daab3e91e0..fdf5760262 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryHandlerMapper.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryHandlerMapper.java
@@ -104,6 +104,14 @@ public interface DiscoveryHandlerMapper extends 
ExistProvider {
      */
     List<DiscoveryHandlerDO> selectAll();
 
+    /**
+     * Select related rows for one page in a single query.
+     *
+     * @param ids identifiers to match
+     * @return matching rows
+     */
+    List<DiscoveryHandlerDO> selectByIds(@Param("ids") List<String> ids);
+
     /**
      * Select handlers bound to selectors in a namespace.
      *
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryMapper.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryMapper.java
index ced0c8ec95..c76aafc36b 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryMapper.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryMapper.java
@@ -55,6 +55,14 @@ public interface DiscoveryMapper extends ExistProvider {
      */
     List<DiscoveryDO> selectAll();
 
+    /**
+     * Select related rows for one page in a single query.
+     *
+     * @param ids identifiers to match
+     * @return matching rows
+     */
+    List<DiscoveryDO> selectByIds(@Param("ids") List<String> ids);
+
     /**
      * selectAllByNamespaceId.
      *
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryRelMapper.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryRelMapper.java
index 51d8279518..6b764382d2 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryRelMapper.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryRelMapper.java
@@ -44,6 +44,14 @@ public interface DiscoveryRelMapper {
      */
     List<DiscoveryRelDO> selectAll();
 
+    /**
+     * Select related rows for one page in a single query.
+     *
+     * @param ids identifiers to match
+     * @return matching rows
+     */
+    List<DiscoveryRelDO> selectByProxySelectorIds(@Param("ids") List<String> 
ids);
+
     /**
      * select discoveryRel by proxy selector id.
      *
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapper.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapper.java
index ad049bcc79..0498552ed9 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapper.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapper.java
@@ -52,6 +52,14 @@ public interface DiscoveryUpstreamMapper extends 
ExistProvider {
      */
     List<DiscoveryUpstreamDO> selectAll();
 
+    /**
+     * Select related rows for one page in a single query.
+     *
+     * @param ids identifiers to match
+     * @return matching rows
+     */
+    List<DiscoveryUpstreamDO> selectByDiscoveryHandlerIds(@Param("ids") 
List<String> ids);
+
     /**
      * selectByProxySelectorId.
      *
diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
index 3c128165de..eb609f0fd4 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
@@ -63,12 +63,14 @@ import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
 import java.sql.Timestamp;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -79,6 +81,9 @@ public class ProxySelectorServiceImpl implements 
ProxySelectorService {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(ProxySelectorServiceImpl.class);
 
+    // Stay below Oracle's 1000-expression IN limit, including for large 
requested pages.
+    private static final int QUERY_BATCH_SIZE = 500;
+
     private final ProxySelectorMapper proxySelectorMapper;
 
     private final DiscoveryMapper discoveryMapper;
@@ -119,6 +124,20 @@ public class ProxySelectorServiceImpl implements 
ProxySelectorService {
     public CommonPager<ProxySelectorVO> listByPage(final ProxySelectorQuery 
query) {
         List<ProxySelectorVO> result = Lists.newArrayList();
         List<ProxySelectorDO> proxySelectorDOList = 
proxySelectorMapper.selectByQuery(query);
+        if (proxySelectorDOList.isEmpty()) {
+            return PageResultUtils.result(query.getPageParameter(), () -> 
result);
+        }
+        List<String> selectorIds = 
proxySelectorDOList.stream().map(ProxySelectorDO::getId).collect(Collectors.toList());
+        Map<String, DiscoveryRelDO> relations = queryBatches(selectorIds, 
discoveryRelMapper::selectByProxySelectorIds).stream()
+                .collect(Collectors.toMap(DiscoveryRelDO::getProxySelectorId, 
relation -> relation));
+        List<String> handlerIds = 
relations.values().stream().map(DiscoveryRelDO::getDiscoveryHandlerId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        Map<String, DiscoveryHandlerDO> handlers = queryBatches(handlerIds, 
discoveryHandlerMapper::selectByIds).stream()
+                .collect(Collectors.toMap(DiscoveryHandlerDO::getId, handler 
-> handler));
+        List<String> discoveryIds = 
handlers.values().stream().map(DiscoveryHandlerDO::getDiscoveryId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        Map<String, DiscoveryDO> discoveries = queryBatches(discoveryIds, 
discoveryMapper::selectByIds).stream()
+                .collect(Collectors.toMap(DiscoveryDO::getId, discovery -> 
discovery));
+        Map<String, List<DiscoveryUpstreamDO>> upstreams = 
queryBatches(Lists.newArrayList(handlers.keySet()), 
discoveryUpstreamMapper::selectByDiscoveryHandlerIds).stream()
+                
.collect(Collectors.groupingBy(DiscoveryUpstreamDO::getDiscoveryHandlerId));
         proxySelectorDOList.forEach(proxySelectorDO -> {
             ProxySelectorVO vo = new ProxySelectorVO();
             vo.setId(proxySelectorDO.getId());
@@ -129,17 +148,17 @@ public class ProxySelectorServiceImpl implements 
ProxySelectorService {
             vo.setCreateTime(proxySelectorDO.getDateCreated());
             vo.setUpdateTime(proxySelectorDO.getDateUpdated());
             vo.setProps(proxySelectorDO.getProps());
-            DiscoveryRelDO discoveryRelDO = 
discoveryRelMapper.selectByProxySelectorId(proxySelectorDO.getId());
+            DiscoveryRelDO discoveryRelDO = 
relations.get(proxySelectorDO.getId());
             if (Objects.nonNull(discoveryRelDO)) {
-                DiscoveryHandlerDO discoveryHandlerDO = 
discoveryHandlerMapper.selectById(discoveryRelDO.getDiscoveryHandlerId());
+                DiscoveryHandlerDO discoveryHandlerDO = 
handlers.get(discoveryRelDO.getDiscoveryHandlerId());
                 if (Objects.nonNull(discoveryHandlerDO)) {
                     vo.setDiscoveryHandlerId(discoveryHandlerDO.getId());
                     vo.setListenerNode(discoveryHandlerDO.getListenerNode());
                     vo.setHandler(discoveryHandlerDO.getHandler());
-                    DiscoveryDO discoveryDO = 
discoveryMapper.selectById(discoveryHandlerDO.getDiscoveryId());
+                    DiscoveryDO discoveryDO = 
discoveries.get(discoveryHandlerDO.getDiscoveryId());
                     DiscoveryDTO discoveryDTO = 
DiscoveryTransfer.INSTANCE.mapToDTO(discoveryDO);
                     vo.setDiscovery(discoveryDTO);
-                    List<DiscoveryUpstreamDO> discoveryUpstreamDOList = 
discoveryUpstreamMapper.selectByDiscoveryHandlerId(discoveryRelDO.getDiscoveryHandlerId());
+                    List<DiscoveryUpstreamDO> discoveryUpstreamDOList = 
upstreams.getOrDefault(discoveryRelDO.getDiscoveryHandlerId(), 
Collections.emptyList());
                     
Optional.ofNullable(discoveryUpstreamDOList).ifPresent(list -> {
                         List<DiscoveryUpstreamVO> upstreamVOS = 
list.stream().map(DiscoveryTransfer.INSTANCE::mapToVo).collect(Collectors.toList());
                         vo.setDiscoveryUpstreams(upstreamVOS);
@@ -151,6 +170,14 @@ public class ProxySelectorServiceImpl implements 
ProxySelectorService {
         return PageResultUtils.result(query.getPageParameter(), () -> result);
     }
 
+    private <T> List<T> queryBatches(final List<String> ids, final 
Function<List<String>, List<T>> query) {
+        List<T> result = Lists.newArrayList();
+        for (List<String> batch : Lists.partition(ids, QUERY_BATCH_SIZE)) {
+            result.addAll(query.apply(batch));
+        }
+        return result;
+    }
+
     /**
      * createOrUpdate.
      *
diff --git 
a/shenyu-admin/src/main/resources/mappers/discovery-handler-sqlmap.xml 
b/shenyu-admin/src/main/resources/mappers/discovery-handler-sqlmap.xml
index f5c69ad640..4a1c77f18f 100644
--- a/shenyu-admin/src/main/resources/mappers/discovery-handler-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/discovery-handler-sqlmap.xml
@@ -217,4 +217,18 @@
         FROM discovery_handler
         WHERE id = #{id, jdbcType=VARCHAR}
     </delete>
+    <select id="selectByIds" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List"/>
+        FROM discovery_handler
+        WHERE
+        <choose>
+            <when test="ids != null and ids.size() > 0">
+                id IN
+                <foreach collection="ids" item="id" open="(" separator="," 
close=")">
+                    #{id, jdbcType=VARCHAR}
+                </foreach>
+            </when>
+            <otherwise>1 = 0</otherwise>
+        </choose>
+    </select>
 </mapper>
diff --git a/shenyu-admin/src/main/resources/mappers/discovery-rel-sqlmap.xml 
b/shenyu-admin/src/main/resources/mappers/discovery-rel-sqlmap.xml
index e536e8d1cc..34534ec01e 100644
--- a/shenyu-admin/src/main/resources/mappers/discovery-rel-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/discovery-rel-sqlmap.xml
@@ -176,4 +176,18 @@
         FROM discovery_rel
         WHERE  discovery_handler_id = #{discoveryHandlerId, jdbcType=VARCHAR}
     </delete>
+    <select id="selectByProxySelectorIds" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List"/>
+        FROM discovery_rel
+        WHERE
+        <choose>
+            <when test="ids != null and ids.size() > 0">
+                proxy_selector_id IN
+                <foreach collection="ids" item="id" open="(" separator="," 
close=")">
+                    #{id, jdbcType=VARCHAR}
+                </foreach>
+            </when>
+            <otherwise>1 = 0</otherwise>
+        </choose>
+    </select>
 </mapper>
diff --git a/shenyu-admin/src/main/resources/mappers/discovery-sqlmap.xml 
b/shenyu-admin/src/main/resources/mappers/discovery-sqlmap.xml
index 715b5335aa..05a803ca9f 100644
--- a/shenyu-admin/src/main/resources/mappers/discovery-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/discovery-sqlmap.xml
@@ -253,4 +253,18 @@
         FROM discovery
         WHERE id = #{id, jdbcType=VARCHAR} AND namespace_id = #{namespaceId, 
jdbcType=VARCHAR}
     </delete>
+    <select id="selectByIds" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List"/>
+        FROM discovery
+        WHERE
+        <choose>
+            <when test="ids != null and ids.size() > 0">
+                id IN
+                <foreach collection="ids" item="id" open="(" separator="," 
close=")">
+                    #{id, jdbcType=VARCHAR}
+                </foreach>
+            </when>
+            <otherwise>1 = 0</otherwise>
+        </choose>
+    </select>
 </mapper>
diff --git 
a/shenyu-admin/src/main/resources/mappers/discovery-upstream-sqlmap.xml 
b/shenyu-admin/src/main/resources/mappers/discovery-upstream-sqlmap.xml
index 7b17d713fd..b79eb049de 100644
--- a/shenyu-admin/src/main/resources/mappers/discovery-upstream-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/discovery-upstream-sqlmap.xml
@@ -239,4 +239,18 @@
         WHERE discovery_handler_id = #{discoveryHandlerId} and upstream_url = 
#{upstreamUrl}
     </update>
 
+    <select id="selectByDiscoveryHandlerIds" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List"/>
+        FROM discovery_upstream
+        WHERE
+        <choose>
+            <when test="ids != null and ids.size() > 0">
+                discovery_handler_id IN
+                <foreach collection="ids" item="id" open="(" separator="," 
close=")">
+                    #{id, jdbcType=VARCHAR}
+                </foreach>
+            </when>
+            <otherwise>1 = 0</otherwise>
+        </choose>
+    </select>
 </mapper>
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryHandlerMapperTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryHandlerMapperTest.java
index fefbb6c184..d7dc9b0457 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryHandlerMapperTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryHandlerMapperTest.java
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
 
 import jakarta.annotation.Resource;
 import java.sql.Timestamp;
+import java.util.Collections;
 import java.util.List;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -72,6 +73,14 @@ public class DiscoveryHandlerMapperTest extends 
AbstractSpringIntegrationTest {
         return discoveryRelDO;
     }
 
+    @Test
+    public void selectPageRelations() {
+        assertEquals(discoveryHandlerDO.getId(), 
discoveryHandlerMapper.selectByIds(Collections.singletonList(discoveryHandlerDO.getId())).get(0).getId());
+        assertEquals(0, 
discoveryHandlerMapper.selectByIds(Collections.emptyList()).size());
+        assertEquals(discoveryRelDO.getId(), 
discoveryRelMapper.selectByProxySelectorIds(Collections.singletonList(discoveryRelDO.getProxySelectorId())).get(0).getId());
+        assertEquals(0, 
discoveryRelMapper.selectByProxySelectorIds(Collections.emptyList()).size());
+    }
+
     @BeforeEach
     public void before() {
         int count = discoveryHandlerMapper.insert(discoveryHandlerDO);
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryMapperTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryMapperTest.java
index 1501866fa3..a32c9f9282 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryMapperTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryMapperTest.java
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
 
 import jakarta.annotation.Resource;
 import java.sql.Timestamp;
+import java.util.Collections;
 
 import static 
org.apache.shenyu.common.constant.Constants.SYS_DEFAULT_NAMESPACE_ID;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -40,6 +41,19 @@ public class DiscoveryMapperTest extends 
AbstractSpringIntegrationTest {
     @Resource
     private DiscoveryMapper discoveryMapper;
 
+    @Test
+    public void selectPageDiscoveries() {
+        DiscoveryDO discovery = buildDiscoveryDO();
+        discoveryMapper.insert(discovery);
+        try {
+            
assertThat(discoveryMapper.selectByIds(Collections.singletonList(discovery.getId())).get(0).getId(),
 equalTo(discovery.getId()));
+            
assertThat(discoveryMapper.selectByIds(Collections.emptyList()).size(), 
equalTo(0));
+            
assertThat(discoveryMapper.selectByIds(Collections.singletonList("missing")).size(),
 equalTo(0));
+        } finally {
+            discoveryMapper.delete(discovery.getId(), 
discovery.getNamespaceId());
+        }
+    }
+
     @Test
     public void deleteScopedByNamespace() {
         DiscoveryDO discoveryInNamespace = buildDiscoveryDO();
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapperTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapperTest.java
index 78dd58dd12..f72197feab 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapperTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/DiscoveryUpstreamMapperTest.java
@@ -50,6 +50,13 @@ class DiscoveryUpstreamMapperTest extends 
AbstractSpringIntegrationTest {
         
discoveryUpstreamMapper.deleteByIds(Collections.singletonList(discoveryUpstreamDO.getId()));
     }
 
+    @Test
+    void selectPageUpstreams() {
+        assertEquals(discoveryUpstreamDO.getId(), 
discoveryUpstreamMapper.selectByDiscoveryHandlerIds(Collections.singletonList(discoveryUpstreamDO.getDiscoveryHandlerId())).get(0).getId());
+        assertEquals(0, 
discoveryUpstreamMapper.selectByDiscoveryHandlerIds(Collections.emptyList()).size());
+        assertEquals(0, 
discoveryUpstreamMapper.selectByDiscoveryHandlerIds(Collections.singletonList("missing")).size());
+    }
+
     @Test
     void existed() {
 
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
index cdad6d53e3..bf38597066 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
@@ -30,6 +30,7 @@ import org.apache.shenyu.admin.model.dto.ProxySelectorAddDTO;
 import org.apache.shenyu.admin.model.entity.DiscoveryDO;
 import org.apache.shenyu.admin.model.entity.DiscoveryHandlerDO;
 import org.apache.shenyu.admin.model.entity.DiscoveryRelDO;
+import org.apache.shenyu.admin.model.entity.DiscoveryUpstreamDO;
 import org.apache.shenyu.admin.model.entity.ProxySelectorDO;
 import org.apache.shenyu.admin.model.page.PageParameter;
 import org.apache.shenyu.admin.model.query.ProxySelectorQuery;
@@ -51,6 +52,7 @@ import org.mockito.quality.Strictness;
 
 import java.sql.Timestamp;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -65,6 +67,12 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.times;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.mockito.ArgumentCaptor;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 @ExtendWith(MockitoExtension.class)
 @MockitoSettings(strictness = Strictness.LENIENT)
@@ -119,6 +127,113 @@ class ProxySelectorServiceTest {
         
assertEquals(proxySelectorService.listByPage(proxySelectorQuery).getDataList().size(),
 list.size());
     }
 
+    @Test
+    void testListByPageBatchesSharedRelations() {
+        final ProxySelectorQuery query = new ProxySelectorQuery("test", new 
PageParameter(), SYS_DEFAULT_NAMESPACE_ID);
+        ProxySelectorDO first = new ProxySelectorDO();
+        first.setId("first");
+        ProxySelectorDO second = new ProxySelectorDO();
+        second.setId("second");
+        ProxySelectorDO missing = new ProxySelectorDO();
+        missing.setId("missing");
+        
given(proxySelectorMapper.selectByQuery(query)).willReturn(Arrays.asList(first, 
second, missing));
+        DiscoveryRelDO firstRel = new DiscoveryRelDO();
+        firstRel.setProxySelectorId("first");
+        firstRel.setDiscoveryHandlerId("handler");
+        DiscoveryRelDO secondRel = new DiscoveryRelDO();
+        secondRel.setProxySelectorId("second");
+        secondRel.setDiscoveryHandlerId("handler");
+        
given(discoveryRelMapper.selectByProxySelectorIds(Arrays.asList("first", 
"second", "missing"))).willReturn(Arrays.asList(firstRel, secondRel));
+        DiscoveryHandlerDO handler = new DiscoveryHandlerDO();
+        handler.setId("handler");
+        handler.setDiscoveryId("discovery");
+        
given(discoveryHandlerMapper.selectByIds(Collections.singletonList("handler"))).willReturn(Collections.singletonList(handler));
+        DiscoveryDO discovery = new DiscoveryDO();
+        discovery.setId("discovery");
+        
given(discoveryMapper.selectByIds(Collections.singletonList("discovery"))).willReturn(Collections.singletonList(discovery));
+        DiscoveryUpstreamDO upstream = new DiscoveryUpstreamDO();
+        upstream.setId("upstream");
+        upstream.setDateCreated(new Timestamp(0));
+        upstream.setDateUpdated(new Timestamp(0));
+        upstream.setDiscoveryHandlerId("handler");
+        
given(discoveryUpstreamMapper.selectByDiscoveryHandlerIds(Collections.singletonList("handler"))).willReturn(Collections.singletonList(upstream));
+
+        List<ProxySelectorVO> result = 
proxySelectorService.listByPage(query).getDataList();
+
+        assertEquals(3, result.size());
+        for (int index = 0; index < 2; index++) {
+            assertEquals("handler", result.get(index).getDiscoveryHandlerId());
+            assertEquals("discovery", 
result.get(index).getDiscovery().getId());
+            assertEquals("upstream", 
result.get(index).getDiscoveryUpstreams().get(0).getId());
+        }
+        
verify(discoveryRelMapper).selectByProxySelectorIds(Arrays.asList("first", 
"second", "missing"));
+        
verify(discoveryHandlerMapper).selectByIds(Collections.singletonList("handler"));
+        
verify(discoveryMapper).selectByIds(Collections.singletonList("discovery"));
+        
verify(discoveryUpstreamMapper).selectByDiscoveryHandlerIds(Collections.singletonList("handler"));
+        verifyNoMoreInteractions(discoveryRelMapper, discoveryHandlerMapper, 
discoveryMapper, discoveryUpstreamMapper);
+    }
+
+    @Test
+    void testEmptyPageSkipsRelations() {
+        ProxySelectorQuery query = new ProxySelectorQuery("test", new 
PageParameter(), SYS_DEFAULT_NAMESPACE_ID);
+        
given(proxySelectorMapper.selectByQuery(query)).willReturn(Collections.emptyList());
+        assertEquals(0, 
proxySelectorService.listByPage(query).getDataList().size());
+        verifyNoInteractions(discoveryRelMapper, discoveryHandlerMapper, 
discoveryMapper, discoveryUpstreamMapper);
+    }
+
+    @Test
+    void chunksEveryRelationQueryForLargePages() {
+        final ProxySelectorQuery query = new ProxySelectorQuery("test", new 
PageParameter(1, 1201), SYS_DEFAULT_NAMESPACE_ID);
+        List<ProxySelectorDO> selectors = IntStream.range(0, 
1201).mapToObj(index -> {
+            ProxySelectorDO selector = new ProxySelectorDO();
+            selector.setId(String.valueOf(index));
+            return selector;
+        }).collect(Collectors.toList());
+        given(proxySelectorMapper.selectByQuery(query)).willReturn(selectors);
+        
given(discoveryRelMapper.selectByProxySelectorIds(any())).willAnswer(invocation 
-> invocation.<List<String>>getArgument(0).stream().map(id -> {
+            DiscoveryRelDO relation = new DiscoveryRelDO();
+            relation.setProxySelectorId(id);
+            relation.setDiscoveryHandlerId(id);
+            return relation;
+        }).collect(Collectors.toList()));
+        given(discoveryHandlerMapper.selectByIds(any())).willAnswer(invocation 
-> invocation.<List<String>>getArgument(0).stream().map(id -> {
+            DiscoveryHandlerDO handler = new DiscoveryHandlerDO();
+            handler.setId(id);
+            handler.setDiscoveryId(id);
+            return handler;
+        }).collect(Collectors.toList()));
+        given(discoveryMapper.selectByIds(any())).willAnswer(invocation -> 
invocation.<List<String>>getArgument(0).stream().map(id -> {
+            DiscoveryDO discovery = new DiscoveryDO();
+            discovery.setId(id);
+            return discovery;
+        }).collect(Collectors.toList()));
+        
given(discoveryUpstreamMapper.selectByDiscoveryHandlerIds(any())).willAnswer(invocation
 -> invocation.<List<String>>getArgument(0).stream().map(id -> {
+            DiscoveryUpstreamDO upstream = new DiscoveryUpstreamDO();
+            upstream.setId(id);
+            upstream.setDiscoveryHandlerId(id);
+            upstream.setDateCreated(new Timestamp(0));
+            upstream.setDateUpdated(new Timestamp(0));
+            return upstream;
+        }).collect(Collectors.toList()));
+        List<ProxySelectorVO> result = 
proxySelectorService.listByPage(query).getDataList();
+        assertEquals(1201, result.size());
+        for (int index = 0; index < result.size(); index++) {
+            String id = String.valueOf(index);
+            assertEquals(id, result.get(index).getId());
+            assertEquals(id, result.get(index).getDiscoveryHandlerId());
+            assertEquals(id, result.get(index).getDiscovery().getId());
+            assertEquals(id, 
result.get(index).getDiscoveryUpstreams().get(0).getId());
+        }
+        ArgumentCaptor<List<String>> batches = 
ArgumentCaptor.forClass(List.class);
+        verify(discoveryRelMapper, 
times(3)).selectByProxySelectorIds(batches.capture());
+        verify(discoveryHandlerMapper, 
times(3)).selectByIds(batches.capture());
+        verify(discoveryMapper, times(3)).selectByIds(batches.capture());
+        verify(discoveryUpstreamMapper, 
times(3)).selectByDiscoveryHandlerIds(batches.capture());
+        assertTrue(batches.getAllValues().stream().allMatch(batch -> 
!batch.isEmpty() && batch.size() <= 500));
+        assertEquals(4 * 1201, 
batches.getAllValues().stream().mapToInt(List::size).sum());
+        verifyNoMoreInteractions(discoveryRelMapper, discoveryHandlerMapper, 
discoveryMapper, discoveryUpstreamMapper);
+    }
+
     @Test
     void testCreateOrUpdate() {
 

Reply via email to