1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.dynamic.sql.where.render;
17
18 import java.util.List;
19 import java.util.Objects;
20 import java.util.Optional;
21 import java.util.function.Function;
22 import java.util.stream.Collectors;
23
24 import org.mybatis.dynamic.sql.AndOrCriteriaGroup;
25 import org.mybatis.dynamic.sql.ColumnAndConditionCriterion;
26 import org.mybatis.dynamic.sql.CriteriaGroup;
27 import org.mybatis.dynamic.sql.ExistsCriterion;
28 import org.mybatis.dynamic.sql.ExistsPredicate;
29 import org.mybatis.dynamic.sql.NotCriterion;
30 import org.mybatis.dynamic.sql.SqlCriterion;
31 import org.mybatis.dynamic.sql.SqlCriterionVisitor;
32 import org.mybatis.dynamic.sql.render.RenderingContext;
33 import org.mybatis.dynamic.sql.select.render.SubQueryRenderer;
34 import org.mybatis.dynamic.sql.util.FragmentAndParameters;
35 import org.mybatis.dynamic.sql.util.FragmentCollector;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class CriterionRenderer implements SqlCriterionVisitor<Optional<RenderedCriterion>> {
56 private final RenderingContext renderingContext;
57
58 public CriterionRenderer(RenderingContext renderingContext) {
59 this.renderingContext = Objects.requireNonNull(renderingContext);
60 }
61
62 @Override
63 public <T> Optional<RenderedCriterion> visit(ColumnAndConditionCriterion<T> criterion) {
64 Optional<FragmentAndParameters> initialCriterion = renderColumnAndCondition(criterion);
65 List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(criterion.subCriteria());
66
67 return initialCriterion.map(fp -> calculateRenderedCriterion(fp, renderedSubCriteria, this::calculateFragment))
68 .orElseGet(() -> calculateRenderedCriterion(renderedSubCriteria, this::calculateFragment));
69 }
70
71 @Override
72 public Optional<RenderedCriterion> visit(ExistsCriterion criterion) {
73 FragmentAndParameters initialCriterion = renderExists(criterion);
74 List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(criterion.subCriteria());
75
76 return calculateRenderedCriterion(initialCriterion, renderedSubCriteria, this::calculateFragment);
77 }
78
79 @Override
80 public Optional<RenderedCriterion> visit(CriteriaGroup criterion) {
81 return renderCriteriaGroup(criterion, this::calculateFragment);
82 }
83
84 @Override
85 public Optional<RenderedCriterion> visit(NotCriterion criterion) {
86 return renderCriteriaGroup(criterion, this::calculateNotFragment);
87 }
88
89 private Optional<RenderedCriterion> renderCriteriaGroup(CriteriaGroup criterion,
90 Function<FragmentCollector, String> fragmentCalculator) {
91 return criterion.initialCriterion().map(ic -> render(ic, criterion.subCriteria(), fragmentCalculator))
92 .orElseGet(() -> render(criterion.subCriteria(), fragmentCalculator));
93 }
94
95 public Optional<RenderedCriterion> render(SqlCriterion initialCriterion, List<AndOrCriteriaGroup> subCriteria,
96 Function<FragmentCollector, String> fragmentCalculator) {
97 Optional<FragmentAndParameters> fragmentAndParameters = initialCriterion.accept(this)
98 .map(RenderedCriterion::fragmentAndParameters);
99 List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(subCriteria);
100
101 return fragmentAndParameters.map(fp -> calculateRenderedCriterion(fp, renderedSubCriteria, fragmentCalculator))
102 .orElseGet(() -> calculateRenderedCriterion(renderedSubCriteria, fragmentCalculator));
103 }
104
105 public Optional<RenderedCriterion> render(List<AndOrCriteriaGroup> subCriteria,
106 Function<FragmentCollector, String> fragmentCalculator) {
107 List<RenderedCriterion> renderedSubCriteria = renderSubCriteria(subCriteria);
108 return calculateRenderedCriterion(renderedSubCriteria, fragmentCalculator);
109 }
110
111 private <T> Optional<FragmentAndParameters> renderColumnAndCondition(ColumnAndConditionCriterion<T> criterion) {
112 if (criterion.condition().shouldRender(renderingContext)) {
113 return Optional.of(renderCondition(criterion));
114 } else {
115 criterion.condition().renderingSkipped();
116 return Optional.empty();
117 }
118 }
119
120 private FragmentAndParameters renderExists(ExistsCriterion criterion) {
121 ExistsPredicate existsPredicate = criterion.existsPredicate();
122 return SubQueryRenderer.withSelectModel(existsPredicate.selectModelBuilder().build())
123 .withRenderingContext(renderingContext)
124 .withPrefix(existsPredicate.operator() + " (")
125 .withSuffix(")")
126 .build()
127 .render();
128 }
129
130 private List<RenderedCriterion> renderSubCriteria(List<AndOrCriteriaGroup> subCriteria) {
131 return subCriteria.stream().map(this::renderAndOrCriteriaGroup)
132 .flatMap(Optional::stream)
133 .toList();
134 }
135
136 private Optional<RenderedCriterion> renderAndOrCriteriaGroup(AndOrCriteriaGroup criterion) {
137 return criterion.initialCriterion().map(ic -> render(ic, criterion.subCriteria(), this::calculateFragment))
138 .orElseGet(() -> render(criterion.subCriteria(), this::calculateFragment))
139 .map(rc -> rc.withConnector(criterion.connector()));
140 }
141
142 private Optional<RenderedCriterion> calculateRenderedCriterion(FragmentAndParameters initialCriterion,
143 List<RenderedCriterion> renderedSubCriteria, Function<FragmentCollector, String> fragmentCalculator) {
144 return Optional.of(calculateRenderedCriterion(
145 collectSqlFragments(initialCriterion, renderedSubCriteria), fragmentCalculator));
146 }
147
148 private RenderedCriterion calculateRenderedCriterion(FragmentCollector fragmentCollector,
149 Function<FragmentCollector, String> fragmentCalculator) {
150 FragmentAndParameters fragmentAndParameters = FragmentAndParameters
151 .withFragment(fragmentCalculator.apply(fragmentCollector))
152 .withParameters(fragmentCollector.parameters())
153 .build();
154
155 return new RenderedCriterion.Builder()
156 .withFragmentAndParameters(fragmentAndParameters)
157 .build();
158 }
159
160 private Optional<RenderedCriterion> calculateRenderedCriterion(List<RenderedCriterion> renderedSubCriteria,
161 Function<FragmentCollector, String> fragmentCalculator) {
162 return collectSqlFragments(renderedSubCriteria).map(fc -> calculateRenderedCriterion(fc, fragmentCalculator));
163 }
164
165 private <T> FragmentAndParameters renderCondition(ColumnAndConditionCriterion<T> criterion) {
166 return new ColumnAndConditionRenderer.Builder<T>()
167 .withColumn(criterion.column())
168 .withCondition(criterion.condition())
169 .withRenderingContext(renderingContext)
170 .build()
171 .render();
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 private FragmentCollector collectSqlFragments(FragmentAndParameters initialCondition,
188 List<RenderedCriterion> renderedSubCriteria) {
189 return renderedSubCriteria.stream()
190 .map(RenderedCriterion::fragmentAndParametersWithConnector)
191 .collect(FragmentCollector.collect(initialCondition));
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206 private Optional<FragmentCollector> collectSqlFragments(List<RenderedCriterion> renderedSubCriteria) {
207 if (renderedSubCriteria.isEmpty()) {
208 return Optional.empty();
209 }
210
211 FragmentAndParameters firstCondition = renderedSubCriteria.get(0).fragmentAndParameters();
212
213 FragmentCollector fc = renderedSubCriteria.stream()
214 .skip(1)
215 .map(RenderedCriterion::fragmentAndParametersWithConnector)
216 .collect(FragmentCollector.collect(firstCondition));
217
218 return Optional.of(fc);
219 }
220
221 private String calculateFragment(FragmentCollector collector) {
222 if (collector.hasMultipleFragments()) {
223 return collector.collectFragments(
224 Collectors.joining(" ", "(", ")"));
225 } else {
226 return collector.firstFragment().orElse("");
227 }
228 }
229
230 private String calculateNotFragment(FragmentCollector collector) {
231 if (collector.hasMultipleFragments()) {
232 return collector.collectFragments(
233 Collectors.joining(" ", "not (", ")"));
234 } else {
235 return collector.firstFragment().map(s -> "not " + s).orElse("");
236 }
237 }
238 }