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.select;
17  
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.Collection;
21  import java.util.List;
22  import java.util.Optional;
23  import java.util.function.Consumer;
24  
25  import org.jspecify.annotations.Nullable;
26  import org.mybatis.dynamic.sql.SortSpecification;
27  import org.mybatis.dynamic.sql.common.OrderByModel;
28  import org.mybatis.dynamic.sql.configuration.StatementConfiguration;
29  import org.mybatis.dynamic.sql.util.Buildable;
30  import org.mybatis.dynamic.sql.util.ConfigurableStatement;
31  
32  public class MultiSelectDSL implements Buildable<MultiSelectModel>, ConfigurableStatement<MultiSelectDSL> {
33      private final List<UnionQuery> unionQueries = new ArrayList<>();
34      private final SelectModel initialSelect;
35      private @Nullable OrderByModel orderByModel;
36      private @Nullable Long limit;
37      private @Nullable Long offset;
38      private @Nullable Long fetchFirstRows;
39      private final StatementConfiguration statementConfiguration = new StatementConfiguration();
40  
41      public MultiSelectDSL(Buildable<SelectModel> builder) {
42          initialSelect = builder.build();
43      }
44  
45      public MultiSelectDSL union(Buildable<SelectModel> builder) {
46          unionQueries.add(new UnionQuery("union", builder.build())); //$NON-NLS-1$
47          return this;
48      }
49  
50      public MultiSelectDSL unionAll(Buildable<SelectModel> builder) {
51          unionQueries.add(new UnionQuery("union all", builder.build())); //$NON-NLS-1$
52          return this;
53      }
54  
55      public MultiSelectDSL orderBy(SortSpecification... columns) {
56          return orderBy(Arrays.asList(columns));
57      }
58  
59      public MultiSelectDSL orderBy(Collection<? extends SortSpecification> columns) {
60          orderByModel = OrderByModel.of(columns);
61          return this;
62      }
63  
64      public MultiSelectDSL.LimitFinisher limit(long limit) {
65          return limitWhenPresent(limit);
66      }
67  
68      public MultiSelectDSL.LimitFinisher limitWhenPresent(@Nullable Long limit) {
69          this.limit = limit;
70          return new LimitFinisher();
71      }
72  
73      public MultiSelectDSL.OffsetFirstFinisher offset(long offset) {
74          return offsetWhenPresent(offset);
75      }
76  
77      public MultiSelectDSL.OffsetFirstFinisher offsetWhenPresent(@Nullable Long offset) {
78          this.offset = offset;
79          return new OffsetFirstFinisher();
80      }
81  
82      public MultiSelectDSL.FetchFirstFinisher fetchFirst(long fetchFirstRows) {
83          return fetchFirstWhenPresent(fetchFirstRows);
84      }
85  
86      public MultiSelectDSL.FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) {
87          this.fetchFirstRows = fetchFirstRows;
88          return new FetchFirstFinisher();
89      }
90  
91      @Override
92      public MultiSelectModel build() {
93          return new MultiSelectModel.Builder()
94                  .withInitialSelect(initialSelect)
95                  .withUnionQueries(unionQueries)
96                  .withOrderByModel(orderByModel)
97                  .withPagingModel(buildPagingModel().orElse(null))
98                  .withStatementConfiguration(statementConfiguration)
99                  .build();
100     }
101 
102     private Optional<PagingModel> buildPagingModel() {
103         return new PagingModel.Builder()
104                 .withLimit(limit)
105                 .withOffset(offset)
106                 .withFetchFirstRows(fetchFirstRows)
107                 .build();
108     }
109 
110     @Override
111     public MultiSelectDSL configureStatement(Consumer<StatementConfiguration> consumer) {
112         consumer.accept(statementConfiguration);
113         return this;
114     }
115 
116     public class OffsetFirstFinisher implements Buildable<MultiSelectModel> {
117         public FetchFirstFinisher fetchFirst(long fetchFirstRows) {
118             return fetchFirstWhenPresent(fetchFirstRows);
119         }
120 
121         public FetchFirstFinisher fetchFirstWhenPresent(@Nullable Long fetchFirstRows) {
122             MultiSelectDSL.this.fetchFirstRows = fetchFirstRows;
123             return new FetchFirstFinisher();
124         }
125 
126         @Override
127         public MultiSelectModel build() {
128             return MultiSelectDSL.this.build();
129         }
130     }
131 
132     public class LimitFinisher implements Buildable<MultiSelectModel> {
133         public MultiSelectDSL offset(long offset) {
134             return offsetWhenPresent(offset);
135         }
136 
137         public MultiSelectDSL offsetWhenPresent(@Nullable Long offset) {
138             MultiSelectDSL.this.offset = offset;
139             return MultiSelectDSL.this;
140         }
141 
142         @Override
143         public MultiSelectModel build() {
144             return MultiSelectDSL.this.build();
145         }
146     }
147 
148     public class FetchFirstFinisher {
149         public MultiSelectDSL rowsOnly() {
150             return MultiSelectDSL.this;
151         }
152     }
153 }