From af3ffabb414c23e88e1b3bcbd6172684d7b676d7 Mon Sep 17 00:00:00 2001 From: jlf-eviden Date: Tue, 17 Jun 2025 14:46:55 +0200 Subject: [PATCH] LUT-29906 : Optimization of sub-entities ids of an entity retrieval --- pom.xml | 2 +- .../unittree/business/unit/IUnitDAO.java | 12 + .../unittree/business/unit/UnitDAO.java | 35 ++- .../unittree/business/unit/UnitHome.java | 9 +- .../unittree/business/unit/UnitHomeTest.java | 217 ++++++++++++++++++ 5 files changed, 265 insertions(+), 10 deletions(-) create mode 100644 src/test/java/fr/paris/lutece/plugins/unittree/business/unit/UnitHomeTest.java diff --git a/pom.xml b/pom.xml index 2222116..a63e023 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ lutece-global-pom fr.paris.lutece.tools - 7.0.1 + 7.0.2-SNAPSHOT 4.0.0 diff --git a/src/java/fr/paris/lutece/plugins/unittree/business/unit/IUnitDAO.java b/src/java/fr/paris/lutece/plugins/unittree/business/unit/IUnitDAO.java index 6f484d9..41689e0 100644 --- a/src/java/fr/paris/lutece/plugins/unittree/business/unit/IUnitDAO.java +++ b/src/java/fr/paris/lutece/plugins/unittree/business/unit/IUnitDAO.java @@ -36,6 +36,7 @@ import fr.paris.lutece.portal.service.plugin.Plugin; import java.util.List; +import java.util.Set; /** * @@ -158,6 +159,17 @@ public interface IUnitDAO */ List getSubUnits( int nIdUnit, Plugin plugin ); + /** + * Retrieve Set of all children units id + * + * @param nIdUnit + * the id unit + * @param plugin + * the plugin + * @return Set of all children unit id + */ + Set getAllSubUnitsId( int nIdUnit, Plugin plugin ); + /** * Remove a unit * diff --git a/src/java/fr/paris/lutece/plugins/unittree/business/unit/UnitDAO.java b/src/java/fr/paris/lutece/plugins/unittree/business/unit/UnitDAO.java index 4c86c5a..1148e08 100644 --- a/src/java/fr/paris/lutece/plugins/unittree/business/unit/UnitDAO.java +++ b/src/java/fr/paris/lutece/plugins/unittree/business/unit/UnitDAO.java @@ -37,7 +37,9 @@ import fr.paris.lutece.util.sql.DAOUtil; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * @@ -70,7 +72,17 @@ public class UnitDAO implements IUnitDAO + " FROM unittree_unit WHERE id_unit NOT IN(SELECT id_parent FROM unittree_unit) "; private static final String SQL_QUERY_SELECT_DIRECT_CHILDREN = "SELECT id_unit, id_parent, code, label, description " + " FROM unittree_unit WHERE id_parent = ?"; - + private static final String SQL_QUERY_SELECT_ALL_CHILDREN = "WITH RECURSIVE unittree (id_unit) AS (" + + " SELECT id_unit" + + " FROM unittree_unit " + + " WHERE id_unit = ?" + + " UNION ALL " + + " SELECT t.id_unit" + + " FROM unittree_unit t" + + " JOIN unittree" + + " ON t.id_parent = unittree.id_unit" + + " ) SELECT id_unit FROM unittree WHERE id_unit != ?"; + // Table unittree_unit_user private static final String SQL_QUERY_ADD_USER_TO_UNIT = " INSERT INTO unittree_unit_user ( id_unit, id_user ) VALUES ( ?, ? ) "; private static final String SQL_QUERY_SELECT_IDS_USER = " SELECT id_user FROM unittree_unit_user WHERE id_unit = ? "; @@ -241,6 +253,27 @@ public List getSubUnits( int nIdUnit, Plugin plugin ) return listUnits; } + /** + * {@inheritDoc} + */ + public Set getAllSubUnitsId( int nIdUnit, Plugin plugin ) + { + Set idsSet = new HashSet( ); + try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECT_ALL_CHILDREN, plugin ) ) + { + daoUtil.setInt( 1, nIdUnit ); + daoUtil.setInt( 2, nIdUnit ); + daoUtil.executeQuery( ); + + while ( daoUtil.next( ) ) + { + idsSet.add( daoUtil.getInt( 1 ) ); + } + } + + return idsSet; + } + /** * {@inheritDoc} */ diff --git a/src/java/fr/paris/lutece/plugins/unittree/business/unit/UnitHome.java b/src/java/fr/paris/lutece/plugins/unittree/business/unit/UnitHome.java index 07f0495..31ba4e3 100644 --- a/src/java/fr/paris/lutece/plugins/unittree/business/unit/UnitHome.java +++ b/src/java/fr/paris/lutece/plugins/unittree/business/unit/UnitHome.java @@ -196,14 +196,7 @@ public static List getDirectSubUnits( int nIdUnit ) */ public static Set getAllSubUnitsId( int nIdUnit ) { - Set setResult = new HashSet<>( ); - List listUnits = _dao.getSubUnits( nIdUnit, _plugin ); - for ( Unit unit : listUnits ) - { - setResult.add( unit.getIdUnit( ) ); - setResult.addAll( getAllSubUnitsId( unit.getIdUnit( ) ) ); - } - return setResult; + return _dao.getAllSubUnitsId( nIdUnit, _plugin ); } /** diff --git a/src/test/java/fr/paris/lutece/plugins/unittree/business/unit/UnitHomeTest.java b/src/test/java/fr/paris/lutece/plugins/unittree/business/unit/UnitHomeTest.java new file mode 100644 index 0000000..db7fb3f --- /dev/null +++ b/src/test/java/fr/paris/lutece/plugins/unittree/business/unit/UnitHomeTest.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2002-2025, City of Paris + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright notice + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice + * and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * License 1.0 + */ +package fr.paris.lutece.plugins.unittree.business.unit; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import fr.paris.lutece.test.LuteceTestCase; + +public class UnitHomeTest extends LuteceTestCase +{ + @Override + protected void setUp( ) throws Exception + { + super.setUp( ); + createTestUnitTree( ); + } + + @Override + protected void tearDown( ) throws Exception + { + //Removing all units created by the previous test (all units except ROOT unit in fact) + for(Unit unit : UnitHome.findAll( ) ) + { + int idUnit = unit.getIdUnit(); + if( idUnit != 0) + { + UnitHome.remove( idUnit ); + } + } + super.tearDown( ); + } + + /** + * Create the unit tree used in this test class. The structure of the tree is as follows : + * + * ROOT + * __________________|____________________ + * | | | + * 1 2 3 + * _____|_____ _____|_____ ______|______ + * | | | | | | | | + * 4 5 6 7 8 9 10 11 + * | + * 12 + */ + private void createTestUnitTree( ) + { + //Units creation + //Level 0 + //ROOT unit is already created by SQL scripts executed before this test class + + //Level 1 + createUnit( 1, 0, "1", "unit 1", "unit 1" ); + createUnit( 2, 0, "2", "unit 2", "unit 2" ); + createUnit( 3, 0, "3", "unit 3", "unit 3" ); + + //Level 2 + createUnit( 4, 1, "4", "unit 4", "unit 4" ); + createUnit( 5, 1, "5", "unit 5", "unit 5" ); + createUnit( 6, 1, "6", "unit 6", "unit 6" ); + createUnit( 7, 2, "7", "unit 7", "unit 7" ); + createUnit( 8, 2, "8", "unit 8", "unit 8" ); + createUnit( 9, 2, "9", "unit 9", "unit 9" ); + createUnit( 10, 3, "10", "unit 10", "unit 10" ); + createUnit( 11, 3, "11", "unit 11", "unit 11" ); + + //Level 3 + createUnit( 12, 4, "12", "unit 12", "unit 12" ); + } + + /* + * Creates a unit + * + * @param nIdUnit + * the unit id + * @param nIdParent + * the unit pareny + * @param strCode + * the unit code + * @param strDescription + * the unit description + * @param strLabel + * the unit label + */ + private void createUnit( int nIdUnit, int nIdParent, String strCode, String strDescription, String strLabel ) + { + Unit unit = new Unit( ); + unit.setIdUnit( nIdUnit ); + unit.setIdParent( nIdParent ); + unit.setCode( strCode ); + unit.setDescription( strDescription ); + unit.setLabel( strLabel ); + UnitHome.create( unit ); + } + + public void testGetAllSubUnitsIdOfNonExistentUnit( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 9999 ) ); + } + + public void testGetAllSubUnitsIdOfUnitROOT( ) + { + assertEquals( Arrays.asList( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ), getAllSubUnitsId( 0 ) ); + } + + public void testGetAllSubUnitsIdOfUnit1( ) + { + assertEquals( Arrays.asList( 4, 5, 6, 12 ), getAllSubUnitsId( 1 ) ); + } + + public void testGetAllSubUnitsIdOfUnit2( ) + { + assertEquals( Arrays.asList( 7, 8, 9), getAllSubUnitsId( 2 ) ); + } + + public void testGetAllSubUnitsIdOfUnit3( ) + { + assertEquals( Arrays.asList( 10, 11), getAllSubUnitsId( 3 ) ); + } + + public void testGetAllSubUnitsIdOfUnit4( ) + { + assertEquals( Arrays.asList( 12 ), getAllSubUnitsId( 4 ) ); + } + + public void testGetAllSubUnitsIdOfUnit5( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 5 ) ); + } + + public void testGetAllSubUnitsIdOfUnit6( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 6 ) ); + } + + public void testGetAllSubUnitsIdOfUnit7( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 7 ) ); + } + + public void testGetAllSubUnitsIdOfUnit8( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 8 ) ); + } + + public void testGetAllSubUnitsIdOfUnit9( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 9 ) ); + } + + public void testGetAllSubUnitsIdOfUnit10( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 10 ) ); + } + + public void testGetAllSubUnitsIdOfUnit11( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 11 ) ); + } + + public void testGetAllSubUnitsIdOfUnit12( ) + { + assertEquals( Arrays.asList( ), getAllSubUnitsId( 12 ) ); + } + + /** + * returns and sort all sub units of the unit of the unit id passed in parameter + * + * @param idUnit + * the id unit + * @return list of sub units ids + */ + private List getAllSubUnitsId( int idUnit ) + { + List subUnitsIdsList= UnitHome.getAllSubUnitsId( idUnit ) + .stream( ) + .collect( Collectors.toCollection( ArrayList::new ) ); + Collections.sort( subUnitsIdsList, Comparator.comparing( Integer::intValue ) ); + return subUnitsIdsList; + } +} \ No newline at end of file