aster_forge_db/
pagination.rs1use sea_orm::{ConnectionTrait, EntityTrait, PaginatorTrait, QuerySelect, Select};
8
9use crate::DbError;
10
11pub async fn fetch_offset_page<C, Entity, Error>(
17 db: &C,
18 query: Select<Entity>,
19 limit: u64,
20 offset: u64,
21) -> std::result::Result<(Vec<Entity::Model>, u64), Error>
22where
23 C: ConnectionTrait,
24 Entity: EntityTrait,
25 Error: From<DbError>,
26 Select<Entity>: QuerySelect,
27 for<'db> Select<Entity>: PaginatorTrait<'db, C>,
28{
29 let total = query
30 .clone()
31 .count(db)
32 .await
33 .map_err(DbError::from)
34 .map_err(Error::from)?;
35 let items = query
36 .limit(limit)
37 .offset(offset)
38 .all(db)
39 .await
40 .map_err(DbError::from)
41 .map_err(Error::from)?;
42 Ok((items, total))
43}
44
45#[cfg(test)]
46mod tests {
47 use super::fetch_offset_page;
48 use sea_orm::{
49 ActiveModelBehavior, ConnectionTrait, Database, DeriveEntityModel, DerivePrimaryKey,
50 DeriveRelation, EntityTrait, EnumIter, PrimaryKeyTrait, QueryOrder,
51 };
52
53 #[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
54 #[sea_orm(table_name = "pagination_items")]
55 pub struct Model {
56 #[sea_orm(primary_key)]
57 pub id: i32,
58 pub name: String,
59 }
60
61 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
62 pub enum Relation {}
63
64 impl ActiveModelBehavior for ActiveModel {}
65
66 #[tokio::test]
67 async fn fetch_offset_page_returns_items_and_total_count() {
68 let db = Database::connect("sqlite::memory:")
69 .await
70 .expect("sqlite memory database should connect");
71 db.execute_unprepared(
72 "CREATE TABLE pagination_items (id INTEGER PRIMARY KEY, name TEXT NOT NULL);",
73 )
74 .await
75 .expect("table should be created");
76 db.execute_unprepared(
77 "INSERT INTO pagination_items (id, name) VALUES (1, 'alpha'), (2, 'beta'), (3, 'gamma');",
78 )
79 .await
80 .expect("rows should be inserted");
81
82 let (items, total) = fetch_offset_page::<_, _, crate::DbError>(
83 &db,
84 Entity::find().order_by_asc(Column::Id),
85 2,
86 1,
87 )
88 .await
89 .expect("page should load");
90
91 assert_eq!(total, 3);
92 assert_eq!(
93 items.into_iter().map(|item| item.name).collect::<Vec<_>>(),
94 vec!["beta".to_string(), "gamma".to_string()]
95 );
96 }
97}