Skip to content

Commit c9e520d

Browse files
committed
feat: implementar paginação com limite e chave de início no Quickleaf
1 parent 9f10fe1 commit c9e520d

File tree

8 files changed

+633
-15
lines changed

8 files changed

+633
-15
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "quickleaf"
3-
version = "0.4.7"
3+
version = "0.4.8"
44
edition = "2021"
55
license = "Apache-2.0"
66
authors = ["Philippe Assis <codephilippe@gmail.com>"]

README.md

Lines changed: 234 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -209,41 +209,263 @@ fn main() {
209209

210210
### 📋 Pagination and Ordering
211211

212+
Quickleaf provides powerful pagination capabilities through `limit` and `start_after_key` parameters, enabling efficient navigation through large datasets.
213+
214+
#### Basic Pagination with `limit`
215+
216+
The `limit` parameter controls how many items are returned in a single query:
217+
212218
```rust
213219
use quickleaf::{Quickleaf, ListProps, Order};
214220

215221
fn main() {
216222
let mut cache = Quickleaf::new(100);
217223

218-
// Add some test data
219-
for i in 1..=20 {
220-
cache.insert(format!("item_{:02}", i), i);
224+
// Add test data
225+
for i in 0..50 {
226+
cache.insert(format!("item_{:03}", i), format!("value_{}", i));
221227
}
222228

223-
// Get first 5 items in ascending order
229+
// Get only the first 10 items
230+
let page = cache.list(
231+
ListProps::default()
232+
.order(Order::Asc)
233+
.limit(10) // Return maximum 10 items
234+
).unwrap();
235+
236+
println!("First page ({} items):", page.len());
237+
for (key, value) in &page {
238+
println!(" {} = {}", key, value);
239+
}
240+
}
241+
```
242+
243+
#### Cursor-Based Pagination with `start_after_key`
244+
245+
Use `start_after_key` to implement efficient cursor-based pagination:
246+
247+
```rust
248+
use quickleaf::{Quickleaf, ListProps, Order};
249+
250+
fn main() {
251+
let mut cache = Quickleaf::new(100);
252+
253+
// Add 30 items
254+
for i in 0..30 {
255+
cache.insert(format!("key_{:02}", i), i);
256+
}
257+
258+
// Get first page
224259
let page1 = cache.list(
225260
ListProps::default()
226261
.order(Order::Asc)
262+
.limit(10)
263+
).unwrap();
264+
265+
println!("Page 1: {} items", page1.len());
266+
let last_key = &page1.last().unwrap().0;
267+
println!("Last key in page 1: {}", last_key);
268+
269+
// Get second page using the last key from page 1
270+
let page2 = cache.list(
271+
ListProps::default()
272+
.order(Order::Asc)
273+
.start_after_key(last_key) // Continue after the last key
274+
.limit(10)
275+
).unwrap();
276+
277+
println!("Page 2: {} items starting after '{}'", page2.len(), last_key);
278+
for (key, value) in page2.iter().take(3) {
279+
println!(" {} = {}", key, value);
280+
}
281+
}
282+
```
283+
284+
#### Complete Pagination Example
285+
286+
Here's a comprehensive example showing how to paginate through all items:
287+
288+
```rust
289+
use quickleaf::{Quickleaf, ListProps, Order};
290+
291+
fn main() {
292+
let mut cache = Quickleaf::new(200);
293+
294+
// Insert 100 items
295+
for i in 0..100 {
296+
cache.insert(format!("doc_{:03}", i), format!("content_{}", i));
297+
}
298+
299+
// Paginate through all items
300+
let mut all_items = Vec::new();
301+
let mut current_key: Option<String> = None;
302+
let page_size = 25;
303+
let mut page_num = 1;
304+
305+
loop {
306+
// Build pagination properties
307+
let mut props = ListProps::default()
308+
.order(Order::Asc)
309+
.limit(page_size);
310+
311+
// Add start_after_key if we have a cursor
312+
if let Some(ref key) = current_key {
313+
props = props.start_after_key(key);
314+
}
315+
316+
// Get the page
317+
let page = cache.list(props).unwrap();
318+
319+
// Break if no more items
320+
if page.is_empty() {
321+
break;
322+
}
323+
324+
println!("Page {}: {} items", page_num, page.len());
325+
326+
// Collect items and update cursor
327+
for (key, value) in &page {
328+
all_items.push((key.clone(), value.clone()));
329+
}
330+
current_key = Some(page.last().unwrap().0.clone());
331+
page_num += 1;
332+
}
333+
334+
println!("Total pages: {}", page_num - 1);
335+
println!("Total items: {}", all_items.len());
336+
}
337+
```
338+
339+
#### Pagination with Filtering
340+
341+
Combine pagination with filtering for more complex queries:
342+
343+
```rust
344+
use quickleaf::{Quickleaf, ListProps, Order, Filter};
345+
346+
fn main() {
347+
let mut cache = Quickleaf::new(100);
348+
349+
// Add mixed data
350+
for i in 0..30 {
351+
cache.insert(format!("user_{:02}", i), format!("User {}", i));
352+
cache.insert(format!("admin_{:02}", i), format!("Admin {}", i));
353+
}
354+
355+
// Paginate through users only
356+
let mut user_cursor: Option<String> = None;
357+
let mut page = 1;
358+
359+
loop {
360+
let mut props = ListProps::default()
361+
.filter(Filter::StartWith("user_".to_string()))
362+
.order(Order::Asc)
363+
.limit(5);
364+
365+
if let Some(ref cursor) = user_cursor {
366+
props = props.start_after_key(cursor);
367+
}
368+
369+
let users = cache.list(props).unwrap();
370+
371+
if users.is_empty() {
372+
break;
373+
}
374+
375+
println!("User page {}: {} users", page, users.len());
376+
for (key, value) in &users {
377+
println!(" {} = {}", key, value);
378+
}
379+
380+
user_cursor = Some(users.last().unwrap().0.clone());
381+
page += 1;
382+
}
383+
}
384+
```
385+
386+
#### Descending Order Pagination
387+
388+
`start_after_key` works correctly with descending order:
389+
390+
```rust
391+
use quickleaf::{Quickleaf, ListProps, Order};
392+
393+
fn main() {
394+
let mut cache = Quickleaf::new(50);
395+
396+
// Add items
397+
for i in 0..20 {
398+
cache.insert(format!("item_{:02}", i), i);
399+
}
400+
401+
// Get first page in descending order
402+
let page1 = cache.list(
403+
ListProps::default()
404+
.order(Order::Desc)
405+
.limit(5)
227406
).unwrap();
228407

229-
println!("First 5 items:");
230-
for (i, (key, value)) in page1.iter().take(5).enumerate() {
231-
println!(" {}: {} = {}", i+1, key, value);
408+
println!("Descending page 1:");
409+
for (key, _) in &page1 {
410+
println!(" {}", key);
232411
}
233412

234-
// Get top 3 items in descending order
235-
let desc_items = cache.list(
413+
// Get next page (continuing in descending order)
414+
let last_key = &page1.last().unwrap().0;
415+
let page2 = cache.list(
236416
ListProps::default()
237417
.order(Order::Desc)
418+
.start_after_key(last_key)
419+
.limit(5)
238420
).unwrap();
239421

240-
println!("Top 3 items (desc):");
241-
for (key, value) in desc_items.iter().take(3) {
242-
println!(" {}: {}", key, value);
422+
println!("\nDescending page 2 (after '{}'):", last_key);
423+
for (key, _) in &page2 {
424+
println!(" {}", key);
243425
}
244426
}
245427
```
246428

429+
#### Edge Cases and Best Practices
430+
431+
```rust
432+
use quickleaf::{Quickleaf, ListProps};
433+
434+
fn main() {
435+
let mut cache = Quickleaf::new(10);
436+
cache.insert("a", 1);
437+
cache.insert("b", 2);
438+
cache.insert("c", 3);
439+
440+
// Edge case: limit of 0 returns empty list
441+
let empty = cache.list(ListProps::default().limit(0)).unwrap();
442+
assert_eq!(empty.len(), 0);
443+
444+
// Edge case: limit greater than total items returns all
445+
let all = cache.list(ListProps::default().limit(100)).unwrap();
446+
assert_eq!(all.len(), 3);
447+
448+
// Edge case: start_after_key with non-existent key returns error
449+
let result = cache.list(
450+
ListProps::default().start_after_key("non_existent")
451+
);
452+
assert!(result.is_err());
453+
454+
// Best practice: Always check if page is empty to detect end
455+
let last_page = cache.list(
456+
ListProps::default().start_after_key("c")
457+
).unwrap();
458+
assert!(last_page.is_empty()); // No items after "c"
459+
}
460+
```
461+
462+
#### Performance Tips
463+
464+
- **Use appropriate page sizes**: Balance between memory usage and number of queries (typically 10-100 items)
465+
- **Cache cursors**: Store the last key for efficient pagination state management
466+
- **Combine with filters**: Apply filters to reduce the dataset before pagination
467+
- **Handle errors gracefully**: Check for non-existent keys when using `start_after_key`
468+
247469
### 💾 Persistent Cache (SQLite Backend)
248470

249471
Quickleaf supports optional persistence using SQLite as a backing store. This provides durability across application restarts while maintaining the same high-performance in-memory operations.

0 commit comments

Comments
 (0)