001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core.paginate;
017
018import com.mybatisflex.core.FlexGlobalConfig;
019
020import java.io.Serializable;
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.List;
024import java.util.function.Function;
025
026/**
027 * 分页对象封装。
028 *
029 * @param <T> 数据类型
030 * @author 开源海哥
031 * @author 王帅
032 */
033public class Page<T> implements Serializable {
034
035    private static final long serialVersionUID = 1L;
036
037    public static final int INIT_VALUE = -1;
038
039    /**
040     * 当前页数据。
041     */
042    private List<T> records = Collections.emptyList();
043
044    /**
045     * 当前页码。
046     */
047    private long pageNumber = 1;
048
049    /**
050     * 每页数据数量。
051     */
052    private long pageSize = FlexGlobalConfig.getDefaultConfig().getDefaultPageSize();
053
054    /**
055     * 总页数。
056     */
057    private long totalPage = INIT_VALUE;
058
059    /**
060     * 总数据数量。
061     */
062    private long totalRow = INIT_VALUE;
063
064    /**
065     * 是否优化分页查询 COUNT 语句。
066     */
067    private boolean optimizeCountQuery = true;
068
069    /**
070     * 创建分页对象。
071     *
072     * @param pageNumber 当前页码
073     * @param pageSize   每页数据数量
074     * @param <T>        数据类型
075     * @return 分页对象
076     */
077    public static <T> Page<T> of(Number pageNumber, Number pageSize) {
078        return new Page<>(pageNumber, pageSize);
079    }
080
081    /**
082     * 创建分页对象。
083     *
084     * @param pageNumber 当前页码
085     * @param pageSize   每页数据数量
086     * @param totalRow   总数据数量
087     * @param <T>        数据类型
088     * @return 分页对象
089     */
090    public static <T> Page<T> of(Number pageNumber, Number pageSize, Number totalRow) {
091        return new Page<>(pageNumber, pageSize, totalRow);
092    }
093
094    /**
095     * 创建分页对象。
096     */
097    public Page() {
098    }
099
100    /**
101     * 创建分页对象。
102     *
103     * @param pageNumber 当前页码
104     * @param pageSize   每页数据数量
105     */
106    public Page(Number pageNumber, Number pageSize) {
107        this.setPageNumber(pageNumber.longValue());
108        this.setPageSize(pageSize.longValue());
109    }
110
111    /**
112     * 创建分页对象。
113     *
114     * @param pageNumber 当前页码
115     * @param pageSize   每页数据数量
116     * @param totalRow   总数居数量
117     */
118    public Page(Number pageNumber, Number pageSize, Number totalRow) {
119        this.setPageNumber(pageNumber.longValue());
120        this.setPageSize(pageSize.longValue());
121        this.setTotalRow(totalRow.longValue());
122    }
123
124    /**
125     * 创建分页对象。
126     *
127     * @param records    当前页数据
128     * @param pageNumber 当前页码
129     * @param pageSize   每页数据数量
130     * @param totalRow   总数居数量
131     */
132    public Page(List<T> records, Number pageNumber, Number pageSize, Number totalRow) {
133        this.setRecords(records);
134        this.setPageNumber(pageNumber.longValue());
135        this.setPageSize(pageSize.longValue());
136        this.setTotalRow(totalRow.longValue());
137    }
138
139    /**
140     * 获取当前页的数据。
141     *
142     * @return 当前页的数据
143     */
144    public List<T> getRecords() {
145        return records;
146    }
147
148    /**
149     * 设置当前页的数据。
150     *
151     * @param records 当前页的数据
152     */
153    public void setRecords(List<T> records) {
154        if (records == null) {
155            records = Collections.emptyList();
156        }
157        this.records = records;
158    }
159
160    /**
161     * 获取当前页码。
162     *
163     * @return 页码
164     */
165    public long getPageNumber() {
166        return pageNumber;
167    }
168
169    /**
170     * 设置当前页码。
171     *
172     * @param pageNumber 页码
173     */
174    public void setPageNumber(long pageNumber) {
175        if (pageNumber < 1) {
176            throw new IllegalArgumentException("pageNumber must greater than or equal 1,current value is: " + pageNumber);
177        }
178        this.pageNumber = pageNumber;
179    }
180
181    /**
182     * 获取当前每页数据数量。
183     *
184     * @return 每页数据数量
185     */
186    public long getPageSize() {
187        return pageSize;
188    }
189
190    /**
191     * 设置当前每页数据数量。
192     *
193     * @param pageSize 每页数据数量
194     */
195    public void setPageSize(long pageSize) {
196        if (pageSize < 0) {
197            throw new IllegalArgumentException("pageSize must greater than or equal 0,current value is: " + pageSize);
198        }
199        this.pageSize = pageSize;
200        this.calcTotalPage();
201    }
202
203    /**
204     * 获取数据总数。
205     *
206     * @return 数据总数
207     */
208    public long getTotalPage() {
209        return totalPage;
210    }
211
212    /**
213     * 设置总页数。
214     *
215     * @param totalPage 总页数
216     */
217    public void setTotalPage(long totalPage) {
218        this.totalPage = totalPage;
219    }
220
221    /**
222     * 获取数据总数。
223     *
224     * @return 数据总数
225     */
226    public long getTotalRow() {
227        return totalRow;
228    }
229
230    /**
231     * 设置数据总数。
232     *
233     * @param totalRow 数据总数
234     */
235    public void setTotalRow(long totalRow) {
236        this.totalRow = totalRow;
237        this.calcTotalPage();
238    }
239
240    /**
241     * 计算总页码。
242     */
243    private void calcTotalPage() {
244        if (pageSize < 0 || totalRow < 0) {
245            totalPage = INIT_VALUE;
246        } else {
247            totalPage = totalRow % pageSize == 0 ? (totalRow / pageSize) : (totalRow / pageSize + 1);
248        }
249    }
250
251    /**
252     * 当前页是否有记录(有内容)。
253     *
254     * @return {@code true} 有内容,{@code false} 没有内容
255     */
256    public boolean hasRecords() {
257        return getTotalRow() > 0 && getPageNumber() <= getTotalPage();
258    }
259
260    /**
261     * 是否存在下一页。
262     *
263     * @return {@code true} 存在下一页,{@code false} 不存在下一页
264     */
265    public boolean hasNext() {
266        return getTotalPage() != 0 && getPageNumber() < getTotalPage();
267    }
268
269    /**
270     * 是否存在上一页。
271     *
272     * @return {@code true} 存在上一页,{@code false} 不存在上一页
273     */
274    public boolean hasPrevious() {
275        return getPageNumber() > 1;
276    }
277
278    /**
279     * 获取当前分页偏移量。
280     *
281     * @return 偏移量
282     */
283    public long offset() {
284        return getPageSize() * (getPageNumber() - 1);
285    }
286
287    /**
288     * 设置是否自动优化 COUNT 查询语句。
289     *
290     * @param optimizeCountQuery 是否优化
291     */
292    public void setOptimizeCountQuery(boolean optimizeCountQuery) {
293        this.optimizeCountQuery = optimizeCountQuery;
294    }
295
296    /**
297     * 是否自动优化 COUNT 查询语句(默认优化)。
298     *
299     * @return {@code true} 优化,{@code false} 不优化
300     */
301    public boolean needOptimizeCountQuery() {
302        return optimizeCountQuery;
303    }
304
305    public <R> Page<R> map(Function<? super T, ? extends R> mapper) {
306        Page<R> newPage = new Page<>();
307        newPage.pageNumber = pageNumber;
308        newPage.pageSize = pageSize;
309        newPage.totalPage = totalPage;
310        newPage.totalRow = totalRow;
311
312        if (records != null && !records.isEmpty()) {
313            List<R> newRecords = new ArrayList<>(records.size());
314            for (T t : records) {
315                newRecords.add(mapper.apply(t));
316            }
317            newPage.records = newRecords;
318        }
319        return newPage;
320    }
321
322    @Override
323    public String toString() {
324        return "Page{" +
325            "pageNumber=" + pageNumber +
326            ", pageSize=" + pageSize +
327            ", totalPage=" + totalPage +
328            ", totalRow=" + totalRow +
329            ", records=" + records +
330            '}';
331    }
332
333}