001/*
002 *  Copyright (c) 2022-2025, 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 maxPageSize = FlexGlobalConfig.getDefaultConfig().getDefaultMaxPageSize();
058
059    /**
060     * 总页数。
061     */
062    private long totalPage = INIT_VALUE;
063
064    /**
065     * 总数据数量。
066     */
067    private long totalRow = INIT_VALUE;
068
069    /**
070     * 是否优化分页查询 COUNT 语句。
071     */
072    private boolean optimizeCountQuery = true;
073
074    /**
075     * 创建分页对象。
076     *
077     * @param pageNumber 当前页码
078     * @param pageSize   每页数据数量
079     * @param <T>        数据类型
080     * @return 分页对象
081     */
082    public static <T> Page<T> of(Number pageNumber, Number pageSize) {
083        return new Page<>(pageNumber, pageSize);
084    }
085
086    /**
087     * 创建分页对象。
088     *
089     * @param pageNumber 当前页码
090     * @param pageSize   每页数据数量
091     * @param totalRow   总数据数量
092     * @param <T>        数据类型
093     * @return 分页对象
094     */
095    public static <T> Page<T> of(Number pageNumber, Number pageSize, Number totalRow) {
096        return new Page<>(pageNumber, pageSize, totalRow);
097    }
098
099    /**
100     * 创建分页对象。
101     */
102    public Page() {
103    }
104
105    /**
106     * 创建分页对象。
107     *
108     * @param pageNumber 当前页码
109     * @param pageSize   每页数据数量
110     */
111    public Page(Number pageNumber, Number pageSize) {
112        this.setPageNumber(pageNumber.longValue());
113        this.setPageSize(pageSize.longValue());
114    }
115
116    /**
117     * 创建分页对象。
118     *
119     * @param pageNumber 当前页码
120     * @param pageSize   每页数据数量
121     * @param totalRow   总数居数量
122     */
123    public Page(Number pageNumber, Number pageSize, Number totalRow) {
124        this.setPageNumber(pageNumber.longValue());
125        this.setPageSize(pageSize.longValue());
126        this.setTotalRow(totalRow.longValue());
127    }
128
129    /**
130     * 创建分页对象。
131     *
132     * @param records    当前页数据
133     * @param pageNumber 当前页码
134     * @param pageSize   每页数据数量
135     * @param totalRow   总数居数量
136     */
137    public Page(List<T> records, Number pageNumber, Number pageSize, Number totalRow) {
138        this.setRecords(records);
139        this.setPageNumber(pageNumber.longValue());
140        this.setPageSize(pageSize.longValue());
141        this.setTotalRow(totalRow.longValue());
142    }
143
144    /**
145     * 获取当前页的数据。
146     *
147     * @return 当前页的数据
148     */
149    public List<T> getRecords() {
150        return records;
151    }
152
153    /**
154     * 设置当前页的数据。
155     *
156     * @param records 当前页的数据
157     */
158    public void setRecords(List<T> records) {
159        if (records == null) {
160            records = Collections.emptyList();
161        }
162        this.records = records;
163    }
164
165    /**
166     * 获取当前页码。
167     *
168     * @return 页码
169     */
170    public long getPageNumber() {
171        return pageNumber;
172    }
173
174    /**
175     * 设置当前页码。
176     *
177     * @param pageNumber 页码
178     */
179    public void setPageNumber(long pageNumber) {
180        if (pageNumber < 1) {
181            throw new IllegalArgumentException("pageNumber must greater than or equal 1,current value is: " + pageNumber);
182        }
183        this.pageNumber = pageNumber;
184    }
185
186    /**
187     * 获取当前每页数据数量。
188     *
189     * @return 每页数据数量
190     */
191    public long getPageSize() {
192        return pageSize;
193    }
194
195    /**
196     * 设置当前每页数据数量。
197     *
198     * @param pageSize 每页数据数量
199     */
200    public void setPageSize(long pageSize) {
201        if (pageSize <= 0) {
202            throw new IllegalArgumentException("pageSize must greater than 0,current value is: " + pageSize);
203        }
204        this.pageSize = Math.min(pageSize, maxPageSize);
205        this.calcTotalPage();
206    }
207
208    /**
209     * 获取数据总数。
210     *
211     * @return 数据总数
212     */
213    public long getTotalPage() {
214        return totalPage;
215    }
216
217    /**
218     * 设置总页数。
219     *
220     * @param totalPage 总页数
221     */
222    public void setTotalPage(long totalPage) {
223        this.totalPage = totalPage;
224    }
225
226    /**
227     * 获取数据总数。
228     *
229     * @return 数据总数
230     */
231    public long getTotalRow() {
232        return totalRow;
233    }
234
235    /**
236     * 设置数据总数。
237     *
238     * @param totalRow 数据总数
239     */
240    public void setTotalRow(long totalRow) {
241        this.totalRow = totalRow;
242        this.calcTotalPage();
243    }
244
245    /**
246     * 计算总页码。
247     */
248    private void calcTotalPage() {
249        if (pageSize < 0 || totalRow < 0) {
250            totalPage = INIT_VALUE;
251        } else {
252            totalPage = totalRow % pageSize == 0 ? (totalRow / pageSize) : (totalRow / pageSize + 1);
253        }
254    }
255
256    /**
257     * 当前页是否有记录(有内容)。
258     *
259     * @return {@code true} 有内容,{@code false} 没有内容
260     */
261    public boolean hasRecords() {
262        return getTotalRow() > 0 && getPageNumber() <= getTotalPage();
263    }
264
265    /**
266     * 是否存在下一页。
267     *
268     * @return {@code true} 存在下一页,{@code false} 不存在下一页
269     */
270    public boolean hasNext() {
271        return getTotalPage() != 0 && getPageNumber() < getTotalPage();
272    }
273
274    /**
275     * 是否存在上一页。
276     *
277     * @return {@code true} 存在上一页,{@code false} 不存在上一页
278     */
279    public boolean hasPrevious() {
280        return getPageNumber() > 1;
281    }
282
283    /**
284     * 获取当前分页偏移量。
285     *
286     * @return 偏移量
287     */
288    public long offset() {
289        return getPageSize() * (getPageNumber() - 1);
290    }
291
292    /**
293     * 设置是否自动优化 COUNT 查询语句。
294     *
295     * @param optimizeCountQuery 是否优化
296     */
297    public void setOptimizeCountQuery(boolean optimizeCountQuery) {
298        this.optimizeCountQuery = optimizeCountQuery;
299    }
300
301    /**
302     * 是否自动优化 COUNT 查询语句(默认优化)。
303     *
304     * @return {@code true} 优化,{@code false} 不优化
305     */
306    public boolean needOptimizeCountQuery() {
307        return optimizeCountQuery;
308    }
309
310    public <R> Page<R> map(Function<? super T, ? extends R> mapper) {
311        Page<R> newPage = new Page<>();
312        newPage.pageNumber = pageNumber;
313        newPage.pageSize = pageSize;
314        newPage.totalPage = totalPage;
315        newPage.totalRow = totalRow;
316
317        if (records != null && !records.isEmpty()) {
318            List<R> newRecords = new ArrayList<>(records.size());
319            for (T t : records) {
320                newRecords.add(mapper.apply(t));
321            }
322            newPage.records = newRecords;
323        }
324        return newPage;
325    }
326
327    @Override
328    public String toString() {
329        return "Page{" +
330            "pageNumber=" + pageNumber +
331            ", pageSize=" + pageSize +
332            ", totalPage=" + totalPage +
333            ", totalRow=" + totalRow +
334            ", records=" + records +
335            '}';
336    }
337
338}