@@ -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
213219use quickleaf :: {Quickleaf , ListProps , Order };
214220
215221fn 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! (" \ n Descending 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
249471Quickleaf 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