#![warn(missing_docs)]
#![warn(clippy::all)]
pub mod policy;
pub mod prelude;
#[cfg(feature = "streams")]
pub mod stream;
pub mod transaction;
pub use async_trait::async_trait;
#[must_use]
pub const fn const_str_eq(a: &str, b: &str) -> bool {
let a = a.as_bytes();
let b = b.as_bytes();
if a.len() != b.len() {
return false;
}
let mut i = 0;
while i < a.len() {
if a[i] != b[i] {
return false;
}
i += 1;
}
true
}
pub trait Repository: Send + Sync {
type Error: std::error::Error + Send + Sync;
type Pool;
fn pool(&self) -> &Self::Pool;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Pagination {
pub limit: i64,
pub offset: i64
}
impl Pagination {
#[must_use]
pub const fn new(limit: i64, offset: i64) -> Self {
Self {
limit,
offset
}
}
#[must_use]
pub const fn page(page: i64, per_page: i64) -> Self {
Self {
limit: per_page,
offset: page * per_page
}
}
}
impl Default for Pagination {
fn default() -> Self {
Self {
limit: 100,
offset: 0
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SortDirection {
#[default]
Asc,
Desc
}
impl SortDirection {
#[must_use]
pub const fn as_sql(&self) -> &'static str {
match self {
Self::Asc => "ASC",
Self::Desc => "DESC"
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EventKind {
Created,
Updated,
SoftDeleted,
HardDeleted,
Restored
}
impl EventKind {
#[must_use]
pub const fn is_delete(&self) -> bool {
matches!(self, Self::SoftDeleted | Self::HardDeleted)
}
#[must_use]
pub const fn is_mutation(&self) -> bool {
!matches!(self, Self::Restored)
}
}
pub trait EntityEvent: Send + Sync + std::fmt::Debug {
type Id;
fn kind(&self) -> EventKind;
fn entity_id(&self) -> &Self::Id;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CommandKind {
Create,
Update,
Delete,
Custom
}
impl CommandKind {
#[must_use]
pub const fn is_create(&self) -> bool {
matches!(self, Self::Create)
}
#[must_use]
pub const fn is_mutation(&self) -> bool {
!matches!(self, Self::Custom)
}
}
pub trait EntityCommand: Send + Sync + std::fmt::Debug {
fn kind(&self) -> CommandKind;
fn name(&self) -> &'static str;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pagination_new() {
let p = Pagination::new(50, 100);
assert_eq!(p.limit, 50);
assert_eq!(p.offset, 100);
}
#[test]
fn pagination_page() {
let p = Pagination::page(2, 25);
assert_eq!(p.limit, 25);
assert_eq!(p.offset, 50);
}
#[test]
fn pagination_default() {
let p = Pagination::default();
assert_eq!(p.limit, 100);
assert_eq!(p.offset, 0);
}
#[test]
fn sort_direction_sql() {
assert_eq!(SortDirection::Asc.as_sql(), "ASC");
assert_eq!(SortDirection::Desc.as_sql(), "DESC");
}
#[test]
fn sort_direction_default() {
assert_eq!(SortDirection::default(), SortDirection::Asc);
}
#[test]
fn event_kind_is_delete() {
assert!(!EventKind::Created.is_delete());
assert!(!EventKind::Updated.is_delete());
assert!(EventKind::SoftDeleted.is_delete());
assert!(EventKind::HardDeleted.is_delete());
assert!(!EventKind::Restored.is_delete());
}
#[test]
fn event_kind_is_mutation() {
assert!(EventKind::Created.is_mutation());
assert!(EventKind::Updated.is_mutation());
assert!(EventKind::SoftDeleted.is_mutation());
assert!(EventKind::HardDeleted.is_mutation());
assert!(!EventKind::Restored.is_mutation());
}
#[test]
fn command_kind_is_create() {
assert!(CommandKind::Create.is_create());
assert!(!CommandKind::Update.is_create());
assert!(!CommandKind::Delete.is_create());
assert!(!CommandKind::Custom.is_create());
}
#[test]
fn command_kind_is_mutation() {
assert!(CommandKind::Create.is_mutation());
assert!(CommandKind::Update.is_mutation());
assert!(CommandKind::Delete.is_mutation());
assert!(!CommandKind::Custom.is_mutation());
}
#[test]
fn const_str_eq_equal_strings() {
assert!(const_str_eq("order_status", "order_status"));
assert!(const_str_eq("", ""));
}
#[test]
fn const_str_eq_different_lengths() {
assert!(!const_str_eq("order", "order_status"));
assert!(!const_str_eq("order_status", ""));
}
#[test]
fn const_str_eq_same_length_different_content() {
assert!(!const_str_eq("order_status", "order_states"));
assert!(!const_str_eq("abc", "abd"));
}
#[test]
fn const_str_eq_in_const_context() {
const OK: bool = const_str_eq("user_role", "user_role");
const MISMATCH: bool = const_str_eq("user_role", "user_rank");
assert_eq!((OK, MISMATCH), (true, false));
}
}