1515 */
1616package org .springframework .data .jdbc .core .convert ;
1717
18- import java .util .*;
18+ import java .util .ArrayList ;
19+ import java .util .Collection ;
20+ import java .util .Collections ;
21+ import java .util .Comparator ;
22+ import java .util .HashSet ;
23+ import java .util .LinkedHashSet ;
24+ import java .util .List ;
25+ import java .util .Map ;
26+ import java .util .Set ;
27+ import java .util .TreeSet ;
1928import java .util .function .BiFunction ;
2029import java .util .function .Function ;
2130import java .util .function .Predicate ;
3847import org .springframework .data .relational .core .sql .*;
3948import org .springframework .data .relational .core .sql .render .SqlRenderer ;
4049import org .springframework .data .util .Lazy ;
41- import org .springframework .data .util .Pair ;
4250import org .springframework .data .util .Predicates ;
4351import org .springframework .jdbc .core .namedparam .MapSqlParameterSource ;
4452import org .springframework .lang .Nullable ;
@@ -123,11 +131,11 @@ public class SqlGenerator {
123131 * @param table the table to base the select on
124132 * @param pathFilter a filter for excluding paths from the select. All paths for which the filter returns
125133 * {@literal true} will be skipped when determining columns to select.
126- * @return A select structure suitable for constructing more specialized selects by adding conditions.
134+ * @return a select structure suitable for constructing more specialized selects by adding conditions.
127135 * @since 4.0
128136 */
129137 public SelectBuilder .SelectWhere createSelectBuilder (Table table , Predicate <AggregatePath > pathFilter ) {
130- return createSelectBuilder (table , pathFilter , Collections .emptyList ());
138+ return createSelectBuilder (table , pathFilter , Collections .emptyList (), Query . empty () );
131139 }
132140
133141 /**
@@ -188,13 +196,7 @@ private Condition getSubselectCondition(AggregatePath path,
188196 AggregatePath .TableInfo parentPathTableInfo = parentPath .getTableInfo ();
189197 Table subSelectTable = Table .create (parentPathTableInfo .qualifiedTableName ());
190198
191- Map <AggregatePath , Column > selectFilterColumns = new TreeMap <>();
192-
193- // TODO: cannot we simply pass on the columnInfos?
194- parentPathTableInfo .effectiveIdColumnInfos ().forEach ( //
195- (ap , ci ) -> //
196- selectFilterColumns .put (ap , subSelectTable .column (ci .name ())) //
197- );
199+ Map <AggregatePath , Column > selectFilterColumns = parentPathTableInfo .effectiveIdColumnInfos ().toMap (subSelectTable );
198200
199201 Condition innerCondition ;
200202
@@ -609,29 +611,24 @@ private SelectBuilder.SelectWhere selectBuilder(Collection<SqlIdentifier> keyCol
609611 }
610612
611613 private SelectBuilder .SelectWhere selectBuilder (Collection <SqlIdentifier > keyColumns , Query query ) {
612-
613- return createSelectBuilder (getTable (), ap -> false , keyColumns );
614+ return createSelectBuilder (getTable (), ap -> false , keyColumns , query );
614615 }
615616
616617 private SelectBuilder .SelectWhere createSelectBuilder (Table table , Predicate <AggregatePath > pathFilter ,
617- Collection <SqlIdentifier > keyColumns ) {
618+ Collection <SqlIdentifier > keyColumns , Query query ) {
618619
619620 Projection projection = getProjection (pathFilter , keyColumns , query , table );
620621 SelectBuilder .SelectJoin baseSelect = StatementBuilder .select (projection .columns ()).from (table );
621622
622- return (SelectBuilder .SelectWhere ) addJoins (baseSelect , joinTables );
623+ return (SelectBuilder .SelectWhere ) addJoins (baseSelect , projection . joins () );
623624 }
624625
625- private static SelectBuilder .SelectJoin addJoins (SelectBuilder .SelectJoin baseSelect , List <Join > joinTables ) {
626-
627- for (Join join : projection .joins ()) {
628-
629- baseSelect = baseSelect .leftOuterJoin (join .joinTable ).on (join .condition );
630- }
631- return baseSelect ;
626+ private static SelectBuilder .SelectJoin addJoins (SelectBuilder .SelectJoin baseSelect , Joins joins ) {
627+ return joins .reduce (baseSelect , (join , select ) -> select .leftOuterJoin (join .joinTable ).on (join .condition ));
632628 }
633629
634- private Projection getProjection (Predicate <AggregatePath > pathFilter , Collection <SqlIdentifier > keyColumns , Query query , Table table ) {
630+ private Projection getProjection (Predicate <AggregatePath > pathFilter , Collection <SqlIdentifier > keyColumns ,
631+ Query query , Table table ) {
635632
636633 Set <Expression > columns = new LinkedHashSet <>();
637634 Set <Join > joins = new LinkedHashSet <>();
@@ -642,7 +639,7 @@ private Projection getProjection(Predicate<AggregatePath> pathFilter, Collection
642639 AggregatePath aggregatePath = mappingContext .getAggregatePath (
643640 mappingContext .getPersistentPropertyPath (columnName .getReference (), entity .getTypeInformation ()));
644641
645- includeColumnAndJoin (aggregatePath , joins , columns );
642+ includeColumnAndJoin (aggregatePath , pathFilter , joins , columns );
646643 } catch (InvalidPersistentPropertyPath e ) {
647644 columns .add (Column .create (columnName , table ));
648645 }
@@ -656,22 +653,40 @@ private Projection getProjection(Predicate<AggregatePath> pathFilter, Collection
656653 AggregatePath aggregatePath = mappingContext .getAggregatePath (path );
657654
658655 if (pathFilter .test (aggregatePath )) {
659- continue ;
660- }
656+ continue ;
657+ }
661658
662- includeColumnAndJoin (aggregatePath , joins , columns );
659+ includeColumnAndJoin (aggregatePath , pathFilter , joins , columns );
663660 }
664661 }
665662
666663 for (SqlIdentifier keyColumn : keyColumns ) {
667664 columns .add (table .column (keyColumn ).as (keyColumn ));
668665 }
669666
670- return new Projection (columns , joins );
667+ return new Projection (columns , Joins . of ( joins ) );
671668 }
672669
673- private void includeColumnAndJoin (AggregatePath aggregatePath , Collection <Join > joins ,
674- Collection <Expression > columns ) {
670+ private void includeColumnAndJoin (AggregatePath aggregatePath , Predicate <AggregatePath > pathFilter ,
671+ Collection <Join > joins , Collection <Expression > columns ) {
672+
673+ if (aggregatePath .isEmbedded ()) {
674+
675+ RelationalPersistentEntity <?> entity = aggregatePath .getRequiredLeafEntity ();
676+
677+ for (RelationalPersistentProperty property : entity ) {
678+
679+ AggregatePath nested = aggregatePath .append (property );
680+
681+ if (pathFilter .test (nested )) {
682+ continue ;
683+ }
684+
685+ includeColumnAndJoin (nested , pathFilter , joins , columns );
686+ }
687+
688+ return ;
689+ }
675690
676691 joins .addAll (getJoins (aggregatePath ));
677692
@@ -687,7 +702,24 @@ private void includeColumnAndJoin(AggregatePath aggregatePath, Collection<Join>
687702 * @param columns
688703 * @param joins
689704 */
690- record Projection (Set <Expression > columns , Set <Join > joins ) {
705+ record Projection (Collection <Expression > columns , Joins joins ) {
706+
707+ }
708+
709+ record Joins (Collection <Join > joins ) {
710+
711+ public static Joins of (Collection <Join > joins ) {
712+ return new Joins (joins );
713+ }
714+
715+ public <T > T reduce (T identity , BiFunction <Join , T , T > accumulator ) {
716+
717+ T result = identity ;
718+ for (Join join : joins ) {
719+ result = accumulator .apply (join , result );
720+ }
721+ return result ;
722+ }
691723 }
692724
693725 private SelectBuilder .SelectOrdered selectBuilder (Collection <SqlIdentifier > keyColumns , Sort sort ,
@@ -922,11 +954,8 @@ private String createDeleteByPathAndCriteria(AggregatePath path,
922954 .from (table );
923955 Delete delete ;
924956
925- Map <AggregatePath , Column > columns = new TreeMap <>();
926957 AggregatePath .ColumnInfos columnInfos = path .getTableInfo ().backReferenceColumnInfos ();
927-
928- // TODO: cannot we simply pass on the columnInfos?
929- columnInfos .forEach ((ag , ci ) -> columns .put (ag , table .column (ci .name ())));
958+ Map <AggregatePath , Column > columns = columnInfos .toMap (table );
930959
931960 if (isFirstNonRoot (path )) {
932961
@@ -978,22 +1007,19 @@ private Table getTable() {
9781007 * @return a single column of the primary key to be used in places where one need something not null to be selected.
9791008 */
9801009 private Column getSingleNonNullColumn () {
981-
982- // getColumn() is slightly different from the code in any(…). Why?
983- // AggregatePath.ColumnInfo columnInfo = path.getColumnInfo();
984- // return getTable(path).column(columnInfo.name()).as(columnInfo.alias());
985-
986- AggregatePath .ColumnInfos columnInfos = mappingContext .getAggregatePath (entity ).getTableInfo ().idColumnInfos ();
987- return columnInfos .any ((ap , ci ) -> sqlContext .getColumn (ap ));
1010+ return doGetColumn (AggregatePath .ColumnInfos ::any );
9881011 }
9891012
9901013 private List <Column > getIdColumns () {
1014+ return doGetColumn (AggregatePath .ColumnInfos ::toColumnList );
1015+ }
1016+
1017+ private <T > T doGetColumn (
1018+ BiFunction <AggregatePath .ColumnInfos , BiFunction <AggregatePath , AggregatePath .ColumnInfo , Column >, T > columnListFunction ) {
9911019
9921020 AggregatePath .ColumnInfos columnInfos = mappingContext .getAggregatePath (entity ).getTableInfo ().idColumnInfos ();
9931021
994- // sqlcontext.getColumn (vs sqlContext.getTable
995- return columnInfos
996- .toColumnList ((aggregatePath , columnInfo ) -> sqlContext .getColumn (aggregatePath ));
1022+ return columnListFunction .apply (columnInfos , (aggregatePath , columnInfo ) -> sqlContext .getColumn (aggregatePath ));
9971023 }
9981024
9991025 private Column getVersionColumn () {
@@ -1164,7 +1190,7 @@ private SelectBuilder.SelectJoin getExistsSelect() {
11641190 }
11651191 }
11661192
1167- return addJoins (baseSelect , joins );
1193+ return addJoins (baseSelect , Joins . of ( joins ) );
11681194 }
11691195
11701196 /**
@@ -1199,7 +1225,7 @@ private SelectBuilder.SelectJoin getSelectCountWithExpression(Expression... coun
11991225 joins .add (join );
12001226 }
12011227 }
1202- return addJoins (baseSelect , joins );
1228+ return addJoins (baseSelect , Joins . of ( joins ) );
12031229 }
12041230
12051231 private SelectBuilder .SelectOrdered applyQueryOnSelect (Query query , MapSqlParameterSource parameterSource ,
0 commit comments