1919import java .util .Objects ;
2020import java .util .Optional ;
2121import java .util .concurrent .atomic .AtomicInteger ;
22+ import java .util .function .Function ;
2223import java .util .stream .Collectors ;
2324
2425import 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 ()
0 commit comments