#pagination #page-model #paginator

page-hunter

分页强大工具,使用 Rust 构建

2 个不稳定版本

0.2.0 2024 年 6 月 1 日
0.1.4 2024 年 5 月 30 日

#377开发工具

Download history 315/week @ 2024-05-13 309/week @ 2024-05-20 315/week @ 2024-05-27 28/week @ 2024-06-03 10/week @ 2024-06-10

369 每月下载

自定义许可

47KB
681

页面猎手

License: MIT dependency status CI codecov crates.io docs.rs

页面猎手 库是一个基于 Rust 的分页工具,提供了一种管理和导航数据页面的方法。它提供了一套资源,封装了所有必要的分页信息,例如当前页、总页数、上一页、下一页以及当前页上的项目。

该库还包括验证方法以确保分页数据的完整性。它旨在灵活且易于集成到任何需要分页功能的标准数据验证的 Rust 项目中。

要从 GitHub 仓库使用特定版本的 page-hunter,请在 Cargo.toml 文件中设置依赖项如下

[dependencies]
page-hunter = { git = "https://github.com/JMTamayo/page-hunter.git", version = "0.2.0", features = ["serde"] }

您可以通过向您的 Cargo.toml 文件添加以下依赖项来依赖它

[dependencies]
page-hunter = { version = "0.2.0", features = ["utoipa", "pg-sqlx"] }

CRATE 特性

  • serde: 为 PageBook 添加基于 serdeSerializeDeserialize 支持。此功能对于在 REST API 中实现分页模型作为请求或响应体非常有用。
  • utoipa: 为 PageBook 添加基于 utoipaToSchema 支持。此功能对于生成分页模型的 OpenAPI 架构非常有用。此功能依赖于 serde 特性,因此您只需实现 utoipa 即可同时获得两者。
  • pg-sqlx: 为 PostgreSQL 数据库添加与 SQLx 的分页支持。
  • mysql-sqlx: 为 MySQL 数据库添加与 SQLx 的分页支持。

基本操作

page-hunter 库提供了两种主要模型来管理分页

  • Page: 代表一个记录页,包含当前页、总页数、上一页、下一页以及当前页上的项目。
  • Book: 代表一个页面集,包含一系列 Page 实例。

该库还提供了一套函数,将记录分页到 Page 模型,并将记录绑定到 Book 模型。以下示例展示了如何使用 page-hunter

分页记录

如果您需要分页记录并获取特定的 Page 页面

    use page_hunter::*;

    let records: Vec<u32> = vec![1, 2, 3, 4, 5];
    let page: usize = 0;
    let size: usize = 2;

    let pagination_result: PaginationResult<Page<u32>> =
        paginate_records(&records, page, size);

要从已知参数创建一个 Page 实例

    use page_hunter::*;

    let items: Vec<u32> = vec![1, 2];
    let page: usize = 0;
    let size: usize = 2;
    let total_elements: usize = 5;

    let page_model_result: PaginationResult<Page<u32>> = Page::new(
        &items,
        page,
        size,
        total_elements,
    );

在启用 serde 功能的情况下,您可以按照以下方式序列化和反序列化一个 Page

    use page_hunter::*;

    let items: Vec<u32> = vec![1, 2];
    let page: usize = 0;
    let size: usize = 2;
    let total_elements: usize = 5;

    let page_model: PaginationResult<Page<u32>> = Page::new(
        &items,
        page,
        size,
        total_elements,
    ).unwrap_or_else(|error| {
        panic!("Error creating page model: {:?}", error);
    });

    let serialized_page: String = serde_json::to_string(&page_model).unwrap_or_else(|error| {
        panic!("Error serializing page model: {:?}", error);
    });

    let deserialized_page: Page<u32> = serde_json::from_str(&serialized_page).unwrap_or_else(|error| {
        panic!("Error deserializing page model: {:?}", error);
    });

当您从构造函数或反序列化创建一个新的 Page 实例时,对页面上的字段进行以下验证

  • pages 必须等于 total 除以 size 并向上取整。当 size 为 0 时,pages 必须为 1。
  • page 必须小于或等于 pages - 1。
  • 如果 page 小于 pages - 1,则 items 的长度必须等于 size
  • 如果 page 等于 pages - 1,则 total 必须等于 (pages - 1) * size + items 的长度。
  • previous_page 必须等于 page - 1,如果 page 大于 0,否则它必须是 None
  • next_page 必须等于 page + 1,如果 page 小于 pages - 1,否则它必须是 None

如果违反了这些规则中的任何一个,将返回一个 PaginationError

绑定记录

如果您需要将记录绑定到 Book 模型

    use page_hunter::*;

    let records: Vec<u32> = vec![1, 2, 3, 4, 5];
    let size: usize = 2;

    let book_result: PaginationResult<Book<u32>> =
        bind_records(&records, size);

要从已知参数创建一个 Book 实例

    use page_hunter::*;

    let sheets: Vec<Page<u32>> = vec![
        Page::new(&vec![1, 2], 0, 2, 5).unwrap(),
        Page::new(&vec![3, 4], 1, 2, 5).unwrap(),
    ];

    let book: Book<u32> = Book::new(&sheets);

在启用 serde 功能的情况下,您可以按照以下方式序列化和反序列化一个 Book

    use page_hunter::*;

    let sheets: Vec<Page<u32>> = vec![
        Page::new(&vec![1, 2], 0, 2, 5).unwrap(),
        Page::new(&vec![3, 4], 1, 2, 5).unwrap(),
    ];

    let book: Book<u32> = Book::new(&sheets);

    let serialized_book: String = serde_json::to_string(&book).unwrap_or_else(|error| {
        panic!("Error serializing book model: {:?}", error);
    });

    let deserialized_book: Book<u32> = serde_json::from_str(&serialized_book).unwrap_or_else(|error| {
        panic!("Error deserializing book model: {:?}", error);
    });

生成 OpenAPI 架构

在启用 utoipa 功能的情况下,您可以按照以下方式为 PageBook 模型生成 OpenAPI 架构

   use page_hunter::*;
   use utoipa::ToSchema;
   use serde::{Deserialize, Serialize};

   #[derive(Clone, ToSchema)]
   pub struct Person {
       id: u16,
       name: String,
       last_name: String,
       still_alive: bool,
   }

   pub type PeoplePage = Page<Person>;
   pub type PeopleBook = Book<Person>;

   #[derive(OpenApi)]
   #[openapi(
       components(schemas(PeoplePage, PeopleBook))
   )]
   pub struct ApiDoc;

请查看 示例 文件夹,其中包含一些 Web 框架中 REST API 实现的实用示例。

使用 SQLx 从 PostgreSQL 数据库分页记录

从 PostgreSQL 数据库分页记录

    use page_hunter::*;
    use sqlx::postgres::{PgPool, Postgres};
    use sqlx::{FromRow, QueryBuilder};
    use uuid::Uuid;

    #[tokio::main]
    async fn main() {
        #[derive(Clone, Debug, FromRow)]
        pub struct Country {
            id: Uuid,
            name: String,
        }

        let pool: PgPool = PgPool::connect(
            "postgres://username:password@localhost/db"
        ).await.unwrap_or_else(|error| {
           panic!("Error connecting to database: {:?}", error);
       });

        let query: QueryBuilder<Postgres> = QueryBuilder::new(
            "SELECT * FROM db.geo.countries"
        );

        let page: Page<Country> =
            query.paginate(&pool, 0, 10).await.unwrap_or_else(|error| {
                panic!("Error paginating records: {:?}", error);
            });
    }

从 MySQL 数据库分页记录

    use page_hunter::*;
    use sqlx::mysql::{MySqlPool, MySql};
    use sqlx::{FromRow, QueryBuilder};
    use uuid::Uuid;

    #[tokio::main]
    async fn main() {
        #[derive(Clone, Debug, FromRow)]
        pub struct Country {
            id: Uuid,
            name: String,
        }

        let pool: MySqlPool = MySqlPool::connect(
            "mysql://username:password@localhost/db"
        ).await.unwrap_or_else(|error| {
            panic!("Error connecting to database: {:?}", error);
        });

        let query: QueryBuilder<MySql> = QueryBuilder::new(
            "SELECT * FROM countries"
        );

        let page: Page<Country> =
            query.paginate(&pool, 0, 10).await.unwrap_or_else(|error| {
               panic!("Error paginating records: {:?}", error);
            });
    }

开发

要测试 page-hunter,请遵循以下建议

设置环境变量

在工作空间文件夹中创建 local.env 文件以存储所需的环境变量

    DB_HOST=localhost
    DB_USER=test
    DB_PASSWORD=docker
    DB_NAME=test
    PG_DB_PORT=5432
    MYSQL_DB_PORT=3306

设置数据库

使用以下命令以 Docker 容器运行数据库

Postgres SQL
    make pg-db-docker 
MySQL
    make mysql-db-docker

运行数据库迁移

  • 安装 sqlx-cli
    make install-sqlx-cli
Postgres SQL
  • 运行迁移
    make run-postgres-migrations
  • 撤销迁移
    make revert-postgres-migrations
MySQL
  • 运行迁移
    make run-mysql-migrations
  • 撤销迁移
    make revert-mysql-migrations

测试

    make test

使用 tarpaulin 进行测试

  • 安装 cargo-tarpaulin
    make install-tarpaulin
  • 运行测试
    make test-tarpaulin

使用 llvm-cov 进行测试

  • 安装 llvm-cov
    make install-llvm-cov
  • 运行测试
    make test-llvm-cov

贡献

Page Hunter 项目是开源的,因此任何感兴趣的软件开发者都可以为其改进做出贡献。要做出贡献,请查看以下建议

  • 错误报告:如果您发现了一个错误,请创建一个问题,详细说明问题、重现步骤和预期行为。
  • 功能请求:如果您有一个新功能或对现有功能进行改进的想法,请创建一个问题来描述您的想法。
  • 拉取请求:如果您修复了一个错误或实现了一个新的功能,我们非常愿意看到您的工作!请提交一个拉取请求。请确保您的代码遵循现有的风格并且所有测试都通过。

依赖项

~0–15MB
~145K SLoC