robinpath_modules/modules/
pagination_mod.rs1use robinpath::{RobinPath, Value};
2
3pub fn register(rp: &mut RobinPath) {
4 rp.register_builtin("pagination.paginate", |args, _| {
6 let total_items = args.first().map(|v| v.to_number()).unwrap_or(0.0) as i64;
7 let current_page = args.get(1).map(|v| v.to_number()).unwrap_or(1.0) as i64;
8 let page_size = args.get(2).map(|v| v.to_number()).unwrap_or(10.0) as i64;
9
10 let page_size = page_size.max(1);
11 let total_pages = if total_items <= 0 {
12 0
13 } else {
14 (total_items + page_size - 1) / page_size
15 };
16 let current_page = current_page.clamp(1, total_pages.max(1));
17 let start_index = (current_page - 1) * page_size;
18 let end_index = (start_index + page_size - 1).min(total_items - 1).max(0);
19 let has_next = current_page < total_pages;
20 let has_prev = current_page > 1;
21
22 let mut obj = indexmap::IndexMap::new();
23 obj.insert("totalItems".to_string(), Value::Number(total_items as f64));
24 obj.insert("pageSize".to_string(), Value::Number(page_size as f64));
25 obj.insert("currentPage".to_string(), Value::Number(current_page as f64));
26 obj.insert("totalPages".to_string(), Value::Number(total_pages as f64));
27 obj.insert("startIndex".to_string(), Value::Number(start_index as f64));
28 obj.insert("endIndex".to_string(), Value::Number(end_index as f64));
29 obj.insert("hasNext".to_string(), Value::Bool(has_next));
30 obj.insert("hasPrev".to_string(), Value::Bool(has_prev));
31 Ok(Value::Object(obj))
32 });
33
34 rp.register_builtin("pagination.offset", |args, _| {
36 let page = args.first().map(|v| v.to_number()).unwrap_or(1.0) as i64;
37 let page_size = args.get(1).map(|v| v.to_number()).unwrap_or(10.0) as i64;
38 let offset = (page.max(1) - 1) * page_size.max(1);
39 Ok(Value::Number(offset as f64))
40 });
41
42 rp.register_builtin("pagination.cursor", |args, _| {
44 let items = match args.first() {
45 Some(Value::Array(arr)) => arr.clone(),
46 _ => return Err("pagination.cursor expects an array as first argument".to_string()),
47 };
48 let cursor_field = args.get(1).map(|v| v.to_display_string()).unwrap_or_else(|| "id".to_string());
49 let limit = args.get(2).map(|v| v.to_number()).unwrap_or(10.0) as usize;
50
51 let has_more = items.len() > limit;
52 let page_items: Vec<Value> = items.into_iter().take(limit).collect();
53
54 let next_cursor = if has_more {
55 if let Some(Value::Object(last)) = page_items.last() {
57 last.get(&cursor_field)
58 .cloned()
59 .unwrap_or(Value::Null)
60 } else {
61 Value::Null
62 }
63 } else {
64 Value::Null
65 };
66
67 let mut obj = indexmap::IndexMap::new();
68 obj.insert("items".to_string(), Value::Array(page_items));
69 obj.insert("nextCursor".to_string(), next_cursor);
70 obj.insert("hasMore".to_string(), Value::Bool(has_more));
71 Ok(Value::Object(obj))
72 });
73
74 rp.register_builtin("pagination.hasNext", |args, _| {
76 let current_page = args.first().map(|v| v.to_number()).unwrap_or(1.0) as i64;
77 let total_pages = args.get(1).map(|v| v.to_number()).unwrap_or(1.0) as i64;
78 Ok(Value::Bool(current_page < total_pages))
79 });
80
81 rp.register_builtin("pagination.hasPrev", |args, _| {
83 let current_page = args.first().map(|v| v.to_number()).unwrap_or(1.0) as i64;
84 Ok(Value::Bool(current_page > 1))
85 });
86
87 rp.register_builtin("pagination.totalPages", |args, _| {
89 let total_items = args.first().map(|v| v.to_number()).unwrap_or(0.0) as i64;
90 let page_size = args.get(1).map(|v| v.to_number()).unwrap_or(10.0) as i64;
91 let page_size = page_size.max(1);
92 let total_pages = if total_items <= 0 {
93 0
94 } else {
95 (total_items + page_size - 1) / page_size
96 };
97 Ok(Value::Number(total_pages as f64))
98 });
99}