View Javadoc
1   /*
2    *    Copyright 2016-2025 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.mybatis.dynamic.sql.delete.render;
17  
18  import java.util.Objects;
19  import java.util.Optional;
20  import java.util.stream.Collectors;
21  
22  import org.jspecify.annotations.Nullable;
23  import org.mybatis.dynamic.sql.common.OrderByModel;
24  import org.mybatis.dynamic.sql.common.OrderByRenderer;
25  import org.mybatis.dynamic.sql.delete.DeleteModel;
26  import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator;
27  import org.mybatis.dynamic.sql.render.RenderedParameterInfo;
28  import org.mybatis.dynamic.sql.render.RenderingContext;
29  import org.mybatis.dynamic.sql.render.RenderingStrategy;
30  import org.mybatis.dynamic.sql.render.TableAliasCalculator;
31  import org.mybatis.dynamic.sql.util.FragmentAndParameters;
32  import org.mybatis.dynamic.sql.util.FragmentCollector;
33  import org.mybatis.dynamic.sql.where.EmbeddedWhereModel;
34  
35  public class DeleteRenderer {
36      private final DeleteModel deleteModel;
37      private final RenderingContext renderingContext;
38  
39      private DeleteRenderer(Builder builder) {
40          deleteModel = Objects.requireNonNull(builder.deleteModel);
41          TableAliasCalculator tableAliasCalculator = builder.deleteModel.tableAlias()
42                  .map(a -> ExplicitTableAliasCalculator.of(deleteModel.table(), a))
43                  .orElseGet(TableAliasCalculator::empty);
44          renderingContext = RenderingContext
45                  .withRenderingStrategy(Objects.requireNonNull(builder.renderingStrategy))
46                  .withTableAliasCalculator(tableAliasCalculator)
47                  .withStatementConfiguration(deleteModel.statementConfiguration())
48                  .build();
49      }
50  
51      public DeleteStatementProvider render() {
52          FragmentCollector fragmentCollector = new FragmentCollector();
53  
54          fragmentCollector.add(calculateDeleteStatementStart());
55          calculateWhereClause().ifPresent(fragmentCollector::add);
56          calculateOrderByClause().ifPresent(fragmentCollector::add);
57          calculateLimitClause().ifPresent(fragmentCollector::add);
58  
59          return toDeleteStatementProvider(fragmentCollector);
60      }
61  
62      private DeleteStatementProvider toDeleteStatementProvider(FragmentCollector fragmentCollector) {
63          return DefaultDeleteStatementProvider
64                  .withDeleteStatement(fragmentCollector.collectFragments(Collectors.joining(" "))) //$NON-NLS-1$
65                  .withParameters(fragmentCollector.parameters())
66                  .build();
67      }
68  
69      private FragmentAndParameters calculateDeleteStatementStart() {
70          String aliasedTableName = renderingContext.aliasedTableName(deleteModel.table());
71          return FragmentAndParameters.fromFragment("delete from " + aliasedTableName); //$NON-NLS-1$
72      }
73  
74      private Optional<FragmentAndParameters> calculateWhereClause() {
75          return deleteModel.whereModel().flatMap(this::renderWhereClause);
76      }
77  
78      private Optional<FragmentAndParameters> renderWhereClause(EmbeddedWhereModel whereModel) {
79          return whereModel.render(renderingContext);
80      }
81  
82      private Optional<FragmentAndParameters> calculateLimitClause() {
83          return deleteModel.limit().map(this::renderLimitClause);
84      }
85  
86      private FragmentAndParameters renderLimitClause(Long limit) {
87          RenderedParameterInfo parameterInfo = renderingContext.calculateLimitParameterInfo();
88  
89          return FragmentAndParameters.withFragment("limit " + parameterInfo.renderedPlaceHolder()) //$NON-NLS-1$
90                  .withParameter(parameterInfo.parameterMapKey(), limit)
91                  .build();
92      }
93  
94      private Optional<FragmentAndParameters> calculateOrderByClause() {
95          return deleteModel.orderByModel().map(this::renderOrderByClause);
96      }
97  
98      private FragmentAndParameters renderOrderByClause(OrderByModel orderByModel) {
99          return new OrderByRenderer(renderingContext).render(orderByModel);
100     }
101 
102     public static Builder withDeleteModel(DeleteModel deleteModel) {
103         return new Builder().withDeleteModel(deleteModel);
104     }
105 
106     public static class Builder {
107         private @Nullable DeleteModel deleteModel;
108         private @Nullable RenderingStrategy renderingStrategy;
109 
110         public Builder withDeleteModel(DeleteModel deleteModel) {
111             this.deleteModel = deleteModel;
112             return this;
113         }
114 
115         public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) {
116             this.renderingStrategy = renderingStrategy;
117             return this;
118         }
119 
120         public DeleteRenderer build() {
121             return new DeleteRenderer(this);
122         }
123     }
124 }