Skip to content

Commit 38710e1

Browse files
committed
Refactor CriterionRenderer
1 parent 3fe1e8c commit 38710e1

File tree

2 files changed

+104
-116
lines changed

2 files changed

+104
-116
lines changed

src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java

Lines changed: 97 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Objects;
2020
import java.util.Optional;
2121
import java.util.concurrent.atomic.AtomicInteger;
22+
import java.util.function.Function;
2223
import java.util.stream.Collectors;
2324

2425
import org.mybatis.dynamic.sql.AndOrCriteriaGroup;
@@ -69,30 +70,57 @@ private CriterionRenderer(Builder builder) {
6970

7071
@Override
7172
public <T> Optional<RenderedCriterion> visit(ColumnAndConditionCriterion<T> criterion) {
72-
FragmentAndParameters fp = null;
73-
if (criterion.condition().shouldRender()) {
74-
fp = renderCondition(criterion);
75-
} else {
76-
criterion.condition().renderingSkipped();
77-
}
78-
73+
Optional<FragmentAndParameters> initialCriterion = renderColumnAndCondition(criterion);
7974
List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(criterion.subCriteria());
8075

81-
Optional<FragmentCollector> fragmentCollector = collectSqlFragments(fp, renderedSubCriteria);
82-
return fragmentCollector.map(fc -> {
83-
FragmentAndParameters fp1 = FragmentAndParameters.withFragment(calculateFragment(fc))
84-
.withParameters(fc.parameters())
85-
.build();
76+
return initialCriterion.map(fp -> calculateRenderedCriterion(fp, renderedSubCriteria, this::calculateFragment))
77+
.orElseGet(() -> calculateRenderedCriterion(renderedSubCriteria, this::calculateFragment));
78+
}
79+
80+
@Override
81+
public Optional<RenderedCriterion> visit(ExistsCriterion criterion) {
82+
FragmentAndParameters initialCriterion = renderExists(criterion);
83+
List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(criterion.subCriteria());
8684

87-
return new RenderedCriterion.Builder()
88-
.withFragmentAndParameters(fp1)
89-
.build();
85+
return calculateRenderedCriterion(initialCriterion, renderedSubCriteria, this::calculateFragment);
86+
}
9087

91-
});
88+
@Override
89+
public Optional<RenderedCriterion> visit(CriteriaGroup criterion) {
90+
return render(criterion.initialCriterion(), criterion.subCriteria(), this::calculateFragment);
9291
}
9392

9493
@Override
95-
public Optional<RenderedCriterion> visit(ExistsCriterion criterion) {
94+
public Optional<RenderedCriterion> visit(NotCriterion criterion) {
95+
return render(criterion.initialCriterion(), criterion.subCriteria(), this::calculateNotFragment);
96+
}
97+
98+
public Optional<RenderedCriterion> render(SqlCriterion initialCriterion, List<AndOrCriteriaGroup> subCriteria,
99+
Function<FragmentCollector, String> fragmentCalculator) {
100+
Optional<FragmentAndParameters> fragmentAndParameters = initialCriterion.accept(this)
101+
.map(RenderedCriterion::fragmentAndParameters);
102+
List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(subCriteria);
103+
104+
return fragmentAndParameters.map(fp -> calculateRenderedCriterion(fp, renderedSubCriteria, fragmentCalculator))
105+
.orElseGet(() -> calculateRenderedCriterion(renderedSubCriteria, fragmentCalculator));
106+
}
107+
108+
public Optional<RenderedCriterion> render(List<AndOrCriteriaGroup> subCriteria,
109+
Function<FragmentCollector, String> fragmentCalculator) {
110+
List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(subCriteria);
111+
return calculateRenderedCriterion(renderedSubCriteria, fragmentCalculator);
112+
}
113+
114+
private <T> Optional<FragmentAndParameters> renderColumnAndCondition(ColumnAndConditionCriterion<T> criterion) {
115+
if (criterion.condition().shouldRender()) {
116+
return Optional.of(renderCondition(criterion));
117+
} else {
118+
criterion.condition().renderingSkipped();
119+
return Optional.empty();
120+
}
121+
}
122+
123+
private FragmentAndParameters renderExists(ExistsCriterion criterion) {
96124
ExistsPredicate existsPredicate = criterion.existsPredicate();
97125

98126
SelectStatementProvider selectStatement = SelectRenderer
@@ -107,86 +135,33 @@ public Optional<RenderedCriterion> visit(ExistsCriterion criterion) {
107135
+ selectStatement.getSelectStatement()
108136
+ ")"; //$NON-NLS-1$
109137

110-
FragmentAndParameters initialCondition = FragmentAndParameters
138+
return FragmentAndParameters
111139
.withFragment(fragment)
112140
.withParameters(selectStatement.getParameters())
113141
.build();
114-
115-
List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(criterion.subCriteria());
116-
117-
Optional<FragmentCollector> fragmentCollector = collectSqlFragments(initialCondition, renderedSubCriteria);
118-
return fragmentCollector.map(fc -> {
119-
FragmentAndParameters fp1 = FragmentAndParameters.withFragment(calculateFragment(fc))
120-
.withParameters(fc.parameters())
121-
.build();
122-
123-
return new RenderedCriterion.Builder()
124-
.withFragmentAndParameters(fp1)
125-
.build();
126-
127-
});
128-
}
129-
130-
@Override
131-
public Optional<RenderedCriterion> visit(CriteriaGroup criterion) {
132-
Optional<RenderedCriterion> initialCriterion = criterion.initialCriterion().accept(this);
133-
List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(criterion.subCriteria());
134-
135-
Optional<FragmentCollector> fragmentCollector = collectSqlFragments(initialCriterion.map(RenderedCriterion::fragmentAndParameters)
136-
.orElse(null), renderedSubCriteria);
137-
return fragmentCollector.map(fc -> {
138-
FragmentAndParameters fp1 = FragmentAndParameters.withFragment(calculateFragment(fc))
139-
.withParameters(fc.parameters())
140-
.build();
141-
142-
return new RenderedCriterion.Builder()
143-
.withFragmentAndParameters(fp1)
144-
.build();
145-
146-
});
147-
}
148-
149-
@Override
150-
public Optional<RenderedCriterion> visit(NotCriterion criterion) {
151-
Optional<RenderedCriterion> initialCriterion = criterion.initialCriterion().accept(this);
152-
List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(criterion.subCriteria());
153-
154-
Optional<FragmentCollector> fragmentCollector = collectSqlFragments(initialCriterion.map(RenderedCriterion::fragmentAndParameters)
155-
.orElse(null), renderedSubCriteria);
156-
return fragmentCollector.map(fc -> {
157-
FragmentAndParameters fp1 = FragmentAndParameters.withFragment(calculateNotFragment(fc))
158-
.withParameters(fc.parameters())
159-
.build();
160-
161-
return new RenderedCriterion.Builder()
162-
.withFragmentAndParameters(fp1)
163-
.build();
164-
165-
});
166142
}
167143

168-
List<RenderedCriterion> renderSubCriteria(List<AndOrCriteriaGroup> subCriteria) {
144+
private List<RenderedCriterion> renderSubCriteria(List<AndOrCriteriaGroup> subCriteria) {
169145
return subCriteria.stream().map(this::renderAndOrCriteriaGroup)
170146
.filter(Optional::isPresent)
171147
.map(Optional::get)
172148
.collect(Collectors.toList());
173149
}
174150

175151
private Optional<RenderedCriterion> renderAndOrCriteriaGroup(AndOrCriteriaGroup criterion) {
176-
Optional<RenderedCriterion> initialCriterion = criterion.initialCriterion().accept(this);
177-
List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(criterion.subCriteria());
152+
return render(criterion.initialCriterion(), criterion.subCriteria(), this::calculateFragment)
153+
.map(rc -> rc.withConnector(criterion.connector()));
154+
}
155+
156+
private Optional<RenderedCriterion> calculateRenderedCriterion(FragmentAndParameters initialCriterion,
157+
List<RenderedCriterion> renderedSubCriteria, Function<FragmentCollector, String> fragmentCalculator) {
158+
return Optional.of(calculateRenderedCriterion(
159+
collectSqlFragments(initialCriterion, renderedSubCriteria), fragmentCalculator));
160+
}
178161

179-
Optional<FragmentCollector> fragmentCollector = collectSqlFragments(initialCriterion.map(RenderedCriterion::fragmentAndParameters)
180-
.orElse(null), renderedSubCriteria);
181-
return fragmentCollector.map(fc -> {
182-
FragmentAndParameters fp1 = FragmentAndParameters.withFragment(calculateFragment(fc))
183-
.withParameters(fc.parameters())
184-
.build();
185-
186-
return new RenderedCriterion.Builder()
187-
.withFragmentAndParameters(fp1)
188-
.build();
189-
}).map(rc -> rc.withConnector(criterion.connector()));
162+
private Optional<RenderedCriterion> calculateRenderedCriterion(List<RenderedCriterion> renderedSubCriteria,
163+
Function<FragmentCollector, String> fragmentCalculator) {
164+
return collectSqlFragments(renderedSubCriteria).map(fc -> calculateRenderedCriterion(fc, fragmentCalculator));
190165
}
191166

192167
private <T> FragmentAndParameters renderCondition(ColumnAndConditionCriterion<T> criterion) {
@@ -201,17 +176,9 @@ private <T> FragmentAndParameters renderCondition(ColumnAndConditionCriterion<T>
201176

202177
/**
203178
* This method encapsulates the logic of building a collection of fragments from an initial condition
204-
* and a list of rendered sub criteria. There are three cases:
205-
*
206-
* <ol>
207-
* <li>If there is no initial condition and there are no rendered sub criteria, then there will
208-
* be no rendered criteria and this set of criteria should be skipped altogether</li>
209-
* <li>If there are both and initial condition and rendered sub criteria, then the final set will
210-
* include all fragments in order</li>
211-
* <li>If there is no initial fragment, but there are rendered sub criteria, then the final set
212-
* will include just the sub criteria. However, the connector from the first rendered sub criterion
213-
* will be removed. This to avoid generating an invalid where clause like "where and a < 3"</li>
214-
* </ol>
179+
* and a list of rendered sub criteria. In this overload we know there is an initial condition
180+
* and there may be subcriteria. The collector will contain the initial condition and any rendered subcriteria
181+
* in order.
215182
*
216183
* @param initialCondition - may be null if there is no rendered initial condition (as can be the case of
217184
* optional conditions like isEqualToWhenPresent)
@@ -221,27 +188,52 @@ private <T> FragmentAndParameters renderCondition(ColumnAndConditionCriterion<T>
221188
* The fragment collector can be used to calculate the single composed fragment - either as a where clause, or
222189
* a valid rendered sub criteria in the case of a recursive call.
223190
*/
224-
Optional<FragmentCollector> collectSqlFragments(FragmentAndParameters initialCondition,
225-
List<RenderedCriterion> renderedSubCriteria) {
226-
if (initialCondition == null && renderedSubCriteria.isEmpty()) {
191+
private FragmentCollector collectSqlFragments(FragmentAndParameters initialCondition,
192+
List<RenderedCriterion> renderedSubCriteria) {
193+
return renderedSubCriteria.stream()
194+
.map(RenderedCriterion::fragmentAndParametersWithConnector)
195+
.collect(FragmentCollector.collect(initialCondition));
196+
}
197+
198+
/**
199+
* This method encapsulates the logic of building a collection of fragments from a list of rendered sub criteria.
200+
* In this overload we take the initial condition to be the first element in the subcriteria list.
201+
* The collector will contain the rendered subcriteria in order. However, the connector from the first rendered
202+
* sub criterion will be removed. This to avoid generating an invalid where clause like "where and a < 3"
203+
*
204+
* @param renderedSubCriteria - a list of previously rendered sub criteria. The sub criteria will all
205+
* have connectors (either an AND or an OR)
206+
* @return a fragment collector whose fragments represent the final calculated list of fragments and parameters.
207+
* The fragment collector can be used to calculate the single composed fragment - either as a where clause, or
208+
* a valid rendered sub criteria in the case of a recursive call.
209+
*/
210+
private Optional<FragmentCollector> collectSqlFragments(List<RenderedCriterion> renderedSubCriteria) {
211+
if (renderedSubCriteria.isEmpty()) {
227212
return Optional.empty();
228213
}
229214

230-
int skip = 0;
231-
FragmentAndParameters firstCondition = initialCondition;
232-
if (firstCondition == null) {
233-
firstCondition = renderedSubCriteria.get(0).fragmentAndParameters();
234-
skip = 1;
235-
}
215+
FragmentAndParameters firstCondition = renderedSubCriteria.get(0).fragmentAndParameters();
236216

237217
FragmentCollector fc = renderedSubCriteria.stream()
238-
.skip(skip)
218+
.skip(1)
239219
.map(RenderedCriterion::fragmentAndParametersWithConnector)
240220
.collect(FragmentCollector.collect(firstCondition));
241221

242222
return Optional.of(fc);
243223
}
244224

225+
private RenderedCriterion calculateRenderedCriterion(FragmentCollector fragmentCollector,
226+
Function<FragmentCollector, String> fragmentCalculator) {
227+
FragmentAndParameters fragmentAndParameters = FragmentAndParameters
228+
.withFragment(fragmentCalculator.apply(fragmentCollector))
229+
.withParameters(fragmentCollector.parameters())
230+
.build();
231+
232+
return new RenderedCriterion.Builder()
233+
.withFragmentAndParameters(fragmentAndParameters)
234+
.build();
235+
}
236+
245237
private String calculateFragment(FragmentCollector collector) {
246238
if (collector.hasMultipleFragments()) {
247239
return collector.fragments()

src/main/java/org/mybatis/dynamic/sql/where/render/WhereRenderer.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@
1515
*/
1616
package org.mybatis.dynamic.sql.where.render;
1717

18-
import java.util.List;
1918
import java.util.Objects;
2019
import java.util.Optional;
2120
import java.util.concurrent.atomic.AtomicInteger;
2221
import java.util.stream.Collectors;
2322

2423
import org.mybatis.dynamic.sql.render.RenderingStrategy;
2524
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
26-
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
2725
import org.mybatis.dynamic.sql.util.FragmentCollector;
2826
import org.mybatis.dynamic.sql.where.WhereModel;
2927

@@ -43,15 +41,13 @@ private WhereRenderer(Builder builder) {
4341
}
4442

4543
public Optional<WhereClauseProvider> render() {
46-
Optional<FragmentAndParameters> initialCriterion = whereModel.initialCriterion()
47-
.flatMap(ic -> ic.accept(criterionRenderer))
48-
.map(RenderedCriterion::fragmentAndParameters);
49-
List<RenderedCriterion> renderedCriteria = criterionRenderer.renderSubCriteria(whereModel.subCriteria());
50-
51-
return criterionRenderer.collectSqlFragments(initialCriterion.orElse(null), renderedCriteria)
52-
.map(fcc -> WhereClauseProvider.withWhereClause(calculateWhereClause(fcc))
53-
.withParameters(fcc.parameters())
54-
.build());
44+
return whereModel.initialCriterion().map(ic ->
45+
criterionRenderer.render(ic, whereModel.subCriteria(), this::calculateWhereClause))
46+
.orElseGet(() -> criterionRenderer.render(whereModel.subCriteria(), this::calculateWhereClause))
47+
.map(rc -> WhereClauseProvider.withWhereClause(rc.fragmentAndParameters().fragment())
48+
.withParameters(rc.fragmentAndParameters().parameters())
49+
.build()
50+
);
5551
}
5652

5753
private String calculateWhereClause(FragmentCollector collector) {

0 commit comments

Comments
 (0)