CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-mybatis-flex--mybatis-flex-core

MyBatis-Flex is an elegant enhancement framework for MyBatis providing type-safe query building, active record patterns, and comprehensive ORM capabilities

Pending
Overview
Eval results
Files

pagination.mddocs/

Pagination Support

Comprehensive pagination with performance optimizations, count query optimization, and type conversion support. MyBatis-Flex provides efficient pagination for large datasets with database-specific optimizations.

Capabilities

Page Class

Comprehensive pagination object that encapsulates pagination parameters, results, and metadata.

/**
 * Comprehensive pagination object
 * @param <T> Record type
 */
public class Page<T> {
    /**
     * Create page with page number and size
     * @param pageNumber page number (1-based)
     * @param pageSize number of records per page
     */
    public Page(int pageNumber, int pageSize);
    
    /**
     * Create page with count query optimization setting
     * @param pageNumber page number (1-based)
     * @param pageSize number of records per page
     * @param optimizeCountQuery whether to optimize count query
     */
    public Page(int pageNumber, int pageSize, boolean optimizeCountQuery);
    
    /**
     * Get current page records
     * @return list of records for current page
     */
    public List<T> getRecords();
    
    /**
     * Set current page records
     * @param records records to set
     */
    public void setRecords(List<T> records);
    
    /**
     * Get total number of records
     * @return total record count
     */
    public long getTotalRow();
    
    /**
     * Set total number of records
     * @param totalRow total record count
     */
    public void setTotalRow(long totalRow);
    
    /**
     * Get total number of pages
     * @return total page count
     */
    public int getTotalPage();
    
    /**
     * Get current page number (1-based)
     * @return current page number
     */
    public int getPageNumber();
    
    /**
     * Set current page number
     * @param pageNumber page number to set
     */
    public void setPageNumber(int pageNumber);
    
    /**
     * Get page size
     * @return number of records per page
     */
    public int getPageSize();
    
    /**
     * Set page size
     * @param pageSize records per page
     */
    public void setPageSize(int pageSize);
    
    /**
     * Check if count query optimization is enabled
     * @return true if optimization enabled
     */
    public boolean isOptimizeCountQuery();
    
    /**
     * Set count query optimization
     * @param optimizeCountQuery optimization flag
     */
    public void setOptimizeCountQuery(boolean optimizeCountQuery);
    
    /**
     * Check if there is a previous page
     * @return true if has previous page
     */
    public boolean hasPrevious();
    
    /**
     * Check if there is a next page
     * @return true if has next page
     */
    public boolean hasNext();
    
    /**
     * Get offset for current page (0-based)
     * @return record offset
     */
    public long getOffset();
    
    /**
     * Convert page to different type
     * @param mapper function to convert records
     * @return new page with converted records
     */
    public <R> Page<R> convert(Function<T, R> mapper);
    
    /**
     * Convert page using list transformation
     * @param records new records list
     * @return new page with provided records
     */
    public <R> Page<R> convert(List<R> records);
}

Basic Pagination Usage:

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;

public class BasicPaginationExample {
    public void demonstrateBasicPagination() {
        UserMapper userMapper = // ... get mapper instance
        
        // Create page parameters (page 1, 10 records per page)
        Page<User> page = new Page<>(1, 10);
        
        // Execute paginated query
        QueryWrapper query = QueryWrapper.create()
            .select()
            .from(User.class)
            .where(USER.ACTIVE.eq(true))
            .orderBy(USER.CREATE_TIME.desc());
        
        Page<User> result = userMapper.paginate(page, query);
        
        // Access pagination information
        System.out.println("Current page: " + result.getPageNumber());
        System.out.println("Page size: " + result.getPageSize());
        System.out.println("Total records: " + result.getTotalRow());
        System.out.println("Total pages: " + result.getTotalPage());
        System.out.println("Has next page: " + result.hasNext());
        System.out.println("Has previous page: " + result.hasPrevious());
        
        // Access current page records
        List<User> users = result.getRecords();
        for (User user : users) {
            System.out.println("User: " + user.getName());
        }
    }
}

Performance Optimizations

Advanced pagination features for performance optimization in large datasets.

/**
 * Performance-optimized pagination options
 */
public class Page<T> {
    /**
     * Enable/disable count query optimization
     * When enabled, skips total count query for better performance
     * @param optimizeCountQuery optimization flag
     */
    public void setOptimizeCountQuery(boolean optimizeCountQuery);
    
    /**
     * Set search count flag
     * When false, skips count query entirely
     * @param searchCount whether to perform count query
     */
    public void setSearchCount(boolean searchCount);
    
    /**
     * Check if search count is enabled
     * @return true if count query will be performed
     */
    public boolean isSearchCount();
    
    /**
     * Set custom count query SQL
     * @param countSql custom count SQL
     */
    public void setCountSql(String countSql);
    
    /**
     * Get custom count query SQL
     * @return custom count SQL or null
     */
    public String getCountSql();
}

Performance Optimization Examples:

public class PaginationOptimizationExample {
    public void demonstrateOptimizations() {
        UserMapper userMapper = // ... get mapper instance
        
        // Standard pagination with count query
        Page<User> standardPage = new Page<>(1, 10);
        Page<User> standardResult = userMapper.paginate(standardPage, query);
        // Executes both data query and count query
        
        // Optimized pagination (skips unnecessary count operations)
        Page<User> optimizedPage = new Page<>(1, 10, true);
        Page<User> optimizedResult = userMapper.paginate(optimizedPage, query);
        // Optimizes count query for better performance
        
        // Skip count query entirely for performance
        Page<User> noCountPage = new Page<>(1, 10);
        noCountPage.setSearchCount(false);
        Page<User> noCountResult = userMapper.paginate(noCountPage, query);
        // Only executes data query, no count query
        System.out.println("Total rows: " + noCountResult.getTotalRow()); // Will be 0
        
        // Custom count query for complex scenarios
        Page<User> customCountPage = new Page<>(1, 10);
        customCountPage.setCountSql("SELECT COUNT(*) FROM users u WHERE u.active = 1");
        Page<User> customCountResult = userMapper.paginate(customCountPage, query);
        // Uses custom count SQL instead of generated one
    }
}

Type Conversion

Convert pagination results to different types while maintaining pagination metadata.

/**
 * Type conversion methods for pagination results
 */
public class Page<T> {
    /**
     * Convert page records using mapper function
     * @param mapper function to transform each record
     * @return new page with converted records
     */
    public <R> Page<R> convert(Function<T, R> mapper);
    
    /**
     * Convert page records using provided list
     * @param records new records list
     * @return new page with provided records  
     */
    public <R> Page<R> convert(List<R> records);
}

Type Conversion Examples:

public class PaginationConversionExample {
    public void demonstrateConversion() {
        // Original pagination with User entities
        Page<User> userPage = userMapper.paginate(
            new Page<>(1, 10),
            QueryWrapper.create()
                .select()
                .from(User.class)
                .where(USER.ACTIVE.eq(true))
        );
        
        // Convert to DTO using mapper function
        Page<UserDTO> dtoPage = userPage.convert(user -> {
            UserDTO dto = new UserDTO();
            dto.setId(user.getId());
            dto.setName(user.getName());
            dto.setEmail(user.getEmail());
            dto.setDisplayName(user.getName() + " (" + user.getEmail() + ")");
            return dto;
        });
        
        // Pagination metadata is preserved
        System.out.println("DTO Page - Total: " + dtoPage.getTotalRow());
        System.out.println("DTO Page - Pages: " + dtoPage.getTotalPage());
        
        // Convert using pre-built list
        List<UserSummary> summaries = userPage.getRecords().stream()
            .map(user -> new UserSummary(user.getId(), user.getName()))
            .collect(Collectors.toList());
        
        Page<UserSummary> summaryPage = userPage.convert(summaries);
        
        // Method chaining with conversion
        Page<String> nameOnlyPage = userPage.convert(User::getName);
        List<String> userNames = nameOnlyPage.getRecords();
    }
}

Service Layer Integration

Pagination support in service layer with enhanced functionality.

/**
 * Service layer pagination methods
 */
public interface IService<T> {
    /**
     * Paginate all entities
     * @param page pagination parameters
     * @return page of entities
     */
    Page<T> page(Page<T> page);
    
    /**
     * Paginate entities with query conditions
     * @param page pagination parameters
     * @param queryWrapper query conditions
     * @return page of entities
     */
    Page<T> page(Page<T> page, QueryWrapper queryWrapper);
    
    /**
     * Paginate with type transformation
     * @param page pagination parameters
     * @param queryWrapper query conditions
     * @param asType target type class
     * @return page of transformed objects
     */
    <R> Page<R> pageAs(Page<R> page, QueryWrapper queryWrapper, Class<R> asType);
}

Service Layer Pagination Examples:

@Service
public class UserServiceImpl implements UserService {
    
    public Page<UserDTO> getActiveUsers(int pageNum, int pageSize) {
        Page<User> page = new Page<>(pageNum, pageSize);
        
        // Service layer pagination
        Page<User> userPage = page(page, 
            QueryWrapper.create()
                .from(User.class)
                .where(USER.ACTIVE.eq(true))
                .orderBy(USER.CREATE_TIME.desc())
        );
        
        // Convert to DTO
        return userPage.convert(this::convertToDTO);
    }
    
    public Page<UserSummaryDTO> getUserSummaries(int pageNum, int pageSize, String nameFilter) {
        Page<UserSummaryDTO> page = new Page<>(pageNum, pageSize);
        
        QueryWrapper query = QueryWrapper.create()
            .select(USER.ID, USER.NAME, USER.EMAIL, USER.CREATE_TIME)
            .from(User.class)
            .where(USER.ACTIVE.eq(true));
            
        if (nameFilter != null && !nameFilter.isEmpty()) {
            query.and(USER.NAME.like("%" + nameFilter + "%"));
        }
        
        // Direct type transformation in service
        return pageAs(page, query, UserSummaryDTO.class);
    }
    
    private UserDTO convertToDTO(User user) {
        UserDTO dto = new UserDTO();
        dto.setId(user.getId());
        dto.setName(user.getName());
        dto.setEmail(user.getEmail());
        dto.setAge(user.getAge());
        dto.setCreateTime(user.getCreateTime());
        return dto;
    }
}

Database-Specific Pagination

MyBatis-Flex automatically generates database-specific pagination SQL for optimal performance.

/**
 * Database-specific pagination is handled automatically by dialects
 * No additional configuration required
 */
public class DatabaseSpecificPagination {
    public void demonstrateDatabaseSpecificPagination() {
        Page<User> page = new Page<>(2, 15); // Page 2, 15 records per page
        QueryWrapper query = QueryWrapper.create()
            .select()
            .from(User.class)
            .where(USER.ACTIVE.eq(true))
            .orderBy(USER.NAME.asc());
        
        // MyBatis-Flex generates database-specific SQL:
        
        // MySQL/PostgreSQL/H2:
        // SELECT * FROM users WHERE active = 1 ORDER BY name ASC LIMIT 15 OFFSET 15
        
        // SQL Server 2012+:
        // SELECT * FROM users WHERE active = 1 ORDER BY name ASC 
        // OFFSET 15 ROWS FETCH NEXT 15 ROWS ONLY
        
        // Oracle 12c+:
        // SELECT * FROM users WHERE active = 1 ORDER BY name ASC 
        // OFFSET 15 ROWS FETCH NEXT 15 ROWS ONLY
        
        // Oracle (traditional):
        // SELECT * FROM (
        //   SELECT ROWNUM rn, t.* FROM (
        //     SELECT * FROM users WHERE active = 1 ORDER BY name ASC
        //   ) t WHERE ROWNUM <= 30
        // ) WHERE rn > 15
        
        Page<User> result = userMapper.paginate(page, query);
    }
}

Navigation Helpers

Convenient methods for pagination navigation and metadata.

/**
 * Navigation and metadata helper methods
 */
public class Page<T> {
    /**
     * Check if current page is first page
     * @return true if first page
     */
    public boolean isFirstPage();
    
    /**
     * Check if current page is last page
     * @return true if last page
     */
    public boolean isLastPage();
    
    /**
     * Get previous page number (null if no previous)
     * @return previous page number or null
     */
    public Integer getPreviousPage();
    
    /**
     * Get next page number (null if no next)
     * @return next page number or null
     */
    public Integer getNextPage();
    
    /**
     * Calculate page numbers for pagination UI
     * @param displayCount number of page links to display
     * @return list of page numbers for UI
     */
    public List<Integer> getPageNumbers(int displayCount);
    
    /**
     * Get start record number (1-based)
     * @return start record number
     */
    public long getStartRow();
    
    /**
     * Get end record number (1-based)  
     * @return end record number
     */
    public long getEndRow();
}

Navigation Examples:

public class PaginationNavigationExample {
    public void demonstrateNavigation() {
        Page<User> result = userMapper.paginate(new Page<>(3, 10), query);
        
        // Navigation checks
        System.out.println("Is first page: " + result.isFirstPage()); // false
        System.out.println("Is last page: " + result.isLastPage()); // depends on data
        System.out.println("Has previous: " + result.hasPrevious()); // true
        System.out.println("Has next: " + result.hasNext()); // depends on data
        
        // Page numbers
        Integer prevPage = result.getPreviousPage(); // 2
        Integer nextPage = result.getNextPage(); // 4 or null
        
        // UI pagination helper
        List<Integer> pageNumbers = result.getPageNumbers(5);
        // For page 3: [1, 2, 3, 4, 5] or similar range
        
        // Record range
        System.out.println("Showing records " + result.getStartRow() + 
                          " to " + result.getEndRow() + 
                          " of " + result.getTotalRow());
        // Output: "Showing records 21 to 30 of 157"
    }
}

Types

// Core pagination types
public class Page<T> {
    public Page(int pageNumber, int pageSize);
    public Page(int pageNumber, int pageSize, boolean optimizeCountQuery);
    
    public List<T> getRecords();
    public long getTotalRow();
    public int getTotalPage();
    public int getPageNumber();
    public int getPageSize();
    
    public <R> Page<R> convert(Function<T, R> mapper);
}

// Functional interface for conversion
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

// Standard Java collections
public interface List<E> extends Collection<E> {
    E get(int index);
    int size();
    boolean isEmpty();
}

// Optional for navigation
public interface Optional<T> {
    boolean isPresent();
    T get();
    T orElse(T other);
}

Install with Tessl CLI

npx tessl i tessl/maven-com-mybatis-flex--mybatis-flex-core

docs

active-record.md

bootstrap-config.md

crud-operations.md

database-support.md

index.md

pagination.md

query-builder.md

row-operations.md

service-layer.md

update-chain.md

tile.json