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