#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CursorPosition(String);
impl CursorPosition {
#[must_use]
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct TotalCount(u64);
impl TotalCount {
#[must_use]
pub const fn new(value: u64) -> Self {
Self(value)
}
#[must_use]
pub const fn value(self) -> u64 {
self.0
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct HasMore(bool);
impl HasMore {
#[must_use]
pub const fn new(value: bool) -> Self {
Self(value)
}
#[must_use]
pub const fn value(self) -> bool {
self.0
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ResultSetMetadata {
total_count: Option<TotalCount>,
has_more: HasMore,
}
impl ResultSetMetadata {
#[must_use]
pub const fn new(total_count: Option<TotalCount>, has_more: HasMore) -> Self {
Self {
total_count,
has_more,
}
}
#[must_use]
pub const fn total_count(&self) -> Option<TotalCount> {
self.total_count
}
#[must_use]
pub const fn has_more(&self) -> HasMore {
self.has_more
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ResultSet<T> {
items: Vec<T>,
metadata: ResultSetMetadata,
}
impl<T> ResultSet<T> {
#[must_use]
pub const fn new(items: Vec<T>, metadata: ResultSetMetadata) -> Self {
Self { items, metadata }
}
#[must_use]
pub fn items(&self) -> &[T] {
&self.items
}
#[must_use]
pub const fn metadata(&self) -> &ResultSetMetadata {
&self.metadata
}
#[must_use]
pub fn len(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct PageInfo {
cursor: Option<CursorPosition>,
total_count: Option<TotalCount>,
has_more: HasMore,
}
impl PageInfo {
#[must_use]
pub const fn new(
cursor: Option<CursorPosition>,
total_count: Option<TotalCount>,
has_more: HasMore,
) -> Self {
Self {
cursor,
total_count,
has_more,
}
}
#[must_use]
pub const fn cursor(&self) -> Option<&CursorPosition> {
self.cursor.as_ref()
}
#[must_use]
pub const fn has_more(&self) -> HasMore {
self.has_more
}
#[must_use]
pub const fn total_count(&self) -> Option<TotalCount> {
self.total_count
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ResultPage<T> {
items: Vec<T>,
page_info: PageInfo,
}
impl<T> ResultPage<T> {
#[must_use]
pub const fn new(items: Vec<T>, page_info: PageInfo) -> Self {
Self { items, page_info }
}
#[must_use]
pub fn items(&self) -> &[T] {
&self.items
}
#[must_use]
pub const fn page_info(&self) -> &PageInfo {
&self.page_info
}
}
#[cfg(test)]
mod tests {
use super::{
CursorPosition, HasMore, PageInfo, ResultPage, ResultSet, ResultSetMetadata, TotalCount,
};
#[test]
fn stores_result_sets_and_pages() {
let metadata = ResultSetMetadata::new(Some(TotalCount::new(2)), HasMore::new(false));
let result_set = ResultSet::new(vec!["a", "b"], metadata);
let page_info = PageInfo::new(
Some(CursorPosition::new("next")),
Some(TotalCount::new(2)),
HasMore::new(true),
);
let page = ResultPage::new(vec![1, 2], page_info);
assert_eq!(result_set.len(), 2);
assert!(!result_set.is_empty());
assert_eq!(
result_set.metadata().total_count().expect("total").value(),
2
);
assert_eq!(page.page_info().cursor().expect("cursor").as_str(), "next");
assert!(page.page_info().has_more().value());
}
}