1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//! Pagination utilities for cursor and keyset pagination.
//!
//! # Pagination Strategies
//!
//! | Strategy | Jump to Page | Performance | Stability | Use Case |
//! |------------|--------------|-------------|-----------|------------------------|
//! | **Offset** | Yes | O(n) skip | Unstable* | Admin panels, reports |
//! | **Cursor** | No | O(1) | Stable | Feeds, infinite scroll |
//! | **Keyset** | No | O(1) | Stable | Large datasets, APIs |
//!
//! *Unstable = results shift if data changes between requests
//!
//! # Cursor Pagination Example
//!
//! ```
//! use mik_sql::{postgres, Cursor, PageInfo, SortDir};
//!
//! // Build cursor from last item's values
//! let cursor = Cursor::new()
//! .string("created_at", "2024-01-15T10:00:00Z")
//! .int("id", 42);
//!
//! // Build query with cursor pagination
//! let result = postgres("users")
//! .fields(&["id", "name", "created_at"])
//! .sort("created_at", SortDir::Desc)
//! .sort("id", SortDir::Asc)
//! .after_cursor(cursor)
//! .limit(20)
//! .build();
//!
//! assert!(result.sql.contains("ORDER BY created_at DESC, id ASC"));
//!
//! // Create page info for response
//! let page_info = PageInfo::new(20, 20)
//! .with_next_cursor(Some("encoded_cursor".to_string()));
//! assert!(page_info.has_next);
//! ```
//!
//! # DX Features
//!
//! The `after_cursor` and `before_cursor` methods accept any type implementing `IntoCursor`:
//! - `&Cursor` - Already parsed cursor
//! - `&str` / `String` - Automatically decoded from base64
//! - `Option<&str>` - Perfect for `req.query("after")`
//!
//! Invalid or missing cursors are silently ignored, making the API resilient.
// Re-export all public items
pub use ;
pub use KeysetCondition;
pub use PageInfo;