191 lines
5.9 KiB
Rust
191 lines
5.9 KiB
Rust
use chrono::Utc;
|
|
use rand::random;
|
|
use uuid::Uuid;
|
|
|
|
mod conn_provider;
|
|
mod filter;
|
|
mod helpers;
|
|
pub mod models;
|
|
mod pagination;
|
|
pub mod repositories;
|
|
mod transaction;
|
|
mod value;
|
|
|
|
pub use pagination::{Page, PageRequest};
|
|
// transaction! macro is exported via #[macro_export] in transaction.rs
|
|
|
|
// Re-export the sqlx_record_derive module on feature flag
|
|
#[cfg(feature = "derive")]
|
|
pub use sqlx_record_derive::{Entity, Update};
|
|
|
|
/// Creates a time-ordered UUID with timestamp prefix for better database indexing.
|
|
/// First 8 bytes: millisecond timestamp (big-endian)
|
|
/// Last 8 bytes: random data
|
|
#[inline]
|
|
pub fn new_uuid() -> Uuid {
|
|
let timestamp = Utc::now().timestamp_millis() as u64;
|
|
let random = random::<u64>();
|
|
let mut bytes = [0u8; 16];
|
|
bytes[..8].copy_from_slice(×tamp.to_be_bytes());
|
|
bytes[8..].copy_from_slice(&random.to_be_bytes());
|
|
|
|
Uuid::from_bytes(bytes)
|
|
}
|
|
|
|
/// Creates a lookup table entity struct with an associated code enum.
|
|
///
|
|
/// Generates:
|
|
/// - A struct with `code`, `name`, `description`, and `is_active` fields
|
|
/// - An enum `{Name}Code` with variants for each code
|
|
/// - Constants on the struct for each code string
|
|
/// - `Display` impl for the enum
|
|
/// - `TryFrom<&str>` impl for the enum
|
|
///
|
|
/// # Example
|
|
/// ```ignore
|
|
/// lookup_table!(UserStatus, "active", "inactive", "suspended");
|
|
/// // Creates:
|
|
/// // - struct UserStatus { code, name, description, is_active }
|
|
/// // - enum UserStatusCode { Active, Inactive, Suspended }
|
|
/// // - UserStatus::ACTIVE, UserStatus::INACTIVE, UserStatus::SUSPENDED constants
|
|
/// ```
|
|
#[macro_export]
|
|
macro_rules! lookup_table {
|
|
($name:ident, $($code:literal),+ $(,)?) => {
|
|
#[allow(dead_code)]
|
|
#[derive(Debug, Clone, sqlx_record::Entity, sqlx::FromRow)]
|
|
pub struct $name {
|
|
#[primary_key]
|
|
pub code: String,
|
|
pub name: String,
|
|
pub description: String,
|
|
pub is_active: bool,
|
|
}
|
|
|
|
paste::paste! {
|
|
#[allow(dead_code)]
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum [<$name Code>] {
|
|
$(
|
|
#[allow(non_camel_case_types)]
|
|
[<$code:camel>],
|
|
)+
|
|
}
|
|
|
|
impl std::fmt::Display for [<$name Code>] {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
$(
|
|
[<$name Code>]::[<$code:camel>] => write!(f, $code),
|
|
)+
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
impl $name {
|
|
$(
|
|
pub const [<$code:upper>]: &'static str = $code;
|
|
)+
|
|
}
|
|
|
|
impl TryFrom<&str> for [<$name Code>] {
|
|
type Error = String;
|
|
|
|
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
|
match s {
|
|
$(
|
|
$code => Ok([<$name Code>]::[<$code:camel>]),
|
|
)+
|
|
_ => Err(format!("Unknown {} code: {}", stringify!($name).to_lowercase(), s)),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/// Creates a code enum without an associated entity struct.
|
|
///
|
|
/// Use this when you need type-safe code constants but the lookup data
|
|
/// is stored elsewhere or doesn't need CRUD operations.
|
|
///
|
|
/// Generates:
|
|
/// - An enum `{Name}Code` with variants for each code
|
|
/// - Constants on a unit struct for each code string
|
|
/// - `Display` impl for the enum
|
|
/// - `TryFrom<&str>` impl for the enum
|
|
///
|
|
/// # Example
|
|
/// ```ignore
|
|
/// lookup_options!(RefundPolicy, "pro-rata", "full-24-hours", "no-refunds");
|
|
/// // Creates:
|
|
/// // - enum RefundPolicyCode { ProRata, Full24Hours, NoRefunds }
|
|
/// // - RefundPolicy::PRO_RATA, RefundPolicy::FULL_24_HOURS, etc.
|
|
/// ```
|
|
#[macro_export]
|
|
macro_rules! lookup_options {
|
|
($name:ident, $($code:literal),+ $(,)?) => {
|
|
paste::paste! {
|
|
#[allow(dead_code)]
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub enum [<$name Code>] {
|
|
$(
|
|
#[allow(non_camel_case_types)]
|
|
[<$code:camel>],
|
|
)+
|
|
}
|
|
|
|
impl std::fmt::Display for [<$name Code>] {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
$(
|
|
[<$name Code>]::[<$code:camel>] => write!(f, $code),
|
|
)+
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Constants for code string values
|
|
#[allow(dead_code)]
|
|
pub struct $name;
|
|
|
|
#[allow(dead_code)]
|
|
impl $name {
|
|
$(
|
|
pub const [<$code:upper>]: &'static str = $code;
|
|
)+
|
|
}
|
|
|
|
impl TryFrom<&str> for [<$name Code>] {
|
|
type Error = String;
|
|
|
|
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
|
match s {
|
|
$(
|
|
$code => Ok([<$name Code>]::[<$code:camel>]),
|
|
)+
|
|
_ => Err(format!("Unknown {} code: {}", stringify!($name).to_lowercase(), s)),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
pub mod prelude {
|
|
pub use crate::filter::*;
|
|
pub use crate::pagination::{Page, PageRequest};
|
|
pub use crate::value::*;
|
|
pub use crate::values;
|
|
pub use crate::{filter_and as and, filter_or as or};
|
|
pub use crate::{filter_and, filter_or, filters, update_entity_func};
|
|
pub use crate::{lookup_options, lookup_table, new_uuid, transaction};
|
|
|
|
#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))]
|
|
pub use crate::conn_provider::ConnProvider;
|
|
|
|
#[cfg(feature = "derive")]
|
|
pub use sqlx_record_derive::{Entity, Update};
|
|
}
|