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