refactor(tests): reformat code and update dependency management
- Reorganized import statements in adapter tests for better readability - Replaced or_insert_with(Vec::new) with or_default() in test closures - Updated Cargo.lock with new dependency versions and checksums - Added TLS features to tonic dependency configuration - Included sqlx, chrono, and uuid dependencies with specific features - Added jsonwebtoken and arc-swap as project dependencies - Reformatted assertion statements to comply with line length limits - Adjusted base64 import order in engine codec module - Updated protobuf include statement formatting
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
//! Cursor-based pagination helpers for repository queries.
|
||||
//!
|
||||
//! UUID v7 IDs are time-ordered, so `WHERE id < $cursor ORDER BY id DESC`
|
||||
//! naturally yields reverse-chronological pages without OFFSET.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Default number of items per page.
|
||||
pub const DEFAULT_PAGE_SIZE: i64 = 50;
|
||||
/// Hard upper bound on page size to prevent abuse.
|
||||
pub const MAX_PAGE_SIZE: i64 = 100;
|
||||
|
||||
/// Generic cursor-based page response.
|
||||
///
|
||||
/// Returned by list operations in the repo layer. The `next_cursor`
|
||||
/// is the last item's UUID — pass it as `before` in the next request.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CursorPage<T> {
|
||||
/// Items in this page (ordered by `id DESC`).
|
||||
pub items: Vec<T>,
|
||||
/// Opaque cursor for the next page. `None` when no more results exist.
|
||||
pub next_cursor: Option<Uuid>,
|
||||
/// Whether there are more results beyond this page.
|
||||
pub has_more: bool,
|
||||
}
|
||||
|
||||
impl<T> CursorPage<T> {
|
||||
/// Build a page from a raw result set that may contain one extra row.
|
||||
///
|
||||
/// If `raw_items.len() > limit`, the extra row is dropped and
|
||||
/// `has_more` is set to `true`.
|
||||
pub fn from_raw(mut raw_items: Vec<T>, limit: i64, get_id: impl Fn(&T) -> Uuid) -> Self {
|
||||
let has_more = raw_items.len() > limit as usize;
|
||||
if has_more {
|
||||
raw_items.truncate(limit as usize);
|
||||
}
|
||||
let next_cursor = if has_more {
|
||||
raw_items.last().map(get_id)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Self {
|
||||
items: raw_items,
|
||||
next_cursor,
|
||||
has_more,
|
||||
}
|
||||
}
|
||||
|
||||
/// Empty page (no results).
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
items: Vec::new(),
|
||||
next_cursor: None,
|
||||
has_more: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clamp a caller-requested limit to `[1, MAX_PAGE_SIZE]`, defaulting to `DEFAULT_PAGE_SIZE`.
|
||||
pub fn clamp_limit(limit: Option<i64>) -> i64 {
|
||||
match limit {
|
||||
Some(n) if n < 1 => DEFAULT_PAGE_SIZE,
|
||||
Some(n) if n > MAX_PAGE_SIZE => MAX_PAGE_SIZE,
|
||||
Some(n) => n,
|
||||
None => DEFAULT_PAGE_SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_clamp_limit_none() {
|
||||
assert_eq!(clamp_limit(None), DEFAULT_PAGE_SIZE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clamp_limit_zero() {
|
||||
assert_eq!(clamp_limit(Some(0)), DEFAULT_PAGE_SIZE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clamp_limit_negative() {
|
||||
assert_eq!(clamp_limit(Some(-5)), DEFAULT_PAGE_SIZE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clamp_limit_over_max() {
|
||||
assert_eq!(clamp_limit(Some(200)), MAX_PAGE_SIZE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clamp_limit_valid() {
|
||||
assert_eq!(clamp_limit(Some(25)), 25);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cursor_page_empty() {
|
||||
let page: CursorPage<String> = CursorPage::empty();
|
||||
assert!(page.items.is_empty());
|
||||
assert!(!page.has_more);
|
||||
assert!(page.next_cursor.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cursor_page_from_raw_no_overflow() {
|
||||
let items = vec!["a".to_string(), "b".to_string()];
|
||||
let page = CursorPage::from_raw(items, 5, |_| Uuid::nil());
|
||||
assert_eq!(page.items.len(), 2);
|
||||
assert!(!page.has_more);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user