Skip to content

Commit

Permalink
Feature/v0.1.2 (#8)
Browse files Browse the repository at this point in the history
- Implementation of `ErrorKind::DatabaseError`.
- Implementation of **From** **sqlx::Error** for `PaginationError`.
- Paginate results from a SQL query into a `Page` from a PostgreSQL
database using *sqlx*. Implementation of the **PgSqlxPagination** for
`QueryBuilder`. Only available on ***pg-sqlx*** feature is enabled.
- Including unitary test for the **Debug** implementation for `Book`.
- Including checking project format in ci.yml.
- Implementation of DB migrations with sqlx for the creation of the
postgres test database.
- Implementation of integration test for pagination with pg-sqlx in CI.

- Changing the implementation of **Clone** and **Debug** using derive to
implement directly in `ErrorKind` and `PaginationError`.
- Changing the implementation of **Clone** and **Debug** using derive to
implement directly in `Page` and `Book`.
- Updating unit tests to get 100% coverage on the errors module.

- Updating project documentation to include new implementations,
utilities and development section.
  • Loading branch information
JMTamayo authored May 23, 2024
2 parents 4fa59ad + 976e05e commit 2255ac4
Show file tree
Hide file tree
Showing 19 changed files with 815 additions and 96 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ jobs:
build:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:15
env:
POSTGRES_USER: ${{ secrets.PG_DB_USER }}
POSTGRES_PASSWORD: ${{ secrets.PG_DB_PASSWORD }}
POSTGRES_DB: ${{ secrets.PG_DB_NAME }}
ports:
- 5432:5432

steps:
- uses: actions/checkout@v2

Expand All @@ -23,13 +33,30 @@ jobs:
with:
tool: cargo-llvm-cov

- name: Install SQLx CLI
run: cargo install sqlx-cli --no-default-features --features postgres

- name: Run migrations for Postgres
env:
DATABASE_URL: postgres://${{ secrets.PG_DB_USER }}:${{ secrets.PG_DB_PASSWORD }}@${{ secrets.PG_DB_HOST }}:${{ secrets.PG_DB_PORT }}/${{ secrets.PG_DB_NAME }}
run: sqlx migrate run --source page-hunter/tests/migrations/postgres

- name: Check project
uses: actions-rs/cargo@v1
with:
command: check
args: --all-features

- name: Check formatting
run: cargo fmt --all -- --check

- name: Run tests with coverage for all features
env:
PG_DB_USER: ${{ secrets.PG_DB_USER }}
PG_DB_PASSWORD: ${{ secrets.PG_DB_PASSWORD }}
PG_DB_NAME: ${{ secrets.PG_DB_NAME }}
PG_DB_HOST: ${{ secrets.PG_DB_HOST }}
PG_DB_PORT: ${{ secrets.PG_DB_PORT }}
run: cargo llvm-cov --workspace --all-features --codecov --output-path codecov.json

- name: Upload coverage to Codecov
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ check:
cargo check --all-features

test-tarpaulin:
cargo tarpaulin --all-features --out Html --output-dir page-hunter/tests
export $(shell cat local.env | xargs) && cargo tarpaulin --all-features --out Html --output-dir page-hunter/tests

test-llvm-cov:
cargo llvm-cov --html --workspace --all-features
export $(shell cat local.env | xargs) && cargo llvm-cov --html --workspace --all-features

test:
cargo test --all-features
export $(shell cat local.env | xargs) && cargo test --all-features
138 changes: 125 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![CI](https://github.com/JMTamayo/page-hunter/actions/workflows/ci.yml/badge.svg)](https://github.com/JMTamayo/page-hunter/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/JMTamayo/page-hunter/graph/badge.svg?token=R1LAPNSV5J)](https://codecov.io/gh/JMTamayo/page-hunter)
[![crates.io](https://img.shields.io/crates/v/page-hunter.svg?label=crates.io&color=orange&logo=rust)](https://crates.io/crates/page-hunter)
[![docs.rs](https://img.shields.io/static/v1?label=docs.rs&message=page-hunter&color=blue&logo=docsdotrs)](http://docs.rs/page-hunter/latest/)
[![docs.rs](https://img.shields.io/static/v1?label=docs.rs&message=latest&color=blue&logo=docsdotrs)](http://docs.rs/page-hunter/latest/)


***Page Hunter*** library is a Rust-based pagination tool that provides a way to manage and navigate through pages of data.
Expand All @@ -18,23 +18,28 @@ To use **page-hunter** from GitHub repository with specific version, set the dep

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

You can depend on it via cargo by adding the following dependency to your `Cargo.toml` file:

```ini
[dependencies]
page-hunter = { version = "0.1.1", features = ["serde"] }
page-hunter = { version = "0.1.2", features = ["serde", "pg-sqlx"] }
```

## CRATE FEATURES
- `serde`: Add [Serialize](https://docs.rs/serde/1.0.197/serde/trait.Serialize.html) and [Deserialize](https://docs.rs/serde/1.0.197/serde/trait.Deserialize.html) support for `Page` and `Book` based on crate [serde](https://crates.io/crates/serde/1.0.197). This feature is useful for implementing pagination models as a request or response body in REST APIs, among other implementations.
- `pg-sqlx`: Add support for pagination with [SQLx](https://crates.io/crates/sqlx) crate for PostgreSQL database. This feature is useful for paginating records from a PostgreSQL database.

## BASIC OPERATION
The **page-hunter** library provides two main models to manage pagination:
- `Page`: Represents a page of records with the current page, total pages, previous page, next page, and the items on the current page.
- `Book`: Represents a book of pages with a collection of `Page` instances.

### Paginate records:
The library also provides a set of functions to paginate records into a `Page` model and bind records into a `Book` model. The following examples show how to use the **page-hunter** library:

### Paginate records:
If you need to paginate records and get a specific `Page`:
```rust,no_run
use page_hunter::*;
Expand Down Expand Up @@ -78,10 +83,17 @@ On feature `serde` enabled, you can serialize and deserialize a `Page` as follow
page,
size,
total_elements,
).unwrap();
).unwrap_or_else(|error| {
panic!("Error creating page model: {:?}", error);
});
let serialized_page: String = serde_json::to_string(&page_model).unwrap();
let deserialized_page: Page<u32> = serde_json::from_str(&serialized_page).unwrap();
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);
});
```

When you create a new `Page` instance from the constructor or deserialization, the following rules are validated for the fields on the page:
Expand All @@ -95,7 +107,6 @@ When you create a new `Page` instance from the constructor or deserialization, t
If any of these rules are violated, a `PaginationError` will be returned.

### Bind records:

If you need to bind records into a `Book` model:
```rust,no_run
use page_hunter::*;
Expand All @@ -105,8 +116,6 @@ If you need to bind records into a `Book` model:
let book_result: PaginationResult<Book<u32>> =
bind_records(&records, size);
let book: Book<u32> = book_result.unwrap();
```

To create a new `Book` instance from known parameters:
Expand All @@ -121,7 +130,7 @@ To create a new `Book` instance from known parameters:
let book: Book<u32> = Book::new(&sheets);
```

On feature `serde` enabled, you can serialize and deserialize a [`Book`] as follows:
On feature `serde` enabled, you can serialize and deserialize a `Book` as follows:
```rust,no_run
use page_hunter::*;
Expand All @@ -132,8 +141,111 @@ On feature `serde` enabled, you can serialize and deserialize a [`Book`] as foll
let book: Book<u32> = Book::new(&sheets);
let serialized_book: String = serde_json::to_string(&book).unwrap();
let deserialized_book: Book<u32> = serde_json::from_str(&serialized_book).unwrap();
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);
});
```

#### Paginate records from a PostgreSQL database with SQLx:
If you need to paginate records from a PostgreSQL database using the [SQLx](https://crates.io/crates/sqlx) crate:
```rust,no_run
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);
});
}
```

## DEVELOPMENT
To test `page-hunter`, follow these recommendations:

#### Set env variables:
Create `local.env` file at workspace folder to store the required environment variables
```text
PG_DB_HOST=localhost
PG_DB_PORT=5432
PG_DB_USER=test
PG_DB_PASSWORD=docker
PG_DB_NAME=test
```

#### Setup databases:
Run databases as Docker containers using the following commands:

##### Postgres SQL:
```bash
docker run --name postgres-db -e POSTGRES_PASSWORD=docker -e POSTGRES_DB=test -e POSTGRES_USER=test -p 5432:5432 postgres
```

#### Run database migrations:
##### Postgres SQL
- Install sqlx-cli for postgres:
```bash
cargo install sqlx-cli --no-default-features --features postgres
```

- Export DATABASE_URL:
```bash
export DATABASE_URL=postgres://test:docker@localhost:5432/test
```

- Run migrations:
```bash
sqlx migrate run --source page-hunter/tests/migrations/postgres
```

#### To test:
```bash
make test
```

#### To test using tarpaulin:
- Install cargo-tarpaulin:
```bash
cargo install cargo-tarpaulin
```

- Run tests:
```bash
make test-tarpaulin
```

#### To test using llvm-cov:
- Install llvm-cov:
```bash
cargo install cargo-llvm-cov
```

- Run tests:
```bash
make test-llvm-cov
```

## CONTRIBUTIONS
Expand Down
28 changes: 25 additions & 3 deletions page-hunter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,42 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 🚀 v0.1.2 [2024-05-22]

### Added:

- 🧑🏻‍💻 Implementation of `ErrorKind::DatabaseError`.
- 🧑🏻‍💻 Implementation of **From** **sqlx::Error** for `PaginationError`.
- 🧑🏻‍💻 Paginate results from a SQL query into a `Page` from a PostgreSQL database using *sqlx*. Implementation of the **PgSqlxPagination** for `QueryBuilder`. Only available on ***pg-sqlx*** feature is enabled.
- 🧑🏻‍💻 Including unitary test for the **Debug** implementation for `Book`.
- 🧑🏻‍💻 Including checking project format in ci.yml.
- 🧑🏻‍💻 Implementation of DB migrations with sqlx for the creation of the postgres test database.
- 🧑🏻‍💻 Implementation of integration test for pagination with pg-sqlx in CI.

### Changed:

- 🔨 Changing the implementation of **Clone** and **Debug** using derive to implement directly in `ErrorKind` and `PaginationError`.
- 🔨 Changing the implementation of **Clone** and **Debug** using derive to implement directly in `Page` and `Book`.
- 🔨 Updating unit tests to get 100% coverage on the errors module.

### Docs:

- 📝 Updating project documentation to include new implementations, utilities and development section.

## 🚀 v0.1.1 [2024-05-18]

### Added:

- 🧑🏻‍💻 Implementation of `Book` model for binding uses.
- 🧑🏻‍💻 Implementation of **Default**, **Clone**, **Debug**, **Display** and **IntoIterator** in `Book` model for default feature.
- 🧑🏻‍💻 Implementation of **Serialize** and **Deserialize** in `Book` model for feature **serde**.
- 🧑🏻‍💻 Implementation of **Serialize** and **Deserialize** in `Book` model for feature ***serde***.
- 🧑🏻‍💻 Implementation of `bind_records()` function for binding uses.
- 🧑🏻‍💻 Implementation of unitary tests for `bind_records()` and `Book` model.
- 🧑🏻‍💻 Codecov implementation to verify 90% of coverage in unit tests.

### Changed:

- 🔨 Changing the implementation of Serialize trait using derive to implement directly in `Page` and `Book` models.
- 🔨 Changing the implementation of **Serialize** trait using derive to implement directly in `Page` and `Book` models.

### Docs:

Expand All @@ -32,7 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- 🧑🏻‍💻 Implementation of `Page` model for pagination uses.
- 🧑🏻‍💻 Implementation of **Default**, **Clone**, **Debug**, **Display** and **IntoIterator** in `Page` model for default feature.
- 🧑🏻‍💻 Implementation of **Serialize** and **Deserialize** in `Page` model for feature **serde**.
- 🧑🏻‍💻 Implementation of **Serialize** and **Deserialize** in `Page` model for feature ***serde***.
- 🧑🏻‍💻 Implementation of `paginate_records()` function for record pagination.
- 🧑🏻‍💻 Implementation of unitary tests for `paginate_records()` and `Page` model.
- 🧑🏻‍💻 Implementation of CI workflow with GitHub actions to verify unit testing.
Expand Down
9 changes: 7 additions & 2 deletions page-hunter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "page-hunter"
description = "The pagination powerhouse, built with Rust"
version = "0.1.1"
version = "0.1.2"
authors = [
"Juan Manuel Tamayo <[email protected]>",
]
Expand All @@ -21,10 +21,15 @@ categories = [
]

[dependencies]
serde = { version = "1.0.202", features = ["derive"], optional = true }
serde = { version = "1.0.202", optional = true }
sqlx = { version = "0.7.4", features = ["runtime-tokio", "uuid", "time", "chrono", "json", "postgres"], optional = true }

[dev-dependencies]
serde_json = { version = "1.0.117" }
tokio = { version = "1.37.0", features =["full"] }
uuid = { version = "1.8.0" }
time = { version = "0.3.36" }

[features]
serde = ["dep:serde"]
pg-sqlx = ["dep:sqlx"]
Loading

0 comments on commit 2255ac4

Please sign in to comment.